table_walker.hh revision 7878:d3e6ebcccabf
16019Shines@cs.fsu.edu/*
210037SARM gem5 Developers * Copyright (c) 2010 ARM Limited
37093Sgblack@eecs.umich.edu * All rights reserved
47093Sgblack@eecs.umich.edu *
57093Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
67093Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
77093Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
87093Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
97093Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
107093Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
117093Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
127093Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
137093Sgblack@eecs.umich.edu *
146019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without
156019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are
166019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright
176019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer;
186019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright
196019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the
206019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution;
216019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its
226019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from
236019Shines@cs.fsu.edu * this software without specific prior written permission.
246019Shines@cs.fsu.edu *
256019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
276019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
296019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
306019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
316019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
326019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
336019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
346019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
356019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366019Shines@cs.fsu.edu *
376019Shines@cs.fsu.edu * Authors: Ali Saidi
386019Shines@cs.fsu.edu */
396019Shines@cs.fsu.edu
407399SAli.Saidi@ARM.com#ifndef __ARCH_ARM_TABLE_WALKER_HH__
417399SAli.Saidi@ARM.com#define __ARCH_ARM_TABLE_WALKER_HH__
426019Shines@cs.fsu.edu
436019Shines@cs.fsu.edu#include <list>
446019Shines@cs.fsu.edu
4510873Sandreas.sandberg@arm.com#include "arch/arm/miscregs.hh"
4610873Sandreas.sandberg@arm.com#include "arch/arm/tlb.hh"
4710474Sandreas.hansson@arm.com#include "mem/mem_object.hh"
486019Shines@cs.fsu.edu#include "mem/request.hh"
496019Shines@cs.fsu.edu#include "mem/request.hh"
506019Shines@cs.fsu.edu#include "params/ArmTableWalker.hh"
516116Snate@binkert.org#include "sim/eventq.hh"
526019Shines@cs.fsu.edu#include "sim/fault_fwd.hh"
538782Sgblack@eecs.umich.edu
548756Sgblack@eecs.umich.educlass DmaPort;
5510037SARM gem5 Developersclass ThreadContext;
5610037SARM gem5 Developers
576019Shines@cs.fsu.edunamespace ArmISA {
586019Shines@cs.fsu.educlass Translation;
596019Shines@cs.fsu.educlass TLB;
606019Shines@cs.fsu.edu
6110024Sdam.sunwoo@arm.comclass TableWalker : public MemObject
626019Shines@cs.fsu.edu{
638232Snate@binkert.org  public:
648232Snate@binkert.org    struct L1Descriptor {
658232Snate@binkert.org        /** Type of page table entry ARM DDI 0406B: B3-8*/
666116Snate@binkert.org        enum EntryType {
676116Snate@binkert.org            Ignore,
688756Sgblack@eecs.umich.edu            PageTable,
696019Shines@cs.fsu.edu            Section,
706019Shines@cs.fsu.edu            Reserved
716019Shines@cs.fsu.edu        };
726019Shines@cs.fsu.edu
736019Shines@cs.fsu.edu        /** The raw bits of the entry */
7410037SARM gem5 Developers        uint32_t data;
7510037SARM gem5 Developers
7610418Sandreas.hansson@arm.com        /** This entry has been modified (access flag set) and needs to be
7710418Sandreas.hansson@arm.com         * written back to memory */
7810822Sandreas.hansson@arm.com        bool _dirty;
7910537Sandreas.hansson@arm.com
8010537Sandreas.hansson@arm.com        EntryType type() const
8111152Smitch.hayenga@arm.com        {
826019Shines@cs.fsu.edu            return (EntryType)(data & 0x3);
8310037SARM gem5 Developers        }
847399SAli.Saidi@ARM.com
8510037SARM gem5 Developers        /** Is the page a Supersection (16MB)?*/
8610037SARM gem5 Developers        bool supersection() const
8710037SARM gem5 Developers        {
8810037SARM gem5 Developers            return bits(data, 18);
896019Shines@cs.fsu.edu        }
906019Shines@cs.fsu.edu
916019Shines@cs.fsu.edu        /** Return the physcal address of the entry, bits in position*/
926019Shines@cs.fsu.edu        Addr paddr() const
9310037SARM gem5 Developers        {
9410037SARM gem5 Developers            if (supersection())
9510037SARM gem5 Developers                panic("Super sections not implemented\n");
9610037SARM gem5 Developers            return mbits(data, 31,20);
9710037SARM gem5 Developers        }
9810037SARM gem5 Developers        /** Return the physcal address of the entry, bits in position*/
9910037SARM gem5 Developers        Addr paddr(Addr va) const
10010037SARM gem5 Developers        {
10110037SARM gem5 Developers            if (supersection())
10210037SARM gem5 Developers                panic("Super sections not implemented\n");
10310037SARM gem5 Developers            return mbits(data, 31,20) | mbits(va, 20, 0);
10410717Sandreas.hansson@arm.com        }
10510037SARM gem5 Developers
10610037SARM gem5 Developers
10710717Sandreas.hansson@arm.com        /** Return the physical frame, bits shifted right */
1086019Shines@cs.fsu.edu        Addr pfn() const
1096019Shines@cs.fsu.edu        {
1107694SAli.Saidi@ARM.com            if (supersection())
1117694SAli.Saidi@ARM.com                panic("Super sections not implemented\n");
1127694SAli.Saidi@ARM.com            return bits(data, 31,20);
11310037SARM gem5 Developers        }
11410037SARM gem5 Developers
11510037SARM gem5 Developers        /** Is the translation global (no asid used)? */
11610037SARM gem5 Developers        bool global() const
11710037SARM gem5 Developers        {
11810037SARM gem5 Developers            return bits(data, 17);
11910037SARM gem5 Developers        }
12010037SARM gem5 Developers
12110037SARM gem5 Developers        /** Is the translation not allow execution? */
1227694SAli.Saidi@ARM.com        bool xn() const
1237694SAli.Saidi@ARM.com        {
1247694SAli.Saidi@ARM.com            return bits(data, 4);
1257694SAli.Saidi@ARM.com        }
1267694SAli.Saidi@ARM.com
1277694SAli.Saidi@ARM.com        /** Three bit access protection flags */
1289738Sandreas@sandberg.pp.se        uint8_t ap() const
1299738Sandreas@sandberg.pp.se        {
1309738Sandreas@sandberg.pp.se            return (bits(data, 15) << 2) | bits(data,11,10);
1319738Sandreas@sandberg.pp.se        }
1329738Sandreas@sandberg.pp.se
1339738Sandreas@sandberg.pp.se        /** Domain Client/Manager: ARM DDI 0406B: B3-31 */
1347404SAli.Saidi@ARM.com        uint8_t domain() const
13510037SARM gem5 Developers        {
13610037SARM gem5 Developers            return bits(data,8,5);
1376019Shines@cs.fsu.edu        }
1387404SAli.Saidi@ARM.com
1397404SAli.Saidi@ARM.com        /** Address of L2 descriptor if it exists */
1407404SAli.Saidi@ARM.com        Addr l2Addr() const
14110037SARM gem5 Developers        {
1427404SAli.Saidi@ARM.com            return mbits(data, 31,10);
1437404SAli.Saidi@ARM.com        }
14410037SARM gem5 Developers
14510037SARM gem5 Developers        /** Memory region attributes: ARM DDI 0406B: B3-32.
14610037SARM gem5 Developers         * These bits are largly ignored by M5 and only used to
14710037SARM gem5 Developers         * provide the illusion that the memory system cares about
14810037SARM gem5 Developers         * anything but cachable vs. uncachable.
1499535Smrinmoy.ghosh@arm.com         */
1507697SAli.Saidi@ARM.com        uint8_t texcb() const
1517697SAli.Saidi@ARM.com        {
15210037SARM gem5 Developers            return bits(data, 2) | bits(data,3) << 1 | bits(data, 14, 12) << 2;
1537697SAli.Saidi@ARM.com        }
1547697SAli.Saidi@ARM.com
1557697SAli.Saidi@ARM.com        /** If the section is shareable. See texcb() comment. */
1567697SAli.Saidi@ARM.com        bool shareable() const
1577697SAli.Saidi@ARM.com        {
1587404SAli.Saidi@ARM.com            return bits(data, 16);
1597404SAli.Saidi@ARM.com        }
16010037SARM gem5 Developers
1617404SAli.Saidi@ARM.com        /** Set access flag that this entry has been touched. Mark
1627404SAli.Saidi@ARM.com         * the entry as requiring a writeback, in the future.
16310037SARM gem5 Developers         */
16410037SARM gem5 Developers        void setAp0()
16510037SARM gem5 Developers        {
16610037SARM gem5 Developers            data |= 1 << 10;
16710037SARM gem5 Developers            _dirty = true;
16810037SARM gem5 Developers        }
16910037SARM gem5 Developers
17010037SARM gem5 Developers        /** This entry needs to be written back to memory */
17110367SAndrew.Bardsley@arm.com        bool dirty() const
17210037SARM gem5 Developers        {
1737404SAli.Saidi@ARM.com            return _dirty;
1746019Shines@cs.fsu.edu        }
1756019Shines@cs.fsu.edu    };
1766019Shines@cs.fsu.edu
1776019Shines@cs.fsu.edu    /** Level 2 page table descriptor */
1787404SAli.Saidi@ARM.com    struct L2Descriptor {
1796019Shines@cs.fsu.edu
1807404SAli.Saidi@ARM.com        /** The raw bits of the entry. */
18110037SARM gem5 Developers        uint32_t data;
18210037SARM gem5 Developers
18310037SARM gem5 Developers        /** This entry has been modified (access flag set) and needs to be
18410037SARM gem5 Developers         * written back to memory */
18510037SARM gem5 Developers        bool _dirty;
18610037SARM gem5 Developers
1877404SAli.Saidi@ARM.com        /** Is the entry invalid */
18810037SARM gem5 Developers        bool invalid() const
18910037SARM gem5 Developers        {
19010037SARM gem5 Developers            return bits(data, 1,0) == 0;;
1917697SAli.Saidi@ARM.com        }
19210037SARM gem5 Developers
19310037SARM gem5 Developers        /** What is the size of the mapping? */
19410037SARM gem5 Developers        bool large() const
19510037SARM gem5 Developers        {
1967404SAli.Saidi@ARM.com            return bits(data, 1) == 0;
1977697SAli.Saidi@ARM.com        }
1987404SAli.Saidi@ARM.com
19910037SARM gem5 Developers        /** Is execution allowed on this mapping? */
20010037SARM gem5 Developers        bool xn() const
2017697SAli.Saidi@ARM.com        {
2027734SAli.Saidi@ARM.com            return large() ? bits(data, 15) : bits(data, 0);
2037734SAli.Saidi@ARM.com        }
20410463SAndreas.Sandberg@ARM.com
2056019Shines@cs.fsu.edu        /** Is the translation global (no asid used)? */
2066019Shines@cs.fsu.edu        bool global() const
2076019Shines@cs.fsu.edu        {
20810037SARM gem5 Developers            return !bits(data, 11);
2097404SAli.Saidi@ARM.com        }
2107404SAli.Saidi@ARM.com
2117404SAli.Saidi@ARM.com        /** Three bit access protection flags */
2127404SAli.Saidi@ARM.com        uint8_t ap() const
2137404SAli.Saidi@ARM.com        {
21410037SARM gem5 Developers           return bits(data, 5, 4) | (bits(data, 9) << 2);
21510037SARM gem5 Developers        }
21610037SARM gem5 Developers
21710037SARM gem5 Developers        /** Memory region attributes: ARM DDI 0406B: B3-32 */
2187404SAli.Saidi@ARM.com        uint8_t texcb() const
2197404SAli.Saidi@ARM.com        {
2207404SAli.Saidi@ARM.com            return large() ?
2217404SAli.Saidi@ARM.com                (bits(data, 2) | (bits(data,3) << 1) | (bits(data, 14, 12) << 2)) :
22210037SARM gem5 Developers                (bits(data, 2) | (bits(data,3) << 1) | (bits(data, 8, 6) << 2));
2236019Shines@cs.fsu.edu        }
22410037SARM gem5 Developers
22510037SARM gem5 Developers        /** Return the physical frame, bits shifted right */
2267404SAli.Saidi@ARM.com        Addr pfn() const
2277404SAli.Saidi@ARM.com        {
2287404SAli.Saidi@ARM.com            return large() ? bits(data, 31, 16) : bits(data, 31, 12);
22910037SARM gem5 Developers        }
23010037SARM gem5 Developers
23110037SARM gem5 Developers        /** Return complete physical address given a VA */
23210037SARM gem5 Developers        Addr paddr(Addr va) const
23310037SARM gem5 Developers        {
23410037SARM gem5 Developers            if (large())
23510037SARM gem5 Developers                return mbits(data, 31, 16) | mbits(va, 15, 0);
23610037SARM gem5 Developers            else
23710037SARM gem5 Developers                return mbits(data, 31, 12) | mbits(va, 11, 0);
23810037SARM gem5 Developers        }
2397404SAli.Saidi@ARM.com
2407404SAli.Saidi@ARM.com        /** If the section is shareable. See texcb() comment. */
24110037SARM gem5 Developers        bool shareable() const
24210037SARM gem5 Developers        {
24310037SARM gem5 Developers            return bits(data, 10);
24410037SARM gem5 Developers        }
24510037SARM gem5 Developers
24610037SARM gem5 Developers        /** Set access flag that this entry has been touched. Mark
24710037SARM gem5 Developers         * the entry as requiring a writeback, in the future.
24810037SARM gem5 Developers         */
24910037SARM gem5 Developers        void setAp0()
25010037SARM gem5 Developers        {
25110037SARM gem5 Developers            data |= 1 << 4;
25210037SARM gem5 Developers            _dirty = true;
25310037SARM gem5 Developers        }
25410037SARM gem5 Developers
25510037SARM gem5 Developers        /** This entry needs to be written back to memory */
25610037SARM gem5 Developers        bool dirty() const
25710037SARM gem5 Developers        {
25810037SARM gem5 Developers            return _dirty;
25910037SARM gem5 Developers        }
26010037SARM gem5 Developers
26110037SARM gem5 Developers    };
26210037SARM gem5 Developers
26310037SARM gem5 Developers    struct WalkerState //: public SimObject
26410037SARM gem5 Developers    {
26510037SARM gem5 Developers        /** Thread context that we're doing the walk for */
26610037SARM gem5 Developers        ThreadContext *tc;
26710037SARM gem5 Developers
2687734SAli.Saidi@ARM.com        /** Request that is currently being serviced */
2697734SAli.Saidi@ARM.com        RequestPtr req;
27010037SARM gem5 Developers
27110037SARM gem5 Developers        /** Context ID that we're servicing the request under */
27210037SARM gem5 Developers        uint8_t contextId;
27310037SARM gem5 Developers
27410037SARM gem5 Developers        /** Translation state for delayed requests */
2756019Shines@cs.fsu.edu        TLB::Translation *transState;
2766019Shines@cs.fsu.edu
2777404SAli.Saidi@ARM.com        /** The fault that we are going to return */
27810037SARM gem5 Developers        Fault fault;
2797404SAli.Saidi@ARM.com
28010037SARM gem5 Developers        /** The virtual address that is being translated */
28110037SARM gem5 Developers        Addr vaddr;
28210037SARM gem5 Developers
28310037SARM gem5 Developers        /** Cached copy of the sctlr as it existed when translation began */
2847734SAli.Saidi@ARM.com        SCTLR sctlr;
2857404SAli.Saidi@ARM.com
2867404SAli.Saidi@ARM.com        /** Width of the base address held in TTRB0 */
2877404SAli.Saidi@ARM.com        uint32_t N;
28810037SARM gem5 Developers
2897404SAli.Saidi@ARM.com        /** If the access is a write */
29010037SARM gem5 Developers        bool isWrite;
29110037SARM gem5 Developers
2927404SAli.Saidi@ARM.com        /** If the access is a fetch (for execution, and no-exec) must be checked?*/
29310037SARM gem5 Developers        bool isFetch;
2947404SAli.Saidi@ARM.com
2957404SAli.Saidi@ARM.com        /** If the mode is timing or atomic */
2967404SAli.Saidi@ARM.com        bool timing;
2977404SAli.Saidi@ARM.com
29810037SARM gem5 Developers        /** Save mode for use in delayed response */
29910037SARM gem5 Developers        BaseTLB::Mode mode;
30010037SARM gem5 Developers
30110037SARM gem5 Developers        L1Descriptor l1Desc;
3027404SAli.Saidi@ARM.com        L2Descriptor l2Desc;
30310037SARM gem5 Developers
3047734SAli.Saidi@ARM.com        /** Whether L1/L2 descriptor response is delayed in timing mode */
3057404SAli.Saidi@ARM.com        bool delayed;
30610037SARM gem5 Developers
3077404SAli.Saidi@ARM.com        TableWalker *tableWalker;
3087734SAli.Saidi@ARM.com
3097404SAli.Saidi@ARM.com        void doL1Descriptor();
3107404SAli.Saidi@ARM.com        void doL2Descriptor();
3117404SAli.Saidi@ARM.com
31210037SARM gem5 Developers        std::string name() const {return tableWalker->name();}
3137404SAli.Saidi@ARM.com    };
31410037SARM gem5 Developers
31510037SARM gem5 Developers
31610037SARM gem5 Developers    /** Queue of requests that need processing first level translation */
31710037SARM gem5 Developers    std::list<WalkerState *> stateQueueL1;
31810037SARM gem5 Developers
3197404SAli.Saidi@ARM.com    /** Queue of requests that have passed first level translation and
32010037SARM gem5 Developers     * require an additional level. */
32110037SARM gem5 Developers    std::list<WalkerState *> stateQueueL2;
32210037SARM gem5 Developers
32310037SARM gem5 Developers    /** Queue of requests that have passed are waiting because the walker is
3247404SAli.Saidi@ARM.com     * currently busy. */
32510037SARM gem5 Developers    std::list<WalkerState *> pendingQueue;;
32610037SARM gem5 Developers
32710037SARM gem5 Developers
32810037SARM gem5 Developers    /** Port to issue translation requests from */
32910037SARM gem5 Developers    DmaPort *port;
33010037SARM gem5 Developers
33110037SARM gem5 Developers    /** TLB that is initiating these table walks */
3327404SAli.Saidi@ARM.com    TLB *tlb;
3337734SAli.Saidi@ARM.com
3347404SAli.Saidi@ARM.com    /** Cached copy of the sctlr as it existed when translation began */
33510037SARM gem5 Developers    SCTLR sctlr;
33610037SARM gem5 Developers
3377404SAli.Saidi@ARM.com    WalkerState *currState;
33810037SARM gem5 Developers
33910037SARM gem5 Developers    /** If a timing translation is currently in progress */
34010037SARM gem5 Developers    bool pending;
34110037SARM gem5 Developers
34210037SARM gem5 Developers  public:
34310037SARM gem5 Developers    typedef ArmTableWalkerParams Params;
34410037SARM gem5 Developers    TableWalker(const Params *p);
34510037SARM gem5 Developers    virtual ~TableWalker();
34610037SARM gem5 Developers
34710037SARM gem5 Developers    const Params *
34810037SARM gem5 Developers    params() const
34910037SARM gem5 Developers    {
35010037SARM gem5 Developers        return dynamic_cast<const Params *>(_params);
35110037SARM gem5 Developers    }
3527404SAli.Saidi@ARM.com
3537404SAli.Saidi@ARM.com    virtual unsigned int drain(Event *de);
3546019Shines@cs.fsu.edu    virtual void resume();
3559439SAndreas.Sandberg@ARM.com    virtual Port *getPort(const std::string &if_name, int idx = -1);
3569439SAndreas.Sandberg@ARM.com
3579439SAndreas.Sandberg@ARM.com    Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
3589439SAndreas.Sandberg@ARM.com            TLB::Translation *_trans, bool timing);
3599439SAndreas.Sandberg@ARM.com
3609439SAndreas.Sandberg@ARM.com    void setTlb(TLB *_tlb) { tlb = _tlb; }
3619439SAndreas.Sandberg@ARM.com    void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
3629439SAndreas.Sandberg@ARM.com                  uint8_t texcb, bool s);
36310194SGeoffrey.Blake@arm.com
36410194SGeoffrey.Blake@arm.com  private:
36510194SGeoffrey.Blake@arm.com
36610194SGeoffrey.Blake@arm.com    void doL1Descriptor();
36710194SGeoffrey.Blake@arm.com    void doL1DescriptorWrapper();
36810194SGeoffrey.Blake@arm.com    EventWrapper<TableWalker, &TableWalker::doL1DescriptorWrapper> doL1DescEvent;
36910194SGeoffrey.Blake@arm.com
37010194SGeoffrey.Blake@arm.com    void doL2Descriptor();
37110194SGeoffrey.Blake@arm.com    void doL2DescriptorWrapper();
37210194SGeoffrey.Blake@arm.com    EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
37310194SGeoffrey.Blake@arm.com
37410194SGeoffrey.Blake@arm.com    Fault processWalk();
37510194SGeoffrey.Blake@arm.com    void processWalkWrapper();
37610194SGeoffrey.Blake@arm.com    EventWrapper<TableWalker, &TableWalker::processWalkWrapper> doProcessEvent;
37710194SGeoffrey.Blake@arm.com
37810194SGeoffrey.Blake@arm.com    void nextWalk(ThreadContext *tc);
37910194SGeoffrey.Blake@arm.com};
38010194SGeoffrey.Blake@arm.com
38110194SGeoffrey.Blake@arm.com
38210194SGeoffrey.Blake@arm.com} // namespace ArmISA
38310194SGeoffrey.Blake@arm.com
38410194SGeoffrey.Blake@arm.com#endif //__ARCH_ARM_TABLE_WALKER_HH__
38510194SGeoffrey.Blake@arm.com
38610905Sandreas.sandberg@arm.com