49#include "debug/Semihosting.hh"
54#include "params/ArmSemihosting.hh"
102 "r",
"rb",
"r+",
"r+b",
103 "w",
"wb",
"w+",
"w+b",
104 "a",
"ab",
"a+",
"a+b",
108 { 0x20000,
"semi:ADP_Stopped_BranchThroughZero" },
109 { 0x20001,
"semi:ADP_Stopped_UndefinedInstr" },
110 { 0x20002,
"semi:ADP_Stopped_SoftwareInterrupt" },
111 { 0x20003,
"semi:ADP_Stopped_PrefetchAbort" },
112 { 0x20004,
"semi:ADP_Stopped_DataAbort" },
113 { 0x20005,
"semi:ADP_Stopped_AddressException" },
114 { 0x20006,
"semi:ADP_Stopped_IRQ" },
115 { 0x20007,
"semi:ADP_Stopped_FIQ" },
117 { 0x20020,
"semi:ADP_Stopped_BreakPoint" },
118 { 0x20021,
"semi:ADP_Stopped_WatchPoint" },
119 { 0x20022,
"semi:ADP_Stopped_StepComplete" },
120 { 0x20023,
"semi:ADP_Stopped_RunTimeErrorUnknown" },
121 { 0x20024,
"semi:ADP_Stopped_InternalError" },
122 { 0x20025,
"semi:ADP_Stopped_UserInterruption" },
123 { 0x20026,
"semi:ADP_Stopped_ApplicationExit" },
124 { 0x20027,
"semi:ADP_Stopped_StackOverflow" },
125 { 0x20028,
"semi:ADP_Stopped_DivisionByZero" },
126 { 0x20029,
"semi:ADP_Stopped_DivisionByZero" },
131 0x53, 0x48, 0x46, 0x42,
139 {
"stdout", ::stdout},
141 {
"stderr", ::stderr},
147 memReserve(
p.mem_reserve),
148 stackSize(
p.stack_size),
150 tickShift(calcTickShift()),
152 filesRootDir(!
p.files_root_dir.empty() &&
153 p.files_root_dir.back() !=
'/' ?
154 p.files_root_dir +
'/' :
p.files_root_dir),
155 stdin(getSTDIO(
"stdin",
p.stdin,
"r")),
156 stdout(getSTDIO(
"stdout",
p.stdout,
"w")),
157 stderr(
p.stderr ==
p.stdout ?
158 stdout : getSTDIO(
"stderr",
p.stderr,
"w"))
162 files.push_back(
nullptr);
165 inform(
"Semihosting: Shifting elapsed ticks by %i bits.",
174 unrecognizedCall<Abi64>(
175 tc,
"Gem5 semihosting op (0x%x) disabled from here.",
op);
180 if (it ==
calls.end()) {
181 unrecognizedCall<Abi64>(
182 tc,
"Unknown aarch64 semihosting call: op = 0x%x",
op);
187 DPRINTF(Semihosting,
"Semihosting call64: %s\n", call.
dump64(tc));
190 DPRINTF(Semihosting,
"\t ->: 0x%x, %i\n",
err.first,
err.second);
200 unrecognizedCall<Abi32>(
201 tc,
"Gem5 semihosting op (0x%x) disabled from here.",
op);
206 if (it ==
calls.end()) {
207 unrecognizedCall<Abi32>(
208 tc,
"Unknown aarch32 semihosting call: op = 0x%x",
op);
213 DPRINTF(Semihosting,
"Semihosting call32: %s\n", call.
dump32(tc));
216 DPRINTF(Semihosting,
"\t ->: 0x%x, %i\n",
err.first,
err.second);
227 for (
int i = 0;
i <
files.size();
i++) {
242 paramIn(cp,
"num_files", num_files);
243 files.resize(num_files);
244 for (
int i = 0;
i < num_files;
i++)
251 static std::unique_ptr<PortProxy> port_proxy_s;
252 static std::unique_ptr<PortProxy> port_proxy_ns;
253 static System *secure_sys =
nullptr;
257 if (sys != secure_sys) {
269 return *port_proxy_s;
271 if (!port_proxy_ns) {
279 return *port_proxy_ns;
292 return std::string(buf.data());
297 int fmode,
size_t name_size)
301 DPRINTF(Semihosting,
"Semihosting SYS_OPEN(0x%x, %i[%s], %i)\n",
302 name_base, fmode,
mode ?
mode :
"-", name_size);
303 if (!
mode || !name_base)
306 std::string fname =
readString(tc, name_base, name_size);
307 if (!fname.empty() && fname.front() !=
'/')
310 std::unique_ptr<ArmSemihosting::FileBase> file =
312 int64_t ret = file->open();
313 DPRINTF(Semihosting,
"Semihosting SYS_OPEN(\"%s\", %i[%s]): %i\n",
314 fname, fmode,
mode, ret);
318 files.push_back(std::move(file));
326 if (handle >
files.size()) {
327 DPRINTF(Semihosting,
"Semihosting SYS_CLOSE(%i): Illegal file\n");
331 std::unique_ptr<FileBase> &file =
files[handle];
332 int64_t
error = file->close();
333 DPRINTF(Semihosting,
"Semihosting SYS_CLOSE(%i[%s]): %i\n",
334 handle, file->fileName(),
error);
340 files[handle].reset();
350 DPRINTF(Semihosting,
"Semihosting SYS_WRITEC('%c')\n",
c);
359 DPRINTF(Semihosting,
"Semihosting SYS_WRITE0(...)\n");
363 std::cout.write(str.c_str(), str.size());
378 int64_t ret =
files[handle]->write(buffer.data(), buffer.size());
397 int64_t ret =
files[handle]->read(buffer.data(), buffer.size());
401 panic_if(ret > buffer.size(),
"Read longer than buffer size.");
406 return retOK(size - ret);
413 return retOK((
char)std::cin.get());
428 int64_t ret =
files[handle]->isTTY();
432 return retOK(ret ? 1 : 0);
442 int64_t ret =
files[handle]->seek(pos);
456 int64_t ret =
files[handle]->flen();
468 std::string
path =
"";
469 int64_t unlink_call_ret = 0;
474 unlink_call_ret = unlink(
path.c_str());
476 }
while ((unlink_call_ret < 0) && (errno == EBUSY));
478 const size_t path_len =
path.length();
479 if (path_len >= size)
489 std::string fname =
readString(tc, name_base, name_size);
491 if (remove(fname.c_str()) != 0) {
500 Addr to_addr,
size_t to_size)
502 std::string from =
readString(tc, from_addr, from_size);
505 if (rename(from.c_str(),
to.c_str()) != 0) {
527 const std::string cmd =
readString(tc, cmd_addr, cmd_size);
528 warn(
"Semihosting: SYS_SYSTEM not implemented. Guest tried to run: %s\n",
547 size_t size = size_arg.
read(tc, endian);
549 if (
cmdLine.size() + 1 < size) {
561 Addr &stack_base,
Addr &stack_limit)
565 fatal_if(memories.size() < 1,
"No memories reported from System");
566 warn_if(memories.size() > 1,
"Multiple physical memory ranges available. "
567 "Using first range heap/stack.");
574 const Addr phys_max = (1ULL << 32) - 1;
576 "Physical memory out of range for a 32-bit guest.");
577 if (mem_end > phys_max) {
578 warn(
"Some physical memory out of range for a 32-bit guest.");
584 "Physical memory too small to fit desired stack and a heap.");
586 heap_base = mem_start;
588 stack_base = (mem_end + 1) & ~0x7ULL;
589 stack_limit = heap_limit;
591 inform(
"Reporting heap/stack info to guest:\n"
592 "\tHeap base: 0x%x\n"
593 "\tHeap limit: 0x%x\n"
594 "\tStack base: 0x%x\n"
595 "\tStack limit: 0x%x\n",
596 heap_base, heap_limit, stack_base, stack_limit);
602 uint64_t heap_base, heap_limit, stack_base, stack_limit;
603 gatherHeapInfo(tc,
false, heap_base, heap_limit, stack_base, stack_limit);
605 std::array<uint32_t, 4> block = {{
606 (uint32_t)heap_base, (uint32_t)heap_limit,
607 (uint32_t)stack_base, (uint32_t)stack_limit
617 uint64_t heap_base, heap_limit, stack_base, stack_limit;
618 gatherHeapInfo(tc,
true, heap_base, heap_limit, stack_base, stack_limit);
620 std::array<uint64_t, 4> block = {{
621 heap_base, heap_limit, stack_base, stack_limit
644 uint64_t code, uint64_t subcode)
669 low.
write(tc, tick, endian);
670 high.write(tc, tick >> 32, endian);
724 public Argument<ArmSemihosting::Abi32, T>
728 public Argument<ArmSemihosting::Abi64, T>
740 if (pseudo_inst::pseudoInst<SemiPseudoAbi32>(tc, func, ret))
753 if (pseudo_inst::pseudoInst<SemiPseudoAbi64>(tc, func, ret))
761 const std::string &
name,
const char *
mode)
767 fatal(
"Failed to open %s (%s): %s\n",
768 stream_name,
name, strerror(errno));
776std::unique_ptr<ArmSemihosting::FileBase>
780 std::unique_ptr<FileBase> file;
781 if (fname ==
":semihosting-features") {
790std::unique_ptr<ArmSemihosting::FileBase>
794 std::unique_ptr<FileBase> file;
801 std::string fname,
mode;
804 file = create(parent, fname,
mode.c_str());
806 file->unserialize(cp);
895 const char *
_name,
const char *_perms)
910 panic_if(file,
"Trying to open an already open file.\n");
912 if (
_name ==
":tt") {
913 if (
mode[0] ==
'r') {
915 }
else if (
mode[0] ==
'w') {
916 file = parent.stdout;
917 }
else if (
mode[0] ==
'a') {
918 file = parent.stderr;
920 warn(
"Unknown file mode for the ':tt' special file");
924 std::string real_mode(this->
mode);
927 if (in_cpt && real_mode[0] ==
'w')
930 file = fopen(
_name.c_str(), real_mode.c_str());
933 return file ? 0 : -errno;
939 panic_if(!file,
"Trying to close an already closed file.\n");
952 return file == parent.stdout ||
953 file == parent.stderr ||
954 file == parent.stdin;
960 panic_if(!file,
"Trying to read from a closed file");
962 size_t ret = fread(buffer, 1, size, file);
966 return ferror(file) ? -EINVAL : 0;
975 panic_if(!file,
"Trying to write to a closed file");
978 size_t ret = fwrite(buffer, 1, size, file);
991 panic_if(!file,
"Trying to seek in a closed file");
994 if (fseek(file, _pos, SEEK_SET) == 0)
1004 long pos = ftell(file);
1008 if (fseek(file, 0, SEEK_END) != 0)
1011 long len = ftell(file);
1015 if (fseek(file, pos, SEEK_SET) != 0)
1028 long pos = file ? ftell(file) : 0;
1029 panic_if(pos < 0,
"Failed to get file position.");
1039 if (openImpl(
true) < 0) {
1046 if (fseek(file, pos, SEEK_SET) != 0) {
1047 fatal(
"Failed seek to current position (%i) in '%s'", pos,
_name);
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Internal state for open files.
virtual int64_t seek(uint64_t pos)
Seek to an absolute position in the file.
virtual int64_t write(const uint8_t *buffer, uint64_t size)
Write data to file.
virtual int64_t read(uint8_t *buffer, uint64_t size)
Read data from file.
virtual int64_t flen()
Get the length of a file in bytes.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
static std::unique_ptr< FileBase > create(ArmSemihosting &parent, const std::string &fname, const char *mode)
Implementation of the ':semihosting-features' magic file.
FileFeatures(ArmSemihosting &_parent, const char *name, const char *mode)
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from file.
void serialize(CheckpointOut &cp) const override
Serialize an object.
File(ArmSemihosting &_parent, const char *name, const char *mode)
int64_t openImpl(bool unserialize)
int64_t write(const uint8_t *buffer, uint64_t size) override
Write data to file.
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
int64_t close() override
Close the file.
void serialize(CheckpointOut &cp) const override
Serialize an object.
bool isTTY() const override
Check if a file corresponds to a TTY device.
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from file.
int64_t flen() override
Get the length of a file in bytes.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Semihosting for AArch32 and AArch64.
std::pair< uint64_t, SemiErrno > RetErrno
void serialize(CheckpointOut &cp) const override
Serialize an object.
RetErrno callSeek(ThreadContext *tc, Handle handle, uint64_t pos)
RetErrno callReadC(ThreadContext *tc)
static const std::map< uint32_t, SemiCall > calls
RetErrno callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
RetErrno callExitExtended(ThreadContext *tc, uint64_t code, uint64_t subcode)
RetErrno callRename(ThreadContext *tc, Addr from_addr, size_t from_size, Addr to_addr, size_t to_size)
RetErrno callClock(ThreadContext *tc)
bool call32(ThreadContext *tc, bool gem5_ops)
Perform an Arm Semihosting call from aarch32 code.
RetErrno callTickFreq(ThreadContext *tc)
RetErrno callWriteC(ThreadContext *tc, InPlaceArg c)
RetErrno callTime(ThreadContext *tc)
static const std::map< const std::string, FILE * > stdioMap
static RetErrno retOK(uint64_t r)
RetErrno callGetCmdLine(ThreadContext *tc, Addr addr, InPlaceArg size_arg)
RetErrno callIsError(ThreadContext *tc, int64_t status)
void gatherHeapInfo(ThreadContext *tc, bool aarch64, Addr &heap_base, Addr &heap_limit, Addr &stack_base, Addr &stack_limit)
static PortProxy & portProxy(ThreadContext *tc)
std::string readString(ThreadContext *tc, Addr ptr, size_t len)
RetErrno callWrite0(ThreadContext *tc, InPlaceArg str)
bool call64(ThreadContext *tc, bool gem5_ops)
Perform an Arm Semihosting call from aarch64 code.
RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks)
void semiExit(uint64_t code, uint64_t subcode)
const time_t timeBase
Base time when the simulation started.
static FILE * getSTDIO(const char *stream_name, const std::string &name, const char *mode)
static const std::map< uint64_t, const char * > exitCodes
void unserialize(CheckpointIn &cp) override
Unserialize an object.
RetErrno callRemove(ThreadContext *tc, Addr name_base, size_t name_size)
RetErrno callFLen(ThreadContext *tc, Handle handle)
RetErrno callIsTTY(ThreadContext *tc, Handle handle)
RetErrno callClose(ThreadContext *tc, Handle handle)
RetErrno callHeapInfo64(ThreadContext *tc, Addr block_addr)
std::vector< std::unique_ptr< FileBase > > files
RetErrno callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
RetErrno callGem5PseudoOp32(ThreadContext *tc, uint32_t encoded_func)
RetErrno callTmpNam(ThreadContext *tc, Addr buffer, uint64_t id, size_t size)
RetErrno callRead(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
static const std::vector< uint8_t > features
RetErrno callHeapInfo32(ThreadContext *tc, Addr block_addr)
ArmSemihosting(const ArmSemihostingParams &p)
uint64_t semiTick(Tick tick) const
static const std::vector< const char * > fmodes
RetErrno callWrite(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
RetErrno callGem5PseudoOp64(ThreadContext *tc, uint64_t encoded_func)
RetErrno callExit32(ThreadContext *tc, InPlaceArg code)
RetErrno callOpen(ThreadContext *tc, const Addr name_base, int fmode, size_t name_size)
static RetErrno retError(SemiErrno e)
RetErrno callElapsed32(ThreadContext *tc, InPlaceArg low, InPlaceArg high)
RetErrno callErrno(ThreadContext *tc)
const std::string cmdLine
virtual std::string name() const
std::string resolve(const std::string &name) const
Returns relative file names prepended with name of this directory.
This object is a proxy for a port or other object which implements the functional response protocol,...
T read(Addr address) const
Read sizeof(T) bytes from address and return as object T.
void writeBlob(Addr addr, const void *p, int size) const
Same as tryWriteBlob, but insists on success.
void write(Addr address, const T &data) const
Write object T to address.
void readString(std::string &str, Addr addr) const
Same as tryReadString, but insists on success.
void readBlob(Addr addr, void *p, int size) const
Higher level interfaces based on the above.
@ SECURE
The request targets the secure memory space.
State(const ThreadContext *tc)
State(const ThreadContext *tc)
static std::stack< std::string > path
Abstract superclass for simulation objects.
memory::PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual RegVal getReg(const RegId ®) const
virtual System * getSystemPtr()=0
This proxy attempts to translate virtual addresses using the TLBs.
The physical memory encapsulates all memories in the system and provides basic functionality for acce...
AddrRangeList getConfAddrRanges() const
Get the memory ranges for all memories that are to be reported to the configuration table.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
#define fatal(...)
This implements a cprintf based fatal() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
static const std::string & currentSection()
Gets the fully-qualified name of the active section.
bool sectionExists(const std::string §ion)
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
ByteOrder byteOrder(const ThreadContext *tc)
bool isSecure(ThreadContext *tc)
static void decodeAddrOffset(Addr offset, uint8_t &func)
double s
These variables equal the number of ticks in the unit of time they're named after in a double.
Tick Frequency
The simulated frequency of curTick(). (In ticks per second)
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
time_t mkutctime(struct tm *time)
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
void exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat, bool serialize)
Schedule an event to exit the simulation loop (returning to Python) at the end of the current cycle (...
std::string csprintf(const char *format, const Args &...args)
void ccprintf(cp::Print &print)
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
uint64_t read(ThreadContext *tc, ByteOrder endian)
void write(ThreadContext *tc, uint64_t val, ByteOrder endian)
Semihosting call information structure.
const std::string & name()