sim: Add a wrapper/subclass for SyscallDesc which uses GuestABI.
authorGabe Black <gabeblack@google.com>
Sat, 23 Nov 2019 02:05:23 +0000 (18:05 -0800)
committerGabe Black <gabeblack@google.com>
Tue, 10 Dec 2019 23:58:14 +0000 (23:58 +0000)
This will let system call implementations take arguments naturally,
and centrally defined, potentially complex, and ISA/context specific
mechanisms will automatically gather the arguments and store any
result.

Jira Issue: https://gem5.atlassian.net/browse/GEM5-187

Change-Id: I68d265e0bab5de372ba975e4c7e9bb2d968c80af
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/23172
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>

src/sim/syscall_desc.hh

index 9a28591480f33ec852143796d379dd4cefe2ee83..e5adf8bd5cec4c425110d1ab7120a5651ddb7757 100644 (file)
@@ -50,6 +50,7 @@
 #include <string>
 
 #include "base/types.hh"
+#include "sim/guest_abi.hh"
 #include "sim/syscall_return.hh"
 
 class Process;
@@ -94,4 +95,63 @@ class SyscallDesc {
     SyscallExecutor executor;
 };
 
+/*
+ * This SyscallDesc subclass template adapts a given syscall implementation so
+ * that some arguments can come from the simulator (desc, num and tc) while the
+ * rest can come from the guest using the GuestABI mechanism.
+ */
+template <typename ABI>
+class SyscallDescABI : public SyscallDesc
+{
+  private:
+    // Aliases to make the code below a little more concise.
+    template <typename ...Args>
+    using SyscallABIExecutor =
+        std::function<SyscallReturn(SyscallDesc *, int,
+                                    ThreadContext *, Args...)>;
+
+    template <typename ...Args>
+    using SyscallABIExecutorPtr =
+        SyscallReturn (*)(SyscallDesc *, int, ThreadContext *, Args...);
+
+
+    // Wrap an executor with guest arguments with a normal executor that gets
+    // those additional arguments from the guest context.
+    template <typename ...Args>
+    static inline SyscallExecutor
+    buildExecutor(SyscallABIExecutor<Args...> target)
+    {
+        return [target](SyscallDesc *desc, int num,
+                        ThreadContext *tc) -> SyscallReturn {
+            // Create a partial function which will stick desc and num to the
+            // front of the parameter list.
+            auto partial = [target,desc,num](
+                    ThreadContext *tc, Args... args) -> SyscallReturn {
+                return target(desc, num, tc, args...);
+            };
+
+            // Use invokeSimcall to gather the other arguments based on the
+            // given ABI and pass them to the syscall implementation.
+            return invokeSimcall<ABI, SyscallReturn, Args...>(tc,
+                    std::function<SyscallReturn(ThreadContext *, Args...)>(
+                        partial));
+        };
+    }
+
+
+  public:
+    // Constructors which plumb in buildExecutor.
+    template <typename ...Args>
+    SyscallDescABI(const char *name, SyscallABIExecutor<Args...> target) :
+        SyscallDesc(name, buildExecutor<Args...>(target))
+    {}
+
+    template <typename ...Args>
+    SyscallDescABI(const char *name, SyscallABIExecutorPtr<Args...> target) :
+        SyscallDescABI(name, SyscallABIExecutor<Args...>(target))
+    {}
+
+    using SyscallDesc::SyscallDesc;
+};
+
 #endif // __SIM_SYSCALL_DESC_HH__