/*
- * Copyright (c) 2018 ARM Limited
+ * Copyright (c) 2018, 2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#include "debug/Semihosting.hh"
#include "dev/serial/serial.hh"
#include "mem/physical.hh"
-#include "mem/port_proxy.hh"
+#include "mem/secure_port_proxy.hh"
#include "params/ArmSemihosting.hh"
#include "sim/byteswap.hh"
#include "sim/sim_exit.hh"
{ 0x11, { "SYS_TIME", &ArmSemihosting::callTime, 0, 0} },
{ 0x12, { "SYS_SYSTEM", &ArmSemihosting::callSystem, 2, 2} },
{ 0x13, { "SYS_ERRNO", &ArmSemihosting::callErrno, 0, 0 } },
- { 0x15, { "SYS_GET_CMDLINE", &ArmSemihosting::callGetCmdLine, 1, 1} },
+ { 0x15, { "SYS_GET_CMDLINE", &ArmSemihosting::callGetCmdLine, 2, 2} },
{ 0x16, { "SYS_HEAPINFO", &ArmSemihosting::callHeapInfo, 1, 1} },
// Exit is special and requires custom handling in aarch32.
0x3, // EXT_EXIT_EXTENDED, EXT_STDOUT_STDERR
};
+const std::map<const std::string, FILE *> ArmSemihosting::stdioMap{
+ {"cin", ::stdin},
+ {"stdin", ::stdin},
+ {"cout", ::stdout},
+ {"stdout", ::stdout},
+ {"cerr", ::stderr},
+ {"stderr", ::stderr},
+};
+
ArmSemihosting::ArmSemihosting(const ArmSemihostingParams *p)
: SimObject(p),
cmdLine(p->cmd_line),
stackSize(p->stack_size),
timeBase([p]{ struct tm t = p->time; return mkutctime(&t); }()),
tickShift(calcTickShift()),
- semiErrno(0)
+ semiErrno(0),
+ filesRootDir(!p->files_root_dir.empty() &&
+ p->files_root_dir.back() != '/' ?
+ p->files_root_dir + '/' : p->files_root_dir),
+ stdin(getSTDIO("stdin", p->stdin, "r")),
+ stdout(getSTDIO("stdout", p->stdout, "w")),
+ stderr(p->stderr == p->stdout ?
+ stdout : getSTDIO("stderr", p->stderr, "w"))
{
// Create an empty place-holder file for position 0 as semi-hosting
// calls typically expect non-zero file handles.
}
std::vector<uint64_t> argv(call->argc64 + 1);
- PortProxy &proxy = tc->getPhysProxy();
+ PortProxy &proxy = physProxy(tc);
ByteOrder endian = ArmISA::byteOrder(tc);
DPRINTF(Semihosting, "Semihosting call64: %s(0x%x)\n", call->name, param);
argv[0] = param;
for (int i = 0; i < call->argc64; ++i) {
- argv[i + 1] = proxy.readGtoH<uint64_t>(param + i * 8, endian);
+ argv[i + 1] = proxy.read<uint64_t>(param + i * 8, endian);
DPRINTF(Semihosting, "\t: 0x%x\n", argv[i + 1]);
}
}
std::vector<uint64_t> argv(call->argc32 + 1);
- PortProxy &proxy = tc->getPhysProxy();
+ PortProxy &proxy = physProxy(tc);
ByteOrder endian = ArmISA::byteOrder(tc);
DPRINTF(Semihosting, "Semihosting call32: %s(0x%x)\n", call->name, param);
argv[0] = param;
for (int i = 0; i < call->argc32; ++i) {
- argv[i + 1] = proxy.readGtoH<uint32_t>(param + i * 4, endian);
+ argv[i + 1] = proxy.read<uint32_t>(param + i * 4, endian);
DPRINTF(Semihosting, "\t: 0x%x\n", argv[i + 1]);
}
files[i] = FileBase::create(*this, cp, csprintf("file%i", i));
}
+PortProxy &
+ArmSemihosting::physProxy(ThreadContext *tc)
+{
+ if (ArmISA::inSecureState(tc)) {
+ if (!physProxyS) {
+ System *sys = tc->getSystemPtr();
+ physProxyS.reset(new SecurePortProxy(
+ sys->getSystemPort(),
+ sys->cacheLineSize()));
+ }
+ return *physProxyS;
+ } else {
+ return tc->getPhysProxy();
+ }
+}
+
+
std::string
ArmSemihosting::readString(ThreadContext *tc, Addr ptr, size_t len)
{
std::vector<char> buf(len + 1);
buf[len] = '\0';
- tc->getPhysProxy().readBlob(ptr, (uint8_t *)buf.data(), len);
+ physProxy(tc).readBlob(ptr, buf.data(), len);
return std::string(buf.data());
}
return retError(EINVAL);
std::string fname = readString(tc, name_base, name_size);
+ if (!fname.empty() && fname.front() != '/')
+ fname = filesRootDir + fname;
std::unique_ptr<ArmSemihosting::FileBase> file =
FileBase::create(*this, fname, mode);
ArmSemihosting::callWriteC(ThreadContext *tc, bool aarch64,
std::vector<uint64_t> &argv)
{
- const char c = tc->getPhysProxy().read<char>(argv[0]);
+ const char c = physProxy(tc).read<char>(argv[0]);
DPRINTF(Semihosting, "Semihosting SYS_WRITEC('%c')\n", c);
std::cout.put(c);
std::vector<uint64_t> &argv)
{
DPRINTF(Semihosting, "Semihosting SYS_WRITE0(...)\n");
- PortProxy &proxy = tc->getPhysProxy();
+ PortProxy &proxy = physProxy(tc);
for (Addr addr = (Addr)argv[0]; ; ++addr) {
char data = proxy.read<char>(addr);
if (data == 0)
return RetErrno(argv[3], EBADF);
std::vector<uint8_t> buffer(argv[3]);
- tc->getPhysProxy().readBlob(argv[2], buffer.data(), buffer.size());
+ physProxy(tc).readBlob(argv[2], buffer.data(), buffer.size());
int64_t ret = files[argv[1]]->write(buffer.data(), buffer.size());
if (ret < 0) {
} else {
panic_if(ret > buffer.size(), "Read longer than buffer size.");
- tc->getPhysProxy().writeBlob(argv[2], buffer.data(), ret);
+ physProxy(tc).writeBlob(argv[2], buffer.data(), ret);
// Return the number of bytes not written
return retOK(argv[3] - ret);
if (argv[1] > files.size() || !files[argv[1]])
return retError(EBADF);
- int64_t ret = files[argv[1]]->isTTY();
+ int64_t ret = files[argv[1]]->flen();
if (ret < 0) {
return retError(-ret);
} else {
- return retOK(0);
+ return retOK(ret);
}
}
if (path_len >= max_len)
return retError(ENOSPC);
- tc->getPhysProxy().writeBlob(
- guest_buf, (const uint8_t *)path, path_len + 1);
+ physProxy(tc).writeBlob(guest_buf, path, path_len + 1);
return retOK(0);
}
std::vector<uint64_t> &argv)
{
if (cmdLine.size() + 1 < argv[2]) {
- PortProxy &proxy = tc->getPhysProxy();
+ PortProxy &proxy = physProxy(tc);
ByteOrder endian = ArmISA::byteOrder(tc);
- proxy.writeBlob(
- (Addr)argv[1],
- (const uint8_t *)cmdLine.c_str(), cmdLine.size() + 1);
+ proxy.writeBlob((Addr)argv[1], cmdLine.c_str(), cmdLine.size() + 1);
if (aarch64)
- proxy.writeHtoG<uint64_t>(argv[0] + 1 * 8, cmdLine.size(), endian);
+ proxy.write<uint64_t>(argv[0] + 1 * 8, cmdLine.size(), endian);
else
- proxy.writeHtoG<uint32_t>(argv[0] + 1 * 4, cmdLine.size(), endian);
+ proxy.write<uint32_t>(argv[0] + 1 * 4, cmdLine.size(), endian);
return retOK(0);
} else {
return retError(0);
heap_base, heap_limit, stack_base, stack_limit);
Addr base = argv[1];
- PortProxy &proxy = tc->getPhysProxy();
+ PortProxy &proxy = physProxy(tc);
ByteOrder endian = ArmISA::byteOrder(tc);
if (aarch64) {
- proxy.writeHtoG<uint64_t>(base + 0 * 8, heap_base, endian);
- proxy.writeHtoG<uint64_t>(base + 1 * 8, heap_limit, endian);
- proxy.writeHtoG<uint64_t>(base + 2 * 8, stack_base, endian);
- proxy.writeHtoG<uint64_t>(base + 3 * 8, stack_limit, endian);
+ proxy.write<uint64_t>(base + 0 * 8, heap_base, endian);
+ proxy.write<uint64_t>(base + 1 * 8, heap_limit, endian);
+ proxy.write<uint64_t>(base + 2 * 8, stack_base, endian);
+ proxy.write<uint64_t>(base + 3 * 8, stack_limit, endian);
} else {
- proxy.writeHtoG<uint32_t>(base + 0 * 4, heap_base, endian);
- proxy.writeHtoG<uint32_t>(base + 1 * 4, heap_limit, endian);
- proxy.writeHtoG<uint32_t>(base + 2 * 4, stack_base, endian);
- proxy.writeHtoG<uint32_t>(base + 3 * 4, stack_limit, endian);
+ proxy.write<uint32_t>(base + 0 * 4, heap_base, endian);
+ proxy.write<uint32_t>(base + 1 * 4, heap_limit, endian);
+ proxy.write<uint32_t>(base + 2 * 4, stack_base, endian);
+ proxy.write<uint32_t>(base + 3 * 4, stack_limit, endian);
}
return retOK(0);
ArmSemihosting::callElapsed(ThreadContext *tc, bool aarch64,
std::vector<uint64_t> &argv)
{
- PortProxy &proxy = tc->getPhysProxy();
+ PortProxy &proxy = physProxy(tc);
ByteOrder endian = ArmISA::byteOrder(tc);
const uint64_t tick = semiTick(curTick());
if (aarch64) {
- proxy.writeHtoG<uint64_t>(argv[0], tick, endian);
+ proxy.write<uint64_t>(argv[0], tick, endian);
} else {
- proxy.writeHtoG<uint32_t>(argv[0] + 0 * 4, tick, endian);
- proxy.writeHtoG<uint32_t>(argv[0] + 1 * 4, tick >> 32, endian);
+ proxy.write<uint32_t>(argv[0] + 0 * 4, tick, endian);
+ proxy.write<uint32_t>(argv[0] + 1 * 4, tick >> 32, endian);
}
return retOK(0);
}
}
+FILE *
+ArmSemihosting::getSTDIO(const char *stream_name,
+ const std::string &name, const char *mode)
+{
+ auto it = stdioMap.find(name);
+ if (it == stdioMap.end()) {
+ FILE *f = fopen(name.c_str(), mode);
+ if (!f) {
+ fatal("Failed to open %s (%s): %s\n",
+ stream_name, name, strerror(errno));
+ }
+ return f;
+ } else {
+ return it->second;
+ }
+}
+
std::unique_ptr<ArmSemihosting::FileBase>
ArmSemihosting::FileBase::create(
ArmSemihosting &parent, const std::string &fname, const char *mode)
if (_name == ":tt") {
if (mode[0] == 'r') {
- file = stdin;
+ file = parent.stdin;
} else if (mode[0] == 'w') {
- file = stdout;
+ file = parent.stdout;
} else if (mode[0] == 'a') {
- file = stderr;
+ file = parent.stderr;
} else {
warn("Unknown file mode for the ':tt' special file");
return -EINVAL;
bool
ArmSemihosting::File::isTTY() const
{
- return file == stdout || file == stderr || file == stdin;
+ return file == parent.stdout ||
+ file == parent.stderr ||
+ file == parent.stdin;
}
int64_t