semihosting.hh revision 12533:a5b047f55eb6
112837Sgabeblack@google.com/* 212837Sgabeblack@google.com * Copyright (c) 2018 ARM Limited 312837Sgabeblack@google.com * All rights reserved 412837Sgabeblack@google.com * 512837Sgabeblack@google.com * The license below extends only to copyright in the software and shall 612837Sgabeblack@google.com * not be construed as granting a license to any other intellectual 712837Sgabeblack@google.com * property including but not limited to intellectual property relating 812837Sgabeblack@google.com * to a hardware implementation of the functionality of the software 912837Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1012837Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1112837Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1212837Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1312837Sgabeblack@google.com * 1412837Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1512837Sgabeblack@google.com * modification, are permitted provided that the following conditions are 1612837Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 1712837Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 1812837Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 1912837Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2012837Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2112837Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2212837Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2312837Sgabeblack@google.com * this software without specific prior written permission. 2412837Sgabeblack@google.com * 2512837Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2612837Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2712837Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2812837Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2912837Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3012837Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3112837Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3212862Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3312837Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3412862Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3512837Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3612862Sgabeblack@google.com * 3712837Sgabeblack@google.com * Authors: Andreas Sandberg 3812837Sgabeblack@google.com */ 3912861Sgabeblack@google.com#ifndef __ARCH_ARM_SEMIHOSTING_HH__ 4012837Sgabeblack@google.com#define __ARCH_ARM_SEMIHOSTING_HH__ 4112837Sgabeblack@google.com 4212837Sgabeblack@google.com#include <cstdio> 4312837Sgabeblack@google.com#include <map> 4412837Sgabeblack@google.com#include <memory> 4512837Sgabeblack@google.com#include <utility> 4612837Sgabeblack@google.com#include <vector> 4712837Sgabeblack@google.com 4812837Sgabeblack@google.com#include "sim/sim_object.hh" 4912837Sgabeblack@google.com 5012837Sgabeblack@google.comstruct ArmSemihostingParams; 5112837Sgabeblack@google.comclass PortProxy; 5212837Sgabeblack@google.comclass SerialDevice; 5312837Sgabeblack@google.comclass ThreadContext; 5412837Sgabeblack@google.com 5512837Sgabeblack@google.com/** 5612837Sgabeblack@google.com * Semihosting for AArch32 and AArch64 5712837Sgabeblack@google.com * 5812837Sgabeblack@google.com * This class implements the Arm semihosting interface. This interface 5912837Sgabeblack@google.com * allows baremetal code access service, such as IO, from the 6012837Sgabeblack@google.com * simulator. It is conceptually a simplified version of gem5's more 6112837Sgabeblack@google.com * general syscall emulation mode. 6212837Sgabeblack@google.com * 6312862Sgabeblack@google.com * Exits calls (SYS_EXIT, SYS_EXIT_EXTENDED) from the guest get 6412862Sgabeblack@google.com * translated into simualtion exits. Well-known exit codes are 6512862Sgabeblack@google.com * translated to messages on the form 'semi:ADP_.*' while unknown 6612862Sgabeblack@google.com * codes are returned in hex ('semi:0x..'). The subcode is reported in 6712862Sgabeblack@google.com * the gem5 exit event. 6812862Sgabeblack@google.com */ 6912862Sgabeblack@google.comclass ArmSemihosting : public SimObject 7012862Sgabeblack@google.com{ 7112862Sgabeblack@google.com public: 7212862Sgabeblack@google.com ArmSemihosting(const ArmSemihostingParams *p); 7312862Sgabeblack@google.com 7412837Sgabeblack@google.com /** Perform an Arm Semihosting call from aarch64 code. */ 7512837Sgabeblack@google.com uint64_t call64(ThreadContext *tc, uint32_t op, uint64_t param); 7612837Sgabeblack@google.com /** Perform an Arm Semihosting call from aarch32 code. */ 7712837Sgabeblack@google.com uint32_t call32(ThreadContext *tc, uint32_t op, uint32_t param); 7812837Sgabeblack@google.com 7912837Sgabeblack@google.com public: // SimObject and related interfaces 8012837Sgabeblack@google.com void serialize(CheckpointOut &cp) const override; 8112837Sgabeblack@google.com void unserialize(CheckpointIn &cp) override; 8212837Sgabeblack@google.com 8312837Sgabeblack@google.com protected: // Configuration 8412837Sgabeblack@google.com const std::string cmdLine; 8512837Sgabeblack@google.com const Addr memReserve; 8612837Sgabeblack@google.com const Addr stackSize; 8712837Sgabeblack@google.com 8812837Sgabeblack@google.com /** 8912837Sgabeblack@google.com * Base time when the simulation started. This is used to 9012837Sgabeblack@google.com * calculate the time of date when the guest call SYS_TIME. 9112837Sgabeblack@google.com */ 9212837Sgabeblack@google.com const time_t timeBase; 9312837Sgabeblack@google.com 9412837Sgabeblack@google.com /** Number of bits to right shift gem5 ticks to fit in a uint32_t */ 9512837Sgabeblack@google.com const unsigned tickShift; 9612837Sgabeblack@google.com 9712837Sgabeblack@google.com protected: // Internal state 9812837Sgabeblack@google.com typedef uint64_t SemiErrno; 9912837Sgabeblack@google.com SemiErrno semiErrno; 10012837Sgabeblack@google.com 10112837Sgabeblack@google.com protected: // File IO 10212837Sgabeblack@google.com /** 10312837Sgabeblack@google.com * Internal state for open files 10412837Sgabeblack@google.com * 10512837Sgabeblack@google.com * This class describes the internal state of a file opened 10612837Sgabeblack@google.com * through the semihosting interface. 10712837Sgabeblack@google.com * 10812837Sgabeblack@google.com * A file instance is normally created using one of the 10912837Sgabeblack@google.com * ArmSemihosting::FileBase::create() factory methods. These 11012837Sgabeblack@google.com * methods handle some the magic file names in the Arm Semihosting 11112862Sgabeblack@google.com * specification and instantiate the right implementation. For the 11212837Sgabeblack@google.com * same, when unserializing a checkpoint, the create method must 11312837Sgabeblack@google.com * be used to unserialize a new instance of a file descriptor. 11412837Sgabeblack@google.com */ 11512837Sgabeblack@google.com class FileBase : public Serializable 11612837Sgabeblack@google.com { 11712837Sgabeblack@google.com public: 11812837Sgabeblack@google.com FileBase(ArmSemihosting &_parent, const char *name, const char *_mode) 11912837Sgabeblack@google.com : parent(_parent), _name(name), mode(_mode) {} 12012837Sgabeblack@google.com virtual ~FileBase() {}; 12112837Sgabeblack@google.com 12212837Sgabeblack@google.com FileBase() = delete; 12312837Sgabeblack@google.com FileBase(FileBase &) = delete; 12412861Sgabeblack@google.com 12512861Sgabeblack@google.com static std::unique_ptr<FileBase> create( 12612861Sgabeblack@google.com ArmSemihosting &parent, const std::string &fname, 12712862Sgabeblack@google.com const char *mode); 12812862Sgabeblack@google.com static std::unique_ptr<FileBase> create( 12912862Sgabeblack@google.com ArmSemihosting &parent, CheckpointIn &cp, const std::string &sec); 13012861Sgabeblack@google.com 13112861Sgabeblack@google.com void serialize(CheckpointOut &cp) const override; 13212837Sgabeblack@google.com void unserialize(CheckpointIn &cp) override; 13312837Sgabeblack@google.com 13412837Sgabeblack@google.com const std::string &fileName() { return _name; } 13512837Sgabeblack@google.com 13612837Sgabeblack@google.com public: 13712837Sgabeblack@google.com /** @{ 13812837Sgabeblack@google.com * Semihosting file IO interfaces 13912837Sgabeblack@google.com * 14012837Sgabeblack@google.com * These interfaces implement common IO functionality in the 14112837Sgabeblack@google.com * Semihosting interface. 14212837Sgabeblack@google.com * 14312837Sgabeblack@google.com * All functions return a negative value that corresponds to a 14412837Sgabeblack@google.com * UNIX errno value when they fail and >=0 on success. 14512837Sgabeblack@google.com */ 14612860Sgabeblack@google.com 14712860Sgabeblack@google.com /** 14812860Sgabeblack@google.com * Open the the file. 14912862Sgabeblack@google.com * 15012862Sgabeblack@google.com * @return <0 on error (-errno), 0 on success. 15112862Sgabeblack@google.com */ 15212862Sgabeblack@google.com virtual int64_t open() { return 0; } 15312862Sgabeblack@google.com 15412860Sgabeblack@google.com /** 15512860Sgabeblack@google.com * Close the file. 15612860Sgabeblack@google.com * 15712860Sgabeblack@google.com * @return <0 on error (-errno), 0 on success. 15812860Sgabeblack@google.com */ 15912860Sgabeblack@google.com virtual int64_t close() { return 0; } 16012860Sgabeblack@google.com 16112860Sgabeblack@google.com /** 16212860Sgabeblack@google.com * Check if a file corresponds to a TTY device. 16312860Sgabeblack@google.com * 16412860Sgabeblack@google.com * @return True if the file is a TTY, false otherwise. 16512862Sgabeblack@google.com */ 16612862Sgabeblack@google.com virtual bool isTTY() const { return false; } 16712862Sgabeblack@google.com 16812862Sgabeblack@google.com /** 16912862Sgabeblack@google.com * Read data from file. 17012862Sgabeblack@google.com * 17112860Sgabeblack@google.com * @return <0 on error (-errno), bytes read on success (0 for EOF). 17212860Sgabeblack@google.com */ 17312860Sgabeblack@google.com virtual int64_t read(uint8_t *buffer, uint64_t size); 17412860Sgabeblack@google.com 17512860Sgabeblack@google.com /** 17612861Sgabeblack@google.com * Write data to file. 17712861Sgabeblack@google.com * 17812861Sgabeblack@google.com * @return <0 on error (-errno), bytes written on success. 17912861Sgabeblack@google.com */ 18012861Sgabeblack@google.com virtual int64_t write(const uint8_t *buffer, uint64_t size); 18112861Sgabeblack@google.com 18212860Sgabeblack@google.com /** 18312860Sgabeblack@google.com * Seek to an absolute position in the file. 18412860Sgabeblack@google.com * 18512860Sgabeblack@google.com * @param pos Byte offset from start of file. 18612860Sgabeblack@google.com * @return <0 on error (-errno), 0 on success. 18712861Sgabeblack@google.com */ 18812860Sgabeblack@google.com virtual int64_t seek(uint64_t pos); 18912860Sgabeblack@google.com 19012860Sgabeblack@google.com /** 19112860Sgabeblack@google.com * Get the length of a file in bytes. 19212860Sgabeblack@google.com * 19312860Sgabeblack@google.com * @return <0 on error (-errno), length on success 19412860Sgabeblack@google.com */ 19512860Sgabeblack@google.com virtual int64_t flen(); 19612860Sgabeblack@google.com 19712860Sgabeblack@google.com /** @} */ 19812860Sgabeblack@google.com 19912860Sgabeblack@google.com protected: 20012860Sgabeblack@google.com ArmSemihosting &parent; 20112860Sgabeblack@google.com std::string _name; 20212860Sgabeblack@google.com std::string mode; 20312860Sgabeblack@google.com }; 20412860Sgabeblack@google.com 20512860Sgabeblack@google.com /** Implementation of the ':semihosting-features' magic file. */ 20612861Sgabeblack@google.com class FileFeatures : public FileBase 20712860Sgabeblack@google.com { 20812860Sgabeblack@google.com public: 20912860Sgabeblack@google.com FileFeatures(ArmSemihosting &_parent, 21012860Sgabeblack@google.com const char *name, const char *mode); 21112860Sgabeblack@google.com 21212861Sgabeblack@google.com void serialize(CheckpointOut &cp) const override; 21312860Sgabeblack@google.com void unserialize(CheckpointIn &cp) override; 21412860Sgabeblack@google.com 21512860Sgabeblack@google.com int64_t read(uint8_t *buffer, uint64_t size) override; 21612860Sgabeblack@google.com int64_t seek(uint64_t pos) override; 21712860Sgabeblack@google.com 21812860Sgabeblack@google.com protected: 21912860Sgabeblack@google.com size_t pos; 22012860Sgabeblack@google.com }; 22112860Sgabeblack@google.com 22212860Sgabeblack@google.com class File : public FileBase 22312860Sgabeblack@google.com { 22412860Sgabeblack@google.com public: 22512860Sgabeblack@google.com File(ArmSemihosting &_parent, const char *name, const char *mode); 22612860Sgabeblack@google.com ~File(); 22712860Sgabeblack@google.com 22812860Sgabeblack@google.com void serialize(CheckpointOut &cp) const override; 22912860Sgabeblack@google.com void unserialize(CheckpointIn &cp) override; 23012860Sgabeblack@google.com 23112860Sgabeblack@google.com int64_t open() override { return openImpl(false); } 23212861Sgabeblack@google.com int64_t close() override; 23312861Sgabeblack@google.com bool isTTY() const override; 23412860Sgabeblack@google.com int64_t read(uint8_t *buffer, uint64_t size) override; 23512860Sgabeblack@google.com int64_t write(const uint8_t *buffer, uint64_t size) override; 23612860Sgabeblack@google.com int64_t seek(uint64_t pos) override; 23712860Sgabeblack@google.com int64_t flen() override; 23812860Sgabeblack@google.com 23912860Sgabeblack@google.com protected: 24012860Sgabeblack@google.com int64_t openImpl(bool unserialize); 24112860Sgabeblack@google.com bool needClose() const { return !isTTY(); } 24212860Sgabeblack@google.com 24312860Sgabeblack@google.com FILE *file; 24412860Sgabeblack@google.com }; 24512860Sgabeblack@google.com 24612861Sgabeblack@google.com std::vector<std::unique_ptr<FileBase>> files; 24712860Sgabeblack@google.com 24812860Sgabeblack@google.com protected: // Helper functions 24912837Sgabeblack@google.com unsigned calcTickShift() const { 250 int msb = findMsbSet(SimClock::Frequency); 251 return msb > 31 ? msb - 31 : 0; 252 } 253 uint64_t semiTick(Tick tick) const { 254 return tick >> tickShift; 255 } 256 void semiExit(uint64_t code, uint64_t subcode); 257 PortProxy &physProxy(ThreadContext *tc); 258 std::string readString(ThreadContext *tc, Addr ptr, size_t len); 259 260 std::unique_ptr<PortProxy> physProxyS; 261 262 private: 263 typedef std::pair<uint64_t, SemiErrno> RetErrno; 264 static constexpr RetErrno retError(SemiErrno e) { 265 return RetErrno((uint64_t)-1, e); 266 } 267 268 static constexpr RetErrno retOK(uint64_t r) { 269 return RetErrno(r, 0); 270 } 271 272 /** 273 * Semihosting call information structure. 274 * 275 * This structure describes how a semi-hosting call is 276 * implemented. It contains debug information (e.g., the name of 277 * the call), a pointer to the implementation, and information 278 * needed to read its parameters from guest memory. 279 */ 280 struct SemiCall 281 { 282 /** Call name */ 283 const char *name; 284 285 /** 286 * Pointer to call implementation 287 * 288 * @param tc ThreadContext pointer for caller 289 * @param aarch64 True if in aarc64 mode, false otherwise. 290 * @parma argv Argument vector. argv[0] always corresponds to 291 * the pointer to the argument list. Remaining 292 * entries are read as consecutive words starting 293 * at the address pointed to by argv[0]. 294 * @return a (return value, errno) pair 295 */ 296 RetErrno (ArmSemihosting::*call)(ThreadContext *tc, bool aarch64, 297 std::vector<uint64_t> &argv); 298 299 /** Number of aarch32 arguments to read from guest memory. -1 300 * if unimplemented.*/ 301 int argc32; 302 /** Number of aarch32 arguments to read from guest memory. -1 303 * if unimplemented.*/ 304 int argc64; 305 306 /** Is call implemented in aarch32? */ 307 bool implemented32() const { return call && argc32 >= 0; } 308 /** Is call implemented in aarch64? */ 309 bool implemented64() const { return call && argc64 >= 0; } 310 }; 311 312#define SEMI_CALL(N) \ 313 RetErrno call ## N (ThreadContext *tc, \ 314 bool aarch64, std::vector<uint64_t> &argv) 315 316 SEMI_CALL(Open); 317 SEMI_CALL(Close); 318 SEMI_CALL(WriteC); 319 SEMI_CALL(Write0); 320 SEMI_CALL(Write); 321 SEMI_CALL(Read); 322 SEMI_CALL(ReadC); 323 SEMI_CALL(IsError); 324 SEMI_CALL(IsTTY); 325 SEMI_CALL(Seek); 326 SEMI_CALL(FLen); 327 SEMI_CALL(TmpNam); 328 SEMI_CALL(Remove); 329 SEMI_CALL(Rename); 330 SEMI_CALL(Clock); 331 SEMI_CALL(Time); 332 SEMI_CALL(System); 333 SEMI_CALL(Errno); 334 SEMI_CALL(GetCmdLine); 335 SEMI_CALL(HeapInfo); 336 SEMI_CALL(Exit); 337 SEMI_CALL(ExitExtended); 338 339 SEMI_CALL(Elapsed); 340 SEMI_CALL(TickFreq); 341 342#undef SEMI_CALL 343 344 static const SemiCall *getCall(uint32_t op, bool aarch64); 345 346 static const std::map<uint32_t, SemiCall> calls; 347 static const std::vector<const char *> fmodes; 348 static const std::map<uint64_t, const char *> exitCodes; 349 static const std::vector<uint8_t> features; 350}; 351 352#endif // __ARCH_ARM_SEMIHOSTING_HH__ 353