x86_cpu.cc revision 9884
19883Sandreas@sandberg.pp.se/* 29883Sandreas@sandberg.pp.se * Copyright (c) 2013 Andreas Sandberg 39883Sandreas@sandberg.pp.se * All rights reserved 49883Sandreas@sandberg.pp.se * 59883Sandreas@sandberg.pp.se * Redistribution and use in source and binary forms, with or without 69883Sandreas@sandberg.pp.se * modification, are permitted provided that the following conditions are 79883Sandreas@sandberg.pp.se * met: redistributions of source code must retain the above copyright 89883Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer; 99883Sandreas@sandberg.pp.se * redistributions in binary form must reproduce the above copyright 109883Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer in the 119883Sandreas@sandberg.pp.se * documentation and/or other materials provided with the distribution; 129883Sandreas@sandberg.pp.se * neither the name of the copyright holders nor the names of its 139883Sandreas@sandberg.pp.se * contributors may be used to endorse or promote products derived from 149883Sandreas@sandberg.pp.se * this software without specific prior written permission. 159883Sandreas@sandberg.pp.se * 169883Sandreas@sandberg.pp.se * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 179883Sandreas@sandberg.pp.se * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 189883Sandreas@sandberg.pp.se * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 199883Sandreas@sandberg.pp.se * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 209883Sandreas@sandberg.pp.se * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 219883Sandreas@sandberg.pp.se * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 229883Sandreas@sandberg.pp.se * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239883Sandreas@sandberg.pp.se * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249883Sandreas@sandberg.pp.se * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259883Sandreas@sandberg.pp.se * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 269883Sandreas@sandberg.pp.se * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 279883Sandreas@sandberg.pp.se * 289883Sandreas@sandberg.pp.se * Authors: Andreas Sandberg 299883Sandreas@sandberg.pp.se */ 309883Sandreas@sandberg.pp.se 319883Sandreas@sandberg.pp.se#include <linux/kvm.h> 329883Sandreas@sandberg.pp.se 339883Sandreas@sandberg.pp.se#include <algorithm> 349883Sandreas@sandberg.pp.se#include <cerrno> 359883Sandreas@sandberg.pp.se#include <memory> 369883Sandreas@sandberg.pp.se 379883Sandreas@sandberg.pp.se#include "arch/x86/regs/msr.hh" 389883Sandreas@sandberg.pp.se#include "arch/x86/cpuid.hh" 399883Sandreas@sandberg.pp.se#include "arch/x86/utility.hh" 409883Sandreas@sandberg.pp.se#include "arch/registers.hh" 419883Sandreas@sandberg.pp.se#include "cpu/kvm/base.hh" 429883Sandreas@sandberg.pp.se#include "cpu/kvm/x86_cpu.hh" 439883Sandreas@sandberg.pp.se#include "debug/Drain.hh" 449883Sandreas@sandberg.pp.se#include "debug/Kvm.hh" 459883Sandreas@sandberg.pp.se#include "debug/KvmContext.hh" 469883Sandreas@sandberg.pp.se#include "debug/KvmIO.hh" 479883Sandreas@sandberg.pp.se#include "debug/KvmInt.hh" 489883Sandreas@sandberg.pp.se 499883Sandreas@sandberg.pp.seusing namespace X86ISA; 509883Sandreas@sandberg.pp.se 519883Sandreas@sandberg.pp.se#define MSR_TSC 0x10 529883Sandreas@sandberg.pp.se 539883Sandreas@sandberg.pp.se#define IO_PCI_CONF_ADDR 0xCF8 549883Sandreas@sandberg.pp.se#define IO_PCI_CONF_DATA_BASE 0xCFC 559883Sandreas@sandberg.pp.se 569883Sandreas@sandberg.pp.se#define FOREACH_IREG() \ 579883Sandreas@sandberg.pp.se do { \ 589883Sandreas@sandberg.pp.se APPLY_IREG(rax, INTREG_RAX); \ 599883Sandreas@sandberg.pp.se APPLY_IREG(rbx, INTREG_RBX); \ 609883Sandreas@sandberg.pp.se APPLY_IREG(rcx, INTREG_RCX); \ 619883Sandreas@sandberg.pp.se APPLY_IREG(rdx, INTREG_RDX); \ 629883Sandreas@sandberg.pp.se APPLY_IREG(rsi, INTREG_RSI); \ 639883Sandreas@sandberg.pp.se APPLY_IREG(rdi, INTREG_RDI); \ 649883Sandreas@sandberg.pp.se APPLY_IREG(rsp, INTREG_RSP); \ 659883Sandreas@sandberg.pp.se APPLY_IREG(rbp, INTREG_RBP); \ 669883Sandreas@sandberg.pp.se APPLY_IREG(r8, INTREG_R8); \ 679883Sandreas@sandberg.pp.se APPLY_IREG(r9, INTREG_R9); \ 689883Sandreas@sandberg.pp.se APPLY_IREG(r10, INTREG_R10); \ 699883Sandreas@sandberg.pp.se APPLY_IREG(r11, INTREG_R11); \ 709883Sandreas@sandberg.pp.se APPLY_IREG(r12, INTREG_R12); \ 719883Sandreas@sandberg.pp.se APPLY_IREG(r13, INTREG_R13); \ 729883Sandreas@sandberg.pp.se APPLY_IREG(r14, INTREG_R14); \ 739883Sandreas@sandberg.pp.se APPLY_IREG(r15, INTREG_R15); \ 749883Sandreas@sandberg.pp.se } while(0) 759883Sandreas@sandberg.pp.se 769883Sandreas@sandberg.pp.se#define FOREACH_SREG() \ 779883Sandreas@sandberg.pp.se do { \ 789883Sandreas@sandberg.pp.se APPLY_SREG(cr0, MISCREG_CR0); \ 799883Sandreas@sandberg.pp.se APPLY_SREG(cr2, MISCREG_CR2); \ 809883Sandreas@sandberg.pp.se APPLY_SREG(cr3, MISCREG_CR3); \ 819883Sandreas@sandberg.pp.se APPLY_SREG(cr4, MISCREG_CR4); \ 829883Sandreas@sandberg.pp.se APPLY_SREG(cr8, MISCREG_CR8); \ 839883Sandreas@sandberg.pp.se APPLY_SREG(efer, MISCREG_EFER); \ 849883Sandreas@sandberg.pp.se APPLY_SREG(apic_base, MISCREG_APIC_BASE); \ 859883Sandreas@sandberg.pp.se } while(0) 869883Sandreas@sandberg.pp.se 879883Sandreas@sandberg.pp.se#define FOREACH_DREG() \ 889883Sandreas@sandberg.pp.se do { \ 899883Sandreas@sandberg.pp.se APPLY_DREG(db[0], MISCREG_DR0); \ 909883Sandreas@sandberg.pp.se APPLY_DREG(db[1], MISCREG_DR1); \ 919883Sandreas@sandberg.pp.se APPLY_DREG(db[2], MISCREG_DR2); \ 929883Sandreas@sandberg.pp.se APPLY_DREG(db[3], MISCREG_DR3); \ 939883Sandreas@sandberg.pp.se APPLY_DREG(dr6, MISCREG_DR6); \ 949883Sandreas@sandberg.pp.se APPLY_DREG(dr7, MISCREG_DR7); \ 959883Sandreas@sandberg.pp.se } while(0) 969883Sandreas@sandberg.pp.se 979883Sandreas@sandberg.pp.se#define FOREACH_SEGMENT() \ 989883Sandreas@sandberg.pp.se do { \ 999883Sandreas@sandberg.pp.se APPLY_SEGMENT(cs, MISCREG_CS - MISCREG_SEG_SEL_BASE); \ 1009883Sandreas@sandberg.pp.se APPLY_SEGMENT(ds, MISCREG_DS - MISCREG_SEG_SEL_BASE); \ 1019883Sandreas@sandberg.pp.se APPLY_SEGMENT(es, MISCREG_ES - MISCREG_SEG_SEL_BASE); \ 1029883Sandreas@sandberg.pp.se APPLY_SEGMENT(fs, MISCREG_FS - MISCREG_SEG_SEL_BASE); \ 1039883Sandreas@sandberg.pp.se APPLY_SEGMENT(gs, MISCREG_GS - MISCREG_SEG_SEL_BASE); \ 1049883Sandreas@sandberg.pp.se APPLY_SEGMENT(ss, MISCREG_SS - MISCREG_SEG_SEL_BASE); \ 1059883Sandreas@sandberg.pp.se APPLY_SEGMENT(tr, MISCREG_TR - MISCREG_SEG_SEL_BASE); \ 1069883Sandreas@sandberg.pp.se APPLY_SEGMENT(ldt, MISCREG_TSL - MISCREG_SEG_SEL_BASE); \ 1079883Sandreas@sandberg.pp.se } while(0) 1089883Sandreas@sandberg.pp.se 1099883Sandreas@sandberg.pp.se#define FOREACH_DTABLE() \ 1109883Sandreas@sandberg.pp.se do { \ 1119883Sandreas@sandberg.pp.se APPLY_DTABLE(gdt, MISCREG_TSG - MISCREG_SEG_SEL_BASE); \ 1129883Sandreas@sandberg.pp.se APPLY_DTABLE(idt, MISCREG_IDTR - MISCREG_SEG_SEL_BASE); \ 1139883Sandreas@sandberg.pp.se } while(0) 1149883Sandreas@sandberg.pp.se 1159883Sandreas@sandberg.pp.setemplate<typename STRUCT, typename ENTRY> 1169883Sandreas@sandberg.pp.sestatic STRUCT *newVarStruct(size_t entries) 1179883Sandreas@sandberg.pp.se{ 1189883Sandreas@sandberg.pp.se return (STRUCT *)operator new(sizeof(STRUCT) + entries * sizeof(ENTRY)); 1199883Sandreas@sandberg.pp.se} 1209883Sandreas@sandberg.pp.se 1219883Sandreas@sandberg.pp.sestatic void 1229883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_regs ®s) 1239883Sandreas@sandberg.pp.se{ 1249883Sandreas@sandberg.pp.se inform("KVM register state:\n"); 1259883Sandreas@sandberg.pp.se 1269883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) \ 1279883Sandreas@sandberg.pp.se inform("\t" # kreg ": 0x%llx\n", regs.kreg) 1289883Sandreas@sandberg.pp.se 1299883Sandreas@sandberg.pp.se FOREACH_IREG(); 1309883Sandreas@sandberg.pp.se 1319883Sandreas@sandberg.pp.se#undef APPLY_IREG 1329883Sandreas@sandberg.pp.se 1339883Sandreas@sandberg.pp.se inform("\trip: 0x%llx\n", regs.rip); 1349883Sandreas@sandberg.pp.se inform("\trflags: 0x%llx\n", regs.rflags); 1359883Sandreas@sandberg.pp.se} 1369883Sandreas@sandberg.pp.se 1379883Sandreas@sandberg.pp.sestatic void 1389883Sandreas@sandberg.pp.sedumpKvm(const char *reg_name, const struct kvm_segment &seg) 1399883Sandreas@sandberg.pp.se{ 1409883Sandreas@sandberg.pp.se inform("\t%s: @0x%llx+%x [sel: 0x%x, type: 0x%x]\n" 1419883Sandreas@sandberg.pp.se "\t\tpres.: %u, dpl: %u, db: %u, s: %u, l: %u, g: %u, avl: %u, unus.: %u\n", 1429883Sandreas@sandberg.pp.se reg_name, 1439883Sandreas@sandberg.pp.se seg.base, seg.limit, seg.selector, seg.type, 1449883Sandreas@sandberg.pp.se seg.present, seg.dpl, seg.db, seg.s, seg.l, seg.g, seg.avl, seg.unusable); 1459883Sandreas@sandberg.pp.se} 1469883Sandreas@sandberg.pp.se 1479883Sandreas@sandberg.pp.sestatic void 1489883Sandreas@sandberg.pp.sedumpKvm(const char *reg_name, const struct kvm_dtable &dtable) 1499883Sandreas@sandberg.pp.se{ 1509883Sandreas@sandberg.pp.se inform("\t%s: @0x%llx+%x\n", 1519883Sandreas@sandberg.pp.se reg_name, dtable.base, dtable.limit); 1529883Sandreas@sandberg.pp.se} 1539883Sandreas@sandberg.pp.se 1549883Sandreas@sandberg.pp.sestatic void 1559883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_sregs &sregs) 1569883Sandreas@sandberg.pp.se{ 1579883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) \ 1589883Sandreas@sandberg.pp.se inform("\t" # kreg ": 0x%llx\n", sregs.kreg); 1599883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) \ 1609883Sandreas@sandberg.pp.se dumpKvm(# kreg, sregs.kreg); 1619883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) \ 1629883Sandreas@sandberg.pp.se dumpKvm(# kreg, sregs.kreg); 1639883Sandreas@sandberg.pp.se 1649883Sandreas@sandberg.pp.se inform("Special registers:\n"); 1659883Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 1669883Sandreas@sandberg.pp.se FOREACH_SREG(); 1679883Sandreas@sandberg.pp.se FOREACH_DTABLE(); 1689883Sandreas@sandberg.pp.se 1699883Sandreas@sandberg.pp.se inform("Interrupt Bitmap:"); 1709883Sandreas@sandberg.pp.se for (int i = 0; i < KVM_NR_INTERRUPTS; i += 64) 1719883Sandreas@sandberg.pp.se inform(" 0x%.8x", sregs.interrupt_bitmap[i / 64]); 1729883Sandreas@sandberg.pp.se 1739883Sandreas@sandberg.pp.se#undef APPLY_SREG 1749883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 1759883Sandreas@sandberg.pp.se#undef APPLY_DTABLE 1769883Sandreas@sandberg.pp.se} 1779883Sandreas@sandberg.pp.se 1789883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS 1799883Sandreas@sandberg.pp.sestatic void 1809883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_debugregs ®s) 1819883Sandreas@sandberg.pp.se{ 1829883Sandreas@sandberg.pp.se inform("KVM debug state:\n"); 1839883Sandreas@sandberg.pp.se 1849883Sandreas@sandberg.pp.se#define APPLY_DREG(kreg, mreg) \ 1859883Sandreas@sandberg.pp.se inform("\t" # kreg ": 0x%llx\n", regs.kreg) 1869883Sandreas@sandberg.pp.se 1879883Sandreas@sandberg.pp.se FOREACH_DREG(); 1889883Sandreas@sandberg.pp.se 1899883Sandreas@sandberg.pp.se#undef APPLY_DREG 1909883Sandreas@sandberg.pp.se 1919883Sandreas@sandberg.pp.se inform("\tflags: 0x%llx\n", regs.flags); 1929883Sandreas@sandberg.pp.se} 1939883Sandreas@sandberg.pp.se#endif 1949883Sandreas@sandberg.pp.se 1959883Sandreas@sandberg.pp.sestatic void 1969883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_fpu &fpu) 1979883Sandreas@sandberg.pp.se{ 1989883Sandreas@sandberg.pp.se inform("FPU registers:\n"); 1999883Sandreas@sandberg.pp.se inform("\tfcw: 0x%x\n", fpu.fcw); 2009883Sandreas@sandberg.pp.se inform("\tfsw: 0x%x\n", fpu.fsw); 2019883Sandreas@sandberg.pp.se inform("\tftwx: 0x%x\n", fpu.ftwx); 2029883Sandreas@sandberg.pp.se inform("\tlast_opcode: 0x%x\n", fpu.last_opcode); 2039883Sandreas@sandberg.pp.se inform("\tlast_ip: 0x%x\n", fpu.last_ip); 2049883Sandreas@sandberg.pp.se inform("\tlast_dp: 0x%x\n", fpu.last_dp); 2059883Sandreas@sandberg.pp.se inform("\tmxcsr: 0x%x\n", fpu.mxcsr); 2069883Sandreas@sandberg.pp.se inform("\tFP Stack:\n"); 2079883Sandreas@sandberg.pp.se for (int i = 0; i < 8; ++i) { 2089883Sandreas@sandberg.pp.se const bool empty(!((fpu.ftwx >> i) & 0x1)); 2099883Sandreas@sandberg.pp.se char hex[33]; 2109883Sandreas@sandberg.pp.se for (int j = 0; j < 16; ++j) 2119883Sandreas@sandberg.pp.se snprintf(&hex[j*2], 3, "%.2x", fpu.fpr[i][j]); 2129883Sandreas@sandberg.pp.se inform("\t\t%i: 0x%s%s\n", i, hex, empty ? " (e)" : ""); 2139883Sandreas@sandberg.pp.se } 2149883Sandreas@sandberg.pp.se inform("\tXMM registers:\n"); 2159883Sandreas@sandberg.pp.se for (int i = 0; i < 16; ++i) { 2169883Sandreas@sandberg.pp.se char hex[33]; 2179883Sandreas@sandberg.pp.se for (int j = 0; j < 16; ++j) 2189883Sandreas@sandberg.pp.se snprintf(&hex[j*2], 3, "%.2x", fpu.xmm[i][j]); 2199883Sandreas@sandberg.pp.se inform("\t\t%i: 0x%s\n", i, hex); 2209883Sandreas@sandberg.pp.se } 2219883Sandreas@sandberg.pp.se} 2229883Sandreas@sandberg.pp.se 2239883Sandreas@sandberg.pp.sestatic void 2249883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_msrs &msrs) 2259883Sandreas@sandberg.pp.se{ 2269883Sandreas@sandberg.pp.se inform("MSRs:\n"); 2279883Sandreas@sandberg.pp.se 2289883Sandreas@sandberg.pp.se for (int i = 0; i < msrs.nmsrs; ++i) { 2299883Sandreas@sandberg.pp.se const struct kvm_msr_entry &e(msrs.entries[i]); 2309883Sandreas@sandberg.pp.se 2319883Sandreas@sandberg.pp.se inform("\t0x%x: 0x%x\n", e.index, e.data); 2329883Sandreas@sandberg.pp.se } 2339883Sandreas@sandberg.pp.se} 2349883Sandreas@sandberg.pp.se 2359883Sandreas@sandberg.pp.sestatic void 2369883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_xcrs ®s) 2379883Sandreas@sandberg.pp.se{ 2389883Sandreas@sandberg.pp.se inform("KVM XCR registers:\n"); 2399883Sandreas@sandberg.pp.se 2409883Sandreas@sandberg.pp.se inform("\tFlags: 0x%x\n", regs.flags); 2419883Sandreas@sandberg.pp.se for (int i = 0; i < regs.nr_xcrs; ++i) { 2429883Sandreas@sandberg.pp.se inform("\tXCR[0x%x]: 0x%x\n", 2439883Sandreas@sandberg.pp.se regs.xcrs[i].xcr, 2449883Sandreas@sandberg.pp.se regs.xcrs[i].value); 2459883Sandreas@sandberg.pp.se } 2469883Sandreas@sandberg.pp.se} 2479883Sandreas@sandberg.pp.se 2489883Sandreas@sandberg.pp.sestatic void 2499883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_xsave &xsave) 2509883Sandreas@sandberg.pp.se{ 2519883Sandreas@sandberg.pp.se inform("KVM XSAVE:\n"); 2529883Sandreas@sandberg.pp.se 2539883Sandreas@sandberg.pp.se Trace::dump((Tick)-1, "xsave.region", 2549883Sandreas@sandberg.pp.se xsave.region, sizeof(xsave.region)); 2559883Sandreas@sandberg.pp.se} 2569883Sandreas@sandberg.pp.se 2579883Sandreas@sandberg.pp.sestatic void 2589883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_vcpu_events &events) 2599883Sandreas@sandberg.pp.se{ 2609883Sandreas@sandberg.pp.se inform("vCPU events:\n"); 2619883Sandreas@sandberg.pp.se 2629883Sandreas@sandberg.pp.se inform("\tException: [inj: %i, nr: %i, has_ec: %i, ec: %i]\n", 2639883Sandreas@sandberg.pp.se events.exception.injected, events.exception.nr, 2649883Sandreas@sandberg.pp.se events.exception.has_error_code, events.exception.error_code); 2659883Sandreas@sandberg.pp.se 2669883Sandreas@sandberg.pp.se inform("\tInterrupt: [inj: %i, nr: %i, soft: %i]\n", 2679883Sandreas@sandberg.pp.se events.interrupt.injected, events.interrupt.nr, 2689883Sandreas@sandberg.pp.se events.interrupt.soft); 2699883Sandreas@sandberg.pp.se 2709883Sandreas@sandberg.pp.se inform("\tNMI: [inj: %i, pending: %i, masked: %i]\n", 2719883Sandreas@sandberg.pp.se events.nmi.injected, events.nmi.pending, 2729883Sandreas@sandberg.pp.se events.nmi.masked); 2739883Sandreas@sandberg.pp.se 2749883Sandreas@sandberg.pp.se inform("\tSIPI vector: 0x%x\n", events.sipi_vector); 2759883Sandreas@sandberg.pp.se inform("\tFlags: 0x%x\n", events.flags); 2769883Sandreas@sandberg.pp.se} 2779883Sandreas@sandberg.pp.se 2789884Sandreas@sandberg.pp.sestatic bool 2799884Sandreas@sandberg.pp.seisCanonicalAddress(uint64_t addr) 2809884Sandreas@sandberg.pp.se{ 2819884Sandreas@sandberg.pp.se // x86-64 doesn't currently use the full 64-bit virtual address 2829884Sandreas@sandberg.pp.se // space, instead it uses signed 48 bit addresses that are 2839884Sandreas@sandberg.pp.se // sign-extended to 64 bits. Such addresses are known as 2849884Sandreas@sandberg.pp.se // "canonical". 2859884Sandreas@sandberg.pp.se uint64_t upper_half(addr & 0xffff800000000000ULL); 2869884Sandreas@sandberg.pp.se return upper_half == 0 || upper_half == 0xffff800000000000; 2879884Sandreas@sandberg.pp.se} 2889884Sandreas@sandberg.pp.se 2899884Sandreas@sandberg.pp.sestatic void 2909884Sandreas@sandberg.pp.secheckSeg(const char *name, const int idx, const struct kvm_segment &seg, 2919884Sandreas@sandberg.pp.se struct kvm_sregs sregs) 2929884Sandreas@sandberg.pp.se{ 2939884Sandreas@sandberg.pp.se // Check the register base 2949884Sandreas@sandberg.pp.se switch (idx) { 2959884Sandreas@sandberg.pp.se case MISCREG_TSL: 2969884Sandreas@sandberg.pp.se case MISCREG_TR: 2979884Sandreas@sandberg.pp.se case MISCREG_FS: 2989884Sandreas@sandberg.pp.se case MISCREG_GS: 2999884Sandreas@sandberg.pp.se if (!isCanonicalAddress(seg.base)) 3009884Sandreas@sandberg.pp.se warn("Illegal %s base: 0x%x\n", name, seg.base); 3019884Sandreas@sandberg.pp.se break; 3029884Sandreas@sandberg.pp.se 3039884Sandreas@sandberg.pp.se case MISCREG_SS: 3049884Sandreas@sandberg.pp.se case MISCREG_DS: 3059884Sandreas@sandberg.pp.se case MISCREG_ES: 3069884Sandreas@sandberg.pp.se if (seg.unusable) 3079884Sandreas@sandberg.pp.se break; 3089884Sandreas@sandberg.pp.se case MISCREG_CS: 3099884Sandreas@sandberg.pp.se if (seg.base & 0xffffffff00000000ULL) 3109884Sandreas@sandberg.pp.se warn("Illegal %s base: 0x%x\n", name, seg.base); 3119884Sandreas@sandberg.pp.se break; 3129884Sandreas@sandberg.pp.se } 3139884Sandreas@sandberg.pp.se 3149884Sandreas@sandberg.pp.se // Check the type 3159884Sandreas@sandberg.pp.se switch (idx) { 3169884Sandreas@sandberg.pp.se case MISCREG_CS: 3179884Sandreas@sandberg.pp.se switch (seg.type) { 3189884Sandreas@sandberg.pp.se case 3: 3199884Sandreas@sandberg.pp.se if (seg.dpl != 0) 3209884Sandreas@sandberg.pp.se warn("CS type is 3 but dpl != 0.\n"); 3219884Sandreas@sandberg.pp.se break; 3229884Sandreas@sandberg.pp.se case 9: 3239884Sandreas@sandberg.pp.se case 11: 3249884Sandreas@sandberg.pp.se if (seg.dpl != sregs.ss.dpl) 3259884Sandreas@sandberg.pp.se warn("CS type is %i but CS DPL != SS DPL\n", seg.type); 3269884Sandreas@sandberg.pp.se break; 3279884Sandreas@sandberg.pp.se case 13: 3289884Sandreas@sandberg.pp.se case 15: 3299884Sandreas@sandberg.pp.se if (seg.dpl > sregs.ss.dpl) 3309884Sandreas@sandberg.pp.se warn("CS type is %i but CS DPL > SS DPL\n", seg.type); 3319884Sandreas@sandberg.pp.se break; 3329884Sandreas@sandberg.pp.se default: 3339884Sandreas@sandberg.pp.se warn("Illegal CS type: %i\n", seg.type); 3349884Sandreas@sandberg.pp.se break; 3359884Sandreas@sandberg.pp.se } 3369884Sandreas@sandberg.pp.se break; 3379884Sandreas@sandberg.pp.se 3389884Sandreas@sandberg.pp.se case MISCREG_SS: 3399884Sandreas@sandberg.pp.se if (seg.unusable) 3409884Sandreas@sandberg.pp.se break; 3419884Sandreas@sandberg.pp.se switch (seg.type) { 3429884Sandreas@sandberg.pp.se case 3: 3439884Sandreas@sandberg.pp.se if (sregs.cs.type == 3 && seg.dpl != 0) 3449884Sandreas@sandberg.pp.se warn("CS type is 3, but SS DPL is != 0.\n"); 3459884Sandreas@sandberg.pp.se /* FALLTHROUGH */ 3469884Sandreas@sandberg.pp.se case 7: 3479884Sandreas@sandberg.pp.se if (!(sregs.cr0 & 1) && seg.dpl != 0) 3489884Sandreas@sandberg.pp.se warn("SS DPL is %i, but CR0 PE is 0\n", seg.dpl); 3499884Sandreas@sandberg.pp.se break; 3509884Sandreas@sandberg.pp.se default: 3519884Sandreas@sandberg.pp.se warn("Illegal SS type: %i\n", seg.type); 3529884Sandreas@sandberg.pp.se break; 3539884Sandreas@sandberg.pp.se } 3549884Sandreas@sandberg.pp.se break; 3559884Sandreas@sandberg.pp.se 3569884Sandreas@sandberg.pp.se case MISCREG_DS: 3579884Sandreas@sandberg.pp.se case MISCREG_ES: 3589884Sandreas@sandberg.pp.se case MISCREG_FS: 3599884Sandreas@sandberg.pp.se case MISCREG_GS: 3609884Sandreas@sandberg.pp.se if (seg.unusable) 3619884Sandreas@sandberg.pp.se break; 3629884Sandreas@sandberg.pp.se if (!(seg.type & 0x1) || 3639884Sandreas@sandberg.pp.se ((seg.type & 0x8) && !(seg.type & 0x2))) 3649884Sandreas@sandberg.pp.se warn("%s has an illegal type field: %i\n", name, seg.type); 3659884Sandreas@sandberg.pp.se break; 3669884Sandreas@sandberg.pp.se 3679884Sandreas@sandberg.pp.se case MISCREG_TR: 3689884Sandreas@sandberg.pp.se // TODO: We should check the CPU mode 3699884Sandreas@sandberg.pp.se if (seg.type != 3 && seg.type != 11) 3709884Sandreas@sandberg.pp.se warn("%s: Illegal segment type (%i)\n", name, seg.type); 3719884Sandreas@sandberg.pp.se break; 3729884Sandreas@sandberg.pp.se 3739884Sandreas@sandberg.pp.se case MISCREG_TSL: 3749884Sandreas@sandberg.pp.se if (seg.unusable) 3759884Sandreas@sandberg.pp.se break; 3769884Sandreas@sandberg.pp.se if (seg.type != 2) 3779884Sandreas@sandberg.pp.se warn("%s: Illegal segment type (%i)\n", name, seg.type); 3789884Sandreas@sandberg.pp.se break; 3799884Sandreas@sandberg.pp.se } 3809884Sandreas@sandberg.pp.se 3819884Sandreas@sandberg.pp.se switch (idx) { 3829884Sandreas@sandberg.pp.se case MISCREG_SS: 3839884Sandreas@sandberg.pp.se case MISCREG_DS: 3849884Sandreas@sandberg.pp.se case MISCREG_ES: 3859884Sandreas@sandberg.pp.se case MISCREG_FS: 3869884Sandreas@sandberg.pp.se case MISCREG_GS: 3879884Sandreas@sandberg.pp.se if (seg.unusable) 3889884Sandreas@sandberg.pp.se break; 3899884Sandreas@sandberg.pp.se case MISCREG_CS: 3909884Sandreas@sandberg.pp.se if (!seg.s) 3919884Sandreas@sandberg.pp.se warn("%s: S flag not set\n", name); 3929884Sandreas@sandberg.pp.se break; 3939884Sandreas@sandberg.pp.se 3949884Sandreas@sandberg.pp.se case MISCREG_TSL: 3959884Sandreas@sandberg.pp.se if (seg.unusable) 3969884Sandreas@sandberg.pp.se break; 3979884Sandreas@sandberg.pp.se case MISCREG_TR: 3989884Sandreas@sandberg.pp.se if (seg.s) 3999884Sandreas@sandberg.pp.se warn("%s: S flag is set\n", name); 4009884Sandreas@sandberg.pp.se break; 4019884Sandreas@sandberg.pp.se } 4029884Sandreas@sandberg.pp.se 4039884Sandreas@sandberg.pp.se switch (idx) { 4049884Sandreas@sandberg.pp.se case MISCREG_SS: 4059884Sandreas@sandberg.pp.se case MISCREG_DS: 4069884Sandreas@sandberg.pp.se case MISCREG_ES: 4079884Sandreas@sandberg.pp.se case MISCREG_FS: 4089884Sandreas@sandberg.pp.se case MISCREG_GS: 4099884Sandreas@sandberg.pp.se case MISCREG_TSL: 4109884Sandreas@sandberg.pp.se if (seg.unusable) 4119884Sandreas@sandberg.pp.se break; 4129884Sandreas@sandberg.pp.se case MISCREG_TR: 4139884Sandreas@sandberg.pp.se case MISCREG_CS: 4149884Sandreas@sandberg.pp.se if (!seg.present) 4159884Sandreas@sandberg.pp.se warn("%s: P flag not set\n", name); 4169884Sandreas@sandberg.pp.se 4179884Sandreas@sandberg.pp.se if (((seg.limit & 0xFFF) == 0 && seg.g) || 4189884Sandreas@sandberg.pp.se ((seg.limit & 0xFFF00000) != 0 && !seg.g)) { 4199884Sandreas@sandberg.pp.se warn("%s limit (0x%x) and g (%i) combination is illegal.\n", 4209884Sandreas@sandberg.pp.se name, seg.limit, seg.g); 4219884Sandreas@sandberg.pp.se } 4229884Sandreas@sandberg.pp.se break; 4239884Sandreas@sandberg.pp.se } 4249884Sandreas@sandberg.pp.se 4259884Sandreas@sandberg.pp.se // TODO: Check CS DB 4269884Sandreas@sandberg.pp.se} 4279884Sandreas@sandberg.pp.se 4289883Sandreas@sandberg.pp.seX86KvmCPU::X86KvmCPU(X86KvmCPUParams *params) 4299883Sandreas@sandberg.pp.se : BaseKvmCPU(params) 4309883Sandreas@sandberg.pp.se{ 4319883Sandreas@sandberg.pp.se Kvm &kvm(vm.kvm); 4329883Sandreas@sandberg.pp.se 4339883Sandreas@sandberg.pp.se if (!kvm.capSetTSSAddress()) 4349883Sandreas@sandberg.pp.se panic("KVM: Missing capability (KVM_CAP_SET_TSS_ADDR)\n"); 4359883Sandreas@sandberg.pp.se if (!kvm.capExtendedCPUID()) 4369883Sandreas@sandberg.pp.se panic("KVM: Missing capability (KVM_CAP_EXT_CPUID)\n"); 4379883Sandreas@sandberg.pp.se if (!kvm.capUserNMI()) 4389883Sandreas@sandberg.pp.se warn("KVM: Missing capability (KVM_CAP_USER_NMI)\n"); 4399883Sandreas@sandberg.pp.se if (!kvm.capVCPUEvents()) 4409883Sandreas@sandberg.pp.se warn("KVM: Missing capability (KVM_CAP_VCPU_EVENTS)\n"); 4419883Sandreas@sandberg.pp.se 4429883Sandreas@sandberg.pp.se haveDebugRegs = kvm.capDebugRegs(); 4439883Sandreas@sandberg.pp.se haveXSave = kvm.capXSave(); 4449883Sandreas@sandberg.pp.se haveXCRs = kvm.capXCRs(); 4459883Sandreas@sandberg.pp.se} 4469883Sandreas@sandberg.pp.se 4479883Sandreas@sandberg.pp.seX86KvmCPU::~X86KvmCPU() 4489883Sandreas@sandberg.pp.se{ 4499883Sandreas@sandberg.pp.se} 4509883Sandreas@sandberg.pp.se 4519883Sandreas@sandberg.pp.sevoid 4529883Sandreas@sandberg.pp.seX86KvmCPU::startup() 4539883Sandreas@sandberg.pp.se{ 4549883Sandreas@sandberg.pp.se BaseKvmCPU::startup(); 4559883Sandreas@sandberg.pp.se 4569883Sandreas@sandberg.pp.se updateCPUID(); 4579883Sandreas@sandberg.pp.se 4589883Sandreas@sandberg.pp.se io_req.setThreadContext(tc->contextId(), 0); 4599883Sandreas@sandberg.pp.se 4609883Sandreas@sandberg.pp.se // TODO: Do we need to create an identity mapped TSS area? We 4619883Sandreas@sandberg.pp.se // should call kvm.vm.setTSSAddress() here in that case. It should 4629883Sandreas@sandberg.pp.se // only be needed for old versions of the virtualization 4639883Sandreas@sandberg.pp.se // extensions. We should make sure that the identity range is 4649883Sandreas@sandberg.pp.se // reserved in the e820 memory map in that case. 4659883Sandreas@sandberg.pp.se} 4669883Sandreas@sandberg.pp.se 4679883Sandreas@sandberg.pp.sevoid 4689883Sandreas@sandberg.pp.seX86KvmCPU::dump() 4699883Sandreas@sandberg.pp.se{ 4709883Sandreas@sandberg.pp.se dumpIntRegs(); 4719883Sandreas@sandberg.pp.se dumpFpuRegs(); 4729883Sandreas@sandberg.pp.se dumpSpecRegs(); 4739883Sandreas@sandberg.pp.se dumpDebugRegs(); 4749883Sandreas@sandberg.pp.se dumpXCRs(); 4759883Sandreas@sandberg.pp.se dumpVCpuEvents(); 4769883Sandreas@sandberg.pp.se dumpMSRs(); 4779883Sandreas@sandberg.pp.se dumpXSave(); 4789883Sandreas@sandberg.pp.se} 4799883Sandreas@sandberg.pp.se 4809883Sandreas@sandberg.pp.sevoid 4819883Sandreas@sandberg.pp.seX86KvmCPU::dumpFpuRegs() const 4829883Sandreas@sandberg.pp.se{ 4839883Sandreas@sandberg.pp.se struct kvm_fpu fpu; 4849883Sandreas@sandberg.pp.se getFPUState(fpu); 4859883Sandreas@sandberg.pp.se dumpKvm(fpu); 4869883Sandreas@sandberg.pp.se} 4879883Sandreas@sandberg.pp.se 4889883Sandreas@sandberg.pp.sevoid 4899883Sandreas@sandberg.pp.seX86KvmCPU::dumpIntRegs() const 4909883Sandreas@sandberg.pp.se{ 4919883Sandreas@sandberg.pp.se struct kvm_regs regs; 4929883Sandreas@sandberg.pp.se getRegisters(regs); 4939883Sandreas@sandberg.pp.se dumpKvm(regs); 4949883Sandreas@sandberg.pp.se} 4959883Sandreas@sandberg.pp.se 4969883Sandreas@sandberg.pp.sevoid 4979883Sandreas@sandberg.pp.seX86KvmCPU::dumpSpecRegs() const 4989883Sandreas@sandberg.pp.se{ 4999883Sandreas@sandberg.pp.se struct kvm_sregs sregs; 5009883Sandreas@sandberg.pp.se getSpecialRegisters(sregs); 5019883Sandreas@sandberg.pp.se dumpKvm(sregs); 5029883Sandreas@sandberg.pp.se} 5039883Sandreas@sandberg.pp.se 5049883Sandreas@sandberg.pp.sevoid 5059883Sandreas@sandberg.pp.seX86KvmCPU::dumpDebugRegs() const 5069883Sandreas@sandberg.pp.se{ 5079883Sandreas@sandberg.pp.se if (haveDebugRegs) { 5089883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS 5099883Sandreas@sandberg.pp.se struct kvm_debugregs dregs; 5109883Sandreas@sandberg.pp.se getDebugRegisters(dregs); 5119883Sandreas@sandberg.pp.se dumpKvm(dregs); 5129883Sandreas@sandberg.pp.se#endif 5139883Sandreas@sandberg.pp.se } else { 5149883Sandreas@sandberg.pp.se inform("Debug registers not supported by kernel.\n"); 5159883Sandreas@sandberg.pp.se } 5169883Sandreas@sandberg.pp.se} 5179883Sandreas@sandberg.pp.se 5189883Sandreas@sandberg.pp.sevoid 5199883Sandreas@sandberg.pp.seX86KvmCPU::dumpXCRs() const 5209883Sandreas@sandberg.pp.se{ 5219883Sandreas@sandberg.pp.se if (haveXCRs) { 5229883Sandreas@sandberg.pp.se struct kvm_xcrs xcrs; 5239883Sandreas@sandberg.pp.se getXCRs(xcrs); 5249883Sandreas@sandberg.pp.se dumpKvm(xcrs); 5259883Sandreas@sandberg.pp.se } else { 5269883Sandreas@sandberg.pp.se inform("XCRs not supported by kernel.\n"); 5279883Sandreas@sandberg.pp.se } 5289883Sandreas@sandberg.pp.se} 5299883Sandreas@sandberg.pp.se 5309883Sandreas@sandberg.pp.sevoid 5319883Sandreas@sandberg.pp.seX86KvmCPU::dumpXSave() const 5329883Sandreas@sandberg.pp.se{ 5339883Sandreas@sandberg.pp.se if (haveXSave) { 5349883Sandreas@sandberg.pp.se struct kvm_xsave xsave; 5359883Sandreas@sandberg.pp.se getXSave(xsave); 5369883Sandreas@sandberg.pp.se dumpKvm(xsave); 5379883Sandreas@sandberg.pp.se } else { 5389883Sandreas@sandberg.pp.se inform("XSave not supported by kernel.\n"); 5399883Sandreas@sandberg.pp.se } 5409883Sandreas@sandberg.pp.se} 5419883Sandreas@sandberg.pp.se 5429883Sandreas@sandberg.pp.sevoid 5439883Sandreas@sandberg.pp.seX86KvmCPU::dumpVCpuEvents() const 5449883Sandreas@sandberg.pp.se{ 5459883Sandreas@sandberg.pp.se struct kvm_vcpu_events events; 5469883Sandreas@sandberg.pp.se getVCpuEvents(events); 5479883Sandreas@sandberg.pp.se dumpKvm(events); 5489883Sandreas@sandberg.pp.se} 5499883Sandreas@sandberg.pp.se 5509883Sandreas@sandberg.pp.sevoid 5519883Sandreas@sandberg.pp.seX86KvmCPU::dumpMSRs() const 5529883Sandreas@sandberg.pp.se{ 5539883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &supported_msrs(vm.kvm.getSupportedMSRs()); 5549883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> msrs( 5559883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>( 5569883Sandreas@sandberg.pp.se supported_msrs.size())); 5579883Sandreas@sandberg.pp.se 5589883Sandreas@sandberg.pp.se msrs->nmsrs = supported_msrs.size(); 5599883Sandreas@sandberg.pp.se for (int i = 0; i < supported_msrs.size(); ++i) { 5609883Sandreas@sandberg.pp.se struct kvm_msr_entry &e(msrs->entries[i]); 5619883Sandreas@sandberg.pp.se e.index = supported_msrs[i]; 5629883Sandreas@sandberg.pp.se e.reserved = 0; 5639883Sandreas@sandberg.pp.se e.data = 0; 5649883Sandreas@sandberg.pp.se } 5659883Sandreas@sandberg.pp.se getMSRs(*msrs.get()); 5669883Sandreas@sandberg.pp.se 5679883Sandreas@sandberg.pp.se dumpKvm(*msrs.get()); 5689883Sandreas@sandberg.pp.se} 5699883Sandreas@sandberg.pp.se 5709883Sandreas@sandberg.pp.sevoid 5719883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmState() 5729883Sandreas@sandberg.pp.se{ 5739883Sandreas@sandberg.pp.se updateKvmStateRegs(); 5749883Sandreas@sandberg.pp.se updateKvmStateSRegs(); 5759883Sandreas@sandberg.pp.se updateKvmStateFPU(); 5769883Sandreas@sandberg.pp.se updateKvmStateMSRs(); 5779883Sandreas@sandberg.pp.se 5789883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "X86KvmCPU::updateKvmState():\n"); 5799883Sandreas@sandberg.pp.se if (DTRACE(KvmContext)) 5809883Sandreas@sandberg.pp.se dump(); 5819883Sandreas@sandberg.pp.se} 5829883Sandreas@sandberg.pp.se 5839883Sandreas@sandberg.pp.sevoid 5849883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateRegs() 5859883Sandreas@sandberg.pp.se{ 5869883Sandreas@sandberg.pp.se struct kvm_regs regs; 5879883Sandreas@sandberg.pp.se 5889883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) regs.kreg = tc->readIntReg(mreg) 5899883Sandreas@sandberg.pp.se FOREACH_IREG(); 5909883Sandreas@sandberg.pp.se#undef APPLY_IREG 5919883Sandreas@sandberg.pp.se 5929883Sandreas@sandberg.pp.se regs.rip = tc->instAddr(); 5939883Sandreas@sandberg.pp.se 5949883Sandreas@sandberg.pp.se /* You might think that setting regs.rflags to the contents 5959883Sandreas@sandberg.pp.se * MISCREG_RFLAGS here would suffice. In that case you're 5969883Sandreas@sandberg.pp.se * mistaken. We need to reconstruct it from a bunch of ucode 5979883Sandreas@sandberg.pp.se * registers and wave a dead chicken over it (aka mask out and set 5989883Sandreas@sandberg.pp.se * reserved bits) to get it to work. 5999883Sandreas@sandberg.pp.se */ 6009883Sandreas@sandberg.pp.se regs.rflags = X86ISA::getRFlags(tc); 6019883Sandreas@sandberg.pp.se 6029883Sandreas@sandberg.pp.se setRegisters(regs); 6039883Sandreas@sandberg.pp.se} 6049883Sandreas@sandberg.pp.se 6059883Sandreas@sandberg.pp.sestatic inline void 6069883Sandreas@sandberg.pp.sesetKvmSegmentReg(ThreadContext *tc, struct kvm_segment &kvm_seg, 6079883Sandreas@sandberg.pp.se const int index) 6089883Sandreas@sandberg.pp.se{ 6099883Sandreas@sandberg.pp.se SegAttr attr(tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(index))); 6109883Sandreas@sandberg.pp.se 6119883Sandreas@sandberg.pp.se kvm_seg.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index)); 6129883Sandreas@sandberg.pp.se kvm_seg.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index)); 6139883Sandreas@sandberg.pp.se kvm_seg.selector = tc->readMiscRegNoEffect(MISCREG_SEG_SEL(index)); 6149883Sandreas@sandberg.pp.se kvm_seg.type = attr.type; 6159883Sandreas@sandberg.pp.se kvm_seg.present = attr.present; 6169883Sandreas@sandberg.pp.se kvm_seg.dpl = attr.dpl; 6179883Sandreas@sandberg.pp.se kvm_seg.db = attr.defaultSize; 6189883Sandreas@sandberg.pp.se kvm_seg.s = attr.system; 6199883Sandreas@sandberg.pp.se kvm_seg.l = attr.longMode; 6209883Sandreas@sandberg.pp.se kvm_seg.g = attr.granularity; 6219883Sandreas@sandberg.pp.se kvm_seg.avl = attr.avl; 6229883Sandreas@sandberg.pp.se 6239883Sandreas@sandberg.pp.se // A segment is unusable when the selector is zero. There is a 6249883Sandreas@sandberg.pp.se // attr.unusable flag in gem5, but it seems unused. 6259883Sandreas@sandberg.pp.se // 6269883Sandreas@sandberg.pp.se // TODO: Are there corner cases where this doesn't work? 6279883Sandreas@sandberg.pp.se kvm_seg.unusable = (kvm_seg.selector == 0); 6289883Sandreas@sandberg.pp.se} 6299883Sandreas@sandberg.pp.se 6309883Sandreas@sandberg.pp.sestatic inline void 6319883Sandreas@sandberg.pp.sesetKvmDTableReg(ThreadContext *tc, struct kvm_dtable &kvm_dtable, 6329883Sandreas@sandberg.pp.se const int index) 6339883Sandreas@sandberg.pp.se{ 6349883Sandreas@sandberg.pp.se kvm_dtable.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index)); 6359883Sandreas@sandberg.pp.se kvm_dtable.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index)); 6369883Sandreas@sandberg.pp.se} 6379883Sandreas@sandberg.pp.se 6389883Sandreas@sandberg.pp.sevoid 6399883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateSRegs() 6409883Sandreas@sandberg.pp.se{ 6419883Sandreas@sandberg.pp.se struct kvm_sregs sregs; 6429883Sandreas@sandberg.pp.se 6439883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) sregs.kreg = tc->readMiscRegNoEffect(mreg) 6449883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setKvmSegmentReg(tc, sregs.kreg, idx) 6459883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setKvmDTableReg(tc, sregs.kreg, idx) 6469883Sandreas@sandberg.pp.se 6479883Sandreas@sandberg.pp.se FOREACH_SREG(); 6489883Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 6499883Sandreas@sandberg.pp.se FOREACH_DTABLE(); 6509883Sandreas@sandberg.pp.se 6519883Sandreas@sandberg.pp.se#undef APPLY_SREG 6529883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 6539883Sandreas@sandberg.pp.se#undef APPLY_DTABLE 6549883Sandreas@sandberg.pp.se 6559883Sandreas@sandberg.pp.se // Clear the interrupt bitmap 6569883Sandreas@sandberg.pp.se memset(&sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap)); 6579883Sandreas@sandberg.pp.se 6589884Sandreas@sandberg.pp.se RFLAGS rflags_nocc(tc->readMiscReg(MISCREG_RFLAGS)); 6599884Sandreas@sandberg.pp.se if (!rflags_nocc.vm) { 6609884Sandreas@sandberg.pp.se // Do segment verification if the CPU isn't entering virtual 6619884Sandreas@sandberg.pp.se // 8086 mode. We currently assume that unrestricted guest 6629884Sandreas@sandberg.pp.se // mode is available. 6639884Sandreas@sandberg.pp.se 6649884Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) \ 6659884Sandreas@sandberg.pp.se checkSeg(# kreg, idx + MISCREG_SEG_SEL_BASE, sregs.kreg, sregs) 6669884Sandreas@sandberg.pp.se 6679884Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 6689884Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 6699884Sandreas@sandberg.pp.se } 6709883Sandreas@sandberg.pp.se setSpecialRegisters(sregs); 6719883Sandreas@sandberg.pp.se} 6729883Sandreas@sandberg.pp.sevoid 6739883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPU() 6749883Sandreas@sandberg.pp.se{ 6759883Sandreas@sandberg.pp.se warn_once("X86KvmCPU::updateKvmStateFPU not implemented\n"); 6769883Sandreas@sandberg.pp.se} 6779883Sandreas@sandberg.pp.se 6789883Sandreas@sandberg.pp.sevoid 6799883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateMSRs() 6809883Sandreas@sandberg.pp.se{ 6819883Sandreas@sandberg.pp.se KvmMSRVector msrs; 6829883Sandreas@sandberg.pp.se 6839883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &indices(getMsrIntersection()); 6849883Sandreas@sandberg.pp.se 6859883Sandreas@sandberg.pp.se for (auto it = indices.cbegin(); it != indices.cend(); ++it) { 6869883Sandreas@sandberg.pp.se struct kvm_msr_entry e; 6879883Sandreas@sandberg.pp.se 6889883Sandreas@sandberg.pp.se e.index = *it; 6899883Sandreas@sandberg.pp.se e.reserved = 0; 6909883Sandreas@sandberg.pp.se e.data = tc->readMiscReg(msrMap.at(*it)); 6919883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "Adding MSR: idx: 0x%x, data: 0x%x\n", 6929883Sandreas@sandberg.pp.se e.index, e.data); 6939883Sandreas@sandberg.pp.se 6949883Sandreas@sandberg.pp.se msrs.push_back(e); 6959883Sandreas@sandberg.pp.se } 6969883Sandreas@sandberg.pp.se 6979883Sandreas@sandberg.pp.se setMSRs(msrs); 6989883Sandreas@sandberg.pp.se} 6999883Sandreas@sandberg.pp.se 7009883Sandreas@sandberg.pp.sevoid 7019883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContext() 7029883Sandreas@sandberg.pp.se{ 7039883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "X86KvmCPU::updateThreadContext():\n"); 7049883Sandreas@sandberg.pp.se if (DTRACE(KvmContext)) 7059883Sandreas@sandberg.pp.se dump(); 7069883Sandreas@sandberg.pp.se 7079883Sandreas@sandberg.pp.se updateThreadContextRegs(); 7089883Sandreas@sandberg.pp.se updateThreadContextSRegs(); 7099883Sandreas@sandberg.pp.se updateThreadContextFPU(); 7109883Sandreas@sandberg.pp.se updateThreadContextMSRs(); 7119883Sandreas@sandberg.pp.se 7129883Sandreas@sandberg.pp.se // The M5 misc reg caches some values from other 7139883Sandreas@sandberg.pp.se // registers. Writing to it with side effects causes it to be 7149883Sandreas@sandberg.pp.se // updated from its source registers. 7159883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_M5_REG, 0); 7169883Sandreas@sandberg.pp.se} 7179883Sandreas@sandberg.pp.se 7189883Sandreas@sandberg.pp.sevoid 7199883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextRegs() 7209883Sandreas@sandberg.pp.se{ 7219883Sandreas@sandberg.pp.se struct kvm_regs regs; 7229883Sandreas@sandberg.pp.se getRegisters(regs); 7239883Sandreas@sandberg.pp.se 7249883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg) 7259883Sandreas@sandberg.pp.se 7269883Sandreas@sandberg.pp.se FOREACH_IREG(); 7279883Sandreas@sandberg.pp.se 7289883Sandreas@sandberg.pp.se#undef APPLY_IREG 7299883Sandreas@sandberg.pp.se 7309883Sandreas@sandberg.pp.se tc->pcState(PCState(regs.rip)); 7319883Sandreas@sandberg.pp.se 7329883Sandreas@sandberg.pp.se // Flags are spread out across multiple semi-magic registers so we 7339883Sandreas@sandberg.pp.se // need some special care when updating them. 7349883Sandreas@sandberg.pp.se X86ISA::setRFlags(tc, regs.rflags); 7359883Sandreas@sandberg.pp.se} 7369883Sandreas@sandberg.pp.se 7379883Sandreas@sandberg.pp.se 7389883Sandreas@sandberg.pp.seinline void 7399883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_segment &kvm_seg, 7409883Sandreas@sandberg.pp.se const int index) 7419883Sandreas@sandberg.pp.se{ 7429883Sandreas@sandberg.pp.se SegAttr attr(0); 7439883Sandreas@sandberg.pp.se 7449883Sandreas@sandberg.pp.se attr.type = kvm_seg.type; 7459883Sandreas@sandberg.pp.se attr.present = kvm_seg.present; 7469883Sandreas@sandberg.pp.se attr.dpl = kvm_seg.dpl; 7479883Sandreas@sandberg.pp.se attr.defaultSize = kvm_seg.db; 7489883Sandreas@sandberg.pp.se attr.system = kvm_seg.s; 7499883Sandreas@sandberg.pp.se attr.longMode = kvm_seg.l; 7509883Sandreas@sandberg.pp.se attr.granularity = kvm_seg.g; 7519883Sandreas@sandberg.pp.se attr.avl = kvm_seg.avl; 7529883Sandreas@sandberg.pp.se attr.unusable = kvm_seg.unusable; 7539883Sandreas@sandberg.pp.se 7549883Sandreas@sandberg.pp.se // We need some setMiscReg magic here to keep the effective base 7559883Sandreas@sandberg.pp.se // addresses in sync. We need an up-to-date version of EFER, so 7569883Sandreas@sandberg.pp.se // make sure this is called after the sregs have been synced. 7579883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_seg.base); 7589883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_seg.limit); 7599883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_SEL(index), kvm_seg.selector); 7609883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_ATTR(index), attr); 7619883Sandreas@sandberg.pp.se} 7629883Sandreas@sandberg.pp.se 7639883Sandreas@sandberg.pp.seinline void 7649883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_dtable &kvm_dtable, 7659883Sandreas@sandberg.pp.se const int index) 7669883Sandreas@sandberg.pp.se{ 7679883Sandreas@sandberg.pp.se // We need some setMiscReg magic here to keep the effective base 7689883Sandreas@sandberg.pp.se // addresses in sync. We need an up-to-date version of EFER, so 7699883Sandreas@sandberg.pp.se // make sure this is called after the sregs have been synced. 7709883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_dtable.base); 7719883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_dtable.limit); 7729883Sandreas@sandberg.pp.se} 7739883Sandreas@sandberg.pp.se 7749883Sandreas@sandberg.pp.sevoid 7759883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextSRegs() 7769883Sandreas@sandberg.pp.se{ 7779883Sandreas@sandberg.pp.se struct kvm_sregs sregs; 7789883Sandreas@sandberg.pp.se getSpecialRegisters(sregs); 7799883Sandreas@sandberg.pp.se 7809883Sandreas@sandberg.pp.se assert(getKvmRunState()->apic_base == sregs.apic_base); 7819883Sandreas@sandberg.pp.se assert(getKvmRunState()->cr8 == sregs.cr8); 7829883Sandreas@sandberg.pp.se 7839883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) tc->setMiscRegNoEffect(mreg, sregs.kreg) 7849883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setContextSegment(tc, sregs.kreg, idx) 7859883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setContextSegment(tc, sregs.kreg, idx) 7869883Sandreas@sandberg.pp.se FOREACH_SREG(); 7879883Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 7889883Sandreas@sandberg.pp.se FOREACH_DTABLE(); 7899883Sandreas@sandberg.pp.se#undef APPLY_SREG 7909883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 7919883Sandreas@sandberg.pp.se#undef APPLY_DTABLE 7929883Sandreas@sandberg.pp.se} 7939883Sandreas@sandberg.pp.se 7949883Sandreas@sandberg.pp.sevoid 7959883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextFPU() 7969883Sandreas@sandberg.pp.se{ 7979883Sandreas@sandberg.pp.se warn_once("X86KvmCPU::updateThreadContextFPU not implemented\n"); 7989883Sandreas@sandberg.pp.se} 7999883Sandreas@sandberg.pp.se 8009883Sandreas@sandberg.pp.sevoid 8019883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextMSRs() 8029883Sandreas@sandberg.pp.se{ 8039883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &msrs(getMsrIntersection()); 8049883Sandreas@sandberg.pp.se 8059883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 8069883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size())); 8079883Sandreas@sandberg.pp.se struct kvm_msr_entry *entry; 8089883Sandreas@sandberg.pp.se 8099883Sandreas@sandberg.pp.se // Create a list of MSRs to read 8109883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = msrs.size(); 8119883Sandreas@sandberg.pp.se entry = &kvm_msrs->entries[0]; 8129883Sandreas@sandberg.pp.se for (auto it = msrs.cbegin(); it != msrs.cend(); ++it, ++entry) { 8139883Sandreas@sandberg.pp.se entry->index = *it; 8149883Sandreas@sandberg.pp.se entry->reserved = 0; 8159883Sandreas@sandberg.pp.se entry->data = 0; 8169883Sandreas@sandberg.pp.se } 8179883Sandreas@sandberg.pp.se 8189883Sandreas@sandberg.pp.se getMSRs(*kvm_msrs.get()); 8199883Sandreas@sandberg.pp.se 8209883Sandreas@sandberg.pp.se // Update M5's state 8219883Sandreas@sandberg.pp.se entry = &kvm_msrs->entries[0]; 8229883Sandreas@sandberg.pp.se for (int i = 0; i < kvm_msrs->nmsrs; ++i, ++entry) { 8239883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "Setting M5 MSR: idx: 0x%x, data: 0x%x\n", 8249883Sandreas@sandberg.pp.se entry->index, entry->data); 8259883Sandreas@sandberg.pp.se 8269883Sandreas@sandberg.pp.se tc->setMiscReg(X86ISA::msrMap.at(entry->index), entry->data); 8279883Sandreas@sandberg.pp.se } 8289883Sandreas@sandberg.pp.se} 8299883Sandreas@sandberg.pp.se 8309883Sandreas@sandberg.pp.sevoid 8319883Sandreas@sandberg.pp.seX86KvmCPU::deliverInterrupts() 8329883Sandreas@sandberg.pp.se{ 8339883Sandreas@sandberg.pp.se syncThreadContext(); 8349883Sandreas@sandberg.pp.se 8359883Sandreas@sandberg.pp.se Fault fault(interrupts->getInterrupt(tc)); 8369883Sandreas@sandberg.pp.se interrupts->updateIntrInfo(tc); 8379883Sandreas@sandberg.pp.se 8389883Sandreas@sandberg.pp.se X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get())); 8399883Sandreas@sandberg.pp.se if (x86int) { 8409883Sandreas@sandberg.pp.se struct kvm_interrupt kvm_int; 8419883Sandreas@sandberg.pp.se kvm_int.irq = x86int->getVector(); 8429883Sandreas@sandberg.pp.se 8439883Sandreas@sandberg.pp.se DPRINTF(KvmInt, "Delivering interrupt: %s (%u)\n", 8449883Sandreas@sandberg.pp.se fault->name(), kvm_int.irq); 8459883Sandreas@sandberg.pp.se 8469883Sandreas@sandberg.pp.se kvmInterrupt(kvm_int); 8479883Sandreas@sandberg.pp.se } else if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) { 8489883Sandreas@sandberg.pp.se DPRINTF(KvmInt, "Delivering NMI\n"); 8499883Sandreas@sandberg.pp.se kvmNonMaskableInterrupt(); 8509883Sandreas@sandberg.pp.se } else { 8519883Sandreas@sandberg.pp.se panic("KVM: Unknown interrupt type\n"); 8529883Sandreas@sandberg.pp.se } 8539883Sandreas@sandberg.pp.se 8549883Sandreas@sandberg.pp.se} 8559883Sandreas@sandberg.pp.se 8569883Sandreas@sandberg.pp.seTick 8579883Sandreas@sandberg.pp.seX86KvmCPU::kvmRun(Tick ticks) 8589883Sandreas@sandberg.pp.se{ 8599883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 8609883Sandreas@sandberg.pp.se 8619883Sandreas@sandberg.pp.se if (interrupts->checkInterruptsRaw()) { 8629883Sandreas@sandberg.pp.se if (kvm_run.ready_for_interrupt_injection) { 8639883Sandreas@sandberg.pp.se // KVM claims that it is ready for an interrupt. It might 8649883Sandreas@sandberg.pp.se // be lying if we just updated rflags and disabled 8659883Sandreas@sandberg.pp.se // interrupts (e.g., by doing a CPU handover). Let's sync 8669883Sandreas@sandberg.pp.se // the thread context and check if there are /really/ 8679883Sandreas@sandberg.pp.se // interrupts that should be delivered now. 8689883Sandreas@sandberg.pp.se syncThreadContext(); 8699883Sandreas@sandberg.pp.se if (interrupts->checkInterrupts(tc)) { 8709883Sandreas@sandberg.pp.se DPRINTF(KvmInt, 8719883Sandreas@sandberg.pp.se "M5 has pending interrupts, delivering interrupt.\n"); 8729883Sandreas@sandberg.pp.se 8739883Sandreas@sandberg.pp.se deliverInterrupts(); 8749883Sandreas@sandberg.pp.se } else { 8759883Sandreas@sandberg.pp.se DPRINTF(KvmInt, 8769883Sandreas@sandberg.pp.se "Interrupt delivery delayed due to KVM confusion.\n"); 8779883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 1; 8789883Sandreas@sandberg.pp.se } 8799883Sandreas@sandberg.pp.se } else if (!kvm_run.request_interrupt_window) { 8809883Sandreas@sandberg.pp.se DPRINTF(KvmInt, 8819883Sandreas@sandberg.pp.se "M5 has pending interrupts, requesting interrupt " 8829883Sandreas@sandberg.pp.se "window.\n"); 8839883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 1; 8849883Sandreas@sandberg.pp.se } 8859883Sandreas@sandberg.pp.se } else { 8869883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 0; 8879883Sandreas@sandberg.pp.se } 8889883Sandreas@sandberg.pp.se 8899883Sandreas@sandberg.pp.se return kvmRunWrapper(ticks); 8909883Sandreas@sandberg.pp.se} 8919883Sandreas@sandberg.pp.se 8929883Sandreas@sandberg.pp.seTick 8939883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunDrain() 8949883Sandreas@sandberg.pp.se{ 8959883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 8969883Sandreas@sandberg.pp.se 8979883Sandreas@sandberg.pp.se if (!archIsDrained()) { 8989883Sandreas@sandberg.pp.se DPRINTF(Drain, "kvmRunDrain: Architecture code isn't drained\n"); 8999883Sandreas@sandberg.pp.se 9009883Sandreas@sandberg.pp.se // Tell KVM to find a suitable place to deliver interrupts. This 9019883Sandreas@sandberg.pp.se // should ensure that pending interrupts have been delivered and 9029883Sandreas@sandberg.pp.se // things are reasonably consistent (i.e., no interrupts pending 9039883Sandreas@sandberg.pp.se // in the guest). 9049883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 1; 9059883Sandreas@sandberg.pp.se 9069883Sandreas@sandberg.pp.se // Limit the run to 1 millisecond. That is hopefully enough to 9079883Sandreas@sandberg.pp.se // reach an interrupt window. Otherwise, we'll just try again 9089883Sandreas@sandberg.pp.se // later. 9099883Sandreas@sandberg.pp.se return kvmRunWrapper(1 * SimClock::Float::ms); 9109883Sandreas@sandberg.pp.se } else { 9119883Sandreas@sandberg.pp.se DPRINTF(Drain, "kvmRunDrain: Delivering pending IO\n"); 9129883Sandreas@sandberg.pp.se 9139883Sandreas@sandberg.pp.se return kvmRunWrapper(0); 9149883Sandreas@sandberg.pp.se } 9159883Sandreas@sandberg.pp.se} 9169883Sandreas@sandberg.pp.se 9179883Sandreas@sandberg.pp.seTick 9189883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunWrapper(Tick ticks) 9199883Sandreas@sandberg.pp.se{ 9209883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 9219883Sandreas@sandberg.pp.se 9229883Sandreas@sandberg.pp.se // Synchronize the APIC base and CR8 here since they are present 9239883Sandreas@sandberg.pp.se // in the kvm_run struct, which makes the synchronization really 9249883Sandreas@sandberg.pp.se // cheap. 9259883Sandreas@sandberg.pp.se kvm_run.apic_base = tc->readMiscReg(MISCREG_APIC_BASE); 9269883Sandreas@sandberg.pp.se kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8); 9279883Sandreas@sandberg.pp.se 9289883Sandreas@sandberg.pp.se const Tick run_ticks(BaseKvmCPU::kvmRun(ticks)); 9299883Sandreas@sandberg.pp.se 9309883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_APIC_BASE, kvm_run.apic_base); 9319883Sandreas@sandberg.pp.se kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8); 9329883Sandreas@sandberg.pp.se 9339883Sandreas@sandberg.pp.se return run_ticks; 9349883Sandreas@sandberg.pp.se} 9359883Sandreas@sandberg.pp.se 9369883Sandreas@sandberg.pp.seuint64_t 9379883Sandreas@sandberg.pp.seX86KvmCPU::getHostCycles() const 9389883Sandreas@sandberg.pp.se{ 9399883Sandreas@sandberg.pp.se return getMSR(MSR_TSC); 9409883Sandreas@sandberg.pp.se} 9419883Sandreas@sandberg.pp.se 9429883Sandreas@sandberg.pp.sevoid 9439883Sandreas@sandberg.pp.seX86KvmCPU::handleIOMiscReg32(int miscreg) 9449883Sandreas@sandberg.pp.se{ 9459883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 9469883Sandreas@sandberg.pp.se const uint16_t port(kvm_run.io.port); 9479883Sandreas@sandberg.pp.se 9489883Sandreas@sandberg.pp.se assert(kvm_run.exit_reason == KVM_EXIT_IO); 9499883Sandreas@sandberg.pp.se 9509883Sandreas@sandberg.pp.se if (kvm_run.io.size != 4) { 9519883Sandreas@sandberg.pp.se panic("Unexpected IO size (%u) for address 0x%x.\n", 9529883Sandreas@sandberg.pp.se kvm_run.io.size, port); 9539883Sandreas@sandberg.pp.se } 9549883Sandreas@sandberg.pp.se 9559883Sandreas@sandberg.pp.se if (kvm_run.io.count != 1) { 9569883Sandreas@sandberg.pp.se panic("Unexpected IO count (%u) for address 0x%x.\n", 9579883Sandreas@sandberg.pp.se kvm_run.io.count, port); 9589883Sandreas@sandberg.pp.se } 9599883Sandreas@sandberg.pp.se 9609883Sandreas@sandberg.pp.se uint32_t *data((uint32_t *)getGuestData(kvm_run.io.data_offset)); 9619883Sandreas@sandberg.pp.se if (kvm_run.io.direction == KVM_EXIT_IO_OUT) 9629883Sandreas@sandberg.pp.se tc->setMiscReg(miscreg, *data); 9639883Sandreas@sandberg.pp.se else 9649883Sandreas@sandberg.pp.se *data = tc->readMiscRegNoEffect(miscreg); 9659883Sandreas@sandberg.pp.se} 9669883Sandreas@sandberg.pp.se 9679883Sandreas@sandberg.pp.seTick 9689883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIO() 9699883Sandreas@sandberg.pp.se{ 9709883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 9719883Sandreas@sandberg.pp.se bool isWrite(kvm_run.io.direction == KVM_EXIT_IO_OUT); 9729883Sandreas@sandberg.pp.se unsigned char *guestData(getGuestData(kvm_run.io.data_offset)); 9739883Sandreas@sandberg.pp.se Tick delay(0); 9749883Sandreas@sandberg.pp.se uint16_t port(kvm_run.io.port); 9759883Sandreas@sandberg.pp.se Addr pAddr; 9769883Sandreas@sandberg.pp.se const int count(kvm_run.io.count); 9779883Sandreas@sandberg.pp.se 9789883Sandreas@sandberg.pp.se assert(kvm_run.io.direction == KVM_EXIT_IO_IN || 9799883Sandreas@sandberg.pp.se kvm_run.io.direction == KVM_EXIT_IO_OUT); 9809883Sandreas@sandberg.pp.se 9819883Sandreas@sandberg.pp.se DPRINTF(KvmIO, "KVM-x86: Handling IO instruction (%s) (port: 0x%x)\n", 9829883Sandreas@sandberg.pp.se (isWrite ? "out" : "in"), kvm_run.io.port); 9839883Sandreas@sandberg.pp.se 9849883Sandreas@sandberg.pp.se /* Vanilla gem5 handles PCI discovery in the TLB(!). Since we 9859883Sandreas@sandberg.pp.se * don't use the TLB component, we need to intercept and handle 9869883Sandreas@sandberg.pp.se * the PCI configuration space IO ports here. 9879883Sandreas@sandberg.pp.se * 9889883Sandreas@sandberg.pp.se * The IO port PCI discovery mechanism uses one address register 9899883Sandreas@sandberg.pp.se * and one data register. We map the address register to a misc 9909883Sandreas@sandberg.pp.se * reg and use that to re-route data register accesses to the 9919883Sandreas@sandberg.pp.se * right location in the PCI configuration space. 9929883Sandreas@sandberg.pp.se */ 9939883Sandreas@sandberg.pp.se if (port == IO_PCI_CONF_ADDR) { 9949883Sandreas@sandberg.pp.se handleIOMiscReg32(MISCREG_PCI_CONFIG_ADDRESS); 9959883Sandreas@sandberg.pp.se return 0; 9969883Sandreas@sandberg.pp.se } else if ((port & ~0x3) == IO_PCI_CONF_DATA_BASE) { 9979883Sandreas@sandberg.pp.se Addr pciConfigAddr(tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS)); 9989883Sandreas@sandberg.pp.se if (pciConfigAddr & 0x80000000) { 9999883Sandreas@sandberg.pp.se pAddr = X86ISA::x86PciConfigAddress((pciConfigAddr & 0x7ffffffc) | 10009883Sandreas@sandberg.pp.se (port & 0x3)); 10019883Sandreas@sandberg.pp.se } else { 10029883Sandreas@sandberg.pp.se pAddr = X86ISA::x86IOAddress(port); 10039883Sandreas@sandberg.pp.se } 10049883Sandreas@sandberg.pp.se } else { 10059883Sandreas@sandberg.pp.se pAddr = X86ISA::x86IOAddress(port); 10069883Sandreas@sandberg.pp.se } 10079883Sandreas@sandberg.pp.se 10089883Sandreas@sandberg.pp.se io_req.setPhys(pAddr, kvm_run.io.size, Request::UNCACHEABLE, 10099883Sandreas@sandberg.pp.se dataMasterId()); 10109883Sandreas@sandberg.pp.se 10119883Sandreas@sandberg.pp.se const MemCmd cmd(isWrite ? MemCmd::WriteReq : MemCmd::ReadReq); 10129883Sandreas@sandberg.pp.se for (int i = 0; i < count; ++i) { 10139883Sandreas@sandberg.pp.se Packet pkt(&io_req, cmd); 10149883Sandreas@sandberg.pp.se 10159883Sandreas@sandberg.pp.se pkt.dataStatic(guestData); 10169883Sandreas@sandberg.pp.se delay += dataPort.sendAtomic(&pkt); 10179883Sandreas@sandberg.pp.se 10189883Sandreas@sandberg.pp.se guestData += kvm_run.io.size; 10199883Sandreas@sandberg.pp.se } 10209883Sandreas@sandberg.pp.se 10219883Sandreas@sandberg.pp.se return delay; 10229883Sandreas@sandberg.pp.se} 10239883Sandreas@sandberg.pp.se 10249883Sandreas@sandberg.pp.seTick 10259883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIRQWindowOpen() 10269883Sandreas@sandberg.pp.se{ 10279883Sandreas@sandberg.pp.se // We don't need to do anything here since this is caught the next 10289883Sandreas@sandberg.pp.se // time we execute kvmRun(). We still overload the exit event to 10299883Sandreas@sandberg.pp.se // silence the warning about an unhandled exit event. 10309883Sandreas@sandberg.pp.se return 0; 10319883Sandreas@sandberg.pp.se} 10329883Sandreas@sandberg.pp.se 10339883Sandreas@sandberg.pp.sebool 10349883Sandreas@sandberg.pp.seX86KvmCPU::archIsDrained() const 10359883Sandreas@sandberg.pp.se{ 10369883Sandreas@sandberg.pp.se struct kvm_vcpu_events events; 10379883Sandreas@sandberg.pp.se 10389883Sandreas@sandberg.pp.se getVCpuEvents(events); 10399883Sandreas@sandberg.pp.se 10409883Sandreas@sandberg.pp.se // We could probably handle this in a by re-inserting interrupts 10419883Sandreas@sandberg.pp.se // that are pending into gem5 on a drain. However, that would 10429883Sandreas@sandberg.pp.se // probably be tricky to do reliably, so we'll just prevent a 10439883Sandreas@sandberg.pp.se // drain if there is anything pending in the 10449883Sandreas@sandberg.pp.se // guest. X86KvmCPU::kvmRunDrain() minimizes the amount of code 10459883Sandreas@sandberg.pp.se // executed in the guest by requesting an interrupt window if 10469883Sandreas@sandberg.pp.se // there are pending interrupts. 10479883Sandreas@sandberg.pp.se const bool pending_events(events.exception.injected || 10489883Sandreas@sandberg.pp.se events.interrupt.injected || 10499883Sandreas@sandberg.pp.se events.nmi.injected || events.nmi.pending); 10509883Sandreas@sandberg.pp.se 10519883Sandreas@sandberg.pp.se if (pending_events) { 10529883Sandreas@sandberg.pp.se DPRINTF(Drain, "archIsDrained: Pending events: %s %s %s %s\n", 10539883Sandreas@sandberg.pp.se events.exception.injected ? "exception" : "", 10549883Sandreas@sandberg.pp.se events.interrupt.injected ? "interrupt" : "", 10559883Sandreas@sandberg.pp.se events.nmi.injected ? "nmi[i]" : "", 10569883Sandreas@sandberg.pp.se events.nmi.pending ? "nmi[p]" : ""); 10579883Sandreas@sandberg.pp.se } 10589883Sandreas@sandberg.pp.se 10599883Sandreas@sandberg.pp.se return !pending_events; 10609883Sandreas@sandberg.pp.se} 10619883Sandreas@sandberg.pp.se 10629883Sandreas@sandberg.pp.sestatic struct kvm_cpuid_entry2 10639883Sandreas@sandberg.pp.semakeKvmCpuid(uint32_t function, uint32_t index, 10649883Sandreas@sandberg.pp.se CpuidResult &result) 10659883Sandreas@sandberg.pp.se{ 10669883Sandreas@sandberg.pp.se struct kvm_cpuid_entry2 e; 10679883Sandreas@sandberg.pp.se e.function = function; 10689883Sandreas@sandberg.pp.se e.index = index; 10699883Sandreas@sandberg.pp.se e.flags = 0; 10709883Sandreas@sandberg.pp.se e.eax = (uint32_t)result.rax; 10719883Sandreas@sandberg.pp.se e.ebx = (uint32_t)result.rbx; 10729883Sandreas@sandberg.pp.se e.ecx = (uint32_t)result.rcx; 10739883Sandreas@sandberg.pp.se e.edx = (uint32_t)result.rdx; 10749883Sandreas@sandberg.pp.se 10759883Sandreas@sandberg.pp.se return e; 10769883Sandreas@sandberg.pp.se} 10779883Sandreas@sandberg.pp.se 10789883Sandreas@sandberg.pp.sevoid 10799883Sandreas@sandberg.pp.seX86KvmCPU::updateCPUID() 10809883Sandreas@sandberg.pp.se{ 10819883Sandreas@sandberg.pp.se Kvm::CPUIDVector m5_supported; 10829883Sandreas@sandberg.pp.se 10839883Sandreas@sandberg.pp.se /* TODO: We currently don't support any of the functions that 10849883Sandreas@sandberg.pp.se * iterate through data structures in the CPU using an index. It's 10859883Sandreas@sandberg.pp.se * currently not a problem since M5 doesn't expose any of them at 10869883Sandreas@sandberg.pp.se * the moment. 10879883Sandreas@sandberg.pp.se */ 10889883Sandreas@sandberg.pp.se 10899883Sandreas@sandberg.pp.se /* Basic features */ 10909883Sandreas@sandberg.pp.se CpuidResult func0; 10919883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, 0x0, 0, func0); 10929883Sandreas@sandberg.pp.se for (uint32_t function = 0; function <= func0.rax; ++function) { 10939883Sandreas@sandberg.pp.se CpuidResult cpuid; 10949883Sandreas@sandberg.pp.se uint32_t idx(0); 10959883Sandreas@sandberg.pp.se 10969883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, function, idx, cpuid); 10979883Sandreas@sandberg.pp.se m5_supported.push_back(makeKvmCpuid(function, idx, cpuid)); 10989883Sandreas@sandberg.pp.se } 10999883Sandreas@sandberg.pp.se 11009883Sandreas@sandberg.pp.se /* Extended features */ 11019883Sandreas@sandberg.pp.se CpuidResult efunc0; 11029883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, 0x80000000, 0, efunc0); 11039883Sandreas@sandberg.pp.se for (uint32_t function = 0x80000000; function <= efunc0.rax; ++function) { 11049883Sandreas@sandberg.pp.se CpuidResult cpuid; 11059883Sandreas@sandberg.pp.se uint32_t idx(0); 11069883Sandreas@sandberg.pp.se 11079883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, function, idx, cpuid); 11089883Sandreas@sandberg.pp.se m5_supported.push_back(makeKvmCpuid(function, idx, cpuid)); 11099883Sandreas@sandberg.pp.se } 11109883Sandreas@sandberg.pp.se 11119883Sandreas@sandberg.pp.se setCPUID(m5_supported); 11129883Sandreas@sandberg.pp.se} 11139883Sandreas@sandberg.pp.se 11149883Sandreas@sandberg.pp.sevoid 11159883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const struct kvm_cpuid2 &cpuid) 11169883Sandreas@sandberg.pp.se{ 11179883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_CPUID2, (void *)&cpuid) == -1) 11189883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest CPUID2 (errno: %i)\n", 11199883Sandreas@sandberg.pp.se errno); 11209883Sandreas@sandberg.pp.se} 11219883Sandreas@sandberg.pp.se 11229883Sandreas@sandberg.pp.sevoid 11239883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const Kvm::CPUIDVector &cpuid) 11249883Sandreas@sandberg.pp.se{ 11259883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_cpuid2> kvm_cpuid( 11269883Sandreas@sandberg.pp.se newVarStruct<struct kvm_cpuid2, struct kvm_cpuid_entry2>(cpuid.size())); 11279883Sandreas@sandberg.pp.se 11289883Sandreas@sandberg.pp.se kvm_cpuid->nent = cpuid.size(); 11299883Sandreas@sandberg.pp.se std::copy(cpuid.begin(), cpuid.end(), kvm_cpuid->entries); 11309883Sandreas@sandberg.pp.se 11319883Sandreas@sandberg.pp.se setCPUID(*kvm_cpuid); 11329883Sandreas@sandberg.pp.se} 11339883Sandreas@sandberg.pp.se 11349883Sandreas@sandberg.pp.sevoid 11359883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const struct kvm_msrs &msrs) 11369883Sandreas@sandberg.pp.se{ 11379883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_MSRS, (void *)&msrs) == -1) 11389883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest MSRs (errno: %i)\n", 11399883Sandreas@sandberg.pp.se errno); 11409883Sandreas@sandberg.pp.se} 11419883Sandreas@sandberg.pp.se 11429883Sandreas@sandberg.pp.sevoid 11439883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const KvmMSRVector &msrs) 11449883Sandreas@sandberg.pp.se{ 11459883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 11469883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size())); 11479883Sandreas@sandberg.pp.se 11489883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = msrs.size(); 11499883Sandreas@sandberg.pp.se std::copy(msrs.begin(), msrs.end(), kvm_msrs->entries); 11509883Sandreas@sandberg.pp.se 11519883Sandreas@sandberg.pp.se setMSRs(*kvm_msrs); 11529883Sandreas@sandberg.pp.se} 11539883Sandreas@sandberg.pp.se 11549883Sandreas@sandberg.pp.sevoid 11559883Sandreas@sandberg.pp.seX86KvmCPU::getMSRs(struct kvm_msrs &msrs) const 11569883Sandreas@sandberg.pp.se{ 11579883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_MSRS, (void *)&msrs) == -1) 11589883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest MSRs (errno: %i)\n", 11599883Sandreas@sandberg.pp.se errno); 11609883Sandreas@sandberg.pp.se} 11619883Sandreas@sandberg.pp.se 11629883Sandreas@sandberg.pp.se 11639883Sandreas@sandberg.pp.sevoid 11649883Sandreas@sandberg.pp.seX86KvmCPU::setMSR(uint32_t index, uint64_t value) 11659883Sandreas@sandberg.pp.se{ 11669883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 11679883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1)); 11689883Sandreas@sandberg.pp.se struct kvm_msr_entry &entry(kvm_msrs->entries[0]); 11699883Sandreas@sandberg.pp.se 11709883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = 1; 11719883Sandreas@sandberg.pp.se entry.index = index; 11729883Sandreas@sandberg.pp.se entry.reserved = 0; 11739883Sandreas@sandberg.pp.se entry.data = value; 11749883Sandreas@sandberg.pp.se 11759883Sandreas@sandberg.pp.se setMSRs(*kvm_msrs.get()); 11769883Sandreas@sandberg.pp.se} 11779883Sandreas@sandberg.pp.se 11789883Sandreas@sandberg.pp.seuint64_t 11799883Sandreas@sandberg.pp.seX86KvmCPU::getMSR(uint32_t index) const 11809883Sandreas@sandberg.pp.se{ 11819883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 11829883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1)); 11839883Sandreas@sandberg.pp.se struct kvm_msr_entry &entry(kvm_msrs->entries[0]); 11849883Sandreas@sandberg.pp.se 11859883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = 1; 11869883Sandreas@sandberg.pp.se entry.index = index; 11879883Sandreas@sandberg.pp.se entry.reserved = 0; 11889883Sandreas@sandberg.pp.se entry.data = 0; 11899883Sandreas@sandberg.pp.se 11909883Sandreas@sandberg.pp.se getMSRs(*kvm_msrs.get()); 11919883Sandreas@sandberg.pp.se return entry.data; 11929883Sandreas@sandberg.pp.se} 11939883Sandreas@sandberg.pp.se 11949883Sandreas@sandberg.pp.seconst Kvm::MSRIndexVector & 11959883Sandreas@sandberg.pp.seX86KvmCPU::getMsrIntersection() const 11969883Sandreas@sandberg.pp.se{ 11979883Sandreas@sandberg.pp.se if (cachedMsrIntersection.empty()) { 11989883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &kvm_msrs(vm.kvm.getSupportedMSRs()); 11999883Sandreas@sandberg.pp.se 12009883Sandreas@sandberg.pp.se DPRINTF(Kvm, "kvm-x86: Updating MSR intersection\n"); 12019883Sandreas@sandberg.pp.se for (auto it = kvm_msrs.cbegin(); it != kvm_msrs.cend(); ++it) { 12029883Sandreas@sandberg.pp.se if (X86ISA::msrMap.find(*it) != X86ISA::msrMap.end()) { 12039883Sandreas@sandberg.pp.se cachedMsrIntersection.push_back(*it); 12049883Sandreas@sandberg.pp.se DPRINTF(Kvm, "kvm-x86: Adding MSR 0x%x\n", *it); 12059883Sandreas@sandberg.pp.se } else { 12069883Sandreas@sandberg.pp.se warn("kvm-x86: MSR (0x%x) unsupported by gem5. Skipping.\n", 12079883Sandreas@sandberg.pp.se *it); 12089883Sandreas@sandberg.pp.se } 12099883Sandreas@sandberg.pp.se } 12109883Sandreas@sandberg.pp.se } 12119883Sandreas@sandberg.pp.se 12129883Sandreas@sandberg.pp.se return cachedMsrIntersection; 12139883Sandreas@sandberg.pp.se} 12149883Sandreas@sandberg.pp.se 12159883Sandreas@sandberg.pp.sevoid 12169883Sandreas@sandberg.pp.seX86KvmCPU::getDebugRegisters(struct kvm_debugregs ®s) const 12179883Sandreas@sandberg.pp.se{ 12189883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS 12199883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_DEBUGREGS, ®s) == -1) 12209883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 12219883Sandreas@sandberg.pp.se#else 12229883Sandreas@sandberg.pp.se panic("KVM: Unsupported getDebugRegisters call.\n"); 12239883Sandreas@sandberg.pp.se#endif 12249883Sandreas@sandberg.pp.se} 12259883Sandreas@sandberg.pp.se 12269883Sandreas@sandberg.pp.sevoid 12279883Sandreas@sandberg.pp.seX86KvmCPU::setDebugRegisters(const struct kvm_debugregs ®s) 12289883Sandreas@sandberg.pp.se{ 12299883Sandreas@sandberg.pp.se#ifdef KVM_SET_DEBUGREGS 12309883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_DEBUGREGS, (void *)®s) == -1) 12319883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 12329883Sandreas@sandberg.pp.se#else 12339883Sandreas@sandberg.pp.se panic("KVM: Unsupported setDebugRegisters call.\n"); 12349883Sandreas@sandberg.pp.se#endif 12359883Sandreas@sandberg.pp.se} 12369883Sandreas@sandberg.pp.se 12379883Sandreas@sandberg.pp.sevoid 12389883Sandreas@sandberg.pp.seX86KvmCPU::getXCRs(struct kvm_xcrs ®s) const 12399883Sandreas@sandberg.pp.se{ 12409883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_XCRS, ®s) == -1) 12419883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 12429883Sandreas@sandberg.pp.se} 12439883Sandreas@sandberg.pp.se 12449883Sandreas@sandberg.pp.sevoid 12459883Sandreas@sandberg.pp.seX86KvmCPU::setXCRs(const struct kvm_xcrs ®s) 12469883Sandreas@sandberg.pp.se{ 12479883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_XCRS, (void *)®s) == -1) 12489883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 12499883Sandreas@sandberg.pp.se} 12509883Sandreas@sandberg.pp.se 12519883Sandreas@sandberg.pp.sevoid 12529883Sandreas@sandberg.pp.seX86KvmCPU::getXSave(struct kvm_xsave &xsave) const 12539883Sandreas@sandberg.pp.se{ 12549883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_XSAVE, &xsave) == -1) 12559883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 12569883Sandreas@sandberg.pp.se} 12579883Sandreas@sandberg.pp.se 12589883Sandreas@sandberg.pp.sevoid 12599883Sandreas@sandberg.pp.seX86KvmCPU::setXSave(const struct kvm_xsave &xsave) 12609883Sandreas@sandberg.pp.se{ 12619883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_XSAVE, (void *)&xsave) == -1) 12629883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 12639883Sandreas@sandberg.pp.se} 12649883Sandreas@sandberg.pp.se 12659883Sandreas@sandberg.pp.se 12669883Sandreas@sandberg.pp.sevoid 12679883Sandreas@sandberg.pp.seX86KvmCPU::getVCpuEvents(struct kvm_vcpu_events &events) const 12689883Sandreas@sandberg.pp.se{ 12699883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_VCPU_EVENTS, &events) == -1) 12709883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 12719883Sandreas@sandberg.pp.se} 12729883Sandreas@sandberg.pp.se 12739883Sandreas@sandberg.pp.sevoid 12749883Sandreas@sandberg.pp.seX86KvmCPU::setVCpuEvents(const struct kvm_vcpu_events &events) 12759883Sandreas@sandberg.pp.se{ 12769883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_VCPU_EVENTS, (void *)&events) == -1) 12779883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 12789883Sandreas@sandberg.pp.se} 12799883Sandreas@sandberg.pp.se 12809883Sandreas@sandberg.pp.seX86KvmCPU * 12819883Sandreas@sandberg.pp.seX86KvmCPUParams::create() 12829883Sandreas@sandberg.pp.se{ 12839883Sandreas@sandberg.pp.se return new X86KvmCPU(this); 12849883Sandreas@sandberg.pp.se} 1285