fastmodel: Enable semihosting, including pseudo insts.
authorGabe Black <gabeblack@google.com>
Thu, 21 Nov 2019 23:36:21 +0000 (15:36 -0800)
committerGabe Black <gabeblack@google.com>
Mon, 20 Apr 2020 07:02:54 +0000 (07:02 +0000)
It is assumed that the semihosting configuration uses the semihosting
number which includes gem5's pseudo insts.

Given the complexity and likely limitted value of letting the user
arbitrarily configure fast model's semihosting, and the fact that that
semihosting implementation would compete with gem5's own, those
parameters should be removed from python and set purely within C++.

Also note that if this semihosting support is used, the System object
needs to have an ArmSemihosting object installed to handle the calls.

Change-Id: I8e1de7717c9784dc7873795acd0a06389ec527b1
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/25623
Tested-by: Gem5 Cloud Project GCB service account <345032938727@cloudbuild.gserviceaccount.com>
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>

src/arch/arm/fastmodel/iris/thread_context.cc
src/arch/arm/fastmodel/iris/thread_context.hh

index 9aed27b7c99cc2a85ea8ffcecced4c8605950d1f..a2cf2bfc6359f915f8cacc60ed3f87d5146334f0 100644 (file)
 
 #include <utility>
 
+#include "arch/arm/system.hh"
 #include "arch/arm/utility.hh"
 #include "iris/detail/IrisCppAdapter.h"
 #include "iris/detail/IrisObjects.h"
 #include "mem/se_translating_port_proxy.hh"
 #include "mem/translating_port_proxy.hh"
+#include "sim/pseudo_inst.hh"
 
 namespace Iris
 {
@@ -62,6 +64,17 @@ ThreadContext::initFromIrisInstance(const ResourceMap &resources)
 
     for (auto it = bps.begin(); it != bps.end(); it++)
         installBp(it);
+
+    client.registerEventCallback<Self, &Self::semihostingEvent>(
+            this, "ec_IRIS_SEMIHOSTING_CALL_EXTENSION",
+            "Handle a semihosting call", "Iris::ThreadContext");
+    call().event_getEventSource(_instId, evSrcInfo,
+            "IRIS_SEMIHOSTING_CALL_EXTENSION");
+    call().eventStream_create(_instId, semihostingEventStreamId,
+            evSrcInfo.evSrcId, client.getInstId(),
+            // Set all arguments to their defaults, except syncEc which is
+            // changed to true.
+            nullptr, "", false, 0, nullptr, false, false, true);
 }
 
 iris::ResourceId
@@ -243,6 +256,28 @@ ThreadContext::breakpointHit(
     return iris::E_ok;
 }
 
+iris::IrisErrorCode
+ThreadContext::semihostingEvent(
+        uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+        uint64_t sInstId, bool syncEc, std::string &error_message_out)
+{
+    if (ArmSystem::callSemihosting(this, true)) {
+        // Stop execution in case an exit of the sim loop was scheduled. We
+        // don't want to keep executing instructions in the mean time.
+        call().perInstanceExecution_setState(_instId, false);
+
+        // Schedule an event to resume execution right after any exit has
+        // had a chance to happen.
+        if (!enableAfterPseudoEvent->scheduled())
+            getCpuPtr()->schedule(enableAfterPseudoEvent, curTick());
+
+        call().semihosting_return(_instId, readIntReg(0));
+    } else {
+        call().semihosting_notImplemented(_instId);
+    }
+    return iris::E_ok;
+}
+
 ThreadContext::ThreadContext(
         BaseCPU *cpu, int id, System *system, ::BaseTLB *dtb, ::BaseTLB *itb,
         iris::IrisConnectionInterface *iris_if, const std::string &iris_path) :
@@ -299,6 +334,14 @@ ThreadContext::ThreadContext(
             evSrcInfo.evSrcId, client.getInstId());
 
     breakpointEventStreamId = iris::IRIS_UINT64_MAX;
+    semihostingEventStreamId = iris::IRIS_UINT64_MAX;
+
+    auto enable_lambda = [this]{
+        call().perInstanceExecution_setState(_instId, true);
+    };
+    enableAfterPseudoEvent = new EventFunctionWrapper(
+            enable_lambda, "resume after pseudo inst",
+            false, Event::Sim_Exit_Pri + 1);
 }
 
 ThreadContext::~ThreadContext()
@@ -317,6 +360,10 @@ ThreadContext::~ThreadContext()
             iris::IrisInstIdGlobalInstance, timeEventStreamId);
     timeEventStreamId = iris::IRIS_UINT64_MAX;
     client.unregisterEventCallback("ec_IRIS_SIMULATION_TIME_EVENT");
+
+    if (enableAfterPseudoEvent->scheduled())
+        getCpuPtr()->deschedule(enableAfterPseudoEvent);
+    delete enableAfterPseudoEvent;
 }
 
 bool
@@ -424,6 +471,8 @@ ThreadContext::status() const
 void
 ThreadContext::setStatus(Status new_status)
 {
+    if (enableAfterPseudoEvent->scheduled())
+        getCpuPtr()->deschedule(enableAfterPseudoEvent);
     if (new_status == Active) {
         if (_status != Active)
             call().perInstanceExecution_setState(_instId, true);
index d4e80f1f90aabd7b1c8d93303ed48574b1332c90..6b16069424ded6717a8edabb8ed913ff30fd424f 100644 (file)
@@ -69,6 +69,7 @@ class ThreadContext : public ::ThreadContext
     mutable std::vector<ArmISA::VecPredRegContainer> vecPredRegs;
 
     Status _status = Active;
+    Event *enableAfterPseudoEvent;
 
     virtual void initFromIrisInstance(const ResourceMap &resources);
 
@@ -147,11 +148,15 @@ class ThreadContext : public ::ThreadContext
     iris::IrisErrorCode breakpointHit(
             uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
             uint64_t sInstId, bool syncEc, std::string &error_message_out);
+    iris::IrisErrorCode semihostingEvent(
+            uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
+            uint64_t sInstId, bool syncEc, std::string &error_message_out);
 
     iris::EventStreamId regEventStreamId;
     iris::EventStreamId initEventStreamId;
     iris::EventStreamId timeEventStreamId;
     iris::EventStreamId breakpointEventStreamId;
+    iris::EventStreamId semihostingEventStreamId;
 
     mutable iris::IrisInstance client;
     iris::IrisCppAdapter &call() const { return client.irisCall(); }