sparc: Use a SPARC specific GuestABI for system calls.
authorGabe Black <gabeblack@google.com>
Sat, 7 Dec 2019 11:07:43 +0000 (03:07 -0800)
committerGabe Black <gabeblack@google.com>
Thu, 12 Mar 2020 01:35:34 +0000 (01:35 +0000)
Change-Id: I41996cada5ccde7b265e5315829ac6690da8902f
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/23447
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/sparc/linux/process.hh
src/arch/sparc/linux/syscalls.cc
src/arch/sparc/process.cc
src/arch/sparc/process.hh
src/arch/sparc/solaris/process.cc
src/arch/sparc/solaris/process.hh

index 3b79b39fd85f812ad66e62b439b15043776747e5..3543773aaa0d8ec6286731e596146ec4c23361ee 100644 (file)
@@ -43,11 +43,11 @@ class SparcLinuxProcess
 {
   public:
      /// Array of syscall descriptors, indexed by call number.
-    static SyscallDescABI<DefaultSyscallABI> syscallDescs[];
+    static SyscallDescABI<Sparc64Process::SyscallABI> syscallDescs[];
 
      /// Array of 32 bit compatibility syscall descriptors,
      /// indexed by call number.
-    static SyscallDescABI<DefaultSyscallABI> syscall32Descs[];
+    static SyscallDescABI<Sparc32Process::SyscallABI> syscall32Descs[];
 
     SyscallDesc *getDesc(int callnum);
     SyscallDesc *getDesc32(int callnum);
index 2c4992ccff3d4832c98e7cf54163de57178a55e0..bb36d1e70f5adfe9dcbfa6eb6e07b90eaafc9776 100644 (file)
@@ -81,7 +81,8 @@ getresuidFunc(SyscallDesc *desc, int num, ThreadContext *tc,
     return 0;
 }
 
-SyscallDescABI<DefaultSyscallABI> SparcLinuxProcess::syscall32Descs[] = {
+SyscallDescABI<Sparc32Process::SyscallABI>
+    SparcLinuxProcess::syscall32Descs[] = {
     /*   0 */ { "restart_syscall" },
     /*   1 */ { "exit", exitFunc }, // 32 bit
     /*   2 */ { "fork" },
@@ -387,7 +388,8 @@ SyscallDescABI<DefaultSyscallABI> SparcLinuxProcess::syscall32Descs[] = {
 const int SparcLinuxProcess::Num_Syscall32_Descs =
     sizeof(SparcLinuxProcess::syscall32Descs) / sizeof(SyscallDesc);
 
-SyscallDescABI<DefaultSyscallABI> SparcLinuxProcess::syscallDescs[] = {
+SyscallDescABI<Sparc64Process::SyscallABI>
+    SparcLinuxProcess::syscallDescs[] = {
     /*  0 */ { "restart_syscall" },
     /*  1 */ { "exit", exitFunc },
     /*  2 */ { "fork" },
index ce201d0b4924c79dc0eb644a268b61b435a1da66..0104b1a580d1a3d69f6d7aef330bc81ff64c74fa 100644 (file)
@@ -48,8 +48,9 @@
 using namespace std;
 using namespace SparcISA;
 
-static const int FirstArgumentReg = 8;
-
+const std::vector<int> SparcProcess::SyscallABI::ArgumentRegs = {
+    INTREG_O0, INTREG_O1, INTREG_O2, INTREG_O3, INTREG_O4, INTREG_O5
+};
 
 SparcProcess::SparcProcess(ProcessParams *params, ObjectFile *objFile,
                            Addr _StackBias)
@@ -490,6 +491,8 @@ Sparc64Process::flushWindows(ThreadContext *tc)
     tc->setMiscReg(MISCREG_CWP, origCWP);
 }
 
+static const int FirstArgumentReg = 8;
+
 RegVal
 Sparc32Process::getSyscallArg(ThreadContext *tc, int &i)
 {
index f8660bddf950d375eeaeb325f5574013bf34992f..4bd99a83447e902ff9bc1328e8bc69c1f052323c 100644 (file)
 #include <vector>
 
 #include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/miscregs.hh"
 #include "base/loader/object_file.hh"
 #include "mem/page_table.hh"
 #include "sim/byteswap.hh"
 #include "sim/process.hh"
+#include "sim/syscall_abi.hh"
 
 class SparcProcess : public Process
 {
@@ -67,8 +69,52 @@ class SparcProcess : public Process
     virtual void flushWindows(ThreadContext *tc) = 0;
     void setSyscallReturn(ThreadContext *tc,
             SyscallReturn return_value) override;
+
+    struct SyscallABI
+    {
+        static const std::vector<int> ArgumentRegs;
+    };
 };
 
+namespace GuestABI
+{
+
+template <typename ABI>
+struct Result<ABI, SyscallReturn,
+    typename std::enable_if<std::is_base_of<
+        SparcProcess::SyscallABI, ABI>::value>::type>
+{
+    static void
+    store(ThreadContext *tc, const SyscallReturn &ret)
+    {
+        if (ret.suppressed() || ret.needsRetry())
+            return;
+
+        // check for error condition.  SPARC syscall convention is to
+        // indicate success/failure in reg the carry bit of the ccr
+        // and put the return value itself in the standard return value reg.
+        SparcISA::PSTATE pstate =
+            tc->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE);
+        SparcISA::CCR ccr = tc->readIntReg(SparcISA::INTREG_CCR);
+        RegVal val;
+        if (ret.successful()) {
+            ccr.xcc.c = ccr.icc.c = 0;
+            val = ret.returnValue();
+        } else {
+            ccr.xcc.c = ccr.icc.c = 1;
+            val = ret.errnoValue();
+        }
+        tc->setIntReg(SparcISA::INTREG_CCR, ccr);
+        if (pstate.am)
+            val = bits(val, 31, 0);
+        tc->setIntReg(SparcISA::ReturnValueReg, val);
+        if (ret.count() == 2)
+            tc->setIntReg(SparcISA::SyscallPseudoReturnReg, ret.value2());
+    }
+};
+
+} // namespace GuestABI
+
 class Sparc32Process : public SparcProcess
 {
   protected:
@@ -109,8 +155,35 @@ class Sparc32Process : public SparcProcess
     RegVal getSyscallArg(ThreadContext *tc, int &i) override;
     /// Explicitly import the otherwise hidden getSyscallArg
     using Process::getSyscallArg;
+
+    struct SyscallABI : public GenericSyscallABI32,
+                        public SparcProcess::SyscallABI
+    {};
 };
 
+namespace GuestABI
+{
+
+template <typename Arg>
+struct Argument<Sparc32Process::SyscallABI, Arg,
+    typename std::enable_if<
+        Sparc32Process::SyscallABI::IsWide<Arg>::value>::type>
+{
+    using ABI = Sparc32Process::SyscallABI;
+
+    static Arg
+    get(ThreadContext *tc, typename ABI::Position &position)
+    {
+        panic_if(position + 1 >= ABI::ArgumentRegs.size(),
+                "Ran out of syscall argument registers.");
+        auto high = ABI::ArgumentRegs[position++];
+        auto low = ABI::ArgumentRegs[position++];
+        return (Arg)ABI::mergeRegs(tc, low, high);
+    }
+};
+
+} // namespace GuestABI
+
 class Sparc64Process : public SparcProcess
 {
   protected:
@@ -150,6 +223,10 @@ class Sparc64Process : public SparcProcess
     RegVal getSyscallArg(ThreadContext *tc, int &i) override;
     /// Explicitly import the otherwise hidden getSyscallArg
     using Process::getSyscallArg;
+
+    struct SyscallABI : public GenericSyscallABI64,
+                        public SparcProcess::SyscallABI
+    {};
 };
 
 #endif // __SPARC_PROCESS_HH__
index 20fb3cf8f5bd86dcd3d6b0dc3f052da2c044f834..bf34f58a58e18c0c158363bc6544b66bcdac99c5 100644 (file)
@@ -87,7 +87,8 @@ unameFunc(SyscallDesc *desc, int callnum, ThreadContext *tc, Addr utsname)
 }
 
 
-SyscallDescABI<DefaultSyscallABI> SparcSolarisProcess::syscallDescs[] = {
+SyscallDescABI<Sparc64Process::SyscallABI>
+    SparcSolarisProcess::syscallDescs[] = {
     /* 0 */ { "syscall" },
     /* 1 */ { "exit", exitFunc },
     /* 2 */ { "fork" },
index 9dac37868070b2a6e96bb78f9045dc7278b04679..0f658ba246e896cca8271cc9ed951af84f2cafa5 100644 (file)
@@ -51,7 +51,7 @@ class SparcSolarisProcess : public Sparc64Process
     void syscall(ThreadContext *tc, Fault *fault) override;
 
      /// Array of syscall descriptors, indexed by call number.
-    static SyscallDescABI<DefaultSyscallABI> syscallDescs[];
+    static SyscallDescABI<Sparc64Process::SyscallABI> syscallDescs[];
 
     const int Num_Syscall_Descs;
 };