arm: Add a gem5 specific pseudo op semihosting call.

This is in the range of call numbers set aside for extensions. When
called, it will extract the function to use from the first argument
slot. Then it calls the pseudoInst dispatching function using an ABI
which drops the return value (which is handled by semihosting itself)
and which extracts arguments from the remaining slots in the param
structure.

This makes gem5 pseudo ops available on CPU models which support
semihosting but not instruction based or address based "magic"
operations, aka hypercalls. This includes the fast model CPUs.

Change-Id: Ic4817f2b1e6aad7784af77a1a494cf614d4d4c6c
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/25950
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Gabe Black
2020-02-26 15:49:39 -08:00
parent f4697687ed
commit 19bba88354
2 changed files with 91 additions and 1 deletions

View File

@@ -48,6 +48,7 @@
#include "mem/secure_port_proxy.hh"
#include "params/ArmSemihosting.hh"
#include "sim/byteswap.hh"
#include "sim/pseudo_inst.hh"
#include "sim/sim_exit.hh"
#include "sim/system.hh"
@@ -83,6 +84,9 @@ const std::map<uint32_t, ArmSemihosting::SemiCall> ArmSemihosting::calls{
{ SYS_ELAPSED, { "SYS_ELAPSED", &ArmSemihosting::callElapsed32,
&ArmSemihosting::callElapsed64 } },
{ SYS_TICKFREQ, { "SYS_TICKFREQ", &ArmSemihosting::callTickFreq } },
{ SYS_GEM5_PSEUDO_OP,
{ "SYS_GEM5_PSEUDO_OP", &ArmSemihosting::callGem5PseudoOp32,
&ArmSemihosting::callGem5PseudoOp64 } },
};
const std::vector<const char *> ArmSemihosting::fmodes{
@@ -653,6 +657,87 @@ ArmSemihosting::callTickFreq(ThreadContext *tc)
return retOK(semiTick(SimClock::Frequency));
}
struct SemiPseudoAbi32 : public ArmSemihosting::Abi32
{
class State : public ArmSemihosting::Abi32::State
{
public:
State(const ThreadContext *tc) : ArmSemihosting::Abi32::State(tc)
{
// Use getAddr() to skip the func number in the first slot.
getAddr();
}
};
};
struct SemiPseudoAbi64 : public ArmSemihosting::Abi64
{
class State : public ArmSemihosting::Abi64::State
{
public:
State(const ThreadContext *tc) : ArmSemihosting::Abi64::State(tc)
{
// Use getAddr() to skip the func number in the first slot.
getAddr();
}
};
};
namespace GuestABI
{
// Ignore return values since those will be handled by semihosting.
template <typename T>
struct Result<SemiPseudoAbi32, T>
{
static void store(ThreadContext *tc, const T &ret) {}
};
template <typename T>
struct Result<SemiPseudoAbi64, T>
{
static void store(ThreadContext *tc, const T &ret) {}
};
// Handle arguments the same as for semihosting operations. Skipping the first
// slot is handled internally by the State type.
template <typename T>
struct Argument<SemiPseudoAbi32, T> :
public Argument<ArmSemihosting::Abi32, T>
{};
template <typename T>
struct Argument<SemiPseudoAbi64, T> :
public Argument<ArmSemihosting::Abi64, T>
{};
} // namespace GuestABI
ArmSemihosting::RetErrno
ArmSemihosting::callGem5PseudoOp32(ThreadContext *tc, uint32_t encoded_func)
{
uint8_t func;
PseudoInst::decodeAddrOffset(encoded_func, func);
uint64_t ret;
if (PseudoInst::pseudoInst<SemiPseudoAbi32>(tc, func, ret))
return retOK(ret);
else
return retError(EINVAL);
}
ArmSemihosting::RetErrno
ArmSemihosting::callGem5PseudoOp64(ThreadContext *tc, uint64_t encoded_func)
{
uint8_t func;
PseudoInst::decodeAddrOffset(encoded_func, func);
uint64_t ret;
if (PseudoInst::pseudoInst<SemiPseudoAbi64>(tc, func, ret))
return retOK(ret);
else
return retError(EINVAL);
}
FILE *
ArmSemihosting::getSTDIO(const char *stream_name,
const std::string &name, const char *mode)

View File

@@ -208,7 +208,9 @@ class ArmSemihosting : public SimObject
SYS_ELAPSED = 0x30,
SYS_TICKFREQ = 0x31,
MaxStandardOp = 0xFF
MaxStandardOp = 0xFF,
SYS_GEM5_PSEUDO_OP = 0x100
};
ArmSemihosting(const ArmSemihostingParams *p);
@@ -547,6 +549,9 @@ class ArmSemihosting : public SimObject
RetErrno callElapsed64(ThreadContext *tc, InPlaceArg ticks);
RetErrno callTickFreq(ThreadContext *tc);
RetErrno callGem5PseudoOp32(ThreadContext *tc, uint32_t encoded_func);
RetErrno callGem5PseudoOp64(ThreadContext *tc, uint64_t encoded_func);
template <typename Abi>
void
unrecognizedCall(ThreadContext *tc, const char *format, uint64_t op)