nxemu/src/nxemu-os/core/arm/cpu_module.cpp

228 lines
5.6 KiB
C++

#include "cpu_module.h"
#include "core/hle/kernel/k_process.h"
#include <nxemu-module-spec/cpu.h>
namespace Core
{
class CpuModuleCallback : public ICpuInfo
{
public:
explicit CpuModuleCallback(IArm64Executor *& arm64Executor, Core::System & system, Kernel::KProcess * process) :
m_arm64Executor(arm64Executor),
m_system(system),
m_process(process),
m_memory(process->GetMemory()),
m_svn(0)
{
}
uint32_t svn()
{
return m_svn;
}
uint64_t & CpuTicks()
{
UNIMPLEMENTED();
static uint64_t ticks = 0;
return ticks;
}
void ServiceCall(uint32_t index)
{
m_svn = index;
m_arm64Executor->HaltExecution(IArm64Executor::HaltReason::SupervisorCall);
}
bool ReadMemory(uint64_t addr, uint8_t * Buffer, uint32_t Len)
{
return m_memory.ReadBlock(addr, Buffer, Len);
}
bool WriteMemory(uint64_t addr, const uint8_t * buffer, uint32_t len)
{
return m_memory.WriteBlock(addr, buffer, len);
}
IArm64Executor *& m_arm64Executor;
Kernel::KProcess * m_process{};
Core::System & m_system;
Core::Memory::Memory & m_memory;
uint32_t m_svn;
};
ArmCpuModule::ArmCpuModule(Core::System & system, bool is64Bit, bool usesWallClock, Kernel::KProcess * process, uint32_t coreIndex) :
ArmInterface{usesWallClock},
m_system(system),
m_cb(std::make_unique<CpuModuleCallback>(m_arm64Executor, system, process)),
m_arm64Executor(nullptr)
{
if (is64Bit)
{
m_arm64Executor = system.GetSwitchSystem().Cpu().CreateArm64Executor(process->GetExclusiveMonitor(), *m_cb, coreIndex);
}
}
ArmCpuModule::~ArmCpuModule()
{
if (m_arm64Executor != nullptr)
{
m_system.GetSwitchSystem().Cpu().DestroyArm64Executor(m_arm64Executor);
m_arm64Executor = nullptr;
}
}
Architecture ArmCpuModule::GetArchitecture() const
{
UNIMPLEMENTED();
return Architecture::AArch64;
}
HaltReason ArmCpuModule::RunThread(Kernel::KThread * thread)
{
if (m_arm64Executor != nullptr)
{
IArm64Executor::HaltReason reason = m_arm64Executor->Execute();
switch (reason)
{
case IArm64Executor::HaltReason::SupervisorCall: return HaltReason::SupervisorCall;
}
}
UNIMPLEMENTED();
return HaltReason::DataAbort;
}
HaltReason ArmCpuModule::StepThread(Kernel::KThread * thread)
{
UNIMPLEMENTED();
return HaltReason::DataAbort;
}
void ArmCpuModule::GetContext(Kernel::Svc::ThreadContext & ctx) const
{
if (m_arm64Executor != nullptr)
{
IArm64Reg & reg = m_arm64Executor->Reg();
for (size_t i = 0; i < 29; i++)
{
ctx.r[i] = reg.Get64((IArm64Reg::Reg)(((uint32_t)IArm64Reg::Reg::X0) + i));
}
ctx.fp = reg.Get64(IArm64Reg::Reg::FP);
ctx.lr = reg.Get64(IArm64Reg::Reg::LR);
ctx.sp = reg.Get64(IArm64Reg::Reg::SP);
ctx.pc = reg.Get64(IArm64Reg::Reg::PC);
ctx.pstate = reg.Get32(IArm64Reg::Reg::PSTATE);
for (size_t i = 0; i < 32; i++)
{
reg.Get128((IArm64Reg::Reg)(((uint32_t)IArm64Reg::Reg::Q0) + i), ctx.v[i][1], ctx.v[i][0]);
}
ctx.fpcr = reg.GetFPCR();
ctx.fpsr = reg.GetFPSR();
ctx.tpidr = reg.Get64(IArm64Reg::Reg::TPIDR_EL0);
}
else
{
UNIMPLEMENTED();
}
}
void ArmCpuModule::SetContext(const Kernel::Svc::ThreadContext & ctx)
{
if (m_arm64Executor != nullptr)
{
IArm64Reg & reg = m_arm64Executor->Reg();
for (size_t i = 0; i < 29; i++)
{
reg.Set64((IArm64Reg::Reg)(((uint32_t)IArm64Reg::Reg::X0) + i), ctx.r[i]);
}
reg.Set64(IArm64Reg::Reg::FP, ctx.fp);
reg.Set64(IArm64Reg::Reg::LR, ctx.lr);
reg.Set64(IArm64Reg::Reg::SP, ctx.sp);
reg.Set64(IArm64Reg::Reg::PC, ctx.pc);
reg.Set32(IArm64Reg::Reg::PSTATE, ctx.pstate);
for (size_t i = 0; i < 32; i++)
{
reg.Set128((IArm64Reg::Reg)(((uint32_t)IArm64Reg::Reg::Q0) + i), ctx.v[i][1], ctx.v[i][0]);
}
reg.SetFPCR(ctx.fpcr);
reg.SetFPSR(ctx.fpsr);
reg.Set64(IArm64Reg::Reg::TPIDR_EL0, ctx.tpidr);
}
else
{
UNIMPLEMENTED();
}
}
void ArmCpuModule::SetTpidrroEl0(u64 value)
{
if (m_arm64Executor != nullptr)
{
IArm64Reg & reg = m_arm64Executor->Reg();
reg.Set64(IArm64Reg::Reg::TPIDRRO_EL0, value);
}
else
{
UNIMPLEMENTED();
}
}
void ArmCpuModule::GetSvcArguments(std::span<uint64_t, 8> args) const
{
IArm64Reg & reg = m_arm64Executor->Reg();
for (size_t i = 0; i < 8; i++)
{
args[i] = reg.Get64((IArm64Reg::Reg)(((uint32_t)IArm64Reg::Reg::X0) + i));
}
}
void ArmCpuModule::SetSvcArguments(std::span<const uint64_t, 8> args)
{
IArm64Reg & reg = m_arm64Executor->Reg();
for (size_t i = 0; i < 8; i++)
{
reg.Set64((IArm64Reg::Reg)(((uint32_t)IArm64Reg::Reg::X0) + i), args[i]);
}
}
u32 ArmCpuModule::GetSvcNumber() const
{
return m_cb->svn();
}
void ArmCpuModule::SignalInterrupt(Kernel::KThread * thread)
{
UNIMPLEMENTED();
}
void ArmCpuModule::ClearInstructionCache()
{
UNIMPLEMENTED();
}
void ArmCpuModule::InvalidateCacheRange(u64 addr, std::size_t size)
{
if (m_arm64Executor != nullptr)
{
m_arm64Executor->InvalidateCacheRange(addr, size);
}
else
{
UNIMPLEMENTED();
}
}
const Kernel::DebugWatchpoint * ArmCpuModule::HaltedWatchpoint() const
{
UNIMPLEMENTED();
return nullptr;
}
void ArmCpuModule::RewindBreakpointInstruction()
{
UNIMPLEMENTED();
}
}