33 #include <linux/kvm.h> 39 #include "arch/registers.hh" 46 #include "debug/Drain.hh" 47 #include "debug/Kvm.hh" 48 #include "debug/KvmContext.hh" 49 #include "debug/KvmIO.hh" 50 #include "debug/KvmInt.hh" 56 #define IO_PCI_CONF_ADDR 0xCF8 57 #define IO_PCI_CONF_DATA_BASE 0xCFC 60 #define SEG_SYS_TYPE_TSS_AVAILABLE 9 62 #define SEG_SYS_TYPE_TSS_BUSY 11 65 #define SEG_CS_TYPE_ACCESSED 9 67 #define SEG_CS_TYPE_READ_ACCESSED 11 71 #define SEG_TYPE_BIT_ACCESSED 1 101 uint64_t reserved[12];
104 static_assert(
sizeof(
FXSave) == 512,
"Unexpected size of FXSave");
106 #define FOREACH_IREG() \ 108 APPLY_IREG(rax, INTREG_RAX); \ 109 APPLY_IREG(rbx, INTREG_RBX); \ 110 APPLY_IREG(rcx, INTREG_RCX); \ 111 APPLY_IREG(rdx, INTREG_RDX); \ 112 APPLY_IREG(rsi, INTREG_RSI); \ 113 APPLY_IREG(rdi, INTREG_RDI); \ 114 APPLY_IREG(rsp, INTREG_RSP); \ 115 APPLY_IREG(rbp, INTREG_RBP); \ 116 APPLY_IREG(r8, INTREG_R8); \ 117 APPLY_IREG(r9, INTREG_R9); \ 118 APPLY_IREG(r10, INTREG_R10); \ 119 APPLY_IREG(r11, INTREG_R11); \ 120 APPLY_IREG(r12, INTREG_R12); \ 121 APPLY_IREG(r13, INTREG_R13); \ 122 APPLY_IREG(r14, INTREG_R14); \ 123 APPLY_IREG(r15, INTREG_R15); \ 126 #define FOREACH_SREG() \ 128 APPLY_SREG(cr0, MISCREG_CR0); \ 129 APPLY_SREG(cr2, MISCREG_CR2); \ 130 APPLY_SREG(cr3, MISCREG_CR3); \ 131 APPLY_SREG(cr4, MISCREG_CR4); \ 132 APPLY_SREG(cr8, MISCREG_CR8); \ 133 APPLY_SREG(efer, MISCREG_EFER); \ 134 APPLY_SREG(apic_base, MISCREG_APIC_BASE); \ 137 #define FOREACH_DREG() \ 139 APPLY_DREG(db[0], MISCREG_DR0); \ 140 APPLY_DREG(db[1], MISCREG_DR1); \ 141 APPLY_DREG(db[2], MISCREG_DR2); \ 142 APPLY_DREG(db[3], MISCREG_DR3); \ 143 APPLY_DREG(dr6, MISCREG_DR6); \ 144 APPLY_DREG(dr7, MISCREG_DR7); \ 147 #define FOREACH_SEGMENT() \ 149 APPLY_SEGMENT(cs, MISCREG_CS - MISCREG_SEG_SEL_BASE); \ 150 APPLY_SEGMENT(ds, MISCREG_DS - MISCREG_SEG_SEL_BASE); \ 151 APPLY_SEGMENT(es, MISCREG_ES - MISCREG_SEG_SEL_BASE); \ 152 APPLY_SEGMENT(fs, MISCREG_FS - MISCREG_SEG_SEL_BASE); \ 153 APPLY_SEGMENT(gs, MISCREG_GS - MISCREG_SEG_SEL_BASE); \ 154 APPLY_SEGMENT(ss, MISCREG_SS - MISCREG_SEG_SEL_BASE); \ 155 APPLY_SEGMENT(tr, MISCREG_TR - MISCREG_SEG_SEL_BASE); \ 156 APPLY_SEGMENT(ldt, MISCREG_TSL - MISCREG_SEG_SEL_BASE); \ 159 #define FOREACH_DTABLE() \ 161 APPLY_DTABLE(gdt, MISCREG_TSG - MISCREG_SEG_SEL_BASE); \ 162 APPLY_DTABLE(idt, MISCREG_IDTR - MISCREG_SEG_SEL_BASE); \ 165 template<
typename STRUCT,
typename ENTRY>
168 return (STRUCT *)
operator new(
sizeof(STRUCT) + entries *
sizeof(ENTRY));
174 inform(
"KVM register state:\n");
176 #define APPLY_IREG(kreg, mreg) \ 177 inform("\t" # kreg ": 0x%llx\n", regs.kreg) 183 inform(
"\trip: 0x%llx\n", regs.rip);
184 inform(
"\trflags: 0x%llx\n", regs.rflags);
190 inform(
"\t%s: @0x%llx+%x [sel: 0x%x, type: 0x%x]\n" 191 "\t\tpres.: %u, dpl: %u, db: %u, s: %u, l: %u, g: %u, avl: %u, unus.: %u\n",
193 seg.base, seg.limit, seg.selector, seg.type,
194 seg.present, seg.dpl, seg.db, seg.s, seg.l, seg.g, seg.avl, seg.unusable);
198 dumpKvm(
const char *reg_name,
const struct kvm_dtable &dtable)
200 inform(
"\t%s: @0x%llx+%x\n",
201 reg_name, dtable.base, dtable.limit);
207 #define APPLY_SREG(kreg, mreg) \ 208 inform("\t" # kreg ": 0x%llx\n", sregs.kreg); 209 #define APPLY_SEGMENT(kreg, idx) \ 210 dumpKvm(# kreg, sregs.kreg); 211 #define APPLY_DTABLE(kreg, idx) \ 212 dumpKvm(# kreg, sregs.kreg); 214 inform(
"Special registers:\n");
219 inform(
"Interrupt Bitmap:");
220 for (
int i = 0;
i < KVM_NR_INTERRUPTS;
i += 64)
221 inform(
" 0x%.8x", sregs.interrupt_bitmap[
i / 64]);
228 #ifdef KVM_GET_DEBUGREGS 230 dumpKvm(
const struct kvm_debugregs ®s)
232 inform(
"KVM debug state:\n");
234 #define APPLY_DREG(kreg, mreg) \ 235 inform("\t" # kreg ": 0x%llx\n", regs.kreg) 241 inform(
"\tflags: 0x%llx\n", regs.flags);
256 inform(
"\tlast_ip: 0x%x\n", fpu.last_ip);
257 inform(
"\tlast_dp: 0x%x\n", fpu.last_dp);
264 const unsigned top((fpu.fsw >> 11) & 0x7);
265 inform(
"\tfcw: 0x%x\n", fpu.fcw);
267 inform(
"\tfsw: 0x%x (top: %i, " 268 "conditions: %s%s%s%s, exceptions: %s%s%s%s%s%s %s%s%s)\n",
271 (fpu.fsw &
CC0Bit) ?
"C0" :
"",
272 (fpu.fsw &
CC1Bit) ?
"C1" :
"",
273 (fpu.fsw &
CC2Bit) ?
"C2" :
"",
274 (fpu.fsw &
CC3Bit) ?
"C3" :
"",
276 (fpu.fsw &
IEBit) ?
"I" :
"",
277 (fpu.fsw &
DEBit) ?
"D" :
"",
278 (fpu.fsw &
ZEBit) ?
"Z" :
"",
279 (fpu.fsw &
OEBit) ?
"O" :
"",
280 (fpu.fsw &
UEBit) ?
"U" :
"",
281 (fpu.fsw &
PEBit) ?
"P" :
"",
285 (fpu.fsw &
BusyBit) ?
"BUSY " :
"" 287 inform(
"\tftwx: 0x%x\n", fpu.ftwx);
288 inform(
"\tlast_opcode: 0x%x\n", fpu.last_opcode);
290 inform(
"\tmxcsr: 0x%x\n", fpu.mxcsr);
292 for (
int i = 0;
i < 8; ++
i) {
293 const unsigned reg_idx((
i + top) & 0x7);
294 const bool empty(!((fpu.ftwx >> reg_idx) & 0x1));
297 for (
int j = 0;
j < 10; ++
j)
298 snprintf(&hex[
j*2], 3,
"%.2x", fpu.fpr[
i][j]);
299 inform(
"\t\tST%i/%i: 0x%s (%f)%s\n",
i, reg_idx,
300 hex, value, empty ?
" (e)" :
"");
302 inform(
"\tXMM registers:\n");
303 for (
int i = 0;
i < 16; ++
i) {
305 for (
int j = 0;
j < 16; ++
j)
306 snprintf(&hex[
j*2], 3,
"%.2x", fpu.xmm[
i][j]);
307 inform(
"\t\t%i: 0x%s\n",
i, hex);
314 inform(
"FPU registers:\n");
321 inform(
"FPU registers (XSave):\n");
330 for (
int i = 0;
i < msrs.nmsrs; ++
i) {
331 const struct kvm_msr_entry &
e(msrs.entries[
i]);
333 inform(
"\t0x%x: 0x%x\n", e.index, e.data);
340 inform(
"KVM XCR registers:\n");
342 inform(
"\tFlags: 0x%x\n", regs.flags);
343 for (
int i = 0;
i < regs.nr_xcrs; ++
i) {
344 inform(
"\tXCR[0x%x]: 0x%x\n",
355 inform(
"\tException: [inj: %i, nr: %i, has_ec: %i, ec: %i]\n",
356 events.exception.injected, events.exception.nr,
357 events.exception.has_error_code, events.exception.error_code);
359 inform(
"\tInterrupt: [inj: %i, nr: %i, soft: %i]\n",
360 events.interrupt.injected, events.interrupt.nr,
361 events.interrupt.soft);
363 inform(
"\tNMI: [inj: %i, pending: %i, masked: %i]\n",
364 events.nmi.injected, events.nmi.pending,
367 inform(
"\tSIPI vector: 0x%x\n", events.sipi_vector);
368 inform(
"\tFlags: 0x%x\n", events.flags);
378 uint64_t upper_half(addr & 0xffff800000000000ULL);
379 return upper_half == 0 || upper_half == 0xffff800000000000;
384 struct kvm_sregs sregs)
393 warn(
"Illegal %s base: 0x%x\n", name, seg.base);
403 if (seg.base & 0xffffffff00000000ULL)
404 warn(
"Illegal %s base: 0x%x\n", name, seg.base);
414 warn(
"CS type is 3 but dpl != 0.\n");
418 if (seg.dpl != sregs.ss.dpl)
419 warn(
"CS type is %i but CS DPL != SS DPL\n", seg.type);
423 if (seg.dpl > sregs.ss.dpl)
424 warn(
"CS type is %i but CS DPL > SS DPL\n", seg.type);
427 warn(
"Illegal CS type: %i\n", seg.type);
437 if (sregs.cs.type == 3 && seg.dpl != 0)
438 warn(
"CS type is 3, but SS DPL is != 0.\n");
441 if (!(sregs.cr0 & 1) && seg.dpl != 0)
442 warn(
"SS DPL is %i, but CR0 PE is 0\n", seg.dpl);
445 warn(
"Illegal SS type: %i\n", seg.type);
456 if (!(seg.type & 0x1) ||
457 ((seg.type & 0x8) && !(seg.type & 0x2)))
458 warn(
"%s has an illegal type field: %i\n", name, seg.type);
463 if (seg.type != 3 && seg.type != 11)
464 warn(
"%s: Illegal segment type (%i)\n", name, seg.type);
471 warn(
"%s: Illegal segment type (%i)\n", name, seg.type);
486 warn(
"%s: S flag not set\n", name);
495 warn(
"%s: S flag is set\n", name);
512 warn(
"%s: P flag not set\n", name);
514 if (((seg.limit & 0xFFF) == 0 && seg.g) ||
515 ((seg.limit & 0xFFF00000) != 0 && !seg.g)) {
516 warn(
"%s limit (0x%x) and g (%i) combination is illegal.\n",
517 name, seg.limit, seg.g);
527 useXSave(params->useXSave)
532 panic(
"KVM: Missing capability (KVM_CAP_SET_TSS_ADDR)\n");
534 panic(
"KVM: Missing capability (KVM_CAP_EXT_CPUID)\n");
536 warn(
"KVM: Missing capability (KVM_CAP_USER_NMI)\n");
538 warn(
"KVM: Missing capability (KVM_CAP_VCPU_EVENTS)\n");
545 warn(
"KVM: XSAVE not supported by host. MXCSR synchronization might be " 546 "unreliable due to kernel bugs.\n");
549 warn(
"KVM: XSave FPU/SIMD synchronization disabled by user.\n");
597 struct kvm_regs regs;
605 struct kvm_sregs sregs;
614 #ifdef KVM_GET_DEBUGREGS 615 struct kvm_debugregs dregs;
620 inform(
"Debug registers not supported by kernel.\n");
628 struct kvm_xcrs xcrs;
632 inform(
"XCRs not supported by kernel.\n");
640 struct kvm_xsave xsave;
644 inform(
"XSave not supported by kernel.\n");
651 struct kvm_vcpu_events events;
659 const Kvm::MSRIndexVector &supported_msrs(
vm.
kvm->getSupportedMSRs());
660 std::unique_ptr<struct kvm_msrs> msrs(
661 newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(
662 supported_msrs.size()));
664 msrs->nmsrs = supported_msrs.size();
665 for (
int i = 0;
i < supported_msrs.size(); ++
i) {
666 struct kvm_msr_entry &
e(msrs->entries[
i]);
667 e.index = supported_msrs[
i];
684 DPRINTF(KvmContext,
"X86KvmCPU::updateKvmState():\n");
692 struct kvm_regs regs;
694 #define APPLY_IREG(kreg, mreg) regs.kreg = tc->readIntReg(mreg) 720 kvm_seg.type =
attr.type;
721 kvm_seg.present =
attr.present;
722 kvm_seg.dpl =
attr.dpl;
723 kvm_seg.db =
attr.defaultSize;
724 kvm_seg.s =
attr.system;
725 kvm_seg.l =
attr.longMode;
726 kvm_seg.g =
attr.granularity;
727 kvm_seg.avl =
attr.avl;
733 kvm_seg.unusable = 0;
759 struct kvm_sregs sregs;
761 #define APPLY_SREG(kreg, mreg) sregs.kreg = tc->readMiscRegNoEffect(mreg) 762 #define APPLY_SEGMENT(kreg, idx) setKvmSegmentReg(tc, sregs.kreg, idx) 763 #define APPLY_DTABLE(kreg, idx) setKvmDTableReg(tc, sregs.kreg, idx) 774 memset(&sregs.interrupt_bitmap, 0,
sizeof(sregs.interrupt_bitmap));
788 hack(
"tr.type (%i) is not busy. Forcing the busy bit.\n",
799 sregs.cs.dpl != sregs.ss.dpl) {
801 hack(
"CS.DPL (%i) != SS.DPL (%i): Forcing SS.DPL to %i\n",
802 sregs.cs.dpl, sregs.ss.dpl, sregs.cs.dpl);
803 sregs.ss.dpl = sregs.cs.dpl;
809 if (!rflags_nocc.vm) {
814 #define APPLY_SEGMENT(kreg, idx) \ 815 checkSeg(# kreg, idx + MISCREG_SEG_SEL_BASE, sregs.kreg, sregs) 824 template <
typename T>
839 const unsigned top((fpu.fsw >> 11) & 0x7);
840 for (
int i = 0;
i < 8; ++
i) {
841 const unsigned reg_idx((
i + top) & 0x7);
844 DPRINTF(KvmContext,
"Setting KVM FP reg %i (st[%i]) := %f\n",
851 for (
int i = 0;
i < 16; ++
i) {
852 *(uint64_t *)&fpu.xmm[
i][0] =
854 *(uint64_t *)&fpu.xmm[
i][8] =
866 memset(&fpu, 0,
sizeof(fpu));
871 warn_once(
"MISCREG_FISEG is non-zero.\n");
876 warn_once(
"MISCREG_FOSEG is non-zero.\n");
886 struct kvm_xsave kxsave;
891 memset(&kxsave, 0,
sizeof(kxsave));
896 warn_once(
"MISCREG_FISEG is non-zero.\n");
901 warn_once(
"MISCREG_FOSEG is non-zero.\n");
924 for (
auto it = indices.cbegin(); it != indices.cend(); ++it) {
925 struct kvm_msr_entry e;
930 DPRINTF(KvmContext,
"Adding MSR: idx: 0x%x, data: 0x%x\n",
942 struct kvm_regs regs;
943 struct kvm_sregs sregs;
948 DPRINTF(KvmContext,
"X86KvmCPU::updateThreadContext():\n");
955 struct kvm_xsave xsave;
975 const struct kvm_sregs &sregs)
977 #define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg) 997 attr.type = kvm_seg.type;
998 attr.present = kvm_seg.present;
999 attr.dpl = kvm_seg.dpl;
1000 attr.defaultSize = kvm_seg.db;
1001 attr.system = kvm_seg.s;
1002 attr.longMode = kvm_seg.l;
1003 attr.granularity = kvm_seg.g;
1004 attr.avl = kvm_seg.avl;
1005 attr.unusable = kvm_seg.unusable;
1033 #define APPLY_SREG(kreg, mreg) tc->setMiscRegNoEffect(mreg, sregs.kreg) 1034 #define APPLY_SEGMENT(kreg, idx) setContextSegment(tc, sregs.kreg, idx) 1035 #define APPLY_DTABLE(kreg, idx) setContextSegment(tc, sregs.kreg, idx) 1040 #undef APPLY_SEGMENT 1044 template<
typename T>
1048 const unsigned top((fpu.fsw >> 11) & 0x7);
1050 for (
int i = 0;
i < 8; ++
i) {
1051 const unsigned reg_idx((
i + top) & 0x7);
1053 DPRINTF(KvmContext,
"Setting gem5 FP reg %i (st[%i]) := %f\n",
1072 for (
int i = 0;
i < 16; ++
i) {
1107 std::unique_ptr<struct kvm_msrs> kvm_msrs(
1108 newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size()));
1109 struct kvm_msr_entry *entry;
1112 kvm_msrs->nmsrs = msrs.size();
1113 entry = &kvm_msrs->entries[0];
1114 for (
auto it = msrs.cbegin(); it != msrs.cend(); ++it, ++entry) {
1116 entry->reserved = 0;
1123 entry = &kvm_msrs->entries[0];
1124 for (
int i = 0;
i < kvm_msrs->nmsrs; ++
i, ++entry) {
1125 DPRINTF(KvmContext,
"Setting M5 MSR: idx: 0x%x, data: 0x%x\n",
1126 entry->index, entry->data);
1150 X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get()));
1151 if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) {
1152 DPRINTF(KvmInt,
"Delivering NMI\n");
1154 }
else if (dynamic_cast<InitInterrupt *>(fault.get())) {
1155 DPRINTF(KvmInt,
"INIT interrupt\n");
1156 fault.get()->invoke(
tc);
1165 }
else if (dynamic_cast<StartupInterrupt *>(fault.get())) {
1166 DPRINTF(KvmInt,
"STARTUP interrupt\n");
1167 fault.get()->invoke(
tc);
1171 }
else if (x86int) {
1172 struct kvm_interrupt kvm_int;
1175 DPRINTF(KvmInt,
"Delivering interrupt: %s (%u)\n",
1176 fault->name(), kvm_int.irq);
1180 panic(
"KVM: Unknown interrupt type\n");
1192 if (lapic->checkInterruptsRaw()) {
1193 if (lapic->hasPendingUnmaskable()) {
1195 "Delivering unmaskable interrupt.\n");
1198 }
else if (kvm_run.ready_for_interrupt_injection) {
1205 if (lapic->checkInterrupts(
tc)) {
1207 "M5 has pending interrupts, delivering interrupt.\n");
1212 "Interrupt delivery delayed due to KVM confusion.\n");
1213 kvm_run.request_interrupt_window = 1;
1215 }
else if (!kvm_run.request_interrupt_window) {
1217 "M5 has pending interrupts, requesting interrupt " 1219 kvm_run.request_interrupt_window = 1;
1222 kvm_run.request_interrupt_window = 0;
1239 DPRINTF(Drain,
"kvmRunDrain: Architecture code isn't drained\n");
1245 kvm_run.request_interrupt_window = 1;
1252 DPRINTF(Drain,
"kvmRunDrain: Delivering pending IO\n");
1287 const uint16_t port(kvm_run.io.port);
1289 assert(kvm_run.exit_reason == KVM_EXIT_IO);
1291 if (kvm_run.io.size != 4) {
1292 panic(
"Unexpected IO size (%u) for address 0x%x.\n",
1293 kvm_run.io.size, port);
1296 if (kvm_run.io.count != 1) {
1297 panic(
"Unexpected IO count (%u) for address 0x%x.\n",
1298 kvm_run.io.count, port);
1302 if (kvm_run.io.direction == KVM_EXIT_IO_OUT)
1312 bool isWrite(kvm_run.io.direction == KVM_EXIT_IO_OUT);
1313 unsigned char *guestData(
getGuestData(kvm_run.io.data_offset));
1315 uint16_t port(kvm_run.io.port);
1317 const int count(kvm_run.io.count);
1319 assert(kvm_run.io.direction == KVM_EXIT_IO_IN ||
1320 kvm_run.io.direction == KVM_EXIT_IO_OUT);
1322 DPRINTF(KvmIO,
"KVM-x86: Handling IO instruction (%s) (port: 0x%x)\n",
1323 (isWrite ?
"out" :
"in"), kvm_run.io.port);
1339 if (pciConfigAddr & 0x80000000) {
1354 RequestPtr io_req = std::make_shared<Request>(
1355 pAddr, kvm_run.io.size,
1365 guestData += kvm_run.io.size;
1383 struct kvm_vcpu_events events;
1394 const bool pending_events(events.exception.injected ||
1395 events.interrupt.injected ||
1396 events.nmi.injected || events.nmi.pending);
1398 if (pending_events) {
1399 DPRINTF(Drain,
"archIsDrained: Pending events: %s %s %s %s\n",
1400 events.exception.injected ?
"exception" :
"",
1401 events.interrupt.injected ?
"interrupt" :
"",
1402 events.nmi.injected ?
"nmi[i]" :
"",
1403 events.nmi.pending ?
"nmi[p]" :
"");
1406 return !pending_events;
1409 static struct kvm_cpuid_entry2
1413 struct kvm_cpuid_entry2 e;
1414 e.function =
function;
1417 e.eax = (uint32_t)result.rax;
1418 e.ebx = (uint32_t)result.rbx;
1419 e.ecx = (uint32_t)result.rcx;
1420 e.edx = (uint32_t)result.rdx;
1428 Kvm::CPUIDVector m5_supported;
1439 for (uint32_t
function = 0;
function <= func0.
rax; ++
function) {
1444 m5_supported.push_back(
makeKvmCpuid(
function, idx, cpuid));
1450 for (uint32_t
function = 0x80000000;
function <= efunc0.
rax; ++
function) {
1455 m5_supported.push_back(
makeKvmCpuid(
function, idx, cpuid));
1464 if (
ioctl(KVM_SET_CPUID2, (
void *)&cpuid) == -1)
1465 panic(
"KVM: Failed to set guest CPUID2 (errno: %i)\n",
1472 std::unique_ptr<struct kvm_cpuid2> kvm_cpuid(
1473 newVarStruct<struct kvm_cpuid2, struct kvm_cpuid_entry2>(cpuid.size()));
1475 kvm_cpuid->nent = cpuid.size();
1476 std::copy(cpuid.begin(), cpuid.end(), kvm_cpuid->entries);
1484 if (
ioctl(KVM_SET_MSRS, (
void *)&msrs) == -1)
1485 panic(
"KVM: Failed to set guest MSRs (errno: %i)\n",
1492 std::unique_ptr<struct kvm_msrs> kvm_msrs(
1493 newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size()));
1495 kvm_msrs->nmsrs = msrs.size();
1496 std::copy(msrs.begin(), msrs.end(), kvm_msrs->entries);
1504 if (
ioctl(KVM_GET_MSRS, (
void *)&msrs) == -1)
1505 panic(
"KVM: Failed to get guest MSRs (errno: %i)\n",
1513 std::unique_ptr<struct kvm_msrs> kvm_msrs(
1514 newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1));
1515 struct kvm_msr_entry &entry(kvm_msrs->entries[0]);
1517 kvm_msrs->nmsrs = 1;
1518 entry.index =
index;
1528 std::unique_ptr<struct kvm_msrs> kvm_msrs(
1529 newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1));
1530 struct kvm_msr_entry &entry(kvm_msrs->entries[0]);
1532 kvm_msrs->nmsrs = 1;
1533 entry.index =
index;
1541 const Kvm::MSRIndexVector &
1545 const Kvm::MSRIndexVector &kvm_msrs(
vm.
kvm->getSupportedMSRs());
1547 DPRINTF(
Kvm,
"kvm-x86: Updating MSR intersection\n");
1548 for (
auto it = kvm_msrs.cbegin(); it != kvm_msrs.cend(); ++it) {
1551 DPRINTF(
Kvm,
"kvm-x86: Adding MSR 0x%x\n", *it);
1553 warn(
"kvm-x86: MSR (0x%x) unsupported by gem5. Skipping.\n",
1565 #ifdef KVM_GET_DEBUGREGS 1566 if (
ioctl(KVM_GET_DEBUGREGS, ®s) == -1)
1567 panic(
"KVM: Failed to get guest debug registers\n");
1569 panic(
"KVM: Unsupported getDebugRegisters call.\n");
1576 #ifdef KVM_SET_DEBUGREGS 1577 if (
ioctl(KVM_SET_DEBUGREGS, (
void *)®s) == -1)
1578 panic(
"KVM: Failed to set guest debug registers\n");
1580 panic(
"KVM: Unsupported setDebugRegisters call.\n");
1587 if (
ioctl(KVM_GET_XCRS, ®s) == -1)
1588 panic(
"KVM: Failed to get guest debug registers\n");
1594 if (
ioctl(KVM_SET_XCRS, (
void *)®s) == -1)
1595 panic(
"KVM: Failed to set guest debug registers\n");
1601 if (
ioctl(KVM_GET_XSAVE, &xsave) == -1)
1602 panic(
"KVM: Failed to get guest debug registers\n");
1608 if (
ioctl(KVM_SET_XSAVE, (
void *)&xsave) == -1)
1609 panic(
"KVM: Failed to set guest debug registers\n");
1616 if (
ioctl(KVM_GET_VCPU_EVENTS, &events) == -1)
1617 panic(
"KVM: Failed to get guest debug registers\n");
1623 if (
ioctl(KVM_SET_VCPU_EVENTS, (
void *)&events) == -1)
1624 panic(
"KVM: Failed to set guest debug registers\n");
1628 X86KvmCPUParams::create()
#define panic(...)
This implements a cprintf based panic() function.
void getDebugRegisters(struct kvm_debugregs ®s) const
Wrappers around KVM's state transfer methods.
#define SEG_CS_TYPE_ACCESSED
static void updateThreadContextFPUCommon(ThreadContext *tc, const T &fpu)
void handleIOMiscReg32(int miscreg)
Handle a 32-bit IO access that should be mapped to a MiscReg.
bool capExtendedCPUID() const
Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID().
uint64_t getRFlags(ThreadContext *tc)
Reconstruct the rflags register from the internal gem5 register state.
The request is to an uncacheable address.
void setXCRs(const struct kvm_xcrs ®s)
virtual void setMiscReg(RegIndex misc_reg, RegVal val)=0
void setMSRs(const struct kvm_msrs &msrs)
Methods to access MSRs in the guest.
virtual uint8_t getVector() const
Get the vector of an interrupt.
#define SEG_SYS_TYPE_TSS_AVAILABLE
EventQueue * deviceEventQueue()
Get a pointer to the event queue owning devices.
void suspend() override
Set the status to Suspended.
void setDebugRegisters(const struct kvm_debugregs ®s)
static void forceSegAccessed(struct kvm_segment &seg)
const Kvm::MSRIndexVector & getMsrIntersection() const
Get a list of MSRs supported by both gem5 and KVM.
const std::string & name()
void deliverInterrupts()
Inject pending interrupts from gem5 into the virtual CPU.
bool haveXSave
Kvm::capXSave() available?
Tick submitIO(PacketPtr pkt)
Interface to send Atomic or Timing IO request.
bool threadContextDirty
Is the gem5 context dirty? Set to true to force an update of the KVM vCPU state upon the next call to...
virtual TheISA::PCState pcState() const =0
void getSpecialRegisters(struct kvm_sregs ®s) const
virtual void setMiscRegNoEffect(RegIndex misc_reg, RegVal val)=0
std::vector< BaseInterrupts * > interrupts
std::shared_ptr< Request > RequestPtr
virtual Tick kvmRun(Tick ticks)
Request KVM to run the guest for a given number of ticks.
static void setKvmDTableReg(ThreadContext *tc, struct kvm_dtable &kvm_dtable, const int index)
void updateKvmStateFPUXSave()
Update FPU and SIMD registers using the XSave API.
#define SEG_SYS_TYPE_TSS_BUSY
Tick handleKvmExitIRQWindowOpen() override
The guest exited because an interrupt window was requested.
ThreadContext * tc
ThreadContext object, provides an interface for external objects to modify this thread's state...
void kvmNonMaskableInterrupt()
Send a non-maskable interrupt to the guest.
void updateKvmStateRegs()
Support routines to update the state of the KVM CPU from gem5's state representation.
void getXCRs(struct kvm_xcrs ®s) const
void setVCpuEvents(const struct kvm_vcpu_events &events)
void getVCpuEvents(struct kvm_vcpu_events &events) const
void updateThreadContextFPU(const struct kvm_fpu &fpu)
Update FPU and SIMD registers using the legacy API.
#define SEG_CS_TYPE_READ_ACCESSED
void setCPUID(const struct kvm_cpuid2 &cpuid)
Methods to access CPUID information using the extended API.
void updateThreadContextSRegs(const struct kvm_sregs &sregs)
Update control registers (CRx, segments, etc.)
#define SEG_TYPE_BIT_ACCESSED
void getFPUState(struct kvm_fpu &state) const
Get/Set the guest FPU/vector state.
void storeFloat80(void *_mem, double value)
Convert and store a double as an 80-bit float.
Base class for KVM based CPU models.
void dumpSpecRegs() const
bool capVCPUEvents() const
Support for getting and setting the kvm_vcpu_events structure.
void getMSRs(struct kvm_msrs &msrs) const
virtual void setFloatReg(RegIndex reg_idx, RegVal val)=0
ThreadContext is the external interface to all thread state for anything outside of the CPU...
void dataStatic(T *p)
Set the data pointer to the following value that should not be freed.
static void checkSeg(const char *name, const int idx, const struct kvm_segment &seg, struct kvm_sregs sregs)
static bool isCanonicalAddress(uint64_t addr)
static void dumpKvm(const struct kvm_regs ®s)
bool capUserNMI() const
Support for BaseKvmCPU::kvmNonMaskableInterrupt().
void updateKvmState() override
Update the KVM state from the current thread context.
void setSpecialRegisters(const struct kvm_sregs ®s)
static double bitsToFloat64(uint64_t val)
#define FOREACH_SEGMENT()
Temporarily migrate execution to a different event queue.
virtual RegVal readFloatReg(RegIndex reg_idx) const =0
static MiscRegIndex MISCREG_SEG_ATTR(int index)
static MiscRegIndex MISCREG_SEG_LIMIT(int index)
void dump() const override
Dump the internal state to the terminal.
static FloatRegIndex FLOATREG_FPR(int index)
bool archIsDrained() const override
Check if there are pending events in the vCPU that prevents it from being drained.
static FloatRegIndex FLOATREG_XMM_HIGH(int index)
MasterID dataMasterId() const
Reads this CPU's unique data requestor ID.
uint64_t Tick
Tick count type.
void updateCPUID()
Transfer gem5's CPUID values into the virtual CPU.
static STRUCT * newVarStruct(size_t entries)
void getRegisters(struct kvm_regs ®s) const
Get/Set the register state of the guest vCPU.
uint16_t convX87XTagsToTags(uint8_t ftwx)
Convert an x87 xtag word to normal tags format.
void setRFlags(ThreadContext *tc, uint64_t val)
Set update the rflags register and internal gem5 state.
void updateKvmStateFPU()
Update FPU and SIMD registers.
virtual Addr instAddr() const =0
void updateThreadContextMSRs()
Update MSR registers.
static MiscRegIndex MISCREG_SEG_SEL(int index)
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
void updateThreadContextRegs(const struct kvm_regs ®s, const struct kvm_sregs &sregs)
Support routines to update the state of gem5's thread context from KVM's state representation.
void startup() override
startup() is the final initialization call before simulation.
static uint64_t floatToBits64(double val)
void setMSR(uint32_t index, uint64_t value)
static void updateKvmStateFPUCommon(ThreadContext *tc, T &fpu)
void updateKvmStateSRegs()
Update control registers (CRx, segments, etc.)
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Tick handleKvmExitIO() override
Handle x86 legacy IO (in/out)
Status _status
CPU run state.
bool doCpuid(ThreadContext *tc, uint32_t function, uint32_t index, CpuidResult &result)
bool useXSave
Should the XSave interface be used to sync the FPU and SIMD registers?
static void dumpFpuCommon(const T &fpu)
void kvmInterrupt(const struct kvm_interrupt &interrupt)
Send a normal interrupt to the guest.
uint8_t * getGuestData(uint64_t offset) const
Retrieve a pointer to guest data stored at the end of the kvm_run structure.
static Addr x86IOAddress(const uint32_t port)
void setFPUState(const struct kvm_fpu &state)
struct FXSave M5_ATTR_PACKED
void dumpVCpuEvents() const
const MsrMap msrMap
Map between MSR addresses and their corresponding misc registers.
static FloatRegIndex FLOATREG_XMM_LOW(int index)
EventQueue * eventQueue() const
void setXSave(const struct kvm_xsave &xsave)
static SimObject * find(const char *name)
Find the SimObject with the given name and return a pointer to it.
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
static struct kvm_cpuid_entry2 makeKvmCpuid(uint32_t function, uint32_t index, CpuidResult &result)
static MiscRegIndex MISCREG_SEG_BASE(int index)
struct FXSave::@31::@34 ctrl64
KVMCpuPort dataPort
Port for data requests.
bool capSetTSSAddress() const
Support for KvmVM::setTSSAddress()
uint64_t getHostCycles() const override
Get the value of the hardware cycle counter in the guest.
This is exposed globally, independent of the ISA.
void dumpDebugRegs() const
GenericISA::SimplePCState< MachInst > PCState
void setRegisters(const struct kvm_regs ®s)
void getXSave(struct kvm_xsave &xsave) const
uint8_t convX87TagsToXTags(uint16_t ftw)
Convert an x87 tag word to abridged tag format.
static Addr x86PciConfigAddress(const uint32_t addr)
Tick kvmRunDrain() override
Run the virtual CPU until draining completes.
static void setKvmSegmentReg(ThreadContext *tc, struct kvm_segment &kvm_seg, const int index)
bool capXCRs() const
Support for getting and setting the x86 XCRs.
virtual ContextID contextId() const =0
int ioctl(int request, long p1) const
vCPU ioctl interface.
#define IO_PCI_CONF_DATA_BASE
bool capXSave() const
Support for getting and setting the kvm_xsave structure.
void updateThreadContext() override
Update the current thread context with the KVM state.
Tick kvmRunWrapper(Tick ticks)
Wrapper that synchronizes state in kvm_run.
void setContextSegment(ThreadContext *tc, const struct kvm_segment &kvm_seg, const int index)
Kvm * kvm
Global KVM interface.
Context not scheduled in KVM.
void startup() override
startup() is the final initialization call before simulation.
uint64_t getMSR(uint32_t index) const
bool capDebugRegs() const
Support for getting and setting the kvm_debugregs structure.
void updateKvmStateMSRs()
Update MSR registers.
SimpleThread * thread
A cached copy of a thread's state in the form of a SimpleThread object.
double loadFloat80(const void *_mem)
Load an 80-bit float from memory and convert it to double.
Tick kvmRun(Tick ticks) override
Request KVM to run the guest for a given number of ticks.
void updateKvmStateFPULegacy()
Update FPU and SIMD registers using the legacy API.
virtual RegVal readMiscReg(RegIndex misc_reg)=0
void updateThreadContextXSave(const struct kvm_xsave &kxsave)
Update FPU and SIMD registers using the XSave API.
bool haveXCRs
Kvm::capXCRs() available?
X86KvmCPU(X86KvmCPUParams *params)
std::shared_ptr< FaultBase > Fault
static void dumpFpuSpec(const struct FXSave &xs)
bool haveDebugRegs
Kvm::capDebugRegs() available?
x86 implementation of a KVM-based hardware virtualized CPU.
Kvm::MSRIndexVector cachedMsrIntersection
Cached intersection of supported MSRs.
void syncThreadContext()
Update a thread context if the KVM state is dirty with respect to the cached thread context...
ProbePointArg< PacketInfo > Packet
Packet probe point.
struct kvm_run * getKvmRunState()
Get a pointer to the kvm_run structure containing all the input and output parameters from kvmRun()...