sim: enable pseudo instructions with varying pointer size

In this patch, Addr is subtituted by a struct wrapper (uint64_t) in the
pseudo instruction functions. This enables a correct argument handling
in systems where pointer size != 64 bit.

Change-Id: Ie84b43b4ab8e6c0d38c7b6b16e19fc043110681b
This commit is contained in:
Robert Hauser
2024-03-11 15:27:58 +00:00
parent 7ac9733199
commit de52f3614c
9 changed files with 128 additions and 32 deletions

View File

@@ -31,6 +31,7 @@
#include <vector>
#include "base/logging.hh"
#include "sim/pseudo_inst.hh"
#include "sim/syscall_abi.hh"
namespace gem5
@@ -54,11 +55,13 @@ struct RegABI64 : public GenericSyscallABI64
namespace guest_abi
{
using namespace pseudo_inst;
template <typename ABI, typename Arg>
struct Argument<ABI, Arg,
typename std::enable_if_t<
std::is_base_of_v<ArmISA::RegABI32, ABI> &&
std::is_integral_v<Arg> &&
(std::is_integral_v<Arg> || std::is_same<Arg,GuestAddr>::value) &&
ABI::template IsWideV<Arg>>>
{
static Arg
@@ -71,7 +74,8 @@ struct Argument<ABI, Arg,
"Ran out of syscall argument registers.");
auto low = ABI::ArgumentRegs[state++];
auto high = ABI::ArgumentRegs[state++];
return (Arg)ABI::mergeRegs(tc, low, high);
auto merge = ABI::mergeRegs(tc, low, high);
return *reinterpret_cast<Arg*>(&merge);
}
};

View File

@@ -51,6 +51,7 @@
#include "mem/port_proxy.hh"
#include "sim/core.hh"
#include "sim/guest_abi.hh"
#include "sim/pseudo_inst.hh"
#include "sim/sim_object.hh"
namespace gem5
@@ -602,28 +603,37 @@ std::ostream &operator << (
namespace guest_abi
{
using namespace pseudo_inst;
template <typename Arg>
struct Argument<ArmSemihosting::Abi64, Arg,
typename std::enable_if_t<std::is_integral_v<Arg>>>
typename std::enable_if_t<
(std::is_integral_v<Arg> || std::is_same<Arg,GuestAddr>::value)>>
{
static Arg
get(ThreadContext *tc, ArmSemihosting::Abi64::State &state)
{
return state.get(tc);
auto arg = state.get(tc);
return *reinterpret_cast<Arg*>(&arg);
}
};
template <typename Arg>
struct Argument<ArmSemihosting::Abi32, Arg,
typename std::enable_if_t<std::is_integral_v<Arg>>>
typename std::enable_if_t<
(std::is_integral_v<Arg> || std::is_same<Arg,GuestAddr>::value)>>
{
static Arg
get(ThreadContext *tc, ArmSemihosting::Abi32::State &state)
{
if (std::is_signed_v<Arg>)
return sext<32>(state.get(tc));
else
return state.get(tc);
if (std::is_signed_v<Arg>) {
auto arg = sext<32>(state.get(tc));
return *reinterpret_cast<Arg*>(&arg);
}
else {
auto arg = state.get(tc);
return *reinterpret_cast<Arg*>(&arg);
}
}
};

View File

@@ -54,8 +54,10 @@ struct RegABI32 : public GenericSyscallABI32
namespace guest_abi
{
using namespace pseudo_inst;
// This method will be used if the size of argument type of function is
// greater than 4 for Riscv 32.
// greater than 4 byte for Riscv 32.
template <typename ABI, typename Arg>
struct Argument<ABI, Arg,
typename std::enable_if_t<
@@ -68,7 +70,29 @@ struct Argument<ABI, Arg,
{
panic_if(state >= ABI::ArgumentRegs.size(),
"Ran out of syscall argument registers.");
return bits(tc->getReg(ABI::ArgumentRegs[state++]), 31, 0);
auto low = ABI::ArgumentRegs[state++];
auto high = ABI::ArgumentRegs[state++];
return (Arg)ABI::mergeRegs(tc, low, high);
}
};
// This method will be used for Riscv 32 pointers.
template <typename ABI, typename Arg>
struct Argument<ABI, Arg,
typename std::enable_if_t<
std::is_base_of_v<RiscvISA::RegABI32, ABI> &&
std::is_same<Arg,GuestAddr>::value &&
ABI::template IsWideV<Arg>>>
{
static Arg
get(ThreadContext *tc, typename ABI::State &state)
{
panic_if(state >= ABI::ArgumentRegs.size(),
"Ran out of syscall argument registers.");
auto arg = bits(tc->getReg(ABI::ArgumentRegs[state++]), 31, 0);
return *reinterpret_cast<Arg*>(&arg);
}
};

View File

@@ -31,6 +31,7 @@
#include "arch/sparc/regs/int.hh"
#include "cpu/thread_context.hh"
#include "sim/guest_abi.hh"
#include "sim/pseudo_inst.hh"
namespace gem5
{
@@ -43,6 +44,8 @@ struct SparcPseudoInstABI
namespace guest_abi
{
using namespace pseudo_inst;
template <typename T>
struct Result<SparcPseudoInstABI, T>
{
@@ -67,6 +70,18 @@ struct Argument<SparcPseudoInstABI, uint64_t>
}
};
template <>
struct Argument<SparcPseudoInstABI, GuestAddr>
{
static GuestAddr
get(ThreadContext *tc, SparcPseudoInstABI::State &state)
{
panic_if(state >= 6, "Too many psuedo inst arguments.");
auto arg = tc->getReg(SparcISA::int_reg::o(state++));
return *reinterpret_cast<GuestAddr*>(&arg);
}
};
} // namespace guest_abi
} // namespace gem5

View File

@@ -37,6 +37,7 @@
#include "arch/x86/regs/int.hh"
#include "sim/guest_abi.hh"
#include "sim/pseudo_inst.hh"
namespace gem5
{
@@ -49,6 +50,8 @@ struct X86PseudoInstABI
namespace guest_abi
{
using namespace pseudo_inst;
template <typename T>
struct Result<X86PseudoInstABI, T>
{
@@ -84,5 +87,28 @@ struct Argument<X86PseudoInstABI, uint64_t>
}
};
template <>
struct Argument<X86PseudoInstABI, GuestAddr>
{
static GuestAddr
get(ThreadContext *tc, X86PseudoInstABI::State &state)
{
// The first 6 integer arguments are passed in registers, the rest
// are passed on the stack.
panic_if(state >= 6, "Too many psuedo inst arguments.");
using namespace X86ISA;
constexpr RegId int_reg_map[] = {
int_reg::Rdi, int_reg::Rsi, int_reg::Rdx,
int_reg::Rcx, int_reg::R8, int_reg::R9
};
auto arg = tc->getReg(int_reg_map[state++]);
return *reinterpret_cast<GuestAddr*>(&arg);
}
};
} // namespace guest_abi
} // namespace gem5

View File

@@ -169,7 +169,8 @@ template <typename ABI, typename Arg>
static Arg
getArgument(ThreadContext *tc, typename ABI::State &state)
{
return Argument<ABI, Arg>::get(tc, state);
auto arg = Argument<ABI, Arg>::get(tc, state);
return *reinterpret_cast<Arg*>(&arg);
}
} // namespace guest_abi

View File

@@ -256,27 +256,27 @@ loadsymbol(ThreadContext *tc)
}
void
addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
addsymbol(ThreadContext *tc, GuestAddr addr, GuestAddr symbolAddr)
{
DPRINTF(PseudoInst, "pseudo_inst::addsymbol(0x%x, 0x%x)\n",
addr, symbolAddr);
addr.addr, symbolAddr.addr);
std::string symbol;
TranslatingPortProxy fs_proxy(tc);
SETranslatingPortProxy se_proxy(tc);
PortProxy &virt_proxy = FullSystem ? fs_proxy : se_proxy;
virt_proxy.readString(symbol, symbolAddr);
virt_proxy.readString(symbol, symbolAddr.addr);
DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr.addr);
tc->getSystemPtr()->workload->insertSymbol(
{ loader::Symbol::Binding::Global,
loader::Symbol::SymbolType::Function, symbol, addr }
loader::Symbol::SymbolType::Function, symbol, addr.addr }
);
loader::debugSymbolTable.insert(
{ loader::Symbol::Binding::Global,
loader::Symbol::SymbolType::Function, symbol, addr }
loader::Symbol::SymbolType::Function, symbol, addr.addr }
);
}
@@ -368,10 +368,10 @@ m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
}
uint64_t
readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
readfile(ThreadContext *tc, GuestAddr vaddr, uint64_t len, uint64_t offset)
{
DPRINTF(PseudoInst, "pseudo_inst::readfile(0x%x, 0x%x, 0x%x)\n",
vaddr, len, offset);
vaddr.addr, len, offset);
const std::string &file = tc->getSystemPtr()->params().readfile;
if (file.empty()) {
@@ -404,17 +404,17 @@ readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
SETranslatingPortProxy se_proxy(tc);
PortProxy &virt_proxy = FullSystem ? fs_proxy : se_proxy;
virt_proxy.writeBlob(vaddr, buf, result);
virt_proxy.writeBlob(vaddr.addr, buf, result);
delete [] buf;
return result;
}
uint64_t
writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset,
Addr filename_addr)
writefile(ThreadContext *tc, GuestAddr vaddr, uint64_t len, uint64_t offset,
GuestAddr filename_addr)
{
DPRINTF(PseudoInst, "pseudo_inst::writefile(0x%x, 0x%x, 0x%x, 0x%x)\n",
vaddr, len, offset, filename_addr);
vaddr.addr, len, offset, filename_addr.addr);
// copy out target filename
std::string filename;
@@ -422,7 +422,7 @@ writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset,
SETranslatingPortProxy se_proxy(tc);
PortProxy &virt_proxy = FullSystem ? fs_proxy : se_proxy;
virt_proxy.readString(filename, filename_addr);
virt_proxy.readString(filename, filename_addr.addr);
OutputStream *out;
if (offset == 0) {
@@ -448,7 +448,7 @@ writefile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset,
// copy out data and write to file
char *buf = new char[len];
virt_proxy.readBlob(vaddr, buf, len);
virt_proxy.readBlob(vaddr.addr, buf, len);
os->write(buf, len);
if (os->fail() || os->bad())
panic("Error while doing writefile!\n");

View File

@@ -64,18 +64,29 @@ decodeAddrOffset(Addr offset, uint8_t &func)
func = bits(offset, 15, 8);
}
struct GuestAddr
{
uint64_t addr;
};
inline std::ostream&
operator<<(std::ostream& os, const GuestAddr addr)
{
return os << addr.addr;
}
void arm(ThreadContext *tc);
void quiesce(ThreadContext *tc);
void quiesceSkip(ThreadContext *tc);
void quiesceNs(ThreadContext *tc, uint64_t ns);
void quiesceCycles(ThreadContext *tc, uint64_t cycles);
uint64_t quiesceTime(ThreadContext *tc);
uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len,
uint64_t readfile(ThreadContext *tc, GuestAddr vaddr, uint64_t len,
uint64_t offset);
uint64_t writefile(ThreadContext *tc, Addr vaddr, uint64_t len,
uint64_t offset, Addr filenameAddr);
uint64_t writefile(ThreadContext *tc, GuestAddr vaddr, uint64_t len,
uint64_t offset, GuestAddr filenameAddr);
void loadsymbol(ThreadContext *xc);
void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr);
void addsymbol(ThreadContext *tc, GuestAddr addr, GuestAddr symbolAddr);
uint64_t initParam(ThreadContext *xc, uint64_t key_str1, uint64_t key_str2);
uint64_t rpns(ThreadContext *tc);
void wakeCPU(ThreadContext *tc, uint64_t cpuid);
@@ -95,6 +106,7 @@ void m5Syscall(ThreadContext *tc);
void togglesync(ThreadContext *tc);
void triggerWorkloadEvent(ThreadContext *tc);
/**
* Execute a decoded M5 pseudo instruction
*

View File

@@ -32,6 +32,7 @@
#include "base/types.hh"
#include "cpu/thread_context.hh"
#include "sim/guest_abi.hh"
#include "sim/pseudo_inst.hh"
#include "sim/syscall_return.hh"
namespace gem5
@@ -78,19 +79,22 @@ struct GenericSyscallABI32 : public GenericSyscallABI
namespace guest_abi
{
using namespace pseudo_inst;
// For 64 bit systems, return syscall args directly.
template <typename ABI, typename Arg>
struct Argument<ABI, Arg,
typename std::enable_if_t<
std::is_base_of_v<GenericSyscallABI64, ABI> &&
std::is_integral_v<Arg>>>
(std::is_integral_v<Arg> || std::is_same<Arg,GuestAddr>::value)>>
{
static Arg
get(ThreadContext *tc, typename ABI::State &state)
{
panic_if(state >= ABI::ArgumentRegs.size(),
"Ran out of syscall argument registers.");
return tc->getReg(ABI::ArgumentRegs[state++]);
auto arg = tc->getReg(ABI::ArgumentRegs[state++]);
return *reinterpret_cast<Arg*>(&arg);
}
};