40 #include <linux/kvm.h>
51 #include "debug/Kvm.hh"
52 #include "debug/KvmContext.hh"
53 #include "debug/KvmInt.hh"
59 using namespace ArmISA;
73 return (
id & KVM_REG_ARCH_MASK) == KVM_REG_ARM;
77 regIs32Bit(uint64_t
id)
79 return (
id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32;
83 regIs64Bit(uint64_t
id)
85 return (
id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64;
89 regIsCp(uint64_t
id, uint64_t cp)
91 return (
id & KVM_REG_ARM_COPROC_MASK) == cp;
95 regIsCore(uint64_t
id)
97 return regIsCp(
id, KVM_REG_ARM_CORE);
101 regIsVfp(uint64_t
id)
103 return regIsCp(
id, KVM_REG_ARM_VFP);
107 regVfpReg(uint64_t
id)
109 return id & KVM_REG_ARM_VFP_MASK;
115 regIsVfpReg(uint64_t
id)
117 return regVfpReg(
id) < 0x100;
120 regIsVfpCtrl(uint64_t
id)
122 return regVfpReg(
id) >= 0x100;
126 regIsDemux(uint64_t
id)
128 return regIsCp(
id, KVM_REG_ARM_DEMUX);
136 regCoreIdx(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);
173 regCp32(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);
185 regCp64(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);
193 constexpr KvmIntRegInfo
196 return { KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_CORE |
offset,
201 regVfp32(uint64_t regno)
203 return KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_VFP | regno;
207 regVfp64(uint64_t regno)
209 return KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP | regno;
213 regDemux32(uint64_t dmxid, uint64_t
val)
215 return KVM_REG_ARM | KVM_REG_SIZE_U32 | dmxid |
val;
219 interruptId(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);
227 interruptVcpuIrq(uint64_t vcpu)
229 return interruptId(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ);
233 interruptVcpuFiq(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)) {
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;
780 }
else if (regIsVfpCtrl(
id)) {
784 warn(
"Unhandled VFP control register: 0x%x\n",
id);
787 if (!regIs32Bit(
id)) {
789 warn(
"Ignoring VFP control register (%s) with "
790 "unexpected size.\n",
797 warn(
"Unhandled VFP register: 0x%x\n",
id);
827 if (debug::KvmContext)
834 static bool warned(
false);
838 for (RegIndexVector::const_iterator it(reg_ids.begin());
839 it != reg_ids.end(); ++it) {
841 if (!regIsArm(*it)) {
843 warn(
"Skipping non-ARM register: 0x%x\n", *it);
844 }
else if (regIsCore(*it)) {
846 }
else if (regCp(*it) <= 15) {
848 }
else if (regIsVfp(*it)) {
852 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
860 if (debug::KvmContext)
869 assert(regIsArm(
id));
870 assert(regCp(
id) <= 15);
874 hack_once(
"KVM: 64-bit TTBRx workaround\n");
880 if (value & 0x80000000)
881 panic(
"KVM: Guest tried to enable LPAE.\n");
885 warn(
"KVM: Ignoring unknown KVM co-processor register:\n",
id);
886 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
888 id, regCp(
id), regIs64Bit(
id), regCrn(
id),
889 regOpc1(
id), regCrm(
id), regOpc2(
id));
891 }
else if (
reg >= MISCREG_CP15_UNIMP_START &&
reg < MISCREG_CP15_END) {
893 warn_once(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
903 assert(regIsArm(
id));
904 assert(regIsVfp(
id));
906 if (regIsVfpReg(
id)) {
907 if (!regIs64Bit(
id)) {
909 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
912 const unsigned idx =
id & KVM_REG_ARM_VFP_MASK;
913 const unsigned idx_base = idx << 1;
914 const unsigned idx_hi = idx_base + 1;
915 const unsigned idx_lo = idx_base + 0;
919 (value >> 32) & 0xFFFFFFFF);
921 }
else if (regIsVfpCtrl(
id)) {
925 warn(
"Unhandled VFP control register: 0x%x\n",
id);
928 if (!regIs32Bit(
id)) {
930 warn(
"Ignoring VFP control register (%s) with "
931 "unexpected size.\n",
938 warn(
"Unhandled VFP register: 0x%x\n",
id);