Sandipan Das has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/40944 )

Change subject: arch-power: Add multi-mode support
......................................................................

arch-power: Add multi-mode support

This adds multi-mode support and allows the simulator to
read, interpret and execute 32bit and 64-bit, big and
little endian binaries in syscall emulation mode.

During process initialization, a minimal set of hardware
capabilities are also advertised by the simulator to show
support for 64-bit mode and little endian byte order.
This also adds some fixups specific to 64-bit ELF ABI v1
that readjust the entry point and symbol table due to the
use of function descriptors.

Change-Id: I124339eff7b70dbd14e50ff970340c88c13bd0ad
Signed-off-by: Sandipan Das <sandi...@linux.ibm.com>
---
M src/arch/power/PowerSeWorkload.py
M src/arch/power/linux/se_workload.cc
M src/arch/power/process.cc
M src/arch/power/registers.hh
M src/base/loader/elf_object.cc
M src/base/loader/object_file.cc
M src/base/loader/object_file.hh
7 files changed, 100 insertions(+), 18 deletions(-)



diff --git a/src/arch/power/PowerSeWorkload.py b/src/arch/power/PowerSeWorkload.py
index 2d3d3cb..40e989c 100644
--- a/src/arch/power/PowerSeWorkload.py
+++ b/src/arch/power/PowerSeWorkload.py
@@ -40,5 +40,5 @@

     @classmethod
     def _is_compatible_with(cls, obj):
-        return obj.get_arch() == 'power' and \
+        return obj.get_arch() in ('power', 'power64') and  \
                 obj.get_op_sys() in ('linux', 'unknown')
diff --git a/src/arch/power/linux/se_workload.cc b/src/arch/power/linux/se_workload.cc
index 864468f..091fd35 100644
--- a/src/arch/power/linux/se_workload.cc
+++ b/src/arch/power/linux/se_workload.cc
@@ -47,7 +47,9 @@
     Process *
     load(const ProcessParams &params, ::Loader::ObjectFile *obj) override
     {
-        if (obj->getArch() != ::Loader::Power)
+        auto arch = obj->getArch();
+
+        if (arch != ::Loader::Power && arch != ::Loader::Power64)
             return nullptr;

         auto opsys = obj->getOpSys();
@@ -57,7 +59,10 @@
             opsys = ::Loader::Linux;
         }

-        if (opsys != ::Loader::Linux)
+        if ((arch == ::Loader::Power && opsys != ::Loader::Linux) ||
+            (arch == ::Loader::Power64 &&
+             opsys != ::Loader::LinuxPower64ABIv1 &&
+             opsys != ::Loader::LinuxPower64ABIv2))
             return nullptr;

         return new PowerProcess(params, obj);
diff --git a/src/arch/power/process.cc b/src/arch/power/process.cc
index 409f980..735b3d9 100644
--- a/src/arch/power/process.cc
+++ b/src/arch/power/process.cc
@@ -76,7 +76,55 @@
 {
     Process::initState();

-    argsInit<uint32_t>(PageBytes);
+    if (objFile->getArch() == ::Loader::Power)
+        argsInit<uint32_t>(PageBytes);
+    else
+        argsInit<uint64_t>(PageBytes);
+
+    // Fix up entry point and symbol table for 64-bit ELF ABI v1
+    if (objFile->getOpSys() != ::Loader::LinuxPower64ABIv1)
+        return;
+
+    // Fix entry point address and the base TOC pointer by looking the
+    // the function descriptor in the .opd section
+    Addr entryPoint, tocBase;
+    ByteOrder byteOrder = objFile->getByteOrder();
+    ThreadContext *tc = system->threads[contextIds[0]];
+
+    // The first doubleword of the descriptor contains the address of the
+    // entry point of the function
+    initVirtMem->readBlob(getStartPC(), &entryPoint, sizeof(Addr));
+
+    // Update the PC state
+    auto pc = tc->pcState();
+    pc.byteOrder(byteOrder);
+    pc.set(gtoh(entryPoint, byteOrder));
+    tc->pcState(pc);
+
+    // The second doubleword of the descriptor contains the TOC base
+    // address for the function
+    initVirtMem->readBlob(getStartPC() + 8, &tocBase, sizeof(Addr));
+    tc->setIntReg(TOCPointerReg, gtoh(tocBase, byteOrder));
+
+    // Fix symbol table entries as they would otherwise point to the
+    // function descriptor rather than the actual entry point address
+    auto *symbolTable = new ::Loader::SymbolTable;
+
+    for (auto sym : ::Loader::debugSymbolTable) {
+        Addr entry;
+        ::Loader::Symbol symbol = sym;
+
+        // Try to read entry point from function descriptor
+        if (initVirtMem->tryReadBlob(sym.address, &entry, sizeof(Addr)))
+            symbol.address = gtoh(entry, byteOrder);
+
+        symbolTable->insert(symbol);
+    }
+
+    // Replace the current debug symbol table
+    ::Loader::debugSymbolTable.clear();
+    ::Loader::debugSymbolTable.insert(*symbolTable);
+    delete symbolTable;
 }

 template <typename IntType>
@@ -85,6 +133,8 @@
 {
     int intSize = sizeof(IntType);
     ByteOrder byteOrder = objFile->getByteOrder();
+    bool is64bit = (objFile->getArch() == ::Loader::Power64);
+    bool isLittleEndian = (byteOrder == ByteOrder::little);
     std::vector<AuxVector<IntType>> auxv;

     std::string filename;
@@ -104,13 +154,21 @@
     //Auxilliary vectors are loaded only for elf formatted executables.
     auto *elfObject = dynamic_cast<::Loader::ElfObject *>(objFile);
     if (elfObject) {
-        IntType features = 0;
+        IntType features = PPC_FEATURE_32;
+
+        // Check if running in 64-bit mode
+        if (is64bit)
+            features |= PPC_FEATURE_64;
+
+        // Check if running in little endian mode
+        if (isLittleEndian)
+            features |= PPC_FEATURE_PPC_LE | PPC_FEATURE_TRUE_LE;

         //Bits which describe the system hardware capabilities
         //XXX Figure out what these should be
         auxv.emplace_back(M5_AT_HWCAP, features);
         //The system page size
-        auxv.emplace_back(M5_AT_PAGESZ, PowerISA::PageBytes);
+        auxv.emplace_back(M5_AT_PAGESZ, pageSize);
         //Frequency at which times() increments
         auxv.emplace_back(M5_AT_CLKTCK, 0x64);
// For statically linked executables, this is the virtual address of
@@ -276,7 +334,7 @@

     //Set the machine status for a typical userspace
     Msr msr = 0;
-    msr.sf = (intSize == 8);
+    msr.sf = is64bit;
     msr.hv = 1;
     msr.ee = 1;
     msr.pr = 1;
@@ -284,10 +342,13 @@
     msr.ir = 1;
     msr.dr = 1;
     msr.ri = 1;
-    msr.le = (byteOrder == ByteOrder::little);
+    msr.le = isLittleEndian;
     tc->setMiscReg(MISCREG_MSR, msr);

-    tc->pcState(getStartPC());
+    auto pc = tc->pcState();
+    pc.set(getStartPC());
+    pc.byteOrder(byteOrder);
+    tc->pcState(pc);

     //Align the "stack_min" to a page boundary.
     memState->setStackMin(roundDown(stack_min, pageSize));
diff --git a/src/arch/power/registers.hh b/src/arch/power/registers.hh
index c9bdf1c..2745a92 100644
--- a/src/arch/power/registers.hh
+++ b/src/arch/power/registers.hh
@@ -85,6 +85,7 @@
 const int ArgumentReg4 = 7;
 const int ArgumentReg5 = 8;
 const int StackPointerReg = 1;
+const int TOCPointerReg = 2;

 // There isn't one in Power, but we need to define one somewhere
 const int ZeroReg = NumIntRegs - 1;
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
index 4198875..66bd066 100644
--- a/src/base/loader/elf_object.cc
+++ b/src/base/loader/elf_object.cc
@@ -247,15 +247,8 @@
         arch = (eclass == ELFCLASS64) ? Riscv64 : Riscv32;
     } else if (emach == EM_PPC && eclass == ELFCLASS32) {
         arch = Power;
-        if (edata != ELFDATA2MSB) {
-            fatal("The binary you're trying to load is compiled for "
-                  "little endian Power.\ngem5 only supports big "
-                  "endian Power. Please recompile your binary.\n");
-        }
-    } else if (emach == EM_PPC64) {
-        fatal("The binary you're trying to load is compiled for 64-bit "
-              "Power. M5\n only supports 32-bit Power. Please "
-              "recompile your binary.\n");
+    } else if (emach == EM_PPC64 && eclass == ELFCLASS64) {
+        arch = Power64;
     } else {
         warn("Unknown architecture: %d\n", emach);
     }
@@ -264,6 +257,21 @@
 void
 ElfObject::determineOpSys()
 {
+    // For 64-bit Power, EI_OSABI and EI_ABIVERSION cannot be used to
+    // determine the ABI version used by the ELF object
+    if (ehdr.e_machine == EM_PPC64) {
+        switch (ehdr.e_flags & 0x3) {
+            case 0x1: opSys = LinuxPower64ABIv1; return;
+            case 0x2: opSys = LinuxPower64ABIv2; return;
+            default:
+                if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+                    opSys = LinuxPower64ABIv1;
+                if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+                    opSys = LinuxPower64ABIv2;
+                return;
+        }
+    }
+
     // Detect the operating system
     switch (ehdr.e_ident[EI_OSABI]) {
       case ELFOSABI_LINUX:
diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc
index 6fdf228..d8075a5 100644
--- a/src/base/loader/object_file.cc
+++ b/src/base/loader/object_file.cc
@@ -62,6 +62,8 @@
         return "thumb";
       case Power:
         return "power";
+      case Power64:
+        return "power64";
       case Riscv64:
         return "riscv64";
       case Riscv32:
@@ -80,6 +82,8 @@
       case Tru64:
         return "tru64";
       case Linux:
+      case LinuxPower64ABIv1:
+      case LinuxPower64ABIv2:
         return "linux";
       case Solaris:
         return "solaris";
diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh
index 7d542a9..19d9bd6 100644
--- a/src/base/loader/object_file.hh
+++ b/src/base/loader/object_file.hh
@@ -53,6 +53,7 @@
     Arm,
     Thumb,
     Power,
+    Power64,
     Riscv64,
     Riscv32
 };
@@ -65,6 +66,8 @@
     Linux,
     Solaris,
     LinuxArmOABI,
+    LinuxPower64ABIv1,
+    LinuxPower64ABIv2,
     FreeBSD
 };


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/40944
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I124339eff7b70dbd14e50ff970340c88c13bd0ad
Gerrit-Change-Number: 40944
Gerrit-PatchSet: 1
Gerrit-Owner: Sandipan Das <sandi...@linux.ibm.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to