42 #include <linux/kvm.h> 49 #include "arch/registers.hh" 51 #include "debug/Kvm.hh" 52 #include "debug/KvmContext.hh" 53 #include "debug/KvmInt.hh" 58 #define EXTRACT_FIELD(val, mask, shift) \ 59 (((val) & (mask)) >> (shift)) 61 #define REG_IS_ARM(id) \ 62 (((id) & KVM_REG_ARCH_MASK) == KVM_REG_ARM) 64 #define REG_IS_32BIT(id) \ 65 (((id) & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) 67 #define REG_IS_64BIT(id) \ 68 (((id) & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) 70 #define REG_IS_CP(id, cp) \ 71 (((id) & KVM_REG_ARM_COPROC_MASK) == (cp)) 73 #define REG_IS_CORE(id) REG_IS_CP((id), KVM_REG_ARM_CORE) 75 #define REG_IS_VFP(id) REG_IS_CP((id), KVM_REG_ARM_VFP) 76 #define REG_VFP_REG(id) ((id) & KVM_REG_ARM_VFP_MASK) 79 #define REG_IS_VFP_REG(id) (REG_VFP_REG(id) < 0x100) 80 #define REG_IS_VFP_CTRL(id) (REG_VFP_REG(id) >= 0x100) 82 #define REG_IS_DEMUX(id) REG_IS_CP((id), KVM_REG_ARM_DEMUX) 88 #define REG_CORE_IDX(id) \ 89 (~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE)) 92 EXTRACT_FIELD(id, KVM_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_SHIFT) 95 EXTRACT_FIELD(id, KVM_REG_ARM_32_CRN_MASK, KVM_REG_ARM_32_CRN_SHIFT) 97 #define REG_OPC1(id) \ 98 EXTRACT_FIELD(id, KVM_REG_ARM_OPC1_MASK, KVM_REG_ARM_OPC1_SHIFT) 100 #define REG_CRM(id) \ 101 EXTRACT_FIELD(id, KVM_REG_ARM_CRM_MASK, KVM_REG_ARM_CRM_SHIFT) 103 #define REG_OPC2(id) \ 104 EXTRACT_FIELD(id, KVM_REG_ARM_32_OPC2_MASK, KVM_REG_ARM_32_OPC2_SHIFT) 106 #define REG_CP32(cpnum, crn, opc1, crm, opc2) ( \ 107 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \ 108 ((cpnum) << KVM_REG_ARM_COPROC_SHIFT) | \ 109 ((crn) << KVM_REG_ARM_32_CRN_SHIFT) | \ 110 ((opc1) << KVM_REG_ARM_OPC1_SHIFT) | \ 111 ((crm) << KVM_REG_ARM_CRM_SHIFT) | \ 112 ((opc2) << KVM_REG_ARM_32_OPC2_SHIFT)) 114 #define REG_CP64(cpnum, opc1, crm) ( \ 115 (KVM_REG_ARM | KVM_REG_SIZE_U64) | \ 116 ((cpnum) << KVM_REG_ARM_COPROC_SHIFT) | \ 117 ((opc1) << KVM_REG_ARM_OPC1_SHIFT) | \ 118 ((crm) << KVM_REG_ARM_CRM_SHIFT)) 120 #define REG_CORE32(kname) ( \ 121 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \ 122 (KVM_REG_ARM_CORE) | \ 123 (KVM_REG_ARM_CORE_REG(kname))) 125 #define REG_VFP32(regno) ( \ 126 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \ 127 KVM_REG_ARM_VFP | (regno)) 129 #define REG_VFP64(regno) ( \ 130 (KVM_REG_ARM | KVM_REG_SIZE_U64) | \ 131 KVM_REG_ARM_VFP | (regno)) 133 #define REG_DEMUX32(dmxid, val) ( \ 134 (KVM_REG_ARM | KVM_REG_SIZE_U32) | \ 177 #define INTERRUPT_ID(type, vcpu, irq) ( \ 178 ((type) << KVM_ARM_IRQ_TYPE_SHIFT) | \ 179 ((vcpu) << KVM_ARM_IRQ_VCPU_SHIFT) | \ 180 ((irq) << KVM_ARM_IRQ_NUM_SHIFT)) 182 #define INTERRUPT_VCPU_IRQ(vcpu) \ 183 INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ) 185 #define INTERRUPT_VCPU_FIQ(vcpu) \ 186 INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ) 189 #define COUNT_OF(l) (sizeof(l) / sizeof(*l)) 248 irqAsserted(false), fiqAsserted(false)
275 const bool simFIQ(interrupt->checkRaw(
INT_FIQ));
276 const bool simIRQ(interrupt->checkRaw(
INT_IRQ));
280 DPRINTF(KvmInt,
"KVM: Update FIQ state: %i\n", simFIQ);
285 DPRINTF(KvmInt,
"KVM: Update IRQ state: %i\n", simIRQ);
302 DPRINTF(KvmContext,
"Updating KVM state...\n");
311 DPRINTF(KvmContext,
"Updating gem5 state...\n");
322 const uint8_t func((reg_ip >> 8) & 0xFF);
324 DPRINTF(
Kvm,
"KVM Hypercall: %#x/%#x\n", func, subfunc);
326 PseudoInst::pseudoInst<PseudoInstABI>(
getContext(0), func);
341 std::unique_ptr<struct kvm_reg_list> regs;
346 regs.reset((
struct kvm_reg_list *)
347 operator new(
sizeof(
struct kvm_reg_list) +
348 i *
sizeof(uint64_t)));
352 regs->reg + regs->n);
361 struct kvm_vcpu_init init;
363 memset(&init, 0,
sizeof(init));
365 init.target = target;
373 if (
ioctl(KVM_ARM_VCPU_INIT, (
void *)&init) == -1)
374 panic(
"KVM: Failed to initialize vCPU\n");
388 const unsigned crm(
REG_CRM(
id));
389 const unsigned crn(
REG_CRN(
id));
404 }
else if (is_reg64) {
407 warn(
"Unhandled register length, register (0x%x) ignored.\n");
426 case KVM_REG_ARM_VFP_FPINST:
427 case KVM_REG_ARM_VFP_FPINST2:
428 warn_once(
"KVM: FPINST not implemented.\n");
443 id &= ~KVM_REG_ARM_DEMUX_VAL_MASK;
451 if (
ioctl(KVM_GET_REG_LIST, (
void *)®s) == -1) {
452 if (errno == E2BIG) {
455 panic(
"KVM: Failed to get vCPU register list (errno: %i)\n",
474 inform(
"%s: 0x%x\n", ri->name, value);
490 for (RegIndexVector::const_iterator it(reg_ids.begin());
491 it != reg_ids.end(); ++it) {
499 switch (
id & KVM_REG_ARM_DEMUX_ID_MASK) {
500 case KVM_REG_ARM_DEMUX_ID_CCSIDR:
501 inform(
"CCSIDR [0x%x]: %s\n",
503 KVM_REG_ARM_DEMUX_VAL_MASK,
504 KVM_REG_ARM_DEMUX_VAL_SHIFT),
508 inform(
"DEMUX [0x%x, 0x%x]: %s\n",
510 KVM_REG_ARM_DEMUX_ID_MASK,
511 KVM_REG_ARM_DEMUX_ID_SHIFT),
513 KVM_REG_ARM_DEMUX_VAL_MASK,
514 KVM_REG_ARM_DEMUX_VAL_SHIFT),
536 !(idx >= MISCREG_CP15_UNIMP_START && idx < MISCREG_CP15_END)) {
540 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: " 546 inform(
"readMiscReg: %x, readMiscRegNoEffect: %x\n",
551 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i]: [%s]: " 557 inform(
"CP%i: [CRn: c%i opc1: %.2i CRm: c%i opc2: %i inv: %i " 573 const unsigned idx(
id & KVM_REG_ARM_VFP_MASK);
594 DPRINTF(KvmContext,
"kvm(%s) := 0x%x\n", ri->name, value);
605 DPRINTF(KvmContext,
"kvm(%s) := 0x%x\n", ri->name, value);
616 static bool warned(
false);
621 for (RegIndexVector::const_iterator it(regs.begin());
627 warn(
"Skipping non-ARM register: 0x%x\n", *it);
629 DPRINTF(
Kvm,
"Skipping invariant register: 0x%x\n", *it);
633 }
else if (
REG_CP(*it) <= 15) {
639 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
663 hack(
"KVM: 64-bit TTBBRx workaround\n");
668 warn(
"KVM: Ignoring unknown KVM co-processor register (0x%.8x):\n",
670 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i" 675 }
else if (reg >= MISCREG_CP15_UNIMP_START && reg < MISCREG_CP15_END) {
677 warn(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
694 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
697 const unsigned idx(
id & KVM_REG_ARM_VFP_MASK);
698 const unsigned idx_base(idx << 1);
699 const unsigned idx_hi(idx_base + 1);
700 const unsigned idx_lo(idx_base + 0);
710 warn(
"Unhandled VFP control register: 0x%x\n",
id);
715 warn(
"Ignoring VFP control register (%s) with " 716 "unexpected size.\n",
723 warn(
"Unhandled VFP register: 0x%x\n",
id);
760 static bool warned(
false);
764 for (RegIndexVector::const_iterator it(reg_ids.begin());
765 it != reg_ids.end(); ++it) {
769 warn(
"Skipping non-ARM register: 0x%x\n", *it);
772 }
else if (
REG_CP(*it) <= 15) {
778 warn(
"Skipping register with unknown CP (%i) id: 0x%x\n",
800 hack_once(
"KVM: 64-bit TTBRx workaround\n");
806 if (value & 0x80000000)
807 panic(
"KVM: Guest tried to enable LPAE.\n");
811 warn(
"KVM: Ignoring unknown KVM co-processor register:\n",
id);
812 warn(
"\t0x%x: [CP: %i 64: %i CRn: c%i opc1: %.2i CRm: c%i" 817 }
else if (reg >= MISCREG_CP15_UNIMP_START && reg < MISCREG_CP15_END) {
819 warn_once(
"KVM: Co-processor reg. %s not implemented by gem5.\n",
835 warn(
"Unexpected VFP register length (reg: 0x%x).\n",
id);
838 const unsigned idx(
id & KVM_REG_ARM_VFP_MASK);
839 const unsigned idx_base(idx << 1);
840 const unsigned idx_hi(idx_base + 1);
841 const unsigned idx_lo(idx_base + 0);
850 warn(
"Unhandled VFP control register: 0x%x\n",
id);
855 warn(
"Ignoring VFP control register (%s) with " 856 "unexpected size.\n",
863 warn(
"Unhandled VFP register: 0x%x\n",
id);
868 ArmKvmCPUParams::create()
void kvmArmVCpuInit(uint32_t target)
#define panic(...)
This implements a cprintf based panic() function.
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
Tick onKvmExitHypercall()
#define REG_CP64(cpnum, opc1, crm)
void updateKvmStateVFP(uint64_t id, bool show_warnings)
void dumpKvmStateVFP(uint64_t id)
virtual TheISA::PCState pcState() const =0
void updateKvmStateCore()
virtual void setMiscRegNoEffect(RegIndex misc_reg, RegVal val)=0
std::vector< BaseInterrupts * > interrupts
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state...
void updateKvmState()
Update the KVM state from the current thread context.
#define REG_CP32(cpnum, crn, opc1, crm, opc2)
bool irqAsserted
Cached state of the IRQ line.
#define EXTRACT_FIELD(val, mask, shift)
const char *const miscRegName[]
Base class for KVM based CPU models.
void dumpKvmStateCoProc(uint64_t id)
static KvmCoreMiscRegInfo kvmCoreMiscRegs[]
static KvmIntRegInfo kvmIntRegs[]
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
const MiscRegIndex idx
gem5 index
ThreadContext is the external interface to all thread state for anything outside of the CPU...
#define REG_IS_VFP_REG(id)
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
const long vcpuID
KVM internal ID of the vCPU.
static const uint64_t KVM_REG64_TTBR0(REG_CP64(15, 0, 2))
static const uint64_t KVM_REG64_TTBR1(REG_CP64(15, 1, 2))
const IntRegIndex idx
gem5 index
ThreadContext * getContext(int tn) override
Given a thread num get tho thread context for it.
void setOneReg(uint64_t id, const void *addr)
Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
uint64_t Tick
Tick count type.
uint32_t getOneRegU32(uint64_t id) const
Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
std::string getAndFormatOneReg(uint64_t id) const
Get and format one register for printout.
#define INTERRUPT_VCPU_FIQ(vcpu)
void updateThreadContext()
Update the current thread context with the KVM state.
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...
virtual void setFloatRegFlat(RegIndex idx, RegVal val)=0
void updateTCStateVFP(uint64_t id, bool show_warnings)
virtual Addr instAddr() const =0
virtual const std::string name() const
void updateKvmStateCoProc(uint64_t id, bool show_warnings)
static uint64_t invariant_reg_vector[]
#define INTERRUPT_VCPU_IRQ(vcpu)
const RegIndexVector & getRegList() const
Get a list of registers supported by getOneReg() and setOneReg().
#define REG_CORE32(kname)
ArmISA::MiscRegIndex decodeVFPCtrlReg(uint64_t id) const
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
ArmISA::MiscRegIndex decodeCoProcReg(uint64_t id) const
void startup()
startup() is the final initialization call before simulation.
GenericISA::SimplePCState< MachInst > PCState
ArmKvmCPU(ArmKvmCPUParams *params)
virtual RegVal readIntRegFlat(RegIndex idx) const =0
Flat register interfaces.
bool fiqAsserted
Cached state of the FIQ line.
int ioctl(int request, long p1) const
vCPU ioctl interface.
void updateKvmStateMisc()
void startup() override
startup() is the final initialization call before simulation.
#define REG_IS_VFP_CTRL(id)
virtual RegVal readFloatRegFlat(RegIndex idx) const =0
#define REG_DEMUX32(dmxid, val)
virtual void setIntRegFlat(RegIndex idx, RegVal val)=0
RegIndexVector _regIndexList
Cached copy of the list of co-processor registers supported by KVM.
ARM implementation of a KVM-based hardware virtualized CPU.
MiscRegIndex decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
virtual RegVal readMiscReg(RegIndex misc_reg)=0
MiscRegIndex decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
uint64_t getOneRegU64(uint64_t id) const
void updateTCStateCoProc(uint64_t id, bool show_warnings)
bool isInvariantReg(uint64_t id)
Determine if a register is invariant.