51#include "debug/Kvm.hh"
52#include "debug/KvmContext.hh"
53#include "debug/KvmInt.hh"
59using namespace ArmISA;
73 return (
id & KVM_REG_ARCH_MASK) == KVM_REG_ARM;
77regIs32Bit(uint64_t
id)
79 return (
id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32;
83regIs64Bit(uint64_t
id)
85 return (
id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64;
89regIsCp(uint64_t
id, uint64_t cp)
91 return (
id & KVM_REG_ARM_COPROC_MASK) == cp;
97 return regIsCp(
id, KVM_REG_ARM_CORE);
103 return regIsCp(
id, KVM_REG_ARM_VFP);
107regVfpReg(uint64_t
id)
109 return id & KVM_REG_ARM_VFP_MASK;
115regIsVfpReg(uint64_t
id)
117 return regVfpReg(
id) < 0x100;
120regIsVfpCtrl(uint64_t
id)
122 return regVfpReg(
id) >= 0x100;
126regIsDemux(uint64_t
id)
128 return regIsCp(
id, KVM_REG_ARM_DEMUX);
136regCoreIdx(uint64_t
id)
138 return ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
144 return extractField(
id, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_SHIFT);
150 return extractField(
id, KVM_REG_ARM_32_CRN_MASK, KVM_REG_ARM_32_CRN_SHIFT);
156 return extractField(
id, KVM_REG_ARM_OPC1_MASK, KVM_REG_ARM_OPC1_SHIFT);
162 return extractField(
id, KVM_REG_ARM_CRM_MASK, KVM_REG_ARM_CRM_SHIFT);
168 return extractField(
id, KVM_REG_ARM_32_OPC2_MASK,
169 KVM_REG_ARM_32_OPC2_SHIFT);
173regCp32(uint64_t cpnum, uint64_t crn, uint64_t opc1, uint64_t crm,
176 return KVM_REG_ARM | KVM_REG_SIZE_U32 |
177 (cpnum << KVM_REG_ARM_COPROC_SHIFT) |
178 (crn << KVM_REG_ARM_32_CRN_SHIFT) |
179 (opc1 << KVM_REG_ARM_OPC1_SHIFT) |
180 (crm << KVM_REG_ARM_CRM_SHIFT) |
181 (
opc2 << KVM_REG_ARM_32_OPC2_SHIFT);
185regCp64(uint64_t cpnum, uint64_t opc1, uint64_t crm)
187 return KVM_REG_ARM | KVM_REG_SIZE_U64 |
188 (cpnum << KVM_REG_ARM_COPROC_SHIFT) |
189 (opc1 << KVM_REG_ARM_OPC1_SHIFT) |
190 (crm << KVM_REG_ARM_CRM_SHIFT);
193constexpr KvmIntRegInfo
196 return { KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE |
offset,
201regVfp32(uint64_t regno)
203 return KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | regno;
207regVfp64(uint64_t regno)
209 return KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | regno;
213regDemux32(uint64_t dmxid, uint64_t
val)
215 return KVM_REG_ARM | KVM_REG_SIZE_U32 | dmxid |
val;
219interruptId(uint64_t
type, uint64_t vcpu, uint64_t
irq)
221 return (
type << KVM_ARM_IRQ_TYPE_SHIFT) |
222 (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) |
223 (
irq << KVM_ARM_IRQ_NUM_SHIFT);
227interruptVcpuIrq(uint64_t vcpu)
229 return interruptId(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ);
233interruptVcpuFiq(uint64_t vcpu)
235 return interruptId(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ);
244 regCp32(15, 0, 0, 0, 0),
245 regCp32(15, 0, 0, 0, 1),
246 regCp32(15, 0, 0, 0, 2),
247 regCp32(15, 0, 0, 0, 3),
248 regCp32(15, 0, 0, 0, 6),
250 regCp32(15, 0, 0, 1, 0),
251 regCp32(15, 0, 0, 1, 1),
252 regCp32(15, 0, 0, 1, 2),
253 regCp32(15, 0, 0, 1, 3),
254 regCp32(15, 0, 0, 1, 4),
255 regCp32(15, 0, 0, 1, 5),
256 regCp32(15, 0, 0, 1, 6),
257 regCp32(15, 0, 0, 1, 7),
259 regCp32(15, 0, 0, 2, 0),
260 regCp32(15, 0, 0, 2, 1),
261 regCp32(15, 0, 0, 2, 2),
262 regCp32(15, 0, 0, 2, 3),
263 regCp32(15, 0, 0, 2, 4),
264 regCp32(15, 0, 0, 2, 5),
265 regCp32(15, 0, 0, 2, 6),
266 regCp32(15, 0, 0, 2, 7),
268 regCp32(15, 0, 1, 0, 0),
269 regCp32(15, 0, 1, 0, 1),
270 regCp32(15, 0, 1, 0, 7),
272 regVfp32(KVM_REG_ARM_VFP_MVFR0),
273 regVfp32(KVM_REG_ARM_VFP_MVFR1),
274 regVfp32(KVM_REG_ARM_VFP_FPSID),
276 regDemux32(KVM_REG_ARM_DEMUX_ID_CCSIDR, 0),
288 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r0),
int_reg::R0,
"R0"),
289 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r1),
int_reg::R1,
"R1"),
290 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r2),
int_reg::R2,
"R2"),
291 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r3),
int_reg::R3,
"R3"),
292 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r4),
int_reg::R4,
"R4"),
293 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r5),
int_reg::R5,
"R5"),
294 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r6),
int_reg::R6,
"R6"),
295 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r7),
int_reg::R7,
"R7"),
296 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r8),
int_reg::R8,
"R8"),
297 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r9),
int_reg::R9,
"R9"),
298 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_r10),
int_reg::R10,
"R10"),
299 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_fp),
int_reg::R11,
"R11"),
300 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_ip),
int_reg::R12,
"R12"),
301 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_sp),
int_reg::R13,
"R13(USR)"),
302 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_lr),
int_reg::R14,
"R14(USR)"),
304 regCore32(KVM_REG_ARM_CORE_REG(svc_regs[0]),
int_reg::SpSvc,
"R13(SVC)"),
305 regCore32(KVM_REG_ARM_CORE_REG(svc_regs[1]), int_reg::LrSvc,
"R14(SVC)"),
307 regCore32(KVM_REG_ARM_CORE_REG(abt_regs[0]), int_reg::SpAbt,
"R13(ABT)"),
308 regCore32(KVM_REG_ARM_CORE_REG(abt_regs[1]), int_reg::LrAbt,
"R14(ABT)"),
310 regCore32(KVM_REG_ARM_CORE_REG(und_regs[0]), int_reg::SpUnd,
"R13(UND)"),
311 regCore32(KVM_REG_ARM_CORE_REG(und_regs[1]), int_reg::LrUnd,
"R14(UND)"),
313 regCore32(KVM_REG_ARM_CORE_REG(irq_regs[0]), int_reg::SpIrq,
"R13(IRQ)"),
314 regCore32(KVM_REG_ARM_CORE_REG(irq_regs[1]), int_reg::LrIrq,
"R14(IRQ)"),
317 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[0]),
int_reg::R8Fiq,
"R8(FIQ)"),
318 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[1]),
int_reg::R9Fiq,
"R9(FIQ)"),
319 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[2]),
int_reg::R10Fiq,
"R10(FIQ)"),
320 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[3]),
int_reg::R11Fiq,
"R11(FIQ)"),
321 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[4]),
int_reg::R12Fiq,
"R12(FIQ)"),
322 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[5]),
int_reg::R13Fiq,
"R13(FIQ)"),
323 regCore32(KVM_REG_ARM_CORE_REG(fiq_regs[6]),
int_reg::R14Fiq,
"R14(FIQ)"),
328 regCore32(KVM_REG_ARM_CORE_REG(usr_regs.ARM_cpsr),
MISCREG_CPSR,
"CPSR"),
344 irqAsserted(false), fiqAsserted(false)
372 const bool simIRQ = interrupt->checkRaw(
INT_IRQ);
376 DPRINTF(KvmInt,
"KVM: Update FIQ state: %i\n", simFIQ);
381 DPRINTF(KvmInt,
"KVM: Update IRQ state: %i\n", simIRQ);
398 DPRINTF(KvmContext,
"Updating KVM state...\n");
407 DPRINTF(KvmContext,
"Updating gem5 state...\n");
417 std::unique_ptr<
struct kvm_reg_list, void(*)(
void *
p)>
418 regs(
nullptr, [](
void *
p) {
operator delete(
p); });
423 regs.reset((
struct kvm_reg_list *)
424 operator new(
sizeof(
struct kvm_reg_list) +
425 i *
sizeof(uint64_t)));
429 regs->reg + regs->n);
438 struct kvm_vcpu_init
init;
442 init.target = target;
450 if (
ioctl(KVM_ARM_VCPU_INIT, (
void *)&
init) == -1)
451 panic(
"KVM: Failed to initialize vCPU\n");
457 const unsigned cp = regCp(
id);
458 const bool is_reg32 = regIs32Bit(
id);
459 const bool is_reg64 = regIs64Bit(
id);
465 const unsigned crm = regCrm(
id);
466 const unsigned crn = regCrn(
id);
467 const unsigned opc1 = regOpc1(
id);
468 const unsigned opc2 = regOpc2(
id);
481 }
else if (is_reg64) {
484 warn(
"Unhandled register length, register (0x%x) ignored.\n");
492 if (!regIsArm(
id) || !regIsVfp(
id) || !regIsVfpCtrl(
id))
495 const unsigned vfp_reg = regVfpReg(
id);
503 case KVM_REG_ARM_VFP_FPINST:
504 case KVM_REG_ARM_VFP_FPINST2:
505 warn_once(
"KVM: FPINST not implemented.\n");
519 if (regIsArm(
id) && regIsDemux(
id))
520 id &= ~KVM_REG_ARM_DEMUX_VAL_MASK;
528 if (
ioctl(KVM_GET_REG_LIST, (
void *)®s) == -1) {
529 if (errno == E2BIG) {
532 panic(
"KVM: Failed to get vCPU register list (errno: %i)\n",
551 inform(
"%s: 0x%x\n",
ri->name, value);
567 for (RegIndexVector::const_iterator it(reg_ids.begin());
568 it != reg_ids.end(); ++it) {
571 if (regIsArm(
id) && regCp(
id) <= 15) {
573 }
else if (regIsArm(
id) && regIsVfp(
id)) {
575 }
else if (regIsArm(
id) && regIsDemux(
id)) {
576 switch (
id & KVM_REG_ARM_DEMUX_ID_MASK) {
577 case KVM_REG_ARM_DEMUX_ID_CCSIDR:
578 inform(
"CCSIDR [0x%x]: %s\n",
579 extractField(
id, KVM_REG_ARM_DEMUX_VAL_MASK,
580 KVM_REG_ARM_DEMUX_VAL_SHIFT),
584 inform(
"DEMUX [0x%x, 0x%x]: %s\n",
585 extractField(
id, KVM_REG_ARM_DEMUX_ID_MASK,
586 KVM_REG_ARM_DEMUX_ID_SHIFT),
587 extractField(
id, KVM_REG_ARM_DEMUX_VAL_MASK,
588 KVM_REG_ARM_DEMUX_VAL_SHIFT),
592 }
else if (!regIsCore(
id)) {
601 assert(regIsArm(
id));
602 assert(regCp(
id) <= 15);
604 if (regIs32Bit(
id)) {
610 !(idx >= MISCREG_CP15_UNIMP_START && idx < MISCREG_CP15_END)) {
614 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: "
616 regCp(
id), regCrn(
id), regOpc1(
id), regCrm(
id),
620 inform(
"readMiscReg: %x, readMiscRegNoEffect: %x\n",
625 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: "
627 regCp(
id), regCrn(
id), regOpc1(
id), regCrm(
id),
631 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i "
633 regCp(
id), regCrn(
id), regOpc1(
id), regCrm(
id),
635 extractField(
id, KVM_REG_SIZE_MASK, KVM_REG_SIZE_SHIFT),
643 assert(regIsArm(
id));
644 assert(regIsVfp(
id));
646 if (regIsVfpReg(
id)) {
647 const unsigned idx =
id & KVM_REG_ARM_VFP_MASK;
649 }
else if (regIsVfpCtrl(
id)) {
665 ri->
idx != init_reg::NumRegs; ++
ri) {
668 DPRINTF(KvmContext,
"kvm(%s) := 0x%x\n",
ri->name, value);
679 DPRINTF(KvmContext,
"kvm(%s) := 0x%x\n",
ri->name, value);
683 if (debug::KvmContext)
690 static bool warned =
false;
695 for (RegIndexVector::const_iterator it(regs.begin());
699 if (!regIsArm(*it)) {
701 warn(
"Skipping non-ARM register: 0x%x\n", *it);
703 DPRINTF(
Kvm,
"Skipping invariant register: 0x%x\n", *it);
704 }
else if (regIsCore(*it)) {
707 }
else if (regCp(*it) <= 15) {
709 }
else if (regIsVfp(*it)) {
713 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
721 if (debug::KvmContext)
730 assert(regIsArm(
id));
731 assert(regCp(
id) <= 15);
737 hack(
"KVM: 64-bit TTBBRx workaround\n");
742 warn(
"KVM: Ignoring unknown KVM co-processor register (0x%.8x):\n",
744 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
746 id, regCp(
id), regIs64Bit(
id), regCrn(
id),
747 regOpc1(
id), regCrm(
id), regOpc2(
id));
749 }
else if (
reg >= MISCREG_CP15_UNIMP_START &&
reg < MISCREG_CP15_END) {
751 warn(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
762 assert(regIsArm(
id));
763 assert(regIsVfp(
id));
765 if (regIsVfpReg(
id)) {
766 if (!regIs64Bit(
id)) {
768 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
771 const unsigned idx =
id & KVM_REG_ARM_VFP_MASK;
772 const unsigned idx_base = idx << 1;
773 const unsigned idx_hi = idx_base + 1;
774 const unsigned idx_lo = idx_base + 0;
779 }
else if (regIsVfpCtrl(
id)) {
783 warn(
"Unhandled VFP control register: 0x%x\n",
id);
786 if (!regIs32Bit(
id)) {
788 warn(
"Ignoring VFP control register (%s) with "
789 "unexpected size.\n",
796 warn(
"Unhandled VFP register: 0x%x\n",
id);
826 if (debug::KvmContext)
833 static bool warned(
false);
837 for (RegIndexVector::const_iterator it(reg_ids.begin());
838 it != reg_ids.end(); ++it) {
840 if (!regIsArm(*it)) {
842 warn(
"Skipping non-ARM register: 0x%x\n", *it);
843 }
else if (regIsCore(*it)) {
845 }
else if (regCp(*it) <= 15) {
847 }
else if (regIsVfp(*it)) {
851 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
859 if (debug::KvmContext)
868 assert(regIsArm(
id));
869 assert(regCp(
id) <= 15);
873 hack_once(
"KVM: 64-bit TTBRx workaround\n");
879 if (value & 0x80000000)
880 panic(
"KVM: Guest tried to enable LPAE.\n");
884 warn(
"KVM: Ignoring unknown KVM co-processor register:\n",
id);
885 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
887 id, regCp(
id), regIs64Bit(
id), regCrn(
id),
888 regOpc1(
id), regCrm(
id), regOpc2(
id));
890 }
else if (
reg >= MISCREG_CP15_UNIMP_START &&
reg < MISCREG_CP15_END) {
892 warn_once(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
902 assert(regIsArm(
id));
903 assert(regIsVfp(
id));
905 if (regIsVfpReg(
id)) {
906 if (!regIs64Bit(
id)) {
908 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
911 const unsigned idx =
id & KVM_REG_ARM_VFP_MASK;
912 const unsigned idx_base = idx << 1;
913 const unsigned idx_hi = idx_base + 1;
914 const unsigned idx_lo = idx_base + 0;
919 }
else if (regIsVfpCtrl(
id)) {
923 warn(
"Unhandled VFP control register: 0x%x\n",
id);
926 if (!regIs32Bit(
id)) {
928 warn(
"Ignoring VFP control register (%s) with "
929 "unexpected size.\n",
936 warn(
"Unhandled VFP register: 0x%x\n",
id);
bool checkRaw(InterruptTypes interrupt) const
Check the state of a particular interrupt, ignoring CPSR masks.
static const std::set< uint64_t > invariant_regs
List of co-processor registers that KVM requires to be identical on both the host and the guest.
ArmISA::MiscRegIndex decodeVFPCtrlReg(uint64_t id) const
void updateKvmState()
Update the KVM state from the current thread context.
void dumpKvmStateCoProc(uint64_t id)
static KvmIntRegInfo kvmIntRegs[]
bool isInvariantReg(uint64_t id)
Determine if a register is invariant.
void dumpKvmStateVFP(uint64_t id)
void updateKvmStateCore()
void startup()
startup() is the final initialization call before simulation.
void updateKvmStateVFP(uint64_t id, bool show_warnings)
ArmKvmCPU(const ArmKvmCPUParams ¶ms)
void updateTCStateVFP(uint64_t id, bool show_warnings)
void updateKvmStateMisc()
bool irqAsserted
Cached state of the IRQ line.
Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
bool fiqAsserted
Cached state of the FIQ line.
RegIndexVector _regIndexList
Cached copy of the list of co-processor registers supported by KVM.
ArmISA::MiscRegIndex decodeCoProcReg(uint64_t id) const
static KvmCoreMiscRegInfo kvmCoreMiscRegs[]
void updateTCStateCoProc(uint64_t id, bool show_warnings)
const RegIndexVector & getRegList() const
Get a list of registers supported by getOneReg() and setOneReg().
void updateThreadContext()
Update the current thread context with the KVM state.
void updateKvmStateCoProc(uint64_t id, bool show_warnings)
void kvmArmVCpuInit(uint32_t target)
std::vector< BaseInterrupts * > interrupts
Base class for KVM based CPU models.
long vcpuID
KVM internal ID of the vCPU.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
uint64_t getOneRegU64(uint64_t id) const
std::string getAndFormatOneReg(uint64_t id) const
Get and format one register for printout.
uint32_t getOneRegU32(uint64_t id) const
void startup() override
startup() is the final initialization call before simulation.
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
void setOneReg(uint64_t id, const void *addr)
Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state.
void set(Addr val) override
Force this PC to reflect a particular value, resetting all its other fields around it.
Addr instAddr() const
Returns the memory address of the instruction this PC points to.
virtual RegVal readMiscReg(RegIndex misc_reg)=0
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
virtual RegVal getReg(const RegId ®) const
virtual void setMiscRegNoEffect(RegIndex misc_reg, RegVal val)=0
virtual void setReg(const RegId ®, RegVal val)
virtual const PCStateBase & pcState() const =0
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
int ioctl(int request, long p1) const
vCPU ioctl interface.
#define panic(...)
This implements a cprintf based panic() function.
constexpr RegClass flatIntRegClass
MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
constexpr RegClass intRegClass
MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
const char *const miscRegName[]
constexpr RegClass floatRegClass
const FlagsType init
This Stat is Initialized.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
static uint64_t invariant_reg_vector[]
static const uint64_t KVM_REG64_TTBR0(regCp64(15, 0, 2))
uint64_t Tick
Tick count type.
static const uint64_t KVM_REG64_TTBR1(regCp64(15, 1, 2))
const ArmISA::MiscRegIndex idx
gem5 index
const RegIndex idx
gem5 index
const std::string & name()