semihosting.hh revision 13452
17090SN/A/*
27090SN/A * Copyright (c) 2018 ARM Limited
37090SN/A * All rights reserved
47090SN/A *
57090SN/A * The license below extends only to copyright in the software and shall
67090SN/A * not be construed as granting a license to any other intellectual
77090SN/A * property including but not limited to intellectual property relating
87090SN/A * to a hardware implementation of the functionality of the software
97090SN/A * licensed hereunder.  You may use the software subject to the license
107090SN/A * terms below provided that you ensure that this notice is replicated
117090SN/A * unmodified and in its entirety in all distributions of the software,
127090SN/A * modified or unmodified, in source code or in binary form.
134486SN/A *
144486SN/A * Redistribution and use in source and binary forms, with or without
154486SN/A * modification, are permitted provided that the following conditions are
164486SN/A * met: redistributions of source code must retain the above copyright
174486SN/A * notice, this list of conditions and the following disclaimer;
184486SN/A * redistributions in binary form must reproduce the above copyright
194486SN/A * notice, this list of conditions and the following disclaimer in the
204486SN/A * documentation and/or other materials provided with the distribution;
214486SN/A * neither the name of the copyright holders nor the names of its
224486SN/A * contributors may be used to endorse or promote products derived from
234486SN/A * this software without specific prior written permission.
244486SN/A *
254486SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
264486SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
274486SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
284486SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
294486SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
304486SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
314486SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
324486SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
334486SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
344486SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
354486SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
364486SN/A *
374486SN/A * Authors: Andreas Sandberg
384486SN/A */
397584SAli.Saidi@arm.com#ifndef __ARCH_ARM_SEMIHOSTING_HH__
407584SAli.Saidi@arm.com#define __ARCH_ARM_SEMIHOSTING_HH__
417754SWilliam.Wang@arm.com
424486SN/A#include <cstdio>
433630SN/A#include <map>
443630SN/A#include <memory>
457587SAli.Saidi@arm.com#include <utility>
468212SAli.Saidi@ARM.com#include <vector>
475478SN/A
485478SN/A#include "sim/sim_object.hh"
497584SAli.Saidi@arm.com
503630SN/Astruct ArmSemihostingParams;
517584SAli.Saidi@arm.comclass PortProxy;
527584SAli.Saidi@arm.comclass SerialDevice;
537584SAli.Saidi@arm.comclass ThreadContext;
547584SAli.Saidi@arm.com
553898SN/A/**
567950SAli.Saidi@ARM.com * Semihosting for AArch32 and AArch64
577950SAli.Saidi@ARM.com *
587950SAli.Saidi@ARM.com * This class implements the Arm semihosting interface. This interface
597950SAli.Saidi@ARM.com * allows baremetal code access service, such as IO, from the
607950SAli.Saidi@ARM.com * simulator. It is conceptually a simplified version of gem5's more
617950SAli.Saidi@ARM.com * general syscall emulation mode.
627950SAli.Saidi@ARM.com *
637950SAli.Saidi@ARM.com * Exits calls (SYS_EXIT, SYS_EXIT_EXTENDED) from the guest get
647587SAli.Saidi@arm.com * translated into simualtion exits. Well-known exit codes are
657587SAli.Saidi@arm.com * translated to messages on the form 'semi:ADP_.*' while unknown
667587SAli.Saidi@arm.com * codes are returned in hex ('semi:0x..'). The subcode is reported in
677753SWilliam.Wang@arm.com * the gem5 exit event.
687753SWilliam.Wang@arm.com */
697753SWilliam.Wang@arm.comclass ArmSemihosting : public SimObject
707753SWilliam.Wang@arm.com{
717587SAli.Saidi@arm.com  public:
727587SAli.Saidi@arm.com    ArmSemihosting(const ArmSemihostingParams *p);
738282SAli.Saidi@ARM.com
748282SAli.Saidi@ARM.com    /** Perform an Arm Semihosting call from aarch64 code. */
758282SAli.Saidi@ARM.com    uint64_t call64(ThreadContext *tc, uint32_t op, uint64_t param);
767584SAli.Saidi@arm.com    /** Perform an Arm Semihosting call from aarch32 code. */
777584SAli.Saidi@arm.com    uint32_t call32(ThreadContext *tc, uint32_t op, uint32_t param);
788524SAli.Saidi@ARM.com
798524SAli.Saidi@ARM.com  public: // SimObject and related interfaces
808299Schander.sudanthi@arm.com    void serialize(CheckpointOut &cp) const override;
817584SAli.Saidi@arm.com    void unserialize(CheckpointIn &cp) override;
827584SAli.Saidi@arm.com
837584SAli.Saidi@arm.com  protected: // Configuration
847584SAli.Saidi@arm.com    const std::string cmdLine;
857584SAli.Saidi@arm.com    const Addr memReserve;
867584SAli.Saidi@arm.com    const Addr stackSize;
878283SPrakash.Ramrakhyani@arm.com
888283SPrakash.Ramrakhyani@arm.com    /**
897584SAli.Saidi@arm.com     * Base time when the simulation started. This is used to
907584SAli.Saidi@arm.com     * calculate the time of date when the guest call SYS_TIME.
917584SAli.Saidi@arm.com     */
927584SAli.Saidi@arm.com    const time_t timeBase;
937584SAli.Saidi@arm.com
947584SAli.Saidi@arm.com    /** Number of bits to right shift gem5 ticks to fit in a uint32_t */
957584SAli.Saidi@arm.com    const unsigned tickShift;
967584SAli.Saidi@arm.com
977584SAli.Saidi@arm.com  protected: // Internal state
987584SAli.Saidi@arm.com    typedef uint64_t SemiErrno;
997584SAli.Saidi@arm.com    SemiErrno semiErrno;
1007584SAli.Saidi@arm.com
1017584SAli.Saidi@arm.com  protected: // File IO
1027584SAli.Saidi@arm.com    /**
1037584SAli.Saidi@arm.com     * Internal state for open files
1047584SAli.Saidi@arm.com     *
1057584SAli.Saidi@arm.com     * This class describes the internal state of a file opened
1067584SAli.Saidi@arm.com     * through the semihosting interface.
1077584SAli.Saidi@arm.com     *
1087584SAli.Saidi@arm.com     * A file instance is normally created using one of the
1097584SAli.Saidi@arm.com     * ArmSemihosting::FileBase::create() factory methods. These
1107584SAli.Saidi@arm.com     * methods handle some the magic file names in the Arm Semihosting
1117584SAli.Saidi@arm.com     * specification and instantiate the right implementation. For the
1128512Sgeoffrey.blake@arm.com     * same, when unserializing a checkpoint, the create method must
1138512Sgeoffrey.blake@arm.com     * be used to unserialize a new instance of a file descriptor.
1148512Sgeoffrey.blake@arm.com     */
1158512Sgeoffrey.blake@arm.com    class FileBase : public Serializable
1168512Sgeoffrey.blake@arm.com    {
1178512Sgeoffrey.blake@arm.com      public:
1188512Sgeoffrey.blake@arm.com        FileBase(ArmSemihosting &_parent, const char *name, const char *_mode)
1197950SAli.Saidi@ARM.com            : parent(_parent), _name(name), mode(_mode) {}
1207754SWilliam.Wang@arm.com        virtual ~FileBase() {};
1217950SAli.Saidi@ARM.com
1227950SAli.Saidi@ARM.com        FileBase() = delete;
1237950SAli.Saidi@ARM.com        FileBase(FileBase &) = delete;
1247754SWilliam.Wang@arm.com
1257754SWilliam.Wang@arm.com        static std::unique_ptr<FileBase> create(
1267753SWilliam.Wang@arm.com            ArmSemihosting &parent, const std::string &fname,
1277753SWilliam.Wang@arm.com            const char *mode);
1287753SWilliam.Wang@arm.com        static std::unique_ptr<FileBase> create(
1297950SAli.Saidi@ARM.com            ArmSemihosting &parent, CheckpointIn &cp, const std::string &sec);
1307753SWilliam.Wang@arm.com
1317753SWilliam.Wang@arm.com        void serialize(CheckpointOut &cp) const override;
1327584SAli.Saidi@arm.com        void unserialize(CheckpointIn &cp) override;
1337584SAli.Saidi@arm.com
1343630SN/A        const std::string &fileName() { return _name; }
1353630SN/A
1367753SWilliam.Wang@arm.com      public:
1377753SWilliam.Wang@arm.com        /** @{
1387753SWilliam.Wang@arm.com         * Semihosting file IO interfaces
1397584SAli.Saidi@arm.com         *
1407584SAli.Saidi@arm.com         * These interfaces implement common IO functionality in the
1417584SAli.Saidi@arm.com         * Semihosting interface.
1427584SAli.Saidi@arm.com         *
1437584SAli.Saidi@arm.com         * All functions return a negative value that corresponds to a
1447584SAli.Saidi@arm.com         * UNIX errno value when they fail and >=0 on success.
1458512Sgeoffrey.blake@arm.com         */
1467753SWilliam.Wang@arm.com
1477754SWilliam.Wang@arm.com        /**
1487950SAli.Saidi@ARM.com         * Open the the file.
1498282SAli.Saidi@ARM.com         *
1508212SAli.Saidi@ARM.com         * @return <0 on error (-errno), 0 on success.
1518212SAli.Saidi@ARM.com         */
1528212SAli.Saidi@ARM.com        virtual int64_t open() { return 0; }
1538212SAli.Saidi@ARM.com
1548212SAli.Saidi@ARM.com        /**
1558212SAli.Saidi@ARM.com         * Close the file.
1567584SAli.Saidi@arm.com         *
1577731SAli.Saidi@ARM.com         * @return <0 on error (-errno), 0 on success.
1588461SAli.Saidi@ARM.com         */
1598461SAli.Saidi@ARM.com        virtual int64_t close() { return 0; }
1607696SAli.Saidi@ARM.com
1617696SAli.Saidi@ARM.com        /**
1627696SAli.Saidi@ARM.com         * Check if a file corresponds to a TTY device.
1637696SAli.Saidi@ARM.com         *
1647696SAli.Saidi@ARM.com         * @return True if the file is a TTY, false otherwise.
1657696SAli.Saidi@ARM.com         */
1667696SAli.Saidi@ARM.com        virtual bool isTTY() const { return false; }
1677696SAli.Saidi@ARM.com
1687696SAli.Saidi@ARM.com        /**
1697696SAli.Saidi@ARM.com         * Read data from file.
1707696SAli.Saidi@ARM.com         *
1717696SAli.Saidi@ARM.com         * @return <0 on error (-errno), bytes read on success (0 for EOF).
1727696SAli.Saidi@ARM.com         */
1737696SAli.Saidi@ARM.com        virtual int64_t read(uint8_t *buffer, uint64_t size);
1747696SAli.Saidi@ARM.com
1757696SAli.Saidi@ARM.com        /**
1767696SAli.Saidi@ARM.com         * Write data to file.
1777696SAli.Saidi@ARM.com         *
1787696SAli.Saidi@ARM.com         * @return <0 on error (-errno), bytes written on success.
1797696SAli.Saidi@ARM.com         */
1807696SAli.Saidi@ARM.com        virtual int64_t write(const uint8_t *buffer, uint64_t size);
1818282SAli.Saidi@ARM.com
1828512Sgeoffrey.blake@arm.com        /**
1837696SAli.Saidi@ARM.com         * Seek to an absolute position in the file.
1847696SAli.Saidi@ARM.com         *
1857696SAli.Saidi@ARM.com         * @param pos Byte offset from start of file.
1867696SAli.Saidi@ARM.com         * @return <0 on error (-errno), 0 on success.
1877696SAli.Saidi@ARM.com         */
1887696SAli.Saidi@ARM.com        virtual int64_t seek(uint64_t pos);
1897696SAli.Saidi@ARM.com
1907696SAli.Saidi@ARM.com        /**
1917696SAli.Saidi@ARM.com         * Get the length of a file in bytes.
1927753SWilliam.Wang@arm.com         *
1937754SWilliam.Wang@arm.com         * @return <0 on error (-errno), length on success
1947754SWilliam.Wang@arm.com         */
1958212SAli.Saidi@ARM.com        virtual int64_t flen();
1967696SAli.Saidi@ARM.com
1977696SAli.Saidi@ARM.com        /** @} */
1987696SAli.Saidi@ARM.com
1997696SAli.Saidi@ARM.com      protected:
2007696SAli.Saidi@ARM.com        ArmSemihosting &parent;
2017696SAli.Saidi@ARM.com        std::string _name;
2027696SAli.Saidi@ARM.com        std::string mode;
2037696SAli.Saidi@ARM.com    };
2047696SAli.Saidi@ARM.com
2057696SAli.Saidi@ARM.com    /** Implementation of the ':semihosting-features' magic file. */
2067696SAli.Saidi@ARM.com    class FileFeatures : public FileBase
2077696SAli.Saidi@ARM.com    {
2087696SAli.Saidi@ARM.com      public:
2097696SAli.Saidi@ARM.com        FileFeatures(ArmSemihosting &_parent,
2107696SAli.Saidi@ARM.com                     const char *name, const char *mode);
2117696SAli.Saidi@ARM.com
2127696SAli.Saidi@ARM.com        void serialize(CheckpointOut &cp) const override;
2137754SWilliam.Wang@arm.com        void unserialize(CheckpointIn &cp) override;
2147754SWilliam.Wang@arm.com
2157754SWilliam.Wang@arm.com        int64_t read(uint8_t *buffer, uint64_t size) override;
2167696SAli.Saidi@ARM.com        int64_t seek(uint64_t pos) override;
2177696SAli.Saidi@ARM.com
2187696SAli.Saidi@ARM.com      protected:
2197696SAli.Saidi@ARM.com        size_t pos;
2207696SAli.Saidi@ARM.com    };
2217696SAli.Saidi@ARM.com
2227754SWilliam.Wang@arm.com    class File : public FileBase
2237754SWilliam.Wang@arm.com    {
2247950SAli.Saidi@ARM.com      public:
2257696SAli.Saidi@ARM.com        File(ArmSemihosting &_parent, const char *name, const char *mode);
2267696SAli.Saidi@ARM.com        ~File();
2278461SAli.Saidi@ARM.com
2288461SAli.Saidi@ARM.com        void serialize(CheckpointOut &cp) const override;
2297584SAli.Saidi@arm.com        void unserialize(CheckpointIn &cp) override;
2307584SAli.Saidi@arm.com
2317584SAli.Saidi@arm.com        int64_t open() override { return openImpl(false); }
2327584SAli.Saidi@arm.com        int64_t close() override;
2338299Schander.sudanthi@arm.com        bool isTTY() const override;
2347584SAli.Saidi@arm.com        int64_t read(uint8_t *buffer, uint64_t size) override;
2357584SAli.Saidi@arm.com        int64_t write(const uint8_t *buffer, uint64_t size) override;
2367584SAli.Saidi@arm.com        int64_t seek(uint64_t pos) override;
2377584SAli.Saidi@arm.com        int64_t flen() override;
2387584SAli.Saidi@arm.com
2397584SAli.Saidi@arm.com      protected:
2407584SAli.Saidi@arm.com        int64_t openImpl(bool unserialize);
2417584SAli.Saidi@arm.com        bool needClose() const { return !isTTY(); }
2427584SAli.Saidi@arm.com
2437584SAli.Saidi@arm.com        FILE *file;
2447584SAli.Saidi@arm.com    };
2457584SAli.Saidi@arm.com
2467584SAli.Saidi@arm.com    std::vector<std::unique_ptr<FileBase>> files;
2477584SAli.Saidi@arm.com    FILE *stdin;
2484104SN/A    FILE *stdout;
2494104SN/A    FILE *stderr;
2507584SAli.Saidi@arm.com
2517584SAli.Saidi@arm.com  protected: // Helper functions
2524104SN/A    unsigned calcTickShift() const {
2533630SN/A        int msb = findMsbSet(SimClock::Frequency);
2543630SN/A        return msb > 31 ? msb - 31 : 0;
2553630SN/A    }
2563630SN/A    uint64_t semiTick(Tick tick) const {
2577584SAli.Saidi@arm.com        return tick >> tickShift;
2587584SAli.Saidi@arm.com    }
2597584SAli.Saidi@arm.com    void semiExit(uint64_t code, uint64_t subcode);
2607584SAli.Saidi@arm.com    PortProxy &physProxy(ThreadContext *tc);
2617753SWilliam.Wang@arm.com    std::string readString(ThreadContext *tc, Addr ptr, size_t len);
2627754SWilliam.Wang@arm.com
2637754SWilliam.Wang@arm.com    std::unique_ptr<PortProxy> physProxyS;
2647584SAli.Saidi@arm.com
2657584SAli.Saidi@arm.com  private:
2667584SAli.Saidi@arm.com    typedef std::pair<uint64_t, SemiErrno> RetErrno;
2677584SAli.Saidi@arm.com    static  RetErrno retError(SemiErrno e) {
2687584SAli.Saidi@arm.com        return RetErrno((uint64_t)-1, e);
2697584SAli.Saidi@arm.com    }
2707584SAli.Saidi@arm.com
2717584SAli.Saidi@arm.com    static  RetErrno retOK(uint64_t r) {
2727584SAli.Saidi@arm.com        return RetErrno(r, 0);
2737584SAli.Saidi@arm.com    }
2747584SAli.Saidi@arm.com
2757584SAli.Saidi@arm.com    /**
2767584SAli.Saidi@arm.com     * Semihosting call information structure.
2777584SAli.Saidi@arm.com     *
2787584SAli.Saidi@arm.com     * This structure describes how a semi-hosting call is
2798299Schander.sudanthi@arm.com     * implemented. It contains debug information (e.g., the name of
2808299Schander.sudanthi@arm.com     * the call), a pointer to the implementation, and information
2817584SAli.Saidi@arm.com     * needed to read its parameters from guest memory.
2828524SAli.Saidi@ARM.com     */
2838524SAli.Saidi@ARM.com    struct SemiCall
2848524SAli.Saidi@ARM.com    {
2858524SAli.Saidi@ARM.com        /** Call name */
2868524SAli.Saidi@ARM.com        const char *name;
2878524SAli.Saidi@ARM.com
2888524SAli.Saidi@ARM.com        /**
2898524SAli.Saidi@ARM.com         * Pointer to  call implementation
2908524SAli.Saidi@ARM.com         *
2918524SAli.Saidi@ARM.com         * @param tc ThreadContext pointer for caller
2928524SAli.Saidi@ARM.com         * @param aarch64 True if in aarc64 mode, false otherwise.
2938524SAli.Saidi@ARM.com         * @parma argv Argument vector. argv[0] always corresponds to
2948524SAli.Saidi@ARM.com         *             the pointer to the argument list. Remaining
2958524SAli.Saidi@ARM.com         *             entries are read as consecutive words starting
2968524SAli.Saidi@ARM.com         *             at the address pointed to by argv[0].
2978524SAli.Saidi@ARM.com         * @return a (return value, errno) pair
2988524SAli.Saidi@ARM.com         */
2998524SAli.Saidi@ARM.com        RetErrno (ArmSemihosting::*call)(ThreadContext *tc, bool aarch64,
3008524SAli.Saidi@ARM.com                                         std::vector<uint64_t> &argv);
3018524SAli.Saidi@ARM.com
3028524SAli.Saidi@ARM.com        /** Number of aarch32 arguments to read from guest memory. -1
3038524SAli.Saidi@ARM.com         * if unimplemented.*/
3048524SAli.Saidi@ARM.com        int argc32;
3058524SAli.Saidi@ARM.com        /** Number of aarch32 arguments to read from guest memory. -1
3068524SAli.Saidi@ARM.com         * if unimplemented.*/
3078524SAli.Saidi@ARM.com        int argc64;
3088524SAli.Saidi@ARM.com
3098524SAli.Saidi@ARM.com        /** Is call implemented in aarch32? */
3108524SAli.Saidi@ARM.com        bool implemented32() const { return call && argc32 >= 0; }
3118524SAli.Saidi@ARM.com        /** Is call implemented in aarch64? */
3128524SAli.Saidi@ARM.com        bool implemented64() const { return call && argc64 >= 0; }
3138524SAli.Saidi@ARM.com    };
3148524SAli.Saidi@ARM.com
3158524SAli.Saidi@ARM.com#define SEMI_CALL(N)                                                    \
3168524SAli.Saidi@ARM.com    RetErrno call ## N (ThreadContext *tc,                              \
3178524SAli.Saidi@ARM.com                        bool aarch64, std::vector<uint64_t> &argv)
3188524SAli.Saidi@ARM.com
3198524SAli.Saidi@ARM.com    SEMI_CALL(Open);
3208524SAli.Saidi@ARM.com    SEMI_CALL(Close);
3218524SAli.Saidi@ARM.com    SEMI_CALL(WriteC);
3228524SAli.Saidi@ARM.com    SEMI_CALL(Write0);
3238524SAli.Saidi@ARM.com    SEMI_CALL(Write);
3248524SAli.Saidi@ARM.com    SEMI_CALL(Read);
3258524SAli.Saidi@ARM.com    SEMI_CALL(ReadC);
3268524SAli.Saidi@ARM.com    SEMI_CALL(IsError);
3278524SAli.Saidi@ARM.com    SEMI_CALL(IsTTY);
3288524SAli.Saidi@ARM.com    SEMI_CALL(Seek);
3298524SAli.Saidi@ARM.com    SEMI_CALL(FLen);
3308524SAli.Saidi@ARM.com    SEMI_CALL(TmpNam);
3318524SAli.Saidi@ARM.com    SEMI_CALL(Remove);
3328524SAli.Saidi@ARM.com    SEMI_CALL(Rename);
3338524SAli.Saidi@ARM.com    SEMI_CALL(Clock);
3348524SAli.Saidi@ARM.com    SEMI_CALL(Time);
3358524SAli.Saidi@ARM.com    SEMI_CALL(System);
3368524SAli.Saidi@ARM.com    SEMI_CALL(Errno);
3378524SAli.Saidi@ARM.com    SEMI_CALL(GetCmdLine);
3388524SAli.Saidi@ARM.com    SEMI_CALL(HeapInfo);
3398524SAli.Saidi@ARM.com    SEMI_CALL(Exit);
3408524SAli.Saidi@ARM.com    SEMI_CALL(ExitExtended);
3418524SAli.Saidi@ARM.com
3428524SAli.Saidi@ARM.com    SEMI_CALL(Elapsed);
3438524SAli.Saidi@ARM.com    SEMI_CALL(TickFreq);
3448524SAli.Saidi@ARM.com
3458524SAli.Saidi@ARM.com#undef SEMI_CALL
3468524SAli.Saidi@ARM.com
3478524SAli.Saidi@ARM.com    static const SemiCall *getCall(uint32_t op, bool aarch64);
3488524SAli.Saidi@ARM.com    static FILE *getSTDIO(const char *stream_name,
3498524SAli.Saidi@ARM.com                          const std::string &name, const char *mode);
3508524SAli.Saidi@ARM.com
3518524SAli.Saidi@ARM.com    static const std::map<uint32_t, SemiCall> calls;
3528524SAli.Saidi@ARM.com    static const std::vector<const char *> fmodes;
3538524SAli.Saidi@ARM.com    static const std::map<uint64_t, const char *> exitCodes;
3548524SAli.Saidi@ARM.com    static const std::vector<uint8_t> features;
3558524SAli.Saidi@ARM.com    static const std::map<const std::string, FILE *> stdioMap;
3568524SAli.Saidi@ARM.com};
3578524SAli.Saidi@ARM.com
3588524SAli.Saidi@ARM.com#endif // __ARCH_ARM_SEMIHOSTING_HH__
3598524SAli.Saidi@ARM.com