Go to the documentation of this file.
40 #include <linux/kvm.h>
47 #include "arch/registers.hh"
49 #include "debug/Kvm.hh"
50 #include "debug/KvmContext.hh"
51 #include "debug/KvmInt.hh"
56 #define EXTRACT_FIELD(val, mask, shift) \
57 (((val) & (mask)) >> (shift))
59 #define REG_IS_ARM(id) \
60 (((id) & KVM_REG_ARCH_MASK) == KVM_REG_ARM)
62 #define REG_IS_32BIT(id) \
63 (((id) & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32)
65 #define REG_IS_64BIT(id) \
66 (((id) & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64)
68 #define REG_IS_CP(id, cp) \
69 (((id) & KVM_REG_ARM_COPROC_MASK) == (cp))
71 #define REG_IS_CORE(id) REG_IS_CP((id), KVM_REG_ARM_CORE)
73 #define REG_IS_VFP(id) REG_IS_CP((id), KVM_REG_ARM_VFP)
74 #define REG_VFP_REG(id) ((id) & KVM_REG_ARM_VFP_MASK)
77 #define REG_IS_VFP_REG(id) (REG_VFP_REG(id) < 0x100)
78 #define REG_IS_VFP_CTRL(id) (REG_VFP_REG(id) >= 0x100)
80 #define REG_IS_DEMUX(id) REG_IS_CP((id), KVM_REG_ARM_DEMUX)
86 #define REG_CORE_IDX(id) \
87 (~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE))
90 EXTRACT_FIELD(id, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_SHIFT)
93 EXTRACT_FIELD(id, KVM_REG_ARM_32_CRN_MASK, KVM_REG_ARM_32_CRN_SHIFT)
95 #define REG_OPC1(id) \
96 EXTRACT_FIELD(id, KVM_REG_ARM_OPC1_MASK, KVM_REG_ARM_OPC1_SHIFT)
99 EXTRACT_FIELD(id, KVM_REG_ARM_CRM_MASK, KVM_REG_ARM_CRM_SHIFT)
101 #define REG_OPC2(id) \
102 EXTRACT_FIELD(id, KVM_REG_ARM_32_OPC2_MASK, KVM_REG_ARM_32_OPC2_SHIFT)
104 #define REG_CP32(cpnum, crn, opc1, crm, opc2) ( \
105 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
106 ((cpnum) << KVM_REG_ARM_COPROC_SHIFT) | \
107 ((crn) << KVM_REG_ARM_32_CRN_SHIFT) | \
108 ((opc1) << KVM_REG_ARM_OPC1_SHIFT) | \
109 ((crm) << KVM_REG_ARM_CRM_SHIFT) | \
110 ((opc2) << KVM_REG_ARM_32_OPC2_SHIFT))
112 #define REG_CP64(cpnum, opc1, crm) ( \
113 (KVM_REG_ARM | KVM_REG_SIZE_U64) | \
114 ((cpnum) << KVM_REG_ARM_COPROC_SHIFT) | \
115 ((opc1) << KVM_REG_ARM_OPC1_SHIFT) | \
116 ((crm) << KVM_REG_ARM_CRM_SHIFT))
118 #define REG_CORE32(kname) ( \
119 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
120 (KVM_REG_ARM_CORE) | \
121 (KVM_REG_ARM_CORE_REG(kname)))
123 #define REG_VFP32(regno) ( \
124 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
125 KVM_REG_ARM_VFP | (regno))
127 #define REG_VFP64(regno) ( \
128 (KVM_REG_ARM | KVM_REG_SIZE_U64) | \
129 KVM_REG_ARM_VFP | (regno))
131 #define REG_DEMUX32(dmxid, val) ( \
132 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \
175 #define INTERRUPT_ID(type, vcpu, irq) ( \
176 ((type) << KVM_ARM_IRQ_TYPE_SHIFT) | \
177 ((vcpu) << KVM_ARM_IRQ_VCPU_SHIFT) | \
178 ((irq) << KVM_ARM_IRQ_NUM_SHIFT))
180 #define INTERRUPT_VCPU_IRQ(vcpu) \
181 INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ)
183 #define INTERRUPT_VCPU_FIQ(vcpu) \
184 INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ)
187 #define COUNT_OF(l) (sizeof(l) / sizeof(*l))
246 irqAsserted(false), fiqAsserted(false)
273 const bool simFIQ(interrupt->checkRaw(
INT_FIQ));
274 const bool simIRQ(interrupt->checkRaw(
INT_IRQ));
278 DPRINTF(KvmInt,
"KVM: Update FIQ state: %i\n", simFIQ);
283 DPRINTF(KvmInt,
"KVM: Update IRQ state: %i\n", simIRQ);
300 DPRINTF(KvmContext,
"Updating KVM state...\n");
309 DPRINTF(KvmContext,
"Updating gem5 state...\n");
319 std::unique_ptr<struct kvm_reg_list> regs;
324 regs.reset((
struct kvm_reg_list *)
325 operator new(
sizeof(
struct kvm_reg_list) +
326 i *
sizeof(uint64_t)));
330 regs->reg + regs->n);
339 struct kvm_vcpu_init
init;
343 init.target = target;
351 if (
ioctl(KVM_ARM_VCPU_INIT, (
void *)&
init) == -1)
352 panic(
"KVM: Failed to initialize vCPU\n");
366 const unsigned crm(
REG_CRM(
id));
367 const unsigned crn(
REG_CRN(
id));
382 }
else if (is_reg64) {
385 warn(
"Unhandled register length, register (0x%x) ignored.\n");
404 case KVM_REG_ARM_VFP_FPINST:
405 case KVM_REG_ARM_VFP_FPINST2:
406 warn_once(
"KVM: FPINST not implemented.\n");
421 id &= ~KVM_REG_ARM_DEMUX_VAL_MASK;
429 if (
ioctl(KVM_GET_REG_LIST, (
void *)®s) == -1) {
430 if (errno == E2BIG) {
433 panic(
"KVM: Failed to get vCPU register list (errno: %i)\n",
452 inform(
"%s: 0x%x\n", ri->name, value);
468 for (RegIndexVector::const_iterator it(reg_ids.begin());
469 it != reg_ids.end(); ++it) {
477 switch (
id & KVM_REG_ARM_DEMUX_ID_MASK) {
478 case KVM_REG_ARM_DEMUX_ID_CCSIDR:
479 inform(
"CCSIDR [0x%x]: %s\n",
481 KVM_REG_ARM_DEMUX_VAL_MASK,
482 KVM_REG_ARM_DEMUX_VAL_SHIFT),
486 inform(
"DEMUX [0x%x, 0x%x]: %s\n",
488 KVM_REG_ARM_DEMUX_ID_MASK,
489 KVM_REG_ARM_DEMUX_ID_SHIFT),
491 KVM_REG_ARM_DEMUX_VAL_MASK,
492 KVM_REG_ARM_DEMUX_VAL_SHIFT),
514 !(idx >= MISCREG_CP15_UNIMP_START && idx < MISCREG_CP15_END)) {
518 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: "
524 inform(
"readMiscReg: %x, readMiscRegNoEffect: %x\n",
529 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: [%s]: "
535 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i "
551 const unsigned idx(
id & KVM_REG_ARM_VFP_MASK);
572 DPRINTF(KvmContext,
"kvm(%s) := 0x%x\n", ri->name, value);
583 DPRINTF(KvmContext,
"kvm(%s) := 0x%x\n", ri->name, value);
594 static bool warned(
false);
599 for (RegIndexVector::const_iterator it(regs.begin());
605 warn(
"Skipping non-ARM register: 0x%x\n", *it);
607 DPRINTF(
Kvm,
"Skipping invariant register: 0x%x\n", *it);
611 }
else if (
REG_CP(*it) <= 15) {
617 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
641 hack(
"KVM: 64-bit TTBBRx workaround\n");
646 warn(
"KVM: Ignoring unknown KVM co-processor register (0x%.8x):\n",
648 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
653 }
else if (
reg >= MISCREG_CP15_UNIMP_START &&
reg < MISCREG_CP15_END) {
655 warn(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
672 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
675 const unsigned idx(
id & KVM_REG_ARM_VFP_MASK);
676 const unsigned idx_base(idx << 1);
677 const unsigned idx_hi(idx_base + 1);
678 const unsigned idx_lo(idx_base + 0);
688 warn(
"Unhandled VFP control register: 0x%x\n",
id);
693 warn(
"Ignoring VFP control register (%s) with "
694 "unexpected size.\n",
701 warn(
"Unhandled VFP register: 0x%x\n",
id);
738 static bool warned(
false);
742 for (RegIndexVector::const_iterator it(reg_ids.begin());
743 it != reg_ids.end(); ++it) {
747 warn(
"Skipping non-ARM register: 0x%x\n", *it);
750 }
else if (
REG_CP(*it) <= 15) {
756 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
778 hack_once(
"KVM: 64-bit TTBRx workaround\n");
784 if (value & 0x80000000)
785 panic(
"KVM: Guest tried to enable LPAE.\n");
789 warn(
"KVM: Ignoring unknown KVM co-processor register:\n",
id);
790 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i"
795 }
else if (
reg >= MISCREG_CP15_UNIMP_START &&
reg < MISCREG_CP15_END) {
797 warn_once(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
813 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
816 const unsigned idx(
id & KVM_REG_ARM_VFP_MASK);
817 const unsigned idx_base(idx << 1);
818 const unsigned idx_hi(idx_base + 1);
819 const unsigned idx_lo(idx_base + 0);
828 warn(
"Unhandled VFP control register: 0x%x\n",
id);
833 warn(
"Ignoring VFP control register (%s) with "
834 "unexpected size.\n",
841 warn(
"Unhandled VFP register: 0x%x\n",
id);
846 ArmKvmCPUParams::create()
#define REG_CORE32(kname)
#define REG_DEMUX32(dmxid, val)
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
void setOneReg(uint64_t id, const void *addr)
Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
const FlagsType init
This Stat is Initialized.
virtual RegVal readIntRegFlat(RegIndex idx) const =0
Flat register interfaces.
#define INTERRUPT_VCPU_FIQ(vcpu)
void kvmArmVCpuInit(uint32_t target)
void updateKvmState()
Update the KVM state from the current thread context.
const static uint64_t KVM_REG64_TTBR0(REG_CP64(15, 0, 2))
ArmKvmCPU(ArmKvmCPUParams *params)
bool irqAsserted
Cached state of the IRQ line.
std::string getAndFormatOneReg(uint64_t id) const
Get and format one register for printout.
void updateThreadContext()
Update the current thread context with the KVM state.
MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
uint64_t Tick
Tick count type.
void updateKvmStateVFP(uint64_t id, bool show_warnings)
const static uint64_t KVM_REG64_TTBR1(REG_CP64(15, 1, 2))
MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
const ArmISA::IntRegIndex idx
gem5 index
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.
const char *const miscRegName[]
virtual void setFloatRegFlat(RegIndex idx, RegVal val)=0
uint64_t getOneRegU64(uint64_t id) const
ArmISA::MiscRegIndex decodeVFPCtrlReg(uint64_t id) const
static KvmCoreMiscRegInfo kvmCoreMiscRegs[]
bool fiqAsserted
Cached state of the FIQ line.
#define REG_IS_VFP_CTRL(id)
ArmISA::MiscRegIndex decodeCoProcReg(uint64_t id) const
Base class for KVM based CPU models.
RegIndexVector _regIndexList
Cached copy of the list of co-processor registers supported by KVM.
virtual void setIntRegFlat(RegIndex idx, RegVal val)=0
std::vector< BaseInterrupts * > interrupts
void dumpKvmStateVFP(uint64_t id)
void updateKvmStateMisc()
void updateKvmStateCoProc(uint64_t id, bool show_warnings)
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
#define REG_CP32(cpnum, crn, opc1, crm, opc2)
#define REG_CP64(cpnum, opc1, crm)
virtual RegVal readFloatRegFlat(RegIndex idx) const =0
void updateTCStateCoProc(uint64_t id, bool show_warnings)
void dumpKvmStateCoProc(uint64_t id)
const std::string & name()
bool isInvariantReg(uint64_t id)
Determine if a register is invariant.
int ioctl(int request, long p1) const
vCPU ioctl interface.
void updateKvmStateCore()
virtual TheISA::PCState pcState() const =0
const long vcpuID
KVM internal ID of the vCPU.
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state.
GenericISA::DelaySlotPCState< MachInst > PCState
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
virtual RegVal readMiscReg(RegIndex misc_reg)=0
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
#define REG_IS_VFP_REG(id)
static KvmIntRegInfo kvmIntRegs[]
ARM implementation of a KVM-based hardware virtualized CPU.
virtual void setMiscRegNoEffect(RegIndex misc_reg, RegVal val)=0
Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
const RegIndexVector & getRegList() const
Get a list of registers supported by getOneReg() and setOneReg().
#define EXTRACT_FIELD(val, mask, shift)
void updateTCStateVFP(uint64_t id, bool show_warnings)
const ArmISA::MiscRegIndex idx
gem5 index
virtual Addr instAddr() const =0
uint32_t getOneRegU32(uint64_t id) const
static uint64_t invariant_reg_vector[]
#define INTERRUPT_VCPU_IRQ(vcpu)
#define panic(...)
This implements a cprintf based panic() function.
Generated on Wed Sep 30 2020 14:02:00 for gem5 by doxygen 1.8.17