48#include "debug/Semihosting.hh"
51#include "params/BaseSemihosting.hh"
76 {0x20000,
"semi:ADP_Stopped_BranchThroughZero"},
77 {0x20001,
"semi:ADP_Stopped_UndefinedInstr"},
78 {0x20002,
"semi:ADP_Stopped_SoftwareInterrupt"},
79 {0x20003,
"semi:ADP_Stopped_PrefetchAbort"},
80 {0x20004,
"semi:ADP_Stopped_DataAbort"},
81 {0x20005,
"semi:ADP_Stopped_AddressException"},
82 {0x20006,
"semi:ADP_Stopped_IRQ"},
83 {0x20007,
"semi:ADP_Stopped_FIQ"},
85 {0x20020,
"semi:ADP_Stopped_BreakPoint"},
86 {0x20021,
"semi:ADP_Stopped_WatchPoint"},
87 {0x20022,
"semi:ADP_Stopped_StepComplete"},
88 {0x20023,
"semi:ADP_Stopped_RunTimeErrorUnknown"},
89 {0x20024,
"semi:ADP_Stopped_InternalError"},
90 {0x20025,
"semi:ADP_Stopped_UserInterruption"},
91 {0x20026,
"semi:ADP_Stopped_ApplicationExit"},
92 {0x20027,
"semi:ADP_Stopped_StackOverflow"},
93 {0x20028,
"semi:ADP_Stopped_DivisionByZero"},
94 {0x20029,
"semi:ADP_Stopped_DivisionByZero"},
98 0x53, 0x48, 0x46, 0x42,
106 {
"stdout", ::stdout},
108 {
"stderr", ::stderr},
112 :
SimObject(
p), cmdLine(
p.cmd_line), memReserve(
p.mem_reserve),
113 stackSize(
p.stack_size), timeBase([
p] {
114 struct tm t =
p.time;
117 tickShift(calcTickShift()), semiErrno(0),
118 filesRootDir(!
p.files_root_dir.empty() &&
p.files_root_dir.back() !=
'/' ?
119 p.files_root_dir +
'/' :
121 stdin(getSTDIO(
"stdin",
p.stdin,
"r")),
122 stdout(getSTDIO(
"stdout",
p.stdout,
"w")),
123 stderr(
p.stderr ==
p.stdout ? stdout : getSTDIO(
"stderr",
p.stderr,
"w"))
127 files.push_back(
nullptr);
130 inform(
"Semihosting: Shifting elapsed ticks by %i bits.", tickShift);
139 for (
int i = 0;
i <
files.size();
i++) {
154 paramIn(cp,
"num_files", num_files);
155 files.resize(num_files);
156 for (
int i = 0;
i < num_files;
i++)
160std::optional<std::string>
168 warn(
"BaseSemihosting::readString(): attempting to read too large "
169 "(%d bytes) string from %#x",
len, ptr);
177 return std::string(buf.data());
186 DPRINTF(Semihosting,
"Semihosting SYS_OPEN(0x%x, %i[%s], %i)\n", name_base,
187 fmode,
mode ?
mode :
"-", name_size);
188 if (!
mode || !name_base)
191 std::optional<std::string> fnameOpt =
readString(tc, name_base, name_size);
192 if (!fnameOpt.has_value())
194 std::string fname = *fnameOpt;
195 if (!fname.empty() && fname.front() !=
'/' && fname !=
":tt" &&
196 fname !=
":semihosting-features")
199 std::unique_ptr<BaseSemihosting::FileBase> file =
201 int64_t ret = file->open();
202 DPRINTF(Semihosting,
"Semihosting SYS_OPEN(\"%s\", %i[%s]): %i\n", fname,
207 files.push_back(std::move(file));
215 if (handle >
files.size()) {
216 DPRINTF(Semihosting,
"Semihosting SYS_CLOSE(%i): Illegal file\n");
220 std::unique_ptr<FileBase> &file =
files[handle];
221 int64_t
error = file->close();
222 DPRINTF(Semihosting,
"Semihosting SYS_CLOSE(%i[%s]): %i\n", handle,
223 file->fileName(),
error);
229 files[handle].reset();
239 DPRINTF(Semihosting,
"Semihosting SYS_WRITEC('%c')\n",
c);
249 DPRINTF(Semihosting,
"Semihosting SYS_WRITE0(...)\n");
253 std::cout.write(str.c_str(), str.size());
269 int64_t ret =
files[handle]->write(buffer.data(), buffer.size());
288 int64_t ret =
files[handle]->read(buffer.data(), buffer.size());
292 panic_if(ret > buffer.size(),
"Read longer than buffer size.");
297 return retOK(size - ret);
304 return retOK((
char)std::cin.get());
319 int64_t ret =
files[handle]->isTTY();
323 return retOK(ret ? 1 : 0);
333 int64_t ret =
files[handle]->seek(pos);
347 int64_t ret =
files[handle]->flen();
359 std::string
path =
"";
360 int64_t unlink_call_ret = 0;
365 unlink_call_ret = unlink(
path.c_str());
367 }
while ((unlink_call_ret < 0) && (errno == EBUSY));
369 const size_t path_len =
path.length();
370 if (path_len >= size)
381 std::optional<std::string> fname =
readString(tc, name_base, name_size);
383 if (!fname.has_value()) {
385 }
else if (remove(fname->c_str()) != 0) {
394 size_t from_size,
Addr to_addr,
size_t to_size)
396 std::optional<std::string> from =
readString(tc, from_addr, from_size);
397 std::optional<std::string>
to =
readString(tc, to_addr, to_size);
398 if (!from.has_value() || !
to.has_value()) {
400 }
else if (rename(from->c_str(),
to->c_str()) != 0) {
422 const std::optional<std::string> cmd =
readString(tc, cmd_addr, cmd_size);
423 if (!cmd.has_value())
425 warn(
"Semihosting: SYS_SYSTEM not implemented. Guest tried to run: %s\n",
443 size_t size = size_arg.
read(tc, proxy, endian);
445 if (
cmdLine.size() + 1 < size) {
460 fatal_if(memories.size() < 1,
"No memories reported from System");
462 "Multiple physical memory ranges available. "
463 "Using first range heap/stack.");
470 const Addr phys_max = (1ULL << 32) - 1;
472 "Physical memory out of range for a 32-bit guest.");
473 if (mem_end > phys_max) {
474 warn(
"Some physical memory out of range for a 32-bit guest.");
480 "Physical memory too small to fit desired stack and a heap.");
482 heap_base = mem_start;
484 stack_base = (mem_end + 1) & ~0x7ULL;
485 stack_limit = heap_limit;
487 inform(
"Reporting heap/stack info to guest:\n"
488 "\tHeap base: 0x%x\n"
489 "\tHeap limit: 0x%x\n"
490 "\tStack base: 0x%x\n"
491 "\tStack limit: 0x%x\n",
492 heap_base, heap_limit, stack_base, stack_limit);
498 uint64_t heap_base, heap_limit, stack_base, stack_limit;
499 gatherHeapInfo(tc,
false, heap_base, heap_limit, stack_base, stack_limit);
501 std::array<uint32_t, 4> block = {
502 {(uint32_t)heap_base, (uint32_t)heap_limit, (uint32_t)stack_base,
503 (uint32_t)stack_limit}};
512 uint64_t heap_base, heap_limit, stack_base, stack_limit;
513 gatherHeapInfo(tc,
true, heap_base, heap_limit, stack_base, stack_limit);
515 std::array<uint64_t, 4> block = {
516 {heap_base, heap_limit, stack_base, stack_limit}};
563 low.
write(tc, proxy, tick, endian);
564 high.
write(tc, proxy, tick >> 32, endian);
584 const char *stream_name,
const std::string &
name,
const char *
mode)
590 fatal(
"Failed to open %s (%s): %s\n", stream_name,
name,
599std::unique_ptr<BaseSemihosting::FileBase>
603 std::unique_ptr<FileBase> file;
604 if (fname ==
":semihosting-features") {
613std::unique_ptr<BaseSemihosting::FileBase>
617 std::unique_ptr<FileBase> file;
624 std::string fname,
mode;
627 file = create(parent, fname,
mode.c_str());
629 file->unserialize(cp);
724BaseSemihosting::File::~
734 panic_if(file,
"Trying to open an already open file.\n");
736 if (
_name ==
":tt") {
737 if (
mode[0] ==
'r') {
739 }
else if (
mode[0] ==
'w') {
740 file = parent.stdout;
741 }
else if (
mode[0] ==
'a') {
742 file = parent.stderr;
744 warn(
"Unknown file mode for the ':tt' special file");
748 std::string real_mode(this->
mode);
751 if (in_cpt && real_mode[0] ==
'w')
754 file = fopen(
_name.c_str(), real_mode.c_str());
757 return file ? 0 : -errno;
763 panic_if(!file,
"Trying to close an already closed file.\n");
776 return file == parent.stdout || file == parent.stderr ||
777 file == parent.stdin;
783 panic_if(!file,
"Trying to read from a closed file");
785 size_t ret = fread(buffer, 1, size, file);
789 return ferror(file) ? -EINVAL : 0;
798 panic_if(!file,
"Trying to write to a closed file");
800 size_t ret = fwrite(buffer, 1, size, file);
813 panic_if(!file,
"Trying to seek in a closed file");
816 if (fseek(file, _pos, SEEK_SET) == 0)
826 long pos = ftell(file);
830 if (fseek(file, 0, SEEK_END) != 0)
833 long len = ftell(file);
837 if (fseek(file, pos, SEEK_SET) != 0)
849 long pos = file ? ftell(file) : 0;
850 panic_if(pos < 0,
"Failed to get file position.");
860 if (openImpl(
true) < 0) {
867 if (fseek(file, pos, SEEK_SET) != 0) {
868 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 write(const uint8_t *buffer, uint64_t size)
Write data to file.
void serialize(CheckpointOut &cp) const override
Serialize an object.
virtual int64_t seek(uint64_t pos)
Seek to an absolute position in the file.
virtual int64_t read(uint8_t *buffer, uint64_t size)
Read data from file.
static std::unique_ptr< FileBase > create(BaseSemihosting &parent, const std::string &fname, const char *mode)
virtual int64_t flen()
Get the length of a file in bytes.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Implementation of the ':semihosting-features' magic file.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
FileFeatures(BaseSemihosting &_parent, const char *name, const char *mode)
int64_t flen() override
Get the length of a file in bytes.
int64_t read(uint8_t *buffer, uint64_t size) override
Read data from 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 close() override
Close the file.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
File(BaseSemihosting &_parent, const char *name, const char *mode)
void serialize(CheckpointOut &cp) const override
Serialize an object.
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.
int64_t seek(uint64_t pos) override
Seek to an absolute position in the file.
int64_t openImpl(bool unserialize)
int64_t write(const uint8_t *buffer, uint64_t size) override
Write data to file.
Semihosting for AArch32, AArch64, RISCV-32 and RISCV-64: https://github.com/ARM-software/abi-aa/blob/...
RetErrno callReadC(ThreadContext *tc)
RetErrno callElapsed32(ThreadContext *tc, InPlaceArg low, InPlaceArg high)
RetErrno callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
static const std::map< uint64_t, const char * > exitCodes
RetErrno callFLen(ThreadContext *tc, Handle handle)
const std::string cmdLine
static const std::array< uint8_t, 5 > features
static FILE * getSTDIO(const char *stream_name, const std::string &name, const char *mode)
RetErrno callTickFreq(ThreadContext *tc)
std::pair< uint64_t, SemiErrno > RetErrno
virtual ByteOrder byteOrder(ThreadContext *tc) const =0
static const std::map< const std::string, FILE * > stdioMap
RetErrno callRename(ThreadContext *tc, Addr from_addr, size_t from_size, Addr to_addr, size_t to_size)
RetErrno callExitExtended(ThreadContext *tc, uint64_t code, uint64_t subcode)
RetErrno callTmpNam(ThreadContext *tc, Addr buffer, uint64_t id, size_t size)
RetErrno callSeek(ThreadContext *tc, Handle handle, uint64_t pos)
std::vector< std::unique_ptr< FileBase > > files
static const std::vector< const char * > fmodes
RetErrno callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
BaseSemihosting(const BaseSemihostingParams &p)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
RetErrno callWrite(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
RetErrno callOpen(ThreadContext *tc, const Addr name_base, int fmode, size_t name_size)
static RetErrno retError(SemiErrno e)
RetErrno callIsError(ThreadContext *tc, int64_t status)
void semiExit(uint64_t code, uint64_t subcode)
RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks)
RetErrno callRead(ThreadContext *tc, Handle handle, Addr buffer, size_t size)
const time_t timeBase
Base time when the simulation started.
RetErrno callExit32(ThreadContext *tc, InPlaceArg code)
void serialize(CheckpointOut &cp) const override
Serialize an object.
virtual PortProxy & portProxy(ThreadContext *tc) const =0
static RetErrno retOK(uint64_t r)
void gatherHeapInfo(ThreadContext *tc, bool aarch64, Addr &heap_base, Addr &heap_limit, Addr &stack_base, Addr &stack_limit)
RetErrno callGetCmdLine(ThreadContext *tc, Addr addr, InPlaceArg size_arg)
RetErrno callHeapInfo32(ThreadContext *tc, Addr block_addr)
RetErrno callClock(ThreadContext *tc)
std::optional< std::string > readString(ThreadContext *tc, Addr ptr, size_t len)
RetErrno callRemove(ThreadContext *tc, Addr name_base, size_t name_size)
RetErrno callHeapInfo64(ThreadContext *tc, Addr block_addr)
uint64_t semiTick(Tick tick) const
RetErrno callIsTTY(ThreadContext *tc, Handle handle)
RetErrno callWriteC(ThreadContext *tc, InPlaceArg c)
RetErrno callErrno(ThreadContext *tc)
RetErrno callTime(ThreadContext *tc)
RetErrno callWrite0(ThreadContext *tc, InPlaceArg str)
RetErrno callClose(ThreadContext *tc, Handle handle)
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,...
void readBlob(Addr addr, void *p, uint64_t size) const
Higher level interfaces based on the above.
T read(Addr address) const
Read sizeof(T) bytes from address and return as object T.
void writeBlob(Addr addr, const void *p, uint64_t 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.
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 System * getSystemPtr()=0
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...
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)
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
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)
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 (...
static std::ostream & operator<<(std::ostream &os, const DummyMatRegContainer &d)
std::string csprintf(const char *format, const Args &...args)
void ccprintf(cp::Print &print)
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
void write(ThreadContext *tc, PortProxy &proxy, uint64_t val, ByteOrder endian)
uint64_t read(ThreadContext *tc, PortProxy &proxy, ByteOrder endian)
const std::string & name()