arm: Use an ARM specific GuestABI for ARM system calls.
authorGabe Black <gabeblack@google.com>
Sat, 7 Dec 2019 15:28:14 +0000 (07:28 -0800)
committerGabe Black <gabeblack@google.com>
Thu, 12 Mar 2020 01:35:34 +0000 (01:35 +0000)
Change-Id: I2d0d0a563355f43ed791ba2f2a1894e303cca994
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/23448
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/arm/freebsd/process.cc
src/arch/arm/freebsd/process.hh
src/arch/arm/linux/process.cc
src/arch/arm/linux/process.hh
src/arch/arm/process.cc
src/arch/arm/process.hh

index 58edefc47e0271b9fb289c74af5289ba765ddcc0..e384e6aad7202a0a26bad5c4f2504c794f3384e3 100644 (file)
@@ -131,7 +131,7 @@ sysctlFunc(SyscallDesc *desc, int callnum, ThreadContext *tc,
 }
 #endif
 
-static SyscallDescABI<DefaultSyscallABI> syscallDescs32[] = {
+static SyscallDescABI<ArmFreebsdProcess32::SyscallABI> syscallDescs32[] = {
     /*    0 */ { "unused#000" },
     /*    1 */ { "unused#001" },
     /*    2 */ { "unused#002" },
@@ -682,7 +682,7 @@ static SyscallDescABI<DefaultSyscallABI> syscallDescs32[] = {
     /*  547 */ { "unused#547" },
 };
 
-static SyscallDescABI<DefaultSyscallABI> syscallDescs64[] = {
+static SyscallDescABI<ArmFreebsdProcess64::SyscallABI> syscallDescs64[] = {
     /*    0 */ { "unused#000" },
     /*    1 */ { "exit", exitFunc },
     /*    2 */ { "unused#002" },
index 7f3d6fbb57bcaa6adaf0b204fc925805627be4a4..835acc5b28bb2ef3e3ce137a5de94096140e70c7 100644 (file)
@@ -52,8 +52,40 @@ class ArmFreebsdProcessBits
     };
 
     std::vector<SyscallTable> syscallTables;
+
+    struct SyscallABI {};
+};
+
+namespace GuestABI
+{
+
+template <typename ABI>
+struct Result<ABI, SyscallReturn,
+    typename std::enable_if<std::is_base_of<
+        ArmFreebsdProcessBits::SyscallABI, ABI>::value>::type>
+{
+    static void
+    store(ThreadContext *tc, const SyscallReturn &ret)
+    {
+        if (ret.suppressed() || ret.needsRetry())
+            return;
+
+        RegVal val;
+        if (ret.successful()) {
+            tc->setCCReg(ArmISA::CCREG_C, 0);
+            val = ret.returnValue();
+        } else {
+            tc->setCCReg(ArmISA::CCREG_C, 1);
+            val = ret.encodedValue();
+        }
+        tc->setIntReg(ArmISA::ReturnValueReg, val);
+        if (ret.count() > 1)
+            tc->setIntReg(ArmISA::SyscallPseudoReturnReg, ret.value2());
+    }
 };
 
+} // namespace GuestABI
+
 /// A process with emulated Arm/Freebsd syscalls.
 class ArmFreebsdProcess32 : public ArmProcess32, public ArmFreebsdProcessBits
 {
@@ -72,6 +104,10 @@ class ArmFreebsdProcess32 : public ArmProcess32, public ArmFreebsdProcessBits
     static const Addr commPage;
 
     SyscallDesc* getDesc(int callnum) override;
+
+    struct SyscallABI : public ArmProcess32::SyscallABI,
+                        public ArmFreebsdProcessBits::SyscallABI
+    {};
 };
 
 /// A process with emulated Arm/Freebsd syscalls.
@@ -84,6 +120,10 @@ class ArmFreebsdProcess64 : public ArmProcess64, public ArmFreebsdProcessBits
     void initState() override;
     void syscall(ThreadContext *tc, Fault *fault) override;
     SyscallDesc* getDesc(int callnum) override;
+
+    struct SyscallABI : public ArmProcess64::SyscallABI,
+                        public ArmFreebsdProcessBits::SyscallABI
+    {};
 };
 
 #endif // __ARCH_ARM_FREEBSD_PROCESS_HH__
index 6ed37b0489fbfde832455da69d771ce89846c44f..03b85beec0c9f16a707c9d0447f38c4edfe4bc80 100644 (file)
@@ -151,7 +151,7 @@ setTLSFunc64(SyscallDesc *desc, int callnum, ThreadContext *tc,
     return 0;
 }
 
-static SyscallDescABI<DefaultSyscallABI> syscallDescs32[] = {
+static SyscallDescABI<ArmLinuxProcess32::SyscallABI> syscallDescs32[] = {
     /*  0 */ { "syscall" },
     /*  1 */ { "exit", exitFunc },
     /*  2 */ { "fork" },
@@ -528,7 +528,7 @@ static SyscallDescABI<DefaultSyscallABI> syscallDescs32[] = {
     /* 365 */ { "sys_recvmmsg" },
 };
 
-static SyscallDescABI<DefaultSyscallABI> syscallDescs64[] = {
+static SyscallDescABI<ArmLinuxProcess64::SyscallABI> syscallDescs64[] = {
     /*    0 */ { "io_setup" },
     /*    1 */ { "io_destroy" },
     /*    2 */ { "io_submit" },
@@ -1619,7 +1619,7 @@ static SyscallDescABI<DefaultSyscallABI> syscallDescs64[] = {
     /* 1079 */ { "fork" }
 };
 
-static SyscallDescABI<DefaultSyscallABI> privSyscallDescs32[] = {
+static SyscallDescABI<ArmLinuxProcess32::SyscallABI> privSyscallDescs32[] = {
     /*  1 */ { "breakpoint" },
     /*  2 */ { "cacheflush" },
     /*  3 */ { "usr26" },
@@ -1628,7 +1628,7 @@ static SyscallDescABI<DefaultSyscallABI> privSyscallDescs32[] = {
 };
 
 // Indices 1, 3 and 4 are unallocated.
-static SyscallDescABI<DefaultSyscallABI> privSyscallDescs64[] = {
+static SyscallDescABI<ArmLinuxProcess64::SyscallABI> privSyscallDescs64[] = {
     /*  1 */ { "unallocated" },
     /*  2 */ { "cacheflush" },
     /*  3 */ { "unallocated" },
index e37aed19ee8b9415fe610044ae2c8ccb37bd8778..8204f43004a2db5dd3fd1ea9ee3be580f7c03165 100644 (file)
@@ -60,8 +60,32 @@ class ArmLinuxProcessBits
     };
 
     std::vector<SyscallTable> syscallTables;
+
+    struct SyscallABI {};
 };
 
+namespace GuestABI
+{
+
+template <typename ABI>
+struct Result<ABI, SyscallReturn,
+    typename std::enable_if<std::is_base_of<
+        ArmLinuxProcessBits::SyscallABI, ABI>::value>::type>
+{
+    static void
+    store(ThreadContext *tc, const SyscallReturn &ret)
+    {
+        if (ret.suppressed() || ret.needsRetry())
+            return;
+
+        tc->setIntReg(ArmISA::ReturnValueReg, ret.encodedValue());
+        if (ret.count() > 1)
+            tc->setIntReg(ArmISA::SyscallPseudoReturnReg, ret.value2());
+    }
+};
+
+} // namespace GuestABI
+
 /// A process with emulated Arm/Linux syscalls.
 class ArmLinuxProcess32 : public ArmProcess32, public ArmLinuxProcessBits
 {
@@ -80,6 +104,10 @@ class ArmLinuxProcess32 : public ArmProcess32, public ArmLinuxProcessBits
     static const Addr commPage;
 
     SyscallDesc* getDesc(int callnum) override;
+
+    struct SyscallABI : public ArmProcess32::SyscallABI,
+                        public ArmLinuxProcessBits::SyscallABI
+    {};
 };
 
 /// A process with emulated Arm/Linux syscalls.
@@ -92,6 +120,10 @@ class ArmLinuxProcess64 : public ArmProcess64, public ArmLinuxProcessBits
     void initState() override;
     void syscall(ThreadContext *tc, Fault *fault) override;
     SyscallDesc* getDesc(int callnum) override;
+
+    struct SyscallABI : public ArmProcess64::SyscallABI,
+                        public ArmLinuxProcessBits::SyscallABI
+    {};
 };
 
 #endif // __ARM_LINUX_PROCESS_HH__
index bce354e704a9b18640a9fb9d89428846d0966bf2..7eb263dcedd23762c2582548f871a929bb6df39d 100644 (file)
@@ -470,6 +470,14 @@ ArmProcess::argsInit(int pageSize, IntRegIndex spIndex)
     memState->setStackMin(roundDown(memState->getStackMin(), pageSize));
 }
 
+const std::vector<int> ArmProcess32::SyscallABI::ArgumentRegs = {
+    0, 1, 2, 3, 4, 5, 6
+};
+
+const std::vector<int> ArmProcess64::SyscallABI::ArgumentRegs = {
+    0, 1, 2, 3, 4, 5, 6
+};
+
 RegVal
 ArmProcess32::getSyscallArg(ThreadContext *tc, int &i)
 {
index cc9e39d656eba4f351354020ec5a02e9af8a8d32..1650ff680ac927db41b97883471eef2fb2a84f0e 100644 (file)
@@ -48,6 +48,7 @@
 #include "base/loader/object_file.hh"
 #include "mem/page_table.hh"
 #include "sim/process.hh"
+#include "sim/syscall_abi.hh"
 
 class ObjectFile;
 
@@ -89,8 +90,38 @@ class ArmProcess32 : public ArmProcess
     RegVal getSyscallArg(ThreadContext *tc, int &i) override;
     void setSyscallReturn(ThreadContext *tc,
             SyscallReturn return_value) override;
+
+    struct SyscallABI : public GenericSyscallABI32
+    {
+        static const std::vector<int> ArgumentRegs;
+    };
+};
+
+namespace GuestABI
+{
+
+template <typename ABI, typename Arg>
+struct Argument<ABI, Arg,
+    typename std::enable_if<
+        std::is_base_of<ArmProcess32::SyscallABI, ABI>::value &&
+        ABI::template IsWide<Arg>::value>::type>
+{
+    static Arg
+    get(ThreadContext *tc, typename ABI::Position &position)
+    {
+        // 64 bit arguments are passed starting in an even register.
+        if (position % 2)
+            position++;
+        panic_if(position + 1 >= ABI::ArgumentRegs.size(),
+                "Ran out of syscall argument registers.");
+        auto low = ABI::ArgumentRegs[position++];
+        auto high = ABI::ArgumentRegs[position++];
+        return (Arg)ABI::mergeRegs(tc, low, high);
+    }
 };
 
+} // namespace GuestABI
+
 class ArmProcess64 : public ArmProcess
 {
   protected:
@@ -108,6 +139,11 @@ class ArmProcess64 : public ArmProcess
     RegVal getSyscallArg(ThreadContext *tc, int &i) override;
     void setSyscallReturn(ThreadContext *tc,
             SyscallReturn return_value) override;
+
+    struct SyscallABI : public GenericSyscallABI64
+    {
+        static const std::vector<int> ArgumentRegs;
+    };
 };
 
 #endif // __ARM_PROCESS_HH__