diff --git a/src/arch/arm/reg_abi.hh b/src/arch/arm/reg_abi.hh index e892166c5e..34fe44c16d 100644 --- a/src/arch/arm/reg_abi.hh +++ b/src/arch/arm/reg_abi.hh @@ -31,6 +31,7 @@ #include #include "base/logging.hh" +#include "sim/pseudo_inst.hh" #include "sim/syscall_abi.hh" namespace gem5 @@ -75,6 +76,21 @@ struct Argument +struct Argument +{ + using ABI = ArmISA::RegABI32; + using Arg = pseudo_inst::GuestAddr; + + static Arg + get(ThreadContext *tc, typename ABI::State &state) + { + panic_if(state + 1 >= ABI::ArgumentRegs.size(), + "Ran out of syscall argument registers."); + return (Arg)bits(tc->getReg(ABI::ArgumentRegs[state++]), 31, 0); + } +}; + } // namespace guest_abi } // namespace gem5 diff --git a/src/arch/arm/semihosting.hh b/src/arch/arm/semihosting.hh index 557eb76636..7242581eb6 100644 --- a/src/arch/arm/semihosting.hh +++ b/src/arch/arm/semihosting.hh @@ -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 @@ -604,26 +605,32 @@ namespace guest_abi template struct Argument>> + typename std::enable_if_t< + (std::is_integral_v || + std::is_same::value)>> { static Arg get(ThreadContext *tc, ArmSemihosting::Abi64::State &state) { - return state.get(tc); + return (Arg)state.get(tc); } }; template struct Argument>> + typename std::enable_if_t< + (std::is_integral_v || + std::is_same::value)>> { static Arg get(ThreadContext *tc, ArmSemihosting::Abi32::State &state) { - if (std::is_signed_v) - return sext<32>(state.get(tc)); - else - return state.get(tc); + if (std::is_signed_v) { + return (Arg)sext<32>(state.get(tc)); + } + else { + return (Arg)state.get(tc); + } } }; diff --git a/src/arch/riscv/isa/formats/m5ops.isa b/src/arch/riscv/isa/formats/m5ops.isa index 034a0dd2b5..ce2092cac3 100644 --- a/src/arch/riscv/isa/formats/m5ops.isa +++ b/src/arch/riscv/isa/formats/m5ops.isa @@ -1,5 +1,6 @@ // // Copyright (c) 2020 Barkhausen Institut +// Copyright (c) 2024 University of Rostock // All rights reserved // // The license below extends only to copyright in the software and shall @@ -40,10 +41,12 @@ def format M5Op() {{ uint64_t result; if (machInst.rv_type == RV32) { pseudo_inst::pseudoInst(xc->tcBase(), M5FUNC, result); + a0 = bits(result, 31, 0); + a1 = bits(result, 63, 32); } else { pseudo_inst::pseudoInst(xc->tcBase(), M5FUNC, result); - } - a0 = rvSext(result)''', + a0 = rvSext(result); + }''', ['IsNonSpeculative', 'IsSerializeAfter']) header_output = BasicDeclare.subst(iop) decoder_output = BasicConstructor.subst(iop) diff --git a/src/arch/riscv/isa/operands.isa b/src/arch/riscv/isa/operands.isa index 3a16e0994c..de36d902b1 100644 --- a/src/arch/riscv/isa/operands.isa +++ b/src/arch/riscv/isa/operands.isa @@ -3,6 +3,7 @@ // Copyright (c) 2015 RISC-V Foundation // Copyright (c) 2016 The University of Virginia // Copyright (c) 2020 Barkhausen Institut +// Copyright (c) 2024 University of Rostock // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -71,6 +72,7 @@ def operands {{ 'sp': IntReg('ud', 'StackPointerReg', 'IsInteger', 2), 'a0': IntReg('ud', '10', 'IsInteger', 1), + 'a1': IntReg('ud', '11', 'IsInteger', 2), 'Fd': FloatRegOp('df', 'FD', 'IsFloating', 1), 'Fd_bits': FloatRegOp('ud', 'FD', 'IsFloating', 1), diff --git a/src/arch/riscv/linux/linux.hh b/src/arch/riscv/linux/linux.hh index de8bccc85e..997eb6af4c 100644 --- a/src/arch/riscv/linux/linux.hh +++ b/src/arch/riscv/linux/linux.hh @@ -289,6 +289,10 @@ class RiscvLinux32 : public RiscvLinux, public OpenFlagTable // Currently time_t in glibc for riscv32 is 32-bits, but will be changed. typedef int64_t time_t; + // Linux types for RV32 + typedef uint32_t size_t; + typedef int64_t off_t; + /// Limit struct for getrlimit/setrlimit. struct rlimit { diff --git a/src/arch/riscv/reg_abi.hh b/src/arch/riscv/reg_abi.hh index 4c965321f7..383e9df266 100644 --- a/src/arch/riscv/reg_abi.hh +++ b/src/arch/riscv/reg_abi.hh @@ -54,8 +54,9 @@ struct RegABI32 : public GenericSyscallABI32 namespace guest_abi { + // 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 struct Argument= 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 RV32 pointers. +template <> +struct Argument +{ + using ABI = RiscvISA::RegABI32; + using Arg = pseudo_inst::GuestAddr; + + static Arg + get(ThreadContext *tc, typename ABI::State &state) + { + panic_if(state >= ABI::ArgumentRegs.size(), + "Ran out of syscall argument registers."); + + return (Arg)bits(tc->getReg(ABI::ArgumentRegs[state++]), 31, 0); } }; diff --git a/src/arch/sparc/pseudo_inst_abi.hh b/src/arch/sparc/pseudo_inst_abi.hh index 989f0e7dfc..569cfb8da8 100644 --- a/src/arch/sparc/pseudo_inst_abi.hh +++ b/src/arch/sparc/pseudo_inst_abi.hh @@ -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 { @@ -67,6 +68,19 @@ struct Argument } }; +template <> +struct Argument +{ + using Arg = pseudo_inst::GuestAddr; + + static Arg + get(ThreadContext *tc, SparcPseudoInstABI::State &state) + { + panic_if(state >= 6, "Too many psuedo inst arguments."); + return (Arg)tc->getReg(SparcISA::int_reg::o(state++)); + } +}; + } // namespace guest_abi } // namespace gem5 diff --git a/src/arch/x86/pseudo_inst_abi.hh b/src/arch/x86/pseudo_inst_abi.hh index e465c7abd5..bfedb7a8cb 100644 --- a/src/arch/x86/pseudo_inst_abi.hh +++ b/src/arch/x86/pseudo_inst_abi.hh @@ -37,6 +37,7 @@ #include "arch/x86/regs/int.hh" #include "sim/guest_abi.hh" +#include "sim/pseudo_inst.hh" namespace gem5 { @@ -84,5 +85,29 @@ struct Argument } }; +template <> +struct Argument +{ + using Arg = pseudo_inst::GuestAddr; + + static Arg + 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 + }; + + return (Arg)tc->getReg(int_reg_map[state++]); + } +}; + } // namespace guest_abi } // namespace gem5 diff --git a/src/sim/guest_abi/layout.hh b/src/sim/guest_abi/layout.hh index 4d469b177c..9873a61215 100644 --- a/src/sim/guest_abi/layout.hh +++ b/src/sim/guest_abi/layout.hh @@ -169,7 +169,7 @@ template static Arg getArgument(ThreadContext *tc, typename ABI::State &state) { - return Argument::get(tc, state); + return (Arg)Argument::get(tc, state); } } // namespace guest_abi diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index 29caba6661..084be5a419 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -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"); diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh index ba15370c55..2d7b27715b 100644 --- a/src/sim/pseudo_inst.hh +++ b/src/sim/pseudo_inst.hh @@ -64,18 +64,37 @@ decodeAddrOffset(Addr offset, uint8_t &func) func = bits(offset, 15, 8); } +/** + * This struct wrapper for Addr enables m5ops for systems with 32 bit pointer, + * since it allows to distinguish between address arguments and native C++ + * types. GuestAddr is only a temporary solution and will likely replaced in + * the future. +*/ +struct GuestAddr +{ + Addr addr; + /** Constructor is necessary to cast from uint64_t to GuestAddr. */ + GuestAddr(Addr _addr) : addr(_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 +114,7 @@ void m5Syscall(ThreadContext *tc); void togglesync(ThreadContext *tc); void triggerWorkloadEvent(ThreadContext *tc); + /** * Execute a decoded M5 pseudo instruction * diff --git a/src/sim/syscall_abi.hh b/src/sim/syscall_abi.hh index 90dbd9747b..c50b1de16e 100644 --- a/src/sim/syscall_abi.hh +++ b/src/sim/syscall_abi.hh @@ -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 @@ -83,14 +84,15 @@ template struct Argument && - std::is_integral_v>> + (std::is_integral_v || + std::is_same::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++]); + return (Arg)tc->getReg(ABI::ArgumentRegs[state++]); } };