arm: Make the semihosting implementation use GuestABI.
authorGabe Black <gabeblack@google.com>
Wed, 26 Feb 2020 12:44:55 +0000 (04:44 -0800)
committerGabe Black <gabeblack@google.com>
Tue, 24 Mar 2020 20:42:53 +0000 (20:42 +0000)
Remove the ability to not have an implementation for a semihosting call
in 32 or 64 bit mode since that was not actually being used. It can be
reintroduced if needed in the future.

Turn the physProxy helper function into a static function which
maintains a single secure port proxy. That makes the proxy available
outside of the ArmSemihosting class itself.

Change-Id: Ie99e7d79c08c039384250fab0c98117554c93128
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/25946
Tested-by: Gem5 Cloud Project GCB service account <345032938727@cloudbuild.gserviceaccount.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>

src/arch/arm/isa/insts/misc.isa
src/arch/arm/isa/insts/misc64.isa
src/arch/arm/semihosting.cc
src/arch/arm/semihosting.hh
src/arch/arm/system.cc
src/arch/arm/system.hh

index 396930f178a8cd5d433ab8291340e0b89fdbfbd2..88c473d6aeb0de13ff1dc2e8d8f58b5ad3bc1c28 100644 (file)
@@ -43,7 +43,7 @@ let {{
     const auto semihost_imm = Thumb? 0xAB : 0x123456;
 
     if (ArmSystem::haveSemihosting(tc) && imm == semihost_imm) {
-        R0 = ArmSystem::callSemihosting32(tc, R0, R1);
+        ArmSystem::callSemihosting32(tc);
     } else {
         fault = std::make_shared<SupervisorCall>(machInst, imm);
     }
@@ -66,7 +66,7 @@ let {{
     const auto semihost_imm = Thumb? 0x3C : 0xF000;
 
     if (ArmSystem::haveSemihosting(tc) && imm == semihost_imm) {
-        R0 = ArmSystem::callSemihosting32(tc, R0, R1);
+        ArmSystem::callSemihosting32(tc);
     } else {
         // HLT instructions aren't implemented, so treat them as undefined
         // instructions.
@@ -80,7 +80,7 @@ let {{
                              "predicate_test": predicateTest,
                              "thumb_semihost": '0x3C',
                              "arm_semihost": '0xF000' },
-                           ["IsNonSpeculative"])
+                           ["IsNonSpeculative", "IsSerializeAfter"])
     header_output += ImmOpDeclare.subst(hltIop)
     decoder_output += SemihostConstructor.subst(hltIop)
     exec_output += PredOpExecute.subst(hltIop)
index 88c68e623b72bfddd5ceebafc1dd1e36852daba7..e2cfb41dd2c4c6608f0abfa435851771ad417c17 100644 (file)
@@ -186,7 +186,7 @@ let {{
     hltCode = '''
     ThreadContext *tc = xc->tcBase();
     if (ArmSystem::haveSemihosting(tc) && imm == 0xF000) {
-        X0 = ArmSystem::callSemihosting64(tc, X0 & mask(32), X1);
+        ArmSystem::callSemihosting64(tc);
     } else {
         // HLT instructions aren't implemented, so treat them as undefined
         // instructions.
@@ -197,7 +197,7 @@ let {{
     '''
 
     hltIop = InstObjParams("hlt", "Hlt64", "ImmOp64",
-                           hltCode, ["IsNonSpeculative"])
+                           hltCode, ["IsNonSpeculative", "IsSerializeAfter"])
     header_output += ImmOp64Declare.subst(hltIop)
     decoder_output += SemihostConstructor64.subst(hltIop)
     exec_output += BasicExecute.subst(hltIop)
index 4f897e208fe644317e76fdf437c625bf653a5170..5ea894af34220e0578413f96f68ca1140148e1d2 100644 (file)
 #include "sim/system.hh"
 
 const std::map<uint32_t, ArmSemihosting::SemiCall> ArmSemihosting::calls{
-    { SYS_OPEN,     { "SYS_OPEN", &ArmSemihosting::callOpen, 3, 3 } },
-    { SYS_CLOSE,    { "SYS_CLOSE", &ArmSemihosting::callClose, 1, 1 } },
-
-    // Write(C|0) are special since we want to read the character
-    // manually. We therefore declare them as having 0 params.
-    { SYS_WRITEC,   { "SYS_WRITEC", &ArmSemihosting::callWriteC, 0, 0 } },
-    { SYS_WRITE0,   { "SYS_WRITE0", &ArmSemihosting::callWrite0, 1, 1 } },
-
-    { SYS_WRITE,    { "SYS_WRITE", &ArmSemihosting::callWrite, 3, 3 } },
-    { SYS_READ,     { "SYS_READ", &ArmSemihosting::callRead, 3, 3 } },
-    { SYS_READC,    { "SYS_READC", &ArmSemihosting::callReadC, 0, 0 } },
-    { SYS_ISERROR,  { "SYS_ISERROR", &ArmSemihosting::callIsError, 1, 1 } },
-    { SYS_ISTTY,    { "SYS_ISTTY", &ArmSemihosting::callIsTTY, 1, 1 } },
-    { SYS_SEEK,     { "SYS_SEEK", &ArmSemihosting::callSeek, 2, 2 } },
-    { SYS_FLEN,     { "SYS_FLEN", &ArmSemihosting::callFLen, 1, 1 } },
-    { SYS_TMPNAM,   { "SYS_TMPNAM", &ArmSemihosting::callTmpNam, 3, 3 } },
-    { SYS_REMOVE,   { "SYS_REMOVE", &ArmSemihosting::callRemove, 2, 2} },
-    { SYS_RENAME,   { "SYS_RENAME", &ArmSemihosting::callRename, 4, 4} },
-    { SYS_CLOCK,    { "SYS_CLOCK", &ArmSemihosting::callClock, 0, 0} },
-    { SYS_TIME,     { "SYS_TIME", &ArmSemihosting::callTime, 0, 0} },
-    { SYS_SYSTEM,   { "SYS_SYSTEM", &ArmSemihosting::callSystem, 2, 2} },
-    { SYS_ERRNO,    { "SYS_ERRNO", &ArmSemihosting::callErrno, 0, 0 } },
+    { SYS_OPEN,     { "SYS_OPEN", &ArmSemihosting::callOpen } },
+    { SYS_CLOSE,    { "SYS_CLOSE", &ArmSemihosting::callClose } },
+    { SYS_WRITEC,   { "SYS_WRITEC", &ArmSemihosting::callWriteC } },
+    { SYS_WRITE0,   { "SYS_WRITE0", &ArmSemihosting::callWrite0 } },
+    { SYS_WRITE,    { "SYS_WRITE", &ArmSemihosting::callWrite } },
+    { SYS_READ,     { "SYS_READ", &ArmSemihosting::callRead } },
+    { SYS_READC,    { "SYS_READC", &ArmSemihosting::callReadC } },
+    { SYS_ISERROR,  { "SYS_ISERROR", &ArmSemihosting::callIsError } },
+    { SYS_ISTTY,    { "SYS_ISTTY", &ArmSemihosting::callIsTTY } },
+    { SYS_SEEK,     { "SYS_SEEK", &ArmSemihosting::callSeek } },
+    { SYS_FLEN,     { "SYS_FLEN", &ArmSemihosting::callFLen } },
+    { SYS_TMPNAM,   { "SYS_TMPNAM", &ArmSemihosting::callTmpNam } },
+    { SYS_REMOVE,   { "SYS_REMOVE", &ArmSemihosting::callRemove } },
+    { SYS_RENAME,   { "SYS_RENAME", &ArmSemihosting::callRename } },
+    { SYS_CLOCK,    { "SYS_CLOCK", &ArmSemihosting::callClock } },
+    { SYS_TIME,     { "SYS_TIME", &ArmSemihosting::callTime } },
+    { SYS_SYSTEM,   { "SYS_SYSTEM", &ArmSemihosting::callSystem } },
+    { SYS_ERRNO,    { "SYS_ERRNO", &ArmSemihosting::callErrno } },
     { SYS_GET_CMDLINE,
-        { "SYS_GET_CMDLINE", &ArmSemihosting::callGetCmdLine, 2, 2} },
-    { SYS_HEAPINFO, { "SYS_HEAPINFO", &ArmSemihosting::callHeapInfo, 1, 1} },
+        { "SYS_GET_CMDLINE", &ArmSemihosting::callGetCmdLine } },
+    { SYS_HEAPINFO, { "SYS_HEAPINFO", &ArmSemihosting::callHeapInfo32,
+                                      &ArmSemihosting::callHeapInfo64 } },
 
-    // Exit is special and requires custom handling in aarch32.
-    { SYS_EXIT,     { "SYS_EXIT", &ArmSemihosting::callExit, 0, 2 } },
+    { SYS_EXIT,     { "SYS_EXIT", &ArmSemihosting::callExit32,
+                                  &ArmSemihosting::callExit64} },
     { SYS_EXIT_EXTENDED,
-        { "SYS_EXIT_EXTENDED", &ArmSemihosting::callExitExtended, 2, 2 } },
+        { "SYS_EXIT_EXTENDED", &ArmSemihosting::callExitExtended } },
 
-    { SYS_ELAPSED,  { "SYS_ELAPSED", &ArmSemihosting::callElapsed, 0, 0 } },
-    { SYS_TICKFREQ, { "SYS_TICKFREQ", &ArmSemihosting::callTickFreq, 0, 0 } },
+    { SYS_ELAPSED,  { "SYS_ELAPSED", &ArmSemihosting::callElapsed32,
+                                     &ArmSemihosting::callElapsed64 } },
+    { SYS_TICKFREQ, { "SYS_TICKFREQ", &ArmSemihosting::callTickFreq } },
 };
 
 const std::vector<const char *> ArmSemihosting::fmodes{
@@ -155,74 +153,42 @@ ArmSemihosting::ArmSemihosting(const ArmSemihostingParams *p)
                tickShift);
 }
 
-uint64_t
-ArmSemihosting::call64(ThreadContext *tc, uint32_t op, uint64_t param)
+void
+ArmSemihosting::call64(ThreadContext *tc)
 {
-    const SemiCall *call = getCall(op, true);
-    if (!call) {
-        warn("Unknown aarch64 semihosting call: op = 0x%x, param = 0x%x",
-             op, param);
-
-        return (uint64_t)-1;
-    } else if (!call->implemented64()) {
-        warn("Unimplemented aarch64 semihosting call: "
-             "%s (op = 0x%x, param = 0x%x)",
-             call->name, op, param);
-
-        return (uint64_t)-1;
-    }
+    RegVal op = tc->readIntReg(ArmISA::INTREG_X0 & mask(32));
 
-    std::vector<uint64_t> argv(call->argc64 + 1);
-    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.read<uint64_t>(param + i * 8, endian);
-        DPRINTF(Semihosting, "\t: 0x%x\n", argv[i + 1]);
+    auto it = calls.find(op);
+    if (it == calls.end()) {
+        unrecognizedCall<Abi64>(
+                tc, "Unknown aarch64 semihosting call: op = 0x%x", op);
+        return;
     }
+    const SemiCall &call = it->second;
 
-    auto ret_errno = (this->*call->call)(tc, true, argv);
-    semiErrno = ret_errno.second;
-    DPRINTF(Semihosting, "\t ->: 0x%x, %i\n",
-            ret_errno.first, ret_errno.second);
-    return ret_errno.first;
+    DPRINTF(Semihosting, "Semihosting call64: %s\n", call.dump64(tc));
+    auto err = call.call64(this, tc);
+    semiErrno = err.second;
+    DPRINTF(Semihosting, "\t ->: 0x%x, %i\n", err.first, err.second);
 }
 
-uint32_t
-ArmSemihosting::call32(ThreadContext *tc, uint32_t op, uint32_t param)
+void
+ArmSemihosting::call32(ThreadContext *tc)
 {
-    const SemiCall *call = getCall(op, false);
-    if (!call) {
-        warn("Unknown aarch32 semihosting call: op = 0x%x, param = 0x%x",
-             op, param);
-
-        return (uint32_t)-1;
-    } else if (!call->implemented32()) {
-        warn("Unimplemented aarch32 semihosting call: "
-             "%s (op = 0x%x, param = 0x%x)",
-             call->name, op, param);
-
-        return (uint32_t)-1;
-    }
+    RegVal op = tc->readIntReg(ArmISA::INTREG_R0);
 
-    std::vector<uint64_t> argv(call->argc32 + 1);
-    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.read<uint32_t>(param + i * 4, endian);
-        DPRINTF(Semihosting, "\t: 0x%x\n", argv[i + 1]);
+    auto it = calls.find(op);
+    if (it == calls.end()) {
+        unrecognizedCall<Abi32>(
+                tc, "Unknown aarch32 semihosting call: op = 0x%x", op);
+        return;
     }
+    const SemiCall &call = it->second;
 
-    auto ret_errno = (this->*call->call)(tc, false, argv);
-    semiErrno = ret_errno.second;
-    DPRINTF(Semihosting, "\t ->: 0x%x, %i\n",
-            ret_errno.first, ret_errno.second);
-    return ret_errno.first;
+    DPRINTF(Semihosting, "Semihosting call32: %s\n", call.dump32(tc));
+    auto err = call.call32(this, tc);
+    semiErrno = err.second;
+    DPRINTF(Semihosting, "\t ->: 0x%x, %i\n", err.first, err.second);
 }
 
 void
@@ -255,14 +221,17 @@ ArmSemihosting::unserialize(CheckpointIn &cp)
 PortProxy &
 ArmSemihosting::physProxy(ThreadContext *tc)
 {
+    static std::unique_ptr<PortProxy> phys_proxy_s;
+    static System *secure_sys = nullptr;
+
     if (ArmISA::inSecureState(tc)) {
-        if (!physProxyS) {
-            System *sys = tc->getSystemPtr();
-            physProxyS.reset(new SecurePortProxy(
-                                 sys->getSystemPort(),
-                                 sys->cacheLineSize()));
+        System *sys = tc->getSystemPtr();
+        if (sys != secure_sys) {
+            phys_proxy_s.reset(new SecurePortProxy(sys->getSystemPort(),
+                                                   sys->cacheLineSize()));
         }
-        return *physProxyS;
+        secure_sys = sys;
+        return *phys_proxy_s;
     } else {
         return tc->getPhysProxy();
     }
@@ -281,15 +250,13 @@ ArmSemihosting::readString(ThreadContext *tc, Addr ptr, size_t len)
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callOpen(ThreadContext *tc, bool aarch64,
-                         std::vector<uint64_t> &argv)
+ArmSemihosting::callOpen(ThreadContext *tc, const Addr name_base,
+                         int fmode, size_t name_size)
 {
-    const Addr name_base = argv[1];
-    const char *mode = argv[2] < fmodes.size() ? fmodes[argv[2]] : nullptr;
-    const Addr name_size = argv[3];
+    const char *mode = fmode < fmodes.size() ? fmodes[fmode] : nullptr;
 
     DPRINTF(Semihosting, "Semihosting SYS_OPEN(0x%x, %i[%s], %i)\n",
-            name_base, argv[2], mode ? mode : "-", name_size);
+            name_base, fmode, mode ? mode : "-", name_size);
     if (!mode || !name_base)
         return retError(EINVAL);
 
@@ -301,7 +268,7 @@ ArmSemihosting::callOpen(ThreadContext *tc, bool aarch64,
         FileBase::create(*this, fname, mode);
     int64_t ret = file->open();
     DPRINTF(Semihosting, "Semihosting SYS_OPEN(\"%s\", %i[%s]): %i\n",
-            fname, argv[2], mode, ret);
+            fname, fmode, mode, ret);
     if (ret < 0) {
         return retError(-ret);
     } else {
@@ -311,33 +278,31 @@ ArmSemihosting::callOpen(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callClose(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callClose(ThreadContext *tc, uint64_t handle)
 {
-    if (argv[1] > files.size()) {
+    if (handle > files.size()) {
         DPRINTF(Semihosting, "Semihosting SYS_CLOSE(%i): Illegal file\n");
         return retError(EBADF);
     }
 
-    std::unique_ptr<FileBase> &file = files[argv[1]];
+    std::unique_ptr<FileBase> &file = files[handle];
     int64_t error = file->close();
     DPRINTF(Semihosting, "Semihosting SYS_CLOSE(%i[%s]): %i\n",
-            argv[1], file->fileName(), error);
+            handle, file->fileName(), error);
     if (error < 0) {
         return retError(-error);
     } else {
         // Zap the pointer and free the entry in the file table as
         // well.
-        files[argv[1]].reset();
+        files[handle].reset();
         return retOK(0);
     }
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callWriteC(ThreadContext *tc, bool aarch64,
-                           std::vector<uint64_t> &argv)
+ArmSemihosting::callWriteC(ThreadContext *tc, InPlaceArg arg)
 {
-    const char c = physProxy(tc).read<char>(argv[0]);
+    const char c = physProxy(tc).read<char>(arg.addr);
 
     DPRINTF(Semihosting, "Semihosting SYS_WRITEC('%c')\n", c);
     std::cout.put(c);
@@ -346,90 +311,78 @@ ArmSemihosting::callWriteC(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callWrite0(ThreadContext *tc, bool aarch64,
-                           std::vector<uint64_t> &argv)
+ArmSemihosting::callWrite0(ThreadContext *tc, InPlaceArg arg)
 {
     DPRINTF(Semihosting, "Semihosting SYS_WRITE0(...)\n");
     PortProxy &proxy = physProxy(tc);
-    for (Addr addr = (Addr)argv[0]; ; ++addr) {
-        char data = proxy.read<char>(addr);
-        if (data == 0)
-            break;
-
-        std::cout.put(data);
-    }
+    std::string str;
+    proxy.readString(str, arg.addr);
+    std::cout.write(str.c_str(), str.size());
 
     return retOK(0);
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callWrite(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callWrite(ThreadContext *tc, uint64_t handle, Addr addr,
+                          size_t size)
 {
-    if (argv[1] > files.size() || !files[argv[1]])
-        return RetErrno(argv[3], EBADF);
+    if (handle > files.size() || !files[handle])
+        return RetErrno(size, EBADF);
 
-    std::vector<uint8_t> buffer(argv[3]);
-    physProxy(tc).readBlob(argv[2], buffer.data(), buffer.size());
+    std::vector<uint8_t> buffer(size);
+    physProxy(tc).readBlob(addr, buffer.data(), buffer.size());
 
-    int64_t ret = files[argv[1]]->write(buffer.data(), buffer.size());
+    int64_t ret = files[handle]->write(buffer.data(), buffer.size());
     if (ret < 0) {
         // No bytes written (we're returning the number of bytes not
         // written)
-        return RetErrno(argv[3], -ret);
+        return RetErrno(size, -ret);
     } else {
         // Return the number of bytes not written
-        return RetErrno(argv[3] - ret, 0);
+        return RetErrno(size - ret, 0);
     }
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callRead(ThreadContext *tc, bool aarch64,
-                         std::vector<uint64_t> &argv)
+ArmSemihosting::callRead(ThreadContext *tc, uint64_t handle, Addr addr,
+                         size_t size)
 {
-    if (argv[1] > files.size() || !files[argv[1]])
-        return RetErrno(argv[3], EBADF);
+    if (handle > files.size() || !files[handle])
+        return RetErrno(size, EBADF);
 
-    std::vector<uint8_t> buffer(argv[3]);
-    int64_t ret = files[argv[1]]->read(buffer.data(), buffer.size());
+    std::vector<uint8_t> buffer(size);
+    int64_t ret = files[handle]->read(buffer.data(), buffer.size());
     if (ret < 0) {
-        return RetErrno(argv[3], -ret);
+        return RetErrno(size, -ret);
     } else {
         panic_if(ret > buffer.size(), "Read longer than buffer size.");
 
-        physProxy(tc).writeBlob(argv[2], buffer.data(), ret);
+        physProxy(tc).writeBlob(addr, buffer.data(), ret);
 
         // Return the number of bytes not written
-        return retOK(argv[3] - ret);
+        return retOK(size - ret);
     }
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callReadC(ThreadContext *tc, bool aarch64,
-                           std::vector<uint64_t> &argv)
+ArmSemihosting::callReadC(ThreadContext *tc)
 {
     return retOK((char)std::cin.get());
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callIsError(ThreadContext *tc, bool aarch64,
-                            std::vector<uint64_t> &argv)
+ArmSemihosting::callIsError(ThreadContext *tc, int64_t status)
 {
-    // Sign extend from a 32 bit integer in aarch32 since the argument
-    // reader zero extends to a uint64_t.
-    const int64_t status = (int64_t)(aarch64 ? argv[1] :sext<32>(argv[1]));
-    // Assume there was an error if the status value is negative.
     return retOK(status < 0 ? 1 : 0);
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callIsTTY(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callIsTTY(ThreadContext *tc, uint64_t handle)
 {
-    if (argv[1] > files.size() || !files[argv[1]])
+    if (handle > files.size() || !files[handle])
         return retError(EBADF);
 
-    int64_t ret = files[argv[1]]->isTTY();
+    int64_t ret = files[handle]->isTTY();
     if (ret < 0) {
         return retError(-ret);
     } else {
@@ -438,13 +391,12 @@ ArmSemihosting::callIsTTY(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callSeek(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callSeek(ThreadContext *tc, uint64_t handle, uint64_t pos)
 {
-    if (argv[1] > files.size() || !files[argv[1]])
+    if (handle > files.size() || !files[handle])
         return retError(EBADF);
 
-    int64_t ret = files[argv[1]]->seek(argv[2]);
+    int64_t ret = files[handle]->seek(pos);
     if (ret < 0) {
         return retError(-ret);
     } else {
@@ -453,13 +405,12 @@ ArmSemihosting::callSeek(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callFLen(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callFLen(ThreadContext *tc, uint64_t handle)
 {
-    if (argv[1] > files.size() || !files[argv[1]])
+    if (handle > files.size() || !files[handle])
         return retError(EBADF);
 
-    int64_t ret = files[argv[1]]->flen();
+    int64_t ret = files[handle]->flen();
     if (ret < 0) {
         return retError(-ret);
     } else {
@@ -468,31 +419,26 @@ ArmSemihosting::callFLen(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callTmpNam(ThreadContext *tc, bool aarch64,
-                           std::vector<uint64_t> &argv)
+ArmSemihosting::callTmpNam(ThreadContext *tc, Addr addr, uint64_t id,
+                           size_t size)
 {
-    const Addr guest_buf = argv[1];
-    //const uint64_t id = argv[2];
-    const uint64_t max_len = argv[3];
-
     std::vector<char> buf(L_tmpnam);
     char *path = tmpnam(buf.data());
     if (!path)
         return retError(EINVAL);
 
     const size_t path_len = strlen(path);
-    if (path_len >= max_len)
+    if (path_len >= size)
         return retError(ENOSPC);
 
-    physProxy(tc).writeBlob(guest_buf, path, path_len + 1);
+    physProxy(tc).writeBlob(addr, path, path_len + 1);
     return retOK(0);
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callRemove(ThreadContext *tc, bool aarch64,
-                           std::vector<uint64_t> &argv)
+ArmSemihosting::callRemove(ThreadContext *tc, Addr name_base, size_t name_size)
 {
-    std::string fname = readString(tc, argv[1], argv[2]);
+    std::string fname = readString(tc, name_base, name_size);
 
     if (remove(fname.c_str()) != 0) {
         return retError(errno);
@@ -502,11 +448,11 @@ ArmSemihosting::callRemove(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callRename(ThreadContext *tc, bool aarch64,
-                           std::vector<uint64_t> &argv)
+ArmSemihosting::callRename(ThreadContext *tc, Addr from_addr, size_t from_size,
+                           Addr to_addr, size_t to_size)
 {
-    std::string from = readString(tc, argv[1], argv[2]);
-    std::string to = readString(tc, argv[3], argv[4]);
+    std::string from = readString(tc, from_addr, from_size);
+    std::string to = readString(tc, to_addr, to_size);
 
     if (rename(from.c_str(), to.c_str()) != 0) {
         return retError(errno);
@@ -516,24 +462,21 @@ ArmSemihosting::callRename(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callClock(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callClock(ThreadContext *tc)
 {
     return retOK(curTick() / (SimClock::Int::s / 100));
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callTime(ThreadContext *tc, bool aarch64,
-                         std::vector<uint64_t> &argv)
+ArmSemihosting::callTime(ThreadContext *tc)
 {
     return retOK(timeBase + round(curTick() / SimClock::Float::s));
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callSystem(ThreadContext *tc, bool aarch64,
-                         std::vector<uint64_t> &argv)
+ArmSemihosting::callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size)
 {
-    const std::string cmd = readString(tc, argv[1], argv[2]);
+    const std::string cmd = readString(tc, cmd_addr, cmd_size);
     warn("Semihosting: SYS_SYSTEM not implemented. Guest tried to run: %s\n",
          cmd);
     return retError(EINVAL);
@@ -541,35 +484,33 @@ ArmSemihosting::callSystem(ThreadContext *tc, bool aarch64,
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callErrno(ThreadContext *tc, bool aarch64,
-                          std::vector<uint64_t> &argv)
+ArmSemihosting::callErrno(ThreadContext *tc)
 {
     // Preserve errno by returning it in errno as well.
     return RetErrno(semiErrno, semiErrno);
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callGetCmdLine(ThreadContext *tc, bool aarch64,
-                               std::vector<uint64_t> &argv)
-{
-    if (cmdLine.size() + 1 < argv[2]) {
-        PortProxy &proxy = physProxy(tc);
-        ByteOrder endian = ArmISA::byteOrder(tc);
-        proxy.writeBlob((Addr)argv[1], cmdLine.c_str(), cmdLine.size() + 1);
-
-        if (aarch64)
-            proxy.write<uint64_t>(argv[0] + 1 * 8, cmdLine.size(), endian);
-        else
-            proxy.write<uint32_t>(argv[0] + 1 * 4, cmdLine.size(), endian);
+ArmSemihosting::callGetCmdLine(ThreadContext *tc, Addr addr,
+                               InPlaceArg size_arg)
+{
+    PortProxy &proxy = physProxy(tc);
+    ByteOrder endian = ArmISA::byteOrder(tc);
+    size_t size = size_arg.read(tc, endian);
+
+    if (cmdLine.size() + 1 < size) {
+        proxy.writeBlob(addr, cmdLine.c_str(), cmdLine.size() + 1);
+        size_arg.write(tc, cmdLine.size(), endian);
         return retOK(0);
     } else {
         return retError(0);
     }
 }
 
-ArmSemihosting::RetErrno
-ArmSemihosting::callHeapInfo(ThreadContext *tc, bool aarch64,
-                             std::vector<uint64_t> &argv)
+void
+ArmSemihosting::gatherHeapInfo(ThreadContext *tc, bool aarch64,
+                               Addr &heap_base, Addr &heap_limit,
+                               Addr &stack_base, Addr &stack_limit)
 {
     const PhysicalMemory &phys = tc->getSystemPtr()->getPhysMem();
     const AddrRangeList memories = phys.getConfAddrRanges();
@@ -594,11 +535,10 @@ ArmSemihosting::callHeapInfo(ThreadContext *tc, bool aarch64,
     fatal_if(mem_start + stackSize >= mem_end,
              "Physical memory too small to fit desired stack and a heap.");
 
-    const Addr heap_base = mem_start;
-    const Addr heap_limit = mem_end - stackSize + 1;
-    const Addr stack_base = (mem_end + 1) & ~0x7ULL; // 8 byte stack alignment
-    const Addr stack_limit = heap_limit;
-
+    heap_base = mem_start;
+    heap_limit = mem_end - stackSize + 1;
+    stack_base = (mem_end + 1) & ~0x7ULL; // 8 byte stack alignment
+    stack_limit = heap_limit;
 
     inform("Reporting heap/stack info to guest:\n"
            "\tHeap base: 0x%x\n"
@@ -606,44 +546,56 @@ ArmSemihosting::callHeapInfo(ThreadContext *tc, bool aarch64,
            "\tStack base: 0x%x\n"
            "\tStack limit: 0x%x\n",
            heap_base, heap_limit, stack_base, stack_limit);
+}
 
-    Addr base = argv[1];
-    PortProxy &proxy = physProxy(tc);
-    ByteOrder endian = ArmISA::byteOrder(tc);
-    if (aarch64) {
-        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.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);
-    }
+ArmSemihosting::RetErrno
+ArmSemihosting::callHeapInfo32(ThreadContext *tc, Addr block_addr)
+{
+    uint64_t heap_base, heap_limit, stack_base, stack_limit;
+    gatherHeapInfo(tc, false, heap_base, heap_limit, stack_base, stack_limit);
+
+    std::array<uint32_t, 4> block = {
+        (uint32_t)heap_base, (uint32_t)heap_limit,
+        (uint32_t)stack_base, (uint32_t)stack_limit
+    };
+    physProxy(tc).write(block_addr, block, ArmISA::byteOrder(tc));
 
     return retOK(0);
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callExit(ThreadContext *tc, bool aarch64,
-                         std::vector<uint64_t> &argv)
+ArmSemihosting::callHeapInfo64(ThreadContext *tc, Addr block_addr)
 {
-    if (aarch64) {
-        semiExit(argv[1], argv[2]);
-    } else {
-        semiExit(argv[0], 0);
-    }
+    uint64_t heap_base, heap_limit, stack_base, stack_limit;
+    gatherHeapInfo(tc, true, heap_base, heap_limit, stack_base, stack_limit);
+
+    std::array<uint64_t, 4> block = {
+        heap_base, heap_limit, stack_base, stack_limit
+    };
+    physProxy(tc).write(block_addr, block, ArmISA::byteOrder(tc));
 
     return retOK(0);
 }
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callExitExtended(ThreadContext *tc, bool aarch64,
-                                 std::vector<uint64_t> &argv)
+ArmSemihosting::callExit32(ThreadContext *tc, InPlaceArg code)
 {
-    semiExit(argv[1], argv[2]);
+    semiExit(code.addr, 0);
+    return retOK(0);
+}
+
+ArmSemihosting::RetErrno
+ArmSemihosting::callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode)
+{
+    semiExit(code, subcode);
+    return retOK(0);
+}
 
+ArmSemihosting::RetErrno
+ArmSemihosting::callExitExtended(ThreadContext *tc,
+                                 uint64_t code, uint64_t subcode)
+{
+    semiExit(code, subcode);
     return retOK(0);
 }
 
@@ -660,40 +612,31 @@ ArmSemihosting::semiExit(uint64_t code, uint64_t subcode)
 
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callElapsed(ThreadContext *tc, bool aarch64,
-                            std::vector<uint64_t> &argv)
+ArmSemihosting::callElapsed32(ThreadContext *tc, InPlaceArg low,
+                              InPlaceArg high)
 {
-    PortProxy &proxy = physProxy(tc);
     ByteOrder endian = ArmISA::byteOrder(tc);
-    const uint64_t tick = semiTick(curTick());
+    uint64_t tick = semiTick(curTick());
 
-    if (aarch64) {
-        proxy.write<uint64_t>(argv[0], tick, endian);
-    } else {
-        proxy.write<uint32_t>(argv[0] + 0 * 4, tick, endian);
-        proxy.write<uint32_t>(argv[0] + 1 * 4, tick >> 32, endian);
-    }
+    low.write(tc, tick, endian);
+    high.write(tc, tick >> 32, endian);
 
     return retOK(0);
 }
 
 
 ArmSemihosting::RetErrno
-ArmSemihosting::callTickFreq(ThreadContext *tc, bool aarch64,
-                             std::vector<uint64_t> &argv)
+ArmSemihosting::callElapsed64(ThreadContext *tc, InPlaceArg ticks)
 {
-    return retOK(semiTick(SimClock::Frequency));
+    ticks.write(tc, semiTick(curTick()), ArmISA::byteOrder(tc));
+    return retOK(0);
 }
 
-const ArmSemihosting::SemiCall *
-ArmSemihosting::getCall(uint32_t op, bool aarch64)
+
+ArmSemihosting::RetErrno
+ArmSemihosting::callTickFreq(ThreadContext *tc)
 {
-    auto it = calls.find(op);
-    if (it == calls.end())
-        return nullptr;
-    else {
-        return &it->second;
-    }
+    return retOK(semiTick(SimClock::Frequency));
 }
 
 FILE *
@@ -989,6 +932,13 @@ ArmSemihosting::File::unserialize(CheckpointIn &cp)
     }
 }
 
+std::ostream &
+operator << (std::ostream &os, const ArmSemihosting::InPlaceArg &ipa)
+{
+    ccprintf(os, "[%#x-%#x)", ipa.addr, ipa.addr + ipa.size - 1);
+    return os;
+}
+
 
 ArmSemihosting *
 ArmSemihostingParams::create()
index 104b479c5e8a672b5010df04bdd1633fe2ac8aa4..4a8aa2bd96df24270b81deaf3705a126bf4b16bb 100644 (file)
 #define __ARCH_ARM_SEMIHOSTING_HH__
 
 #include <cstdio>
+#include <functional>
 #include <map>
 #include <memory>
 #include <utility>
 #include <vector>
 
+#include "arch/arm/intregs.hh"
+#include "arch/arm/utility.hh"
+#include "cpu/thread_context.hh"
+#include "mem/port_proxy.hh"
+#include "sim/guest_abi.hh"
 #include "sim/sim_object.hh"
 
 struct ArmSemihostingParams;
-class PortProxy;
 class SerialDevice;
-class ThreadContext;
 
 /**
  * Semihosting for AArch32 and AArch64
@@ -69,6 +73,115 @@ class ArmSemihosting : public SimObject
 {
   public:
 
+    static PortProxy &physProxy(ThreadContext *tc);
+
+    struct AbiBase
+    {
+        template <typename Arg>
+        class StateBase
+        {
+          private:
+            Addr argPointer;
+            ByteOrder endian;
+
+          public:
+            StateBase(const ThreadContext *tc, Addr arg_pointer) :
+                argPointer(arg_pointer), endian(ArmISA::byteOrder(tc))
+            {}
+
+            /*
+             * These two methods are used to both read an argument or its
+             * address, and to move position on to the next location. Normally
+             * State would be more passive, but since it behaves almost the
+             * same no matter what the argument type is we can simplify and
+             * consolidate a little bit by centralizing these methods.
+             */
+
+            // Return the address of an argument slot and move past it.
+            Addr
+            getAddr()
+            {
+                Addr addr = argPointer;
+                argPointer += sizeof(Arg);
+                return addr;
+            }
+
+            // Read the value in an argument slot and move past it.
+            Arg
+            get(ThreadContext *tc)
+            {
+                Arg arg = ArmSemihosting::physProxy(tc).read<Arg>(
+                        argPointer, endian);
+                argPointer += sizeof(Arg);
+                return arg;
+            }
+
+            using ArgType = Arg;
+        };
+    };
+
+    struct Abi64 : public AbiBase
+    {
+        class State : public StateBase<uint64_t>
+        {
+          public:
+            // For 64 bit semihosting, the params are pointer to by X1.
+            explicit State(const ThreadContext *tc) :
+                StateBase<uint64_t>(tc, tc->readIntReg(ArmISA::INTREG_X1))
+            {}
+        };
+    };
+
+    struct Abi32 : public AbiBase
+    {
+        class State : public StateBase<uint64_t>
+        {
+          public:
+            // For 32 bit semihosting, the params are pointer to by R1.
+            explicit State(const ThreadContext *tc) :
+                StateBase<uint64_t>(tc, tc->readIntReg(ArmISA::INTREG_R1))
+            {}
+        };
+    };
+
+    // Use this argument type when you need to modify an argument in place.
+    // This will give you the address of the argument itself and the size of
+    // each argument slot, rather than the actual value of the argument.
+    struct InPlaceArg
+    {
+        Addr addr;
+        size_t size;
+
+        InPlaceArg(Addr _addr, size_t _size) : addr(_addr), size(_size) {}
+
+        // A helper function to read the argument since the guest ABI mechanism
+        // didn't do that for us.
+        uint64_t
+        read(ThreadContext *tc, ByteOrder endian)
+        {
+            auto &proxy = ArmSemihosting::physProxy(tc);
+            if (size == 8)
+                return proxy.read<uint64_t>(addr, endian);
+            else if (size == 4)
+                return proxy.read<uint32_t>(addr, endian);
+            else
+                panic("Unexpected semihosting argument size %d.", size);
+        }
+
+        // A helper function to write to the argument's slot in the params.
+        void
+        write(ThreadContext *tc, uint64_t val, ByteOrder endian)
+        {
+            auto &proxy = ArmSemihosting::physProxy(tc);
+            if (size == 8)
+                proxy.write<uint64_t>(addr, val, endian);
+            else if (size == 4)
+                proxy.write<uint32_t>(addr, val, endian);
+            else
+                panic("Unexpected semihosting argument size %d.", size);
+        }
+    };
+
     enum Operation {
         SYS_OPEN = 0x01,
         SYS_CLOSE = 0x02,
@@ -101,9 +214,9 @@ class ArmSemihosting : public SimObject
     ArmSemihosting(const ArmSemihostingParams *p);
 
     /** Perform an Arm Semihosting call from aarch64 code. */
-    uint64_t call64(ThreadContext *tc, uint32_t op, uint64_t param);
+    void call64(ThreadContext *tc);
     /** Perform an Arm Semihosting call from aarch32 code. */
-    uint32_t call32(ThreadContext *tc, uint32_t op, uint32_t param);
+    void call32(ThreadContext *tc);
 
   public: // SimObject and related interfaces
     void serialize(CheckpointOut &cp) const override;
@@ -274,31 +387,39 @@ class ArmSemihosting : public SimObject
 
     std::string filesRootDir;
     std::vector<std::unique_ptr<FileBase>> files;
+    using Handle = size_t;
     FILE *stdin;
     FILE *stdout;
     FILE *stderr;
 
   protected: // Helper functions
-    unsigned calcTickShift() const {
+    unsigned
+    calcTickShift() const
+    {
         int msb = findMsbSet(SimClock::Frequency);
         return msb > 31 ? msb - 31 : 0;
     }
-    uint64_t semiTick(Tick tick) const {
+    uint64_t
+    semiTick(Tick tick) const
+    {
         return tick >> tickShift;
     }
     void semiExit(uint64_t code, uint64_t subcode);
-    PortProxy &physProxy(ThreadContext *tc);
     std::string readString(ThreadContext *tc, Addr ptr, size_t len);
 
-    std::unique_ptr<PortProxy> physProxyS;
+  public:
+    typedef std::pair<uint64_t, SemiErrno> RetErrno;
 
   private:
-    typedef std::pair<uint64_t, SemiErrno> RetErrno;
-    static  RetErrno retError(SemiErrno e) {
+    static RetErrno
+    retError(SemiErrno e)
+    {
         return RetErrno((uint64_t)-1, e);
     }
 
-    static  RetErrno retOK(uint64_t r) {
+    static RetErrno
+    retOK(uint64_t r)
+    {
         return RetErrno(r, 0);
     }
 
@@ -307,74 +428,135 @@ class ArmSemihosting : public SimObject
      *
      * This structure describes how a semi-hosting call is
      * implemented. It contains debug information (e.g., the name of
-     * the call), a pointer to the implementation, and information
-     * needed to read its parameters from guest memory.
+     * the call), and a way to invoke it in a particular context.
      */
     struct SemiCall
     {
         /** Call name */
         const char *name;
 
-        /**
-         * Pointer to  call implementation
-         *
-         * @param tc ThreadContext pointer for caller
-         * @param aarch64 True if in aarc64 mode, false otherwise.
-         * @parma argv Argument vector. argv[0] always corresponds to
-         *             the pointer to the argument list. Remaining
-         *             entries are read as consecutive words starting
-         *             at the address pointed to by argv[0].
-         * @return a (return value, errno) pair
-         */
-        RetErrno (ArmSemihosting::*call)(ThreadContext *tc, bool aarch64,
-                                         std::vector<uint64_t> &argv);
-
-        /** Number of aarch32 arguments to read from guest memory. -1
-         * if unimplemented.*/
-        int argc32;
-        /** Number of aarch32 arguments to read from guest memory. -1
-         * if unimplemented.*/
-        int argc64;
-
-        /** Is call implemented in aarch32? */
-        bool implemented32() const { return call && argc32 >= 0; }
-        /** Is call implemented in aarch64? */
-        bool implemented64() const { return call && argc64 >= 0; }
+        // A type for member functions implementing semihosting calls.
+        template <typename ...Args>
+        using Implementation =
+            RetErrno (ArmSemihosting::*)(ThreadContext *tc, Args... args);
+
+        // Since guest ABI doesn't know how to call member function pointers,
+        // this template builds a wrapper that takes care of that.
+        template <typename ...Args>
+        static inline std::function<RetErrno(ThreadContext *tc, Args... args)>
+        wrapImpl(ArmSemihosting *sh, Implementation<Args...> impl)
+        {
+            return [sh, impl](ThreadContext *tc, Args... args) {
+                return (sh->*impl)(tc, args...);
+            };
+        }
+
+        // A type for functions which dispatch semihosting calls through the
+        // guest ABI mechanism.
+        using Dispatcher =
+            std::function<RetErrno(ArmSemihosting *sh, ThreadContext *tc)>;
+        using Dumper = std::function<std::string(ThreadContext *tc)>;
+
+        // Dispatchers for 32 and 64 bits.
+        Dispatcher call32;
+        Dispatcher call64;
+
+        // Dumpers which print semihosting calls and their arguments.
+        Dumper dump32;
+        Dumper dump64;
+
+        // A function which builds a dispatcher for a semihosting call.
+        template <typename Abi, typename ...Args>
+        static inline Dispatcher
+        buildDispatcher(Implementation<Args...> impl)
+        {
+            // This lambda is the dispatcher we're building.
+            return [impl](ArmSemihosting *sh, ThreadContext *tc) {
+                auto wrapper = wrapImpl(sh, impl);
+                return invokeSimcall<Abi>(tc, wrapper);
+            };
+        }
+
+        // A function which builds a dumper for a semihosting call.
+        template <typename Abi, typename ...Args>
+        static inline Dumper
+        buildDumper(const char *name, Implementation<Args...> impl)
+        {
+            // This lambda is the dumper we're building.
+            return [name](ThreadContext *tc) -> std::string {
+                return dumpSimcall<Abi, RetErrno, Args...>(name, tc);
+            };
+        }
+
+        // When there's one implementation, use it for both 32 and 64 bits.
+        template <typename ...Args>
+        SemiCall(const char *_name, Implementation<Args...> common) :
+            name(_name), call32(buildDispatcher<Abi32>(common)),
+            call64(buildDispatcher<Abi64>(common)),
+            dump32(buildDumper<Abi32>(_name, common)),
+            dump64(buildDumper<Abi64>(_name, common))
+        {}
+
+        // When there are two, use one for 32 bits and one for 64 bits.
+        template <typename ...Args32, typename ...Args64>
+        SemiCall(const char *_name, Implementation<Args32...> impl32,
+                 Implementation<Args64...> impl64) :
+            name(_name), call32(buildDispatcher<Abi32>(impl32)),
+            call64(buildDispatcher<Abi64>(impl64)),
+            dump32(buildDumper<Abi32>(_name, impl32)),
+            dump64(buildDumper<Abi64>(_name, impl64))
+        {}
     };
 
-#define SEMI_CALL(N)                                                    \
-    RetErrno call ## N (ThreadContext *tc,                              \
-                        bool aarch64, std::vector<uint64_t> &argv)
-
-    SEMI_CALL(Open);
-    SEMI_CALL(Close);
-    SEMI_CALL(WriteC);
-    SEMI_CALL(Write0);
-    SEMI_CALL(Write);
-    SEMI_CALL(Read);
-    SEMI_CALL(ReadC);
-    SEMI_CALL(IsError);
-    SEMI_CALL(IsTTY);
-    SEMI_CALL(Seek);
-    SEMI_CALL(FLen);
-    SEMI_CALL(TmpNam);
-    SEMI_CALL(Remove);
-    SEMI_CALL(Rename);
-    SEMI_CALL(Clock);
-    SEMI_CALL(Time);
-    SEMI_CALL(System);
-    SEMI_CALL(Errno);
-    SEMI_CALL(GetCmdLine);
-    SEMI_CALL(HeapInfo);
-    SEMI_CALL(Exit);
-    SEMI_CALL(ExitExtended);
-
-    SEMI_CALL(Elapsed);
-    SEMI_CALL(TickFreq);
-
-#undef SEMI_CALL
-
-    static const SemiCall *getCall(uint32_t op, bool aarch64);
+    RetErrno callOpen(ThreadContext *tc, const Addr name_base,
+                      int fmode, size_t name_size);
+    RetErrno callClose(ThreadContext *tc, Handle handle);
+    RetErrno callWriteC(ThreadContext *tc, InPlaceArg c);
+    RetErrno callWrite0(ThreadContext *tc, InPlaceArg str);
+    RetErrno callWrite(ThreadContext *tc, Handle handle,
+                       Addr buffer, size_t size);
+    RetErrno callRead(ThreadContext *tc, Handle handle,
+                      Addr buffer, size_t size);
+    RetErrno callReadC(ThreadContext *tc);
+    RetErrno callIsError(ThreadContext *tc, int64_t status);
+    RetErrno callIsTTY(ThreadContext *tc, Handle handle);
+    RetErrno callSeek(ThreadContext *tc, Handle handle, uint64_t pos);
+    RetErrno callFLen(ThreadContext *tc, Handle handle);
+    RetErrno callTmpNam(ThreadContext *tc, Addr buffer,
+                        uint64_t id, size_t size);
+    RetErrno callRemove(ThreadContext *tc, Addr name_base, size_t name_size);
+    RetErrno callRename(ThreadContext *tc, Addr from_addr, size_t from_size,
+                        Addr to_addr, size_t to_size);
+    RetErrno callClock(ThreadContext *tc);
+    RetErrno callTime(ThreadContext *tc);
+    RetErrno callSystem(ThreadContext *tc, Addr cmd_addr, size_t cmd_size);
+    RetErrno callErrno(ThreadContext *tc);
+    RetErrno callGetCmdLine(ThreadContext *tc, Addr addr, InPlaceArg size_arg);
+
+    void gatherHeapInfo(ThreadContext *tc, bool aarch64,
+                        Addr &heap_base, Addr &heap_limit,
+                        Addr &stack_base, Addr &stack_limit);
+    RetErrno callHeapInfo32(ThreadContext *tc, Addr block_addr);
+    RetErrno callHeapInfo64(ThreadContext *tc, Addr block_addr);
+    RetErrno callExit32(ThreadContext *tc, InPlaceArg code);
+    RetErrno callExit64(ThreadContext *tc, uint64_t code, uint64_t subcode);
+    RetErrno callExitExtended(ThreadContext *tc, uint64_t code,
+                              uint64_t subcode);
+
+    RetErrno callElapsed32(ThreadContext *tc, InPlaceArg low, InPlaceArg high);
+    RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks);
+    RetErrno callTickFreq(ThreadContext *tc);
+
+    template <typename Abi>
+    void
+    unrecognizedCall(ThreadContext *tc, const char *format, uint64_t op)
+    {
+        warn(format, op);
+        std::function<RetErrno(ThreadContext *tc)> retErr =
+            [](ThreadContext *tc) { return retError(EINVAL); };
+        invokeSimcall<Abi>(tc, retErr);
+    }
+
     static FILE *getSTDIO(const char *stream_name,
                           const std::string &name, const char *mode);
 
@@ -385,4 +567,69 @@ class ArmSemihosting : public SimObject
     static const std::map<const std::string, FILE *> stdioMap;
 };
 
+std::ostream &operator << (
+        std::ostream &os, const ArmSemihosting::InPlaceArg &ipa);
+
+namespace GuestABI
+{
+
+template <typename Arg>
+struct Argument<ArmSemihosting::Abi64, Arg,
+    typename std::enable_if<std::is_integral<Arg>::value>::type>
+{
+    static Arg
+    get(ThreadContext *tc, ArmSemihosting::Abi64::State &state)
+    {
+        return state.get(tc);
+    }
+};
+
+template <typename Arg>
+struct Argument<ArmSemihosting::Abi32, Arg,
+    typename std::enable_if<std::is_integral<Arg>::value>::type>
+{
+    static Arg
+    get(ThreadContext *tc, ArmSemihosting::Abi32::State &state)
+    {
+        if (std::is_signed<Arg>::value)
+            return sext<32>(state.get(tc));
+        else
+            return state.get(tc);
+    }
+};
+
+template <typename Abi>
+struct Argument<Abi, ArmSemihosting::InPlaceArg, typename std::enable_if<
+    std::is_base_of<ArmSemihosting::AbiBase, Abi>::value>::type>
+{
+    static ArmSemihosting::InPlaceArg
+    get(ThreadContext *tc, typename Abi::State &state)
+    {
+        return ArmSemihosting::InPlaceArg(
+                state.getAddr(), sizeof(typename Abi::State::ArgType));
+    }
+};
+
+template <>
+struct Result<ArmSemihosting::Abi32, ArmSemihosting::RetErrno>
+{
+    static void
+    store(ThreadContext *tc, const ArmSemihosting::RetErrno &err)
+    {
+        tc->setIntReg(ArmISA::INTREG_R0, err.first);
+    }
+};
+
+template <>
+struct Result<ArmSemihosting::Abi64, ArmSemihosting::RetErrno>
+{
+    static void
+    store(ThreadContext *tc, const ArmSemihosting::RetErrno &err)
+    {
+        tc->setIntReg(ArmISA::INTREG_X0, err.first);
+    }
+};
+
+} // namespace GuestABI
+
 #endif // __ARCH_ARM_SEMIHOSTING_HH__
index 6094121cc72d4794446710c1355523845caab22c..906cc9eda132dc61d45d9f3e752d51177e4c0185 100644 (file)
@@ -179,20 +179,16 @@ ArmSystem::haveSemihosting(ThreadContext *tc)
     return FullSystem && getArmSystem(tc)->haveSemihosting();
 }
 
-uint64_t
-ArmSystem::callSemihosting64(ThreadContext *tc,
-                             uint32_t op, uint64_t param)
+void
+ArmSystem::callSemihosting64(ThreadContext *tc)
 {
-    ArmSystem *sys = getArmSystem(tc);
-    return sys->semihosting->call64(tc, op, param);
+    getArmSystem(tc)->semihosting->call64(tc);
 }
 
-uint32_t
-ArmSystem::callSemihosting32(ThreadContext *tc,
-                             uint32_t op, uint32_t param)
+void
+ArmSystem::callSemihosting32(ThreadContext *tc)
 {
-    ArmSystem *sys = getArmSystem(tc);
-    return sys->semihosting->call32(tc, op, param);
+    getArmSystem(tc)->semihosting->call32(tc);
 }
 
 void
index d9268f09393f4f1827845d25ab0393a33abcc37f..ae83da07d0b35c0f69b6713c1f668937ca2ed85a 100644 (file)
@@ -314,12 +314,10 @@ class ArmSystem : public System
     static bool haveSemihosting(ThreadContext *tc);
 
     /** Make a Semihosting call from aarch64 */
-    static uint64_t callSemihosting64(ThreadContext *tc,
-                                      uint32_t op, uint64_t param);
+    static void callSemihosting64(ThreadContext *tc);
 
     /** Make a Semihosting call from aarch32 */
-    static uint32_t callSemihosting32(ThreadContext *tc,
-                                      uint32_t op, uint32_t param);
+    static void callSemihosting32(ThreadContext *tc);
 
     /** Make a call to notify the power controller of STANDBYWFI assertion */
     static void callSetStandByWfi(ThreadContext *tc);