Boris Shingarov has submitted this change. (
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>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/40944
Reviewed-by: Boris Shingarov <shinga...@labware.com>
Maintainer: Boris Shingarov <shinga...@labware.com>
Tested-by: kokoro <noreply+kok...@google.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/regs/int.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(-)
Approvals:
Boris Shingarov: Looks good to me, approved; Looks good to me, approved
kokoro: Regressions pass
diff --git a/src/arch/power/PowerSeWorkload.py
b/src/arch/power/PowerSeWorkload.py
index ef7bbb5..2b081f2 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 75eb210..815a145 100644
--- a/src/arch/power/linux/se_workload.cc
+++ b/src/arch/power/linux/se_workload.cc
@@ -50,7 +50,9 @@
Process *
load(const ProcessParams ¶ms, 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();
@@ -60,7 +62,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 688cc1e..8ac5946 100644
--- a/src/arch/power/process.cc
+++ b/src/arch/power/process.cc
@@ -82,7 +82,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>
@@ -91,6 +139,8 @@
{
int intSize = sizeof(IntType);
ByteOrder byteOrder = objFile->getByteOrder();
+ bool is64bit = (objFile->getArch() == loader::Power64);
+ bool isLittleEndian = (byteOrder == ByteOrder::little);
std::vector<gem5::auxv::AuxVector<IntType>> auxv;
std::string filename;
@@ -110,13 +160,21 @@
//Auxilliary vectors are loaded only for elf formatted executables.
auto *elfObject = dynamic_cast<loader::ElfObject *>(objFile);
if (elfObject) {
- IntType features = 0;
+ IntType features = HWCAP_FEATURE_32;
+
+ // Check if running in 64-bit mode
+ if (is64bit)
+ features |= HWCAP_FEATURE_64;
+
+ // Check if running in little endian mode
+ if (isLittleEndian)
+ features |= HWCAP_FEATURE_PPC_LE | HWCAP_FEATURE_TRUE_LE;
//Bits which describe the system hardware capabilities
//XXX Figure out what these should be
auxv.emplace_back(gem5::auxv::Hwcap, features);
//The system page size
- auxv.emplace_back(gem5::auxv::Pagesz, PowerISA::PageBytes);
+ auxv.emplace_back(gem5::auxv::Pagesz, pageSize);
//Frequency at which times() increments
auxv.emplace_back(gem5::auxv::Clktck, 0x64);
// For statically linked executables, this is the virtual address
of
@@ -282,7 +340,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;
@@ -290,10 +348,13 @@
msr.ir = 1;
msr.dr = 1;
msr.ri = 1;
- msr.le = (byteOrder == ByteOrder::little);
+ msr.le = isLittleEndian;
tc->setIntReg(INTREG_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/regs/int.hh b/src/arch/power/regs/int.hh
index 11999e5..968b94f 100644
--- a/src/arch/power/regs/int.hh
+++ b/src/arch/power/regs/int.hh
@@ -53,6 +53,7 @@
const int ArgumentReg4 = 7;
const int ArgumentReg5 = 8;
const int StackPointerReg = 1;
+const int TOCPointerReg = 2;
enum MiscIntRegNums
{
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
index 28721f5..31390cf 100644
--- a/src/base/loader/elf_object.cc
+++ b/src/base/loader/elf_object.cc
@@ -252,15 +252,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);
}
@@ -269,6 +262,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 2566853..bfa0a1d 100644
--- a/src/base/loader/object_file.cc
+++ b/src/base/loader/object_file.cc
@@ -66,6 +66,8 @@
return "thumb";
case Power:
return "power";
+ case Power64:
+ return "power64";
case Riscv64:
return "riscv64";
case Riscv32:
@@ -84,6 +86,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 1079f16..e8a96dc 100644
--- a/src/base/loader/object_file.hh
+++ b/src/base/loader/object_file.hh
@@ -59,6 +59,7 @@
Arm,
Thumb,
Power,
+ Power64,
Riscv64,
Riscv32
};
@@ -72,6 +73,8 @@
Linux,
Solaris,
LinuxArmOABI,
+ LinuxPower64ABIv1,
+ LinuxPower64ABIv2,
FreeBSD
};
10 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the
submitted one.
--
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: 12
Gerrit-Owner: Sandipan Das <sandi...@linux.ibm.com>
Gerrit-Reviewer: Boris Shingarov <shinga...@labware.com>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-MessageType: merged
_______________________________________________
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