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