x86_cpu.cc revision 10653
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 569886Sandreas@sandberg.pp.se// Task segment type of an inactive 32-bit or 64-bit task 579886Sandreas@sandberg.pp.se#define SEG_SYS_TYPE_TSS_AVAILABLE 9 589886Sandreas@sandberg.pp.se// Task segment type of an active 32-bit or 64-bit task 599886Sandreas@sandberg.pp.se#define SEG_SYS_TYPE_TSS_BUSY 11 609886Sandreas@sandberg.pp.se 619886Sandreas@sandberg.pp.se// Non-conforming accessed code segment 629886Sandreas@sandberg.pp.se#define SEG_CS_TYPE_ACCESSED 9 639886Sandreas@sandberg.pp.se// Non-conforming accessed code segment that can be read 649886Sandreas@sandberg.pp.se#define SEG_CS_TYPE_READ_ACCESSED 11 659886Sandreas@sandberg.pp.se 669886Sandreas@sandberg.pp.se// The lowest bit of the type field for normal segments (code and 679886Sandreas@sandberg.pp.se// data) is used to indicate that a segment has been accessed. 689886Sandreas@sandberg.pp.se#define SEG_TYPE_BIT_ACCESSED 1 699886Sandreas@sandberg.pp.se 709890Sandreas@sandberg.pp.sestruct FXSave 719890Sandreas@sandberg.pp.se{ 729890Sandreas@sandberg.pp.se uint16_t fcw; 739890Sandreas@sandberg.pp.se uint16_t fsw; 749890Sandreas@sandberg.pp.se uint8_t ftwx; 759890Sandreas@sandberg.pp.se uint8_t pad0; 769890Sandreas@sandberg.pp.se uint16_t last_opcode; 779890Sandreas@sandberg.pp.se union { 789890Sandreas@sandberg.pp.se struct { 799890Sandreas@sandberg.pp.se uint32_t fpu_ip; 809890Sandreas@sandberg.pp.se uint16_t fpu_cs; 819890Sandreas@sandberg.pp.se uint16_t pad1; 829890Sandreas@sandberg.pp.se uint32_t fpu_dp; 839890Sandreas@sandberg.pp.se uint16_t fpu_ds; 849890Sandreas@sandberg.pp.se uint16_t pad2; 859890Sandreas@sandberg.pp.se } ctrl32; 869890Sandreas@sandberg.pp.se 879890Sandreas@sandberg.pp.se struct { 889890Sandreas@sandberg.pp.se uint64_t fpu_ip; 899890Sandreas@sandberg.pp.se uint64_t fpu_dp; 909890Sandreas@sandberg.pp.se } ctrl64; 919890Sandreas@sandberg.pp.se }; 929890Sandreas@sandberg.pp.se uint32_t mxcsr; 939890Sandreas@sandberg.pp.se uint32_t mxcsr_mask; 949890Sandreas@sandberg.pp.se 959890Sandreas@sandberg.pp.se uint8_t fpr[8][16]; 969890Sandreas@sandberg.pp.se uint8_t xmm[16][16]; 979890Sandreas@sandberg.pp.se 989890Sandreas@sandberg.pp.se uint64_t reserved[12]; 999890Sandreas@sandberg.pp.se} M5_ATTR_PACKED; 1009890Sandreas@sandberg.pp.se 1019890Sandreas@sandberg.pp.sestatic_assert(sizeof(FXSave) == 512, "Unexpected size of FXSave"); 1029886Sandreas@sandberg.pp.se 1039883Sandreas@sandberg.pp.se#define FOREACH_IREG() \ 1049883Sandreas@sandberg.pp.se do { \ 1059883Sandreas@sandberg.pp.se APPLY_IREG(rax, INTREG_RAX); \ 1069883Sandreas@sandberg.pp.se APPLY_IREG(rbx, INTREG_RBX); \ 1079883Sandreas@sandberg.pp.se APPLY_IREG(rcx, INTREG_RCX); \ 1089883Sandreas@sandberg.pp.se APPLY_IREG(rdx, INTREG_RDX); \ 1099883Sandreas@sandberg.pp.se APPLY_IREG(rsi, INTREG_RSI); \ 1109883Sandreas@sandberg.pp.se APPLY_IREG(rdi, INTREG_RDI); \ 1119883Sandreas@sandberg.pp.se APPLY_IREG(rsp, INTREG_RSP); \ 1129883Sandreas@sandberg.pp.se APPLY_IREG(rbp, INTREG_RBP); \ 1139883Sandreas@sandberg.pp.se APPLY_IREG(r8, INTREG_R8); \ 1149883Sandreas@sandberg.pp.se APPLY_IREG(r9, INTREG_R9); \ 1159883Sandreas@sandberg.pp.se APPLY_IREG(r10, INTREG_R10); \ 1169883Sandreas@sandberg.pp.se APPLY_IREG(r11, INTREG_R11); \ 1179883Sandreas@sandberg.pp.se APPLY_IREG(r12, INTREG_R12); \ 1189883Sandreas@sandberg.pp.se APPLY_IREG(r13, INTREG_R13); \ 1199883Sandreas@sandberg.pp.se APPLY_IREG(r14, INTREG_R14); \ 1209883Sandreas@sandberg.pp.se APPLY_IREG(r15, INTREG_R15); \ 1219883Sandreas@sandberg.pp.se } while(0) 1229883Sandreas@sandberg.pp.se 1239883Sandreas@sandberg.pp.se#define FOREACH_SREG() \ 1249883Sandreas@sandberg.pp.se do { \ 1259883Sandreas@sandberg.pp.se APPLY_SREG(cr0, MISCREG_CR0); \ 1269883Sandreas@sandberg.pp.se APPLY_SREG(cr2, MISCREG_CR2); \ 1279883Sandreas@sandberg.pp.se APPLY_SREG(cr3, MISCREG_CR3); \ 1289883Sandreas@sandberg.pp.se APPLY_SREG(cr4, MISCREG_CR4); \ 1299883Sandreas@sandberg.pp.se APPLY_SREG(cr8, MISCREG_CR8); \ 1309883Sandreas@sandberg.pp.se APPLY_SREG(efer, MISCREG_EFER); \ 1319883Sandreas@sandberg.pp.se APPLY_SREG(apic_base, MISCREG_APIC_BASE); \ 1329883Sandreas@sandberg.pp.se } while(0) 1339883Sandreas@sandberg.pp.se 1349883Sandreas@sandberg.pp.se#define FOREACH_DREG() \ 1359883Sandreas@sandberg.pp.se do { \ 1369883Sandreas@sandberg.pp.se APPLY_DREG(db[0], MISCREG_DR0); \ 1379883Sandreas@sandberg.pp.se APPLY_DREG(db[1], MISCREG_DR1); \ 1389883Sandreas@sandberg.pp.se APPLY_DREG(db[2], MISCREG_DR2); \ 1399883Sandreas@sandberg.pp.se APPLY_DREG(db[3], MISCREG_DR3); \ 1409883Sandreas@sandberg.pp.se APPLY_DREG(dr6, MISCREG_DR6); \ 1419883Sandreas@sandberg.pp.se APPLY_DREG(dr7, MISCREG_DR7); \ 1429883Sandreas@sandberg.pp.se } while(0) 1439883Sandreas@sandberg.pp.se 1449883Sandreas@sandberg.pp.se#define FOREACH_SEGMENT() \ 1459883Sandreas@sandberg.pp.se do { \ 1469883Sandreas@sandberg.pp.se APPLY_SEGMENT(cs, MISCREG_CS - MISCREG_SEG_SEL_BASE); \ 1479883Sandreas@sandberg.pp.se APPLY_SEGMENT(ds, MISCREG_DS - MISCREG_SEG_SEL_BASE); \ 1489883Sandreas@sandberg.pp.se APPLY_SEGMENT(es, MISCREG_ES - MISCREG_SEG_SEL_BASE); \ 1499883Sandreas@sandberg.pp.se APPLY_SEGMENT(fs, MISCREG_FS - MISCREG_SEG_SEL_BASE); \ 1509883Sandreas@sandberg.pp.se APPLY_SEGMENT(gs, MISCREG_GS - MISCREG_SEG_SEL_BASE); \ 1519883Sandreas@sandberg.pp.se APPLY_SEGMENT(ss, MISCREG_SS - MISCREG_SEG_SEL_BASE); \ 1529883Sandreas@sandberg.pp.se APPLY_SEGMENT(tr, MISCREG_TR - MISCREG_SEG_SEL_BASE); \ 1539883Sandreas@sandberg.pp.se APPLY_SEGMENT(ldt, MISCREG_TSL - MISCREG_SEG_SEL_BASE); \ 1549883Sandreas@sandberg.pp.se } while(0) 1559883Sandreas@sandberg.pp.se 1569883Sandreas@sandberg.pp.se#define FOREACH_DTABLE() \ 1579883Sandreas@sandberg.pp.se do { \ 1589883Sandreas@sandberg.pp.se APPLY_DTABLE(gdt, MISCREG_TSG - MISCREG_SEG_SEL_BASE); \ 1599883Sandreas@sandberg.pp.se APPLY_DTABLE(idt, MISCREG_IDTR - MISCREG_SEG_SEL_BASE); \ 1609883Sandreas@sandberg.pp.se } while(0) 1619883Sandreas@sandberg.pp.se 1629883Sandreas@sandberg.pp.setemplate<typename STRUCT, typename ENTRY> 1639883Sandreas@sandberg.pp.sestatic STRUCT *newVarStruct(size_t entries) 1649883Sandreas@sandberg.pp.se{ 1659883Sandreas@sandberg.pp.se return (STRUCT *)operator new(sizeof(STRUCT) + entries * sizeof(ENTRY)); 1669883Sandreas@sandberg.pp.se} 1679883Sandreas@sandberg.pp.se 1689883Sandreas@sandberg.pp.sestatic void 1699883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_regs ®s) 1709883Sandreas@sandberg.pp.se{ 1719883Sandreas@sandberg.pp.se inform("KVM register state:\n"); 1729883Sandreas@sandberg.pp.se 1739883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) \ 1749883Sandreas@sandberg.pp.se inform("\t" # kreg ": 0x%llx\n", regs.kreg) 1759883Sandreas@sandberg.pp.se 1769883Sandreas@sandberg.pp.se FOREACH_IREG(); 1779883Sandreas@sandberg.pp.se 1789883Sandreas@sandberg.pp.se#undef APPLY_IREG 1799883Sandreas@sandberg.pp.se 1809883Sandreas@sandberg.pp.se inform("\trip: 0x%llx\n", regs.rip); 1819883Sandreas@sandberg.pp.se inform("\trflags: 0x%llx\n", regs.rflags); 1829883Sandreas@sandberg.pp.se} 1839883Sandreas@sandberg.pp.se 1849883Sandreas@sandberg.pp.sestatic void 1859883Sandreas@sandberg.pp.sedumpKvm(const char *reg_name, const struct kvm_segment &seg) 1869883Sandreas@sandberg.pp.se{ 1879883Sandreas@sandberg.pp.se inform("\t%s: @0x%llx+%x [sel: 0x%x, type: 0x%x]\n" 1889883Sandreas@sandberg.pp.se "\t\tpres.: %u, dpl: %u, db: %u, s: %u, l: %u, g: %u, avl: %u, unus.: %u\n", 1899883Sandreas@sandberg.pp.se reg_name, 1909883Sandreas@sandberg.pp.se seg.base, seg.limit, seg.selector, seg.type, 1919883Sandreas@sandberg.pp.se seg.present, seg.dpl, seg.db, seg.s, seg.l, seg.g, seg.avl, seg.unusable); 1929883Sandreas@sandberg.pp.se} 1939883Sandreas@sandberg.pp.se 1949883Sandreas@sandberg.pp.sestatic void 1959883Sandreas@sandberg.pp.sedumpKvm(const char *reg_name, const struct kvm_dtable &dtable) 1969883Sandreas@sandberg.pp.se{ 1979883Sandreas@sandberg.pp.se inform("\t%s: @0x%llx+%x\n", 1989883Sandreas@sandberg.pp.se reg_name, dtable.base, dtable.limit); 1999883Sandreas@sandberg.pp.se} 2009883Sandreas@sandberg.pp.se 2019883Sandreas@sandberg.pp.sestatic void 2029883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_sregs &sregs) 2039883Sandreas@sandberg.pp.se{ 2049883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) \ 2059883Sandreas@sandberg.pp.se inform("\t" # kreg ": 0x%llx\n", sregs.kreg); 2069883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) \ 2079883Sandreas@sandberg.pp.se dumpKvm(# kreg, sregs.kreg); 2089883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) \ 2099883Sandreas@sandberg.pp.se dumpKvm(# kreg, sregs.kreg); 2109883Sandreas@sandberg.pp.se 2119883Sandreas@sandberg.pp.se inform("Special registers:\n"); 2129883Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 2139883Sandreas@sandberg.pp.se FOREACH_SREG(); 2149883Sandreas@sandberg.pp.se FOREACH_DTABLE(); 2159883Sandreas@sandberg.pp.se 2169883Sandreas@sandberg.pp.se inform("Interrupt Bitmap:"); 2179883Sandreas@sandberg.pp.se for (int i = 0; i < KVM_NR_INTERRUPTS; i += 64) 2189883Sandreas@sandberg.pp.se inform(" 0x%.8x", sregs.interrupt_bitmap[i / 64]); 2199883Sandreas@sandberg.pp.se 2209883Sandreas@sandberg.pp.se#undef APPLY_SREG 2219883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 2229883Sandreas@sandberg.pp.se#undef APPLY_DTABLE 2239883Sandreas@sandberg.pp.se} 2249883Sandreas@sandberg.pp.se 2259883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS 2269883Sandreas@sandberg.pp.sestatic void 2279883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_debugregs ®s) 2289883Sandreas@sandberg.pp.se{ 2299883Sandreas@sandberg.pp.se inform("KVM debug state:\n"); 2309883Sandreas@sandberg.pp.se 2319883Sandreas@sandberg.pp.se#define APPLY_DREG(kreg, mreg) \ 2329883Sandreas@sandberg.pp.se inform("\t" # kreg ": 0x%llx\n", regs.kreg) 2339883Sandreas@sandberg.pp.se 2349883Sandreas@sandberg.pp.se FOREACH_DREG(); 2359883Sandreas@sandberg.pp.se 2369883Sandreas@sandberg.pp.se#undef APPLY_DREG 2379883Sandreas@sandberg.pp.se 2389883Sandreas@sandberg.pp.se inform("\tflags: 0x%llx\n", regs.flags); 2399883Sandreas@sandberg.pp.se} 2409883Sandreas@sandberg.pp.se#endif 2419883Sandreas@sandberg.pp.se 2429883Sandreas@sandberg.pp.sestatic void 2439890Sandreas@sandberg.pp.sedumpFpuSpec(const struct FXSave &xs) 2449883Sandreas@sandberg.pp.se{ 2459890Sandreas@sandberg.pp.se inform("\tlast_ip: 0x%x\n", xs.ctrl64.fpu_ip); 2469890Sandreas@sandberg.pp.se inform("\tlast_dp: 0x%x\n", xs.ctrl64.fpu_dp); 2479890Sandreas@sandberg.pp.se inform("\tmxcsr_mask: 0x%x\n", xs.mxcsr_mask); 2489890Sandreas@sandberg.pp.se} 2499890Sandreas@sandberg.pp.se 2509890Sandreas@sandberg.pp.sestatic void 2519890Sandreas@sandberg.pp.sedumpFpuSpec(const struct kvm_fpu &fpu) 2529890Sandreas@sandberg.pp.se{ 2539890Sandreas@sandberg.pp.se inform("\tlast_ip: 0x%x\n", fpu.last_ip); 2549890Sandreas@sandberg.pp.se inform("\tlast_dp: 0x%x\n", fpu.last_dp); 2559890Sandreas@sandberg.pp.se} 2569890Sandreas@sandberg.pp.se 2579890Sandreas@sandberg.pp.setemplate<typename T> 2589890Sandreas@sandberg.pp.sestatic void 2599890Sandreas@sandberg.pp.sedumpFpuCommon(const T &fpu) 2609890Sandreas@sandberg.pp.se{ 2619890Sandreas@sandberg.pp.se const unsigned top((fpu.fsw >> 11) & 0x7); 2629883Sandreas@sandberg.pp.se inform("\tfcw: 0x%x\n", fpu.fcw); 2639890Sandreas@sandberg.pp.se 2649890Sandreas@sandberg.pp.se inform("\tfsw: 0x%x (top: %i, " 2659890Sandreas@sandberg.pp.se "conditions: %s%s%s%s, exceptions: %s%s%s%s%s%s %s%s%s)\n", 2669890Sandreas@sandberg.pp.se fpu.fsw, top, 2679890Sandreas@sandberg.pp.se 2689890Sandreas@sandberg.pp.se (fpu.fsw & CC0Bit) ? "C0" : "", 2699890Sandreas@sandberg.pp.se (fpu.fsw & CC1Bit) ? "C1" : "", 2709890Sandreas@sandberg.pp.se (fpu.fsw & CC2Bit) ? "C2" : "", 2719890Sandreas@sandberg.pp.se (fpu.fsw & CC3Bit) ? "C3" : "", 2729890Sandreas@sandberg.pp.se 2739890Sandreas@sandberg.pp.se (fpu.fsw & IEBit) ? "I" : "", 2749890Sandreas@sandberg.pp.se (fpu.fsw & DEBit) ? "D" : "", 2759890Sandreas@sandberg.pp.se (fpu.fsw & ZEBit) ? "Z" : "", 2769890Sandreas@sandberg.pp.se (fpu.fsw & OEBit) ? "O" : "", 2779890Sandreas@sandberg.pp.se (fpu.fsw & UEBit) ? "U" : "", 2789890Sandreas@sandberg.pp.se (fpu.fsw & PEBit) ? "P" : "", 2799890Sandreas@sandberg.pp.se 2809890Sandreas@sandberg.pp.se (fpu.fsw & StackFaultBit) ? "SF " : "", 2819890Sandreas@sandberg.pp.se (fpu.fsw & ErrSummaryBit) ? "ES " : "", 2829890Sandreas@sandberg.pp.se (fpu.fsw & BusyBit) ? "BUSY " : "" 2839890Sandreas@sandberg.pp.se ); 2849883Sandreas@sandberg.pp.se inform("\tftwx: 0x%x\n", fpu.ftwx); 2859883Sandreas@sandberg.pp.se inform("\tlast_opcode: 0x%x\n", fpu.last_opcode); 2869890Sandreas@sandberg.pp.se dumpFpuSpec(fpu); 2879883Sandreas@sandberg.pp.se inform("\tmxcsr: 0x%x\n", fpu.mxcsr); 2889883Sandreas@sandberg.pp.se inform("\tFP Stack:\n"); 2899883Sandreas@sandberg.pp.se for (int i = 0; i < 8; ++i) { 2909890Sandreas@sandberg.pp.se const unsigned reg_idx((i + top) & 0x7); 2919890Sandreas@sandberg.pp.se const bool empty(!((fpu.ftwx >> reg_idx) & 0x1)); 2929890Sandreas@sandberg.pp.se const double value(X86ISA::loadFloat80(fpu.fpr[i])); 2939883Sandreas@sandberg.pp.se char hex[33]; 2949890Sandreas@sandberg.pp.se for (int j = 0; j < 10; ++j) 2959883Sandreas@sandberg.pp.se snprintf(&hex[j*2], 3, "%.2x", fpu.fpr[i][j]); 2969890Sandreas@sandberg.pp.se inform("\t\tST%i/%i: 0x%s (%f)%s\n", i, reg_idx, 2979890Sandreas@sandberg.pp.se hex, value, empty ? " (e)" : ""); 2989883Sandreas@sandberg.pp.se } 2999883Sandreas@sandberg.pp.se inform("\tXMM registers:\n"); 3009883Sandreas@sandberg.pp.se for (int i = 0; i < 16; ++i) { 3019883Sandreas@sandberg.pp.se char hex[33]; 3029883Sandreas@sandberg.pp.se for (int j = 0; j < 16; ++j) 3039883Sandreas@sandberg.pp.se snprintf(&hex[j*2], 3, "%.2x", fpu.xmm[i][j]); 3049883Sandreas@sandberg.pp.se inform("\t\t%i: 0x%s\n", i, hex); 3059883Sandreas@sandberg.pp.se } 3069883Sandreas@sandberg.pp.se} 3079883Sandreas@sandberg.pp.se 3089883Sandreas@sandberg.pp.sestatic void 3099890Sandreas@sandberg.pp.sedumpKvm(const struct kvm_fpu &fpu) 3109890Sandreas@sandberg.pp.se{ 3119890Sandreas@sandberg.pp.se inform("FPU registers:\n"); 3129890Sandreas@sandberg.pp.se dumpFpuCommon(fpu); 3139890Sandreas@sandberg.pp.se} 3149890Sandreas@sandberg.pp.se 3159890Sandreas@sandberg.pp.sestatic void 3169890Sandreas@sandberg.pp.sedumpKvm(const struct kvm_xsave &xsave) 3179890Sandreas@sandberg.pp.se{ 3189890Sandreas@sandberg.pp.se inform("FPU registers (XSave):\n"); 3199890Sandreas@sandberg.pp.se dumpFpuCommon(*(FXSave *)xsave.region); 3209890Sandreas@sandberg.pp.se} 3219890Sandreas@sandberg.pp.se 3229890Sandreas@sandberg.pp.sestatic void 3239883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_msrs &msrs) 3249883Sandreas@sandberg.pp.se{ 3259883Sandreas@sandberg.pp.se inform("MSRs:\n"); 3269883Sandreas@sandberg.pp.se 3279883Sandreas@sandberg.pp.se for (int i = 0; i < msrs.nmsrs; ++i) { 3289883Sandreas@sandberg.pp.se const struct kvm_msr_entry &e(msrs.entries[i]); 3299883Sandreas@sandberg.pp.se 3309883Sandreas@sandberg.pp.se inform("\t0x%x: 0x%x\n", e.index, e.data); 3319883Sandreas@sandberg.pp.se } 3329883Sandreas@sandberg.pp.se} 3339883Sandreas@sandberg.pp.se 3349883Sandreas@sandberg.pp.sestatic void 3359883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_xcrs ®s) 3369883Sandreas@sandberg.pp.se{ 3379883Sandreas@sandberg.pp.se inform("KVM XCR registers:\n"); 3389883Sandreas@sandberg.pp.se 3399883Sandreas@sandberg.pp.se inform("\tFlags: 0x%x\n", regs.flags); 3409883Sandreas@sandberg.pp.se for (int i = 0; i < regs.nr_xcrs; ++i) { 3419883Sandreas@sandberg.pp.se inform("\tXCR[0x%x]: 0x%x\n", 3429883Sandreas@sandberg.pp.se regs.xcrs[i].xcr, 3439883Sandreas@sandberg.pp.se regs.xcrs[i].value); 3449883Sandreas@sandberg.pp.se } 3459883Sandreas@sandberg.pp.se} 3469883Sandreas@sandberg.pp.se 3479883Sandreas@sandberg.pp.sestatic void 3489883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_vcpu_events &events) 3499883Sandreas@sandberg.pp.se{ 3509883Sandreas@sandberg.pp.se inform("vCPU events:\n"); 3519883Sandreas@sandberg.pp.se 3529883Sandreas@sandberg.pp.se inform("\tException: [inj: %i, nr: %i, has_ec: %i, ec: %i]\n", 3539883Sandreas@sandberg.pp.se events.exception.injected, events.exception.nr, 3549883Sandreas@sandberg.pp.se events.exception.has_error_code, events.exception.error_code); 3559883Sandreas@sandberg.pp.se 3569883Sandreas@sandberg.pp.se inform("\tInterrupt: [inj: %i, nr: %i, soft: %i]\n", 3579883Sandreas@sandberg.pp.se events.interrupt.injected, events.interrupt.nr, 3589883Sandreas@sandberg.pp.se events.interrupt.soft); 3599883Sandreas@sandberg.pp.se 3609883Sandreas@sandberg.pp.se inform("\tNMI: [inj: %i, pending: %i, masked: %i]\n", 3619883Sandreas@sandberg.pp.se events.nmi.injected, events.nmi.pending, 3629883Sandreas@sandberg.pp.se events.nmi.masked); 3639883Sandreas@sandberg.pp.se 3649883Sandreas@sandberg.pp.se inform("\tSIPI vector: 0x%x\n", events.sipi_vector); 3659883Sandreas@sandberg.pp.se inform("\tFlags: 0x%x\n", events.flags); 3669883Sandreas@sandberg.pp.se} 3679883Sandreas@sandberg.pp.se 3689884Sandreas@sandberg.pp.sestatic bool 3699884Sandreas@sandberg.pp.seisCanonicalAddress(uint64_t addr) 3709884Sandreas@sandberg.pp.se{ 3719884Sandreas@sandberg.pp.se // x86-64 doesn't currently use the full 64-bit virtual address 3729884Sandreas@sandberg.pp.se // space, instead it uses signed 48 bit addresses that are 3739884Sandreas@sandberg.pp.se // sign-extended to 64 bits. Such addresses are known as 3749884Sandreas@sandberg.pp.se // "canonical". 3759884Sandreas@sandberg.pp.se uint64_t upper_half(addr & 0xffff800000000000ULL); 3769884Sandreas@sandberg.pp.se return upper_half == 0 || upper_half == 0xffff800000000000; 3779884Sandreas@sandberg.pp.se} 3789884Sandreas@sandberg.pp.se 3799884Sandreas@sandberg.pp.sestatic void 3809884Sandreas@sandberg.pp.secheckSeg(const char *name, const int idx, const struct kvm_segment &seg, 3819884Sandreas@sandberg.pp.se struct kvm_sregs sregs) 3829884Sandreas@sandberg.pp.se{ 3839884Sandreas@sandberg.pp.se // Check the register base 3849884Sandreas@sandberg.pp.se switch (idx) { 3859884Sandreas@sandberg.pp.se case MISCREG_TSL: 3869884Sandreas@sandberg.pp.se case MISCREG_TR: 3879884Sandreas@sandberg.pp.se case MISCREG_FS: 3889884Sandreas@sandberg.pp.se case MISCREG_GS: 3899884Sandreas@sandberg.pp.se if (!isCanonicalAddress(seg.base)) 3909884Sandreas@sandberg.pp.se warn("Illegal %s base: 0x%x\n", name, seg.base); 3919884Sandreas@sandberg.pp.se break; 3929884Sandreas@sandberg.pp.se 3939884Sandreas@sandberg.pp.se case MISCREG_SS: 3949884Sandreas@sandberg.pp.se case MISCREG_DS: 3959884Sandreas@sandberg.pp.se case MISCREG_ES: 3969884Sandreas@sandberg.pp.se if (seg.unusable) 3979884Sandreas@sandberg.pp.se break; 3989884Sandreas@sandberg.pp.se case MISCREG_CS: 3999884Sandreas@sandberg.pp.se if (seg.base & 0xffffffff00000000ULL) 4009884Sandreas@sandberg.pp.se warn("Illegal %s base: 0x%x\n", name, seg.base); 4019884Sandreas@sandberg.pp.se break; 4029884Sandreas@sandberg.pp.se } 4039884Sandreas@sandberg.pp.se 4049884Sandreas@sandberg.pp.se // Check the type 4059884Sandreas@sandberg.pp.se switch (idx) { 4069884Sandreas@sandberg.pp.se case MISCREG_CS: 4079884Sandreas@sandberg.pp.se switch (seg.type) { 4089884Sandreas@sandberg.pp.se case 3: 4099884Sandreas@sandberg.pp.se if (seg.dpl != 0) 4109884Sandreas@sandberg.pp.se warn("CS type is 3 but dpl != 0.\n"); 4119884Sandreas@sandberg.pp.se break; 4129884Sandreas@sandberg.pp.se case 9: 4139884Sandreas@sandberg.pp.se case 11: 4149884Sandreas@sandberg.pp.se if (seg.dpl != sregs.ss.dpl) 4159884Sandreas@sandberg.pp.se warn("CS type is %i but CS DPL != SS DPL\n", seg.type); 4169884Sandreas@sandberg.pp.se break; 4179884Sandreas@sandberg.pp.se case 13: 4189884Sandreas@sandberg.pp.se case 15: 4199884Sandreas@sandberg.pp.se if (seg.dpl > sregs.ss.dpl) 4209884Sandreas@sandberg.pp.se warn("CS type is %i but CS DPL > SS DPL\n", seg.type); 4219884Sandreas@sandberg.pp.se break; 4229884Sandreas@sandberg.pp.se default: 4239884Sandreas@sandberg.pp.se warn("Illegal CS type: %i\n", seg.type); 4249884Sandreas@sandberg.pp.se break; 4259884Sandreas@sandberg.pp.se } 4269884Sandreas@sandberg.pp.se break; 4279884Sandreas@sandberg.pp.se 4289884Sandreas@sandberg.pp.se case MISCREG_SS: 4299884Sandreas@sandberg.pp.se if (seg.unusable) 4309884Sandreas@sandberg.pp.se break; 4319884Sandreas@sandberg.pp.se switch (seg.type) { 4329884Sandreas@sandberg.pp.se case 3: 4339884Sandreas@sandberg.pp.se if (sregs.cs.type == 3 && seg.dpl != 0) 4349884Sandreas@sandberg.pp.se warn("CS type is 3, but SS DPL is != 0.\n"); 4359884Sandreas@sandberg.pp.se /* FALLTHROUGH */ 4369884Sandreas@sandberg.pp.se case 7: 4379884Sandreas@sandberg.pp.se if (!(sregs.cr0 & 1) && seg.dpl != 0) 4389884Sandreas@sandberg.pp.se warn("SS DPL is %i, but CR0 PE is 0\n", seg.dpl); 4399884Sandreas@sandberg.pp.se break; 4409884Sandreas@sandberg.pp.se default: 4419884Sandreas@sandberg.pp.se warn("Illegal SS type: %i\n", seg.type); 4429884Sandreas@sandberg.pp.se break; 4439884Sandreas@sandberg.pp.se } 4449884Sandreas@sandberg.pp.se break; 4459884Sandreas@sandberg.pp.se 4469884Sandreas@sandberg.pp.se case MISCREG_DS: 4479884Sandreas@sandberg.pp.se case MISCREG_ES: 4489884Sandreas@sandberg.pp.se case MISCREG_FS: 4499884Sandreas@sandberg.pp.se case MISCREG_GS: 4509884Sandreas@sandberg.pp.se if (seg.unusable) 4519884Sandreas@sandberg.pp.se break; 4529884Sandreas@sandberg.pp.se if (!(seg.type & 0x1) || 4539884Sandreas@sandberg.pp.se ((seg.type & 0x8) && !(seg.type & 0x2))) 4549884Sandreas@sandberg.pp.se warn("%s has an illegal type field: %i\n", name, seg.type); 4559884Sandreas@sandberg.pp.se break; 4569884Sandreas@sandberg.pp.se 4579884Sandreas@sandberg.pp.se case MISCREG_TR: 4589884Sandreas@sandberg.pp.se // TODO: We should check the CPU mode 4599884Sandreas@sandberg.pp.se if (seg.type != 3 && seg.type != 11) 4609884Sandreas@sandberg.pp.se warn("%s: Illegal segment type (%i)\n", name, seg.type); 4619884Sandreas@sandberg.pp.se break; 4629884Sandreas@sandberg.pp.se 4639884Sandreas@sandberg.pp.se case MISCREG_TSL: 4649884Sandreas@sandberg.pp.se if (seg.unusable) 4659884Sandreas@sandberg.pp.se break; 4669884Sandreas@sandberg.pp.se if (seg.type != 2) 4679884Sandreas@sandberg.pp.se warn("%s: Illegal segment type (%i)\n", name, seg.type); 4689884Sandreas@sandberg.pp.se break; 4699884Sandreas@sandberg.pp.se } 4709884Sandreas@sandberg.pp.se 4719884Sandreas@sandberg.pp.se switch (idx) { 4729884Sandreas@sandberg.pp.se case MISCREG_SS: 4739884Sandreas@sandberg.pp.se case MISCREG_DS: 4749884Sandreas@sandberg.pp.se case MISCREG_ES: 4759884Sandreas@sandberg.pp.se case MISCREG_FS: 4769884Sandreas@sandberg.pp.se case MISCREG_GS: 4779884Sandreas@sandberg.pp.se if (seg.unusable) 4789884Sandreas@sandberg.pp.se break; 4799884Sandreas@sandberg.pp.se case MISCREG_CS: 4809884Sandreas@sandberg.pp.se if (!seg.s) 4819884Sandreas@sandberg.pp.se warn("%s: S flag not set\n", name); 4829884Sandreas@sandberg.pp.se break; 4839884Sandreas@sandberg.pp.se 4849884Sandreas@sandberg.pp.se case MISCREG_TSL: 4859884Sandreas@sandberg.pp.se if (seg.unusable) 4869884Sandreas@sandberg.pp.se break; 4879884Sandreas@sandberg.pp.se case MISCREG_TR: 4889884Sandreas@sandberg.pp.se if (seg.s) 4899884Sandreas@sandberg.pp.se warn("%s: S flag is set\n", name); 4909884Sandreas@sandberg.pp.se break; 4919884Sandreas@sandberg.pp.se } 4929884Sandreas@sandberg.pp.se 4939884Sandreas@sandberg.pp.se switch (idx) { 4949884Sandreas@sandberg.pp.se case MISCREG_SS: 4959884Sandreas@sandberg.pp.se case MISCREG_DS: 4969884Sandreas@sandberg.pp.se case MISCREG_ES: 4979884Sandreas@sandberg.pp.se case MISCREG_FS: 4989884Sandreas@sandberg.pp.se case MISCREG_GS: 4999884Sandreas@sandberg.pp.se case MISCREG_TSL: 5009884Sandreas@sandberg.pp.se if (seg.unusable) 5019884Sandreas@sandberg.pp.se break; 5029884Sandreas@sandberg.pp.se case MISCREG_TR: 5039884Sandreas@sandberg.pp.se case MISCREG_CS: 5049884Sandreas@sandberg.pp.se if (!seg.present) 5059884Sandreas@sandberg.pp.se warn("%s: P flag not set\n", name); 5069884Sandreas@sandberg.pp.se 5079884Sandreas@sandberg.pp.se if (((seg.limit & 0xFFF) == 0 && seg.g) || 5089884Sandreas@sandberg.pp.se ((seg.limit & 0xFFF00000) != 0 && !seg.g)) { 5099884Sandreas@sandberg.pp.se warn("%s limit (0x%x) and g (%i) combination is illegal.\n", 5109884Sandreas@sandberg.pp.se name, seg.limit, seg.g); 5119884Sandreas@sandberg.pp.se } 5129884Sandreas@sandberg.pp.se break; 5139884Sandreas@sandberg.pp.se } 5149884Sandreas@sandberg.pp.se 5159884Sandreas@sandberg.pp.se // TODO: Check CS DB 5169884Sandreas@sandberg.pp.se} 5179884Sandreas@sandberg.pp.se 5189883Sandreas@sandberg.pp.seX86KvmCPU::X86KvmCPU(X86KvmCPUParams *params) 5199890Sandreas@sandberg.pp.se : BaseKvmCPU(params), 5209890Sandreas@sandberg.pp.se useXSave(params->useXSave) 5219883Sandreas@sandberg.pp.se{ 5229883Sandreas@sandberg.pp.se Kvm &kvm(vm.kvm); 5239883Sandreas@sandberg.pp.se 5249883Sandreas@sandberg.pp.se if (!kvm.capSetTSSAddress()) 5259883Sandreas@sandberg.pp.se panic("KVM: Missing capability (KVM_CAP_SET_TSS_ADDR)\n"); 5269883Sandreas@sandberg.pp.se if (!kvm.capExtendedCPUID()) 5279883Sandreas@sandberg.pp.se panic("KVM: Missing capability (KVM_CAP_EXT_CPUID)\n"); 5289883Sandreas@sandberg.pp.se if (!kvm.capUserNMI()) 5299883Sandreas@sandberg.pp.se warn("KVM: Missing capability (KVM_CAP_USER_NMI)\n"); 5309883Sandreas@sandberg.pp.se if (!kvm.capVCPUEvents()) 5319883Sandreas@sandberg.pp.se warn("KVM: Missing capability (KVM_CAP_VCPU_EVENTS)\n"); 5329883Sandreas@sandberg.pp.se 5339883Sandreas@sandberg.pp.se haveDebugRegs = kvm.capDebugRegs(); 5349883Sandreas@sandberg.pp.se haveXSave = kvm.capXSave(); 5359883Sandreas@sandberg.pp.se haveXCRs = kvm.capXCRs(); 5369890Sandreas@sandberg.pp.se 5379890Sandreas@sandberg.pp.se if (useXSave && !haveXSave) { 5389890Sandreas@sandberg.pp.se warn("KVM: XSAVE not supported by host. MXCSR synchronization might be " 5399890Sandreas@sandberg.pp.se "unreliable due to kernel bugs.\n"); 5409890Sandreas@sandberg.pp.se useXSave = false; 5419890Sandreas@sandberg.pp.se } else if (!useXSave) { 5429890Sandreas@sandberg.pp.se warn("KVM: XSave FPU/SIMD synchronization disabled by user.\n"); 5439890Sandreas@sandberg.pp.se } 5449883Sandreas@sandberg.pp.se} 5459883Sandreas@sandberg.pp.se 5469883Sandreas@sandberg.pp.seX86KvmCPU::~X86KvmCPU() 5479883Sandreas@sandberg.pp.se{ 5489883Sandreas@sandberg.pp.se} 5499883Sandreas@sandberg.pp.se 5509883Sandreas@sandberg.pp.sevoid 5519883Sandreas@sandberg.pp.seX86KvmCPU::startup() 5529883Sandreas@sandberg.pp.se{ 5539883Sandreas@sandberg.pp.se BaseKvmCPU::startup(); 5549883Sandreas@sandberg.pp.se 5559883Sandreas@sandberg.pp.se updateCPUID(); 5569883Sandreas@sandberg.pp.se 5579883Sandreas@sandberg.pp.se // TODO: Do we need to create an identity mapped TSS area? We 5589883Sandreas@sandberg.pp.se // should call kvm.vm.setTSSAddress() here in that case. It should 5599883Sandreas@sandberg.pp.se // only be needed for old versions of the virtualization 5609883Sandreas@sandberg.pp.se // extensions. We should make sure that the identity range is 5619883Sandreas@sandberg.pp.se // reserved in the e820 memory map in that case. 5629883Sandreas@sandberg.pp.se} 5639883Sandreas@sandberg.pp.se 5649883Sandreas@sandberg.pp.sevoid 5659883Sandreas@sandberg.pp.seX86KvmCPU::dump() 5669883Sandreas@sandberg.pp.se{ 5679883Sandreas@sandberg.pp.se dumpIntRegs(); 5689890Sandreas@sandberg.pp.se if (useXSave) 5699890Sandreas@sandberg.pp.se dumpXSave(); 5709890Sandreas@sandberg.pp.se else 5719890Sandreas@sandberg.pp.se dumpFpuRegs(); 5729883Sandreas@sandberg.pp.se dumpSpecRegs(); 5739883Sandreas@sandberg.pp.se dumpDebugRegs(); 5749883Sandreas@sandberg.pp.se dumpXCRs(); 5759883Sandreas@sandberg.pp.se dumpVCpuEvents(); 5769883Sandreas@sandberg.pp.se dumpMSRs(); 5779883Sandreas@sandberg.pp.se} 5789883Sandreas@sandberg.pp.se 5799883Sandreas@sandberg.pp.sevoid 5809883Sandreas@sandberg.pp.seX86KvmCPU::dumpFpuRegs() const 5819883Sandreas@sandberg.pp.se{ 5829883Sandreas@sandberg.pp.se struct kvm_fpu fpu; 5839883Sandreas@sandberg.pp.se getFPUState(fpu); 5849883Sandreas@sandberg.pp.se dumpKvm(fpu); 5859883Sandreas@sandberg.pp.se} 5869883Sandreas@sandberg.pp.se 5879883Sandreas@sandberg.pp.sevoid 5889883Sandreas@sandberg.pp.seX86KvmCPU::dumpIntRegs() const 5899883Sandreas@sandberg.pp.se{ 5909883Sandreas@sandberg.pp.se struct kvm_regs regs; 5919883Sandreas@sandberg.pp.se getRegisters(regs); 5929883Sandreas@sandberg.pp.se dumpKvm(regs); 5939883Sandreas@sandberg.pp.se} 5949883Sandreas@sandberg.pp.se 5959883Sandreas@sandberg.pp.sevoid 5969883Sandreas@sandberg.pp.seX86KvmCPU::dumpSpecRegs() const 5979883Sandreas@sandberg.pp.se{ 5989883Sandreas@sandberg.pp.se struct kvm_sregs sregs; 5999883Sandreas@sandberg.pp.se getSpecialRegisters(sregs); 6009883Sandreas@sandberg.pp.se dumpKvm(sregs); 6019883Sandreas@sandberg.pp.se} 6029883Sandreas@sandberg.pp.se 6039883Sandreas@sandberg.pp.sevoid 6049883Sandreas@sandberg.pp.seX86KvmCPU::dumpDebugRegs() const 6059883Sandreas@sandberg.pp.se{ 6069883Sandreas@sandberg.pp.se if (haveDebugRegs) { 6079883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS 6089883Sandreas@sandberg.pp.se struct kvm_debugregs dregs; 6099883Sandreas@sandberg.pp.se getDebugRegisters(dregs); 6109883Sandreas@sandberg.pp.se dumpKvm(dregs); 6119883Sandreas@sandberg.pp.se#endif 6129883Sandreas@sandberg.pp.se } else { 6139883Sandreas@sandberg.pp.se inform("Debug registers not supported by kernel.\n"); 6149883Sandreas@sandberg.pp.se } 6159883Sandreas@sandberg.pp.se} 6169883Sandreas@sandberg.pp.se 6179883Sandreas@sandberg.pp.sevoid 6189883Sandreas@sandberg.pp.seX86KvmCPU::dumpXCRs() const 6199883Sandreas@sandberg.pp.se{ 6209883Sandreas@sandberg.pp.se if (haveXCRs) { 6219883Sandreas@sandberg.pp.se struct kvm_xcrs xcrs; 6229883Sandreas@sandberg.pp.se getXCRs(xcrs); 6239883Sandreas@sandberg.pp.se dumpKvm(xcrs); 6249883Sandreas@sandberg.pp.se } else { 6259883Sandreas@sandberg.pp.se inform("XCRs not supported by kernel.\n"); 6269883Sandreas@sandberg.pp.se } 6279883Sandreas@sandberg.pp.se} 6289883Sandreas@sandberg.pp.se 6299883Sandreas@sandberg.pp.sevoid 6309883Sandreas@sandberg.pp.seX86KvmCPU::dumpXSave() const 6319883Sandreas@sandberg.pp.se{ 6329883Sandreas@sandberg.pp.se if (haveXSave) { 6339883Sandreas@sandberg.pp.se struct kvm_xsave xsave; 6349883Sandreas@sandberg.pp.se getXSave(xsave); 6359883Sandreas@sandberg.pp.se dumpKvm(xsave); 6369883Sandreas@sandberg.pp.se } else { 6379883Sandreas@sandberg.pp.se inform("XSave not supported by kernel.\n"); 6389883Sandreas@sandberg.pp.se } 6399883Sandreas@sandberg.pp.se} 6409883Sandreas@sandberg.pp.se 6419883Sandreas@sandberg.pp.sevoid 6429883Sandreas@sandberg.pp.seX86KvmCPU::dumpVCpuEvents() const 6439883Sandreas@sandberg.pp.se{ 6449883Sandreas@sandberg.pp.se struct kvm_vcpu_events events; 6459883Sandreas@sandberg.pp.se getVCpuEvents(events); 6469883Sandreas@sandberg.pp.se dumpKvm(events); 6479883Sandreas@sandberg.pp.se} 6489883Sandreas@sandberg.pp.se 6499883Sandreas@sandberg.pp.sevoid 6509883Sandreas@sandberg.pp.seX86KvmCPU::dumpMSRs() const 6519883Sandreas@sandberg.pp.se{ 6529883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &supported_msrs(vm.kvm.getSupportedMSRs()); 6539883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> msrs( 6549883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>( 6559883Sandreas@sandberg.pp.se supported_msrs.size())); 6569883Sandreas@sandberg.pp.se 6579883Sandreas@sandberg.pp.se msrs->nmsrs = supported_msrs.size(); 6589883Sandreas@sandberg.pp.se for (int i = 0; i < supported_msrs.size(); ++i) { 6599883Sandreas@sandberg.pp.se struct kvm_msr_entry &e(msrs->entries[i]); 6609883Sandreas@sandberg.pp.se e.index = supported_msrs[i]; 6619883Sandreas@sandberg.pp.se e.reserved = 0; 6629883Sandreas@sandberg.pp.se e.data = 0; 6639883Sandreas@sandberg.pp.se } 6649883Sandreas@sandberg.pp.se getMSRs(*msrs.get()); 6659883Sandreas@sandberg.pp.se 6669883Sandreas@sandberg.pp.se dumpKvm(*msrs.get()); 6679883Sandreas@sandberg.pp.se} 6689883Sandreas@sandberg.pp.se 6699883Sandreas@sandberg.pp.sevoid 6709883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmState() 6719883Sandreas@sandberg.pp.se{ 6729883Sandreas@sandberg.pp.se updateKvmStateRegs(); 6739883Sandreas@sandberg.pp.se updateKvmStateSRegs(); 6749883Sandreas@sandberg.pp.se updateKvmStateFPU(); 6759883Sandreas@sandberg.pp.se updateKvmStateMSRs(); 6769883Sandreas@sandberg.pp.se 6779883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "X86KvmCPU::updateKvmState():\n"); 6789883Sandreas@sandberg.pp.se if (DTRACE(KvmContext)) 6799883Sandreas@sandberg.pp.se dump(); 6809883Sandreas@sandberg.pp.se} 6819883Sandreas@sandberg.pp.se 6829883Sandreas@sandberg.pp.sevoid 6839883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateRegs() 6849883Sandreas@sandberg.pp.se{ 6859883Sandreas@sandberg.pp.se struct kvm_regs regs; 6869883Sandreas@sandberg.pp.se 6879883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) regs.kreg = tc->readIntReg(mreg) 6889883Sandreas@sandberg.pp.se FOREACH_IREG(); 6899883Sandreas@sandberg.pp.se#undef APPLY_IREG 6909883Sandreas@sandberg.pp.se 69110113Sandreas@sandberg.pp.se regs.rip = tc->instAddr() - tc->readMiscReg(MISCREG_CS_BASE); 6929883Sandreas@sandberg.pp.se 6939883Sandreas@sandberg.pp.se /* You might think that setting regs.rflags to the contents 6949883Sandreas@sandberg.pp.se * MISCREG_RFLAGS here would suffice. In that case you're 6959883Sandreas@sandberg.pp.se * mistaken. We need to reconstruct it from a bunch of ucode 6969883Sandreas@sandberg.pp.se * registers and wave a dead chicken over it (aka mask out and set 6979883Sandreas@sandberg.pp.se * reserved bits) to get it to work. 6989883Sandreas@sandberg.pp.se */ 6999883Sandreas@sandberg.pp.se regs.rflags = X86ISA::getRFlags(tc); 7009883Sandreas@sandberg.pp.se 7019883Sandreas@sandberg.pp.se setRegisters(regs); 7029883Sandreas@sandberg.pp.se} 7039883Sandreas@sandberg.pp.se 7049883Sandreas@sandberg.pp.sestatic inline void 7059883Sandreas@sandberg.pp.sesetKvmSegmentReg(ThreadContext *tc, struct kvm_segment &kvm_seg, 7069883Sandreas@sandberg.pp.se const int index) 7079883Sandreas@sandberg.pp.se{ 7089883Sandreas@sandberg.pp.se SegAttr attr(tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(index))); 7099883Sandreas@sandberg.pp.se 7109883Sandreas@sandberg.pp.se kvm_seg.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index)); 7119883Sandreas@sandberg.pp.se kvm_seg.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index)); 7129883Sandreas@sandberg.pp.se kvm_seg.selector = tc->readMiscRegNoEffect(MISCREG_SEG_SEL(index)); 7139883Sandreas@sandberg.pp.se kvm_seg.type = attr.type; 7149883Sandreas@sandberg.pp.se kvm_seg.present = attr.present; 7159883Sandreas@sandberg.pp.se kvm_seg.dpl = attr.dpl; 7169883Sandreas@sandberg.pp.se kvm_seg.db = attr.defaultSize; 7179883Sandreas@sandberg.pp.se kvm_seg.s = attr.system; 7189883Sandreas@sandberg.pp.se kvm_seg.l = attr.longMode; 7199883Sandreas@sandberg.pp.se kvm_seg.g = attr.granularity; 7209883Sandreas@sandberg.pp.se kvm_seg.avl = attr.avl; 7219883Sandreas@sandberg.pp.se 72210099Sandreas@sandberg.pp.se // A segment is normally unusable when the selector is zero. There 72310099Sandreas@sandberg.pp.se // is a attr.unusable flag in gem5, but it seems unused. qemu 72410099Sandreas@sandberg.pp.se // seems to set this to 0 all the time, so we just do the same and 72510099Sandreas@sandberg.pp.se // hope for the best. 72610099Sandreas@sandberg.pp.se kvm_seg.unusable = 0; 7279883Sandreas@sandberg.pp.se} 7289883Sandreas@sandberg.pp.se 7299883Sandreas@sandberg.pp.sestatic inline void 7309883Sandreas@sandberg.pp.sesetKvmDTableReg(ThreadContext *tc, struct kvm_dtable &kvm_dtable, 7319883Sandreas@sandberg.pp.se const int index) 7329883Sandreas@sandberg.pp.se{ 7339883Sandreas@sandberg.pp.se kvm_dtable.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index)); 7349883Sandreas@sandberg.pp.se kvm_dtable.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index)); 7359883Sandreas@sandberg.pp.se} 7369883Sandreas@sandberg.pp.se 7379886Sandreas@sandberg.pp.sestatic void 7389886Sandreas@sandberg.pp.seforceSegAccessed(struct kvm_segment &seg) 7399886Sandreas@sandberg.pp.se{ 7409886Sandreas@sandberg.pp.se // Intel's VMX requires that (some) usable segments are flagged as 7419886Sandreas@sandberg.pp.se // 'accessed' (i.e., the lowest bit in the segment type is set) 7429886Sandreas@sandberg.pp.se // when entering VMX. This wouldn't necessary be the case even if 7439886Sandreas@sandberg.pp.se // gem5 did set the access bits correctly, so we force it to one 7449886Sandreas@sandberg.pp.se // in that case. 7459886Sandreas@sandberg.pp.se if (!seg.unusable) 7469886Sandreas@sandberg.pp.se seg.type |= SEG_TYPE_BIT_ACCESSED; 7479886Sandreas@sandberg.pp.se} 7489886Sandreas@sandberg.pp.se 7499883Sandreas@sandberg.pp.sevoid 7509883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateSRegs() 7519883Sandreas@sandberg.pp.se{ 7529883Sandreas@sandberg.pp.se struct kvm_sregs sregs; 7539883Sandreas@sandberg.pp.se 7549883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) sregs.kreg = tc->readMiscRegNoEffect(mreg) 7559883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setKvmSegmentReg(tc, sregs.kreg, idx) 7569883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setKvmDTableReg(tc, sregs.kreg, idx) 7579883Sandreas@sandberg.pp.se 7589883Sandreas@sandberg.pp.se FOREACH_SREG(); 7599883Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 7609883Sandreas@sandberg.pp.se FOREACH_DTABLE(); 7619883Sandreas@sandberg.pp.se 7629883Sandreas@sandberg.pp.se#undef APPLY_SREG 7639883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 7649883Sandreas@sandberg.pp.se#undef APPLY_DTABLE 7659883Sandreas@sandberg.pp.se 7669883Sandreas@sandberg.pp.se // Clear the interrupt bitmap 7679883Sandreas@sandberg.pp.se memset(&sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap)); 7689883Sandreas@sandberg.pp.se 7699886Sandreas@sandberg.pp.se // VMX requires CS, SS, DS, ES, FS, and GS to have the accessed 7709886Sandreas@sandberg.pp.se // bit in the type field set. 7719886Sandreas@sandberg.pp.se forceSegAccessed(sregs.cs); 7729886Sandreas@sandberg.pp.se forceSegAccessed(sregs.ss); 7739886Sandreas@sandberg.pp.se forceSegAccessed(sregs.ds); 7749886Sandreas@sandberg.pp.se forceSegAccessed(sregs.es); 7759886Sandreas@sandberg.pp.se forceSegAccessed(sregs.fs); 7769886Sandreas@sandberg.pp.se forceSegAccessed(sregs.gs); 7779886Sandreas@sandberg.pp.se 7789886Sandreas@sandberg.pp.se // There are currently some cases where the active task isn't 7799886Sandreas@sandberg.pp.se // marked as busy. This is illegal in VMX, so we force it to busy. 7809886Sandreas@sandberg.pp.se if (sregs.tr.type == SEG_SYS_TYPE_TSS_AVAILABLE) { 7819886Sandreas@sandberg.pp.se hack("tr.type (%i) is not busy. Forcing the busy bit.\n", 7829886Sandreas@sandberg.pp.se sregs.tr.type); 7839886Sandreas@sandberg.pp.se sregs.tr.type = SEG_SYS_TYPE_TSS_BUSY; 7849886Sandreas@sandberg.pp.se } 7859886Sandreas@sandberg.pp.se 7869886Sandreas@sandberg.pp.se // VMX requires the DPL of SS and CS to be the same for 7879886Sandreas@sandberg.pp.se // non-conforming code segments. It seems like m5 doesn't set the 7889886Sandreas@sandberg.pp.se // DPL of SS correctly when taking interrupts, so we need to fix 7899886Sandreas@sandberg.pp.se // that here. 7909886Sandreas@sandberg.pp.se if ((sregs.cs.type == SEG_CS_TYPE_ACCESSED || 7919886Sandreas@sandberg.pp.se sregs.cs.type == SEG_CS_TYPE_READ_ACCESSED) && 7929886Sandreas@sandberg.pp.se sregs.cs.dpl != sregs.ss.dpl) { 7939886Sandreas@sandberg.pp.se 7949886Sandreas@sandberg.pp.se hack("CS.DPL (%i) != SS.DPL (%i): Forcing SS.DPL to %i\n", 7959886Sandreas@sandberg.pp.se sregs.cs.dpl, sregs.ss.dpl, sregs.cs.dpl); 7969886Sandreas@sandberg.pp.se sregs.ss.dpl = sregs.cs.dpl; 7979886Sandreas@sandberg.pp.se } 7989886Sandreas@sandberg.pp.se 7999886Sandreas@sandberg.pp.se // Do checks after fixing up the state to avoid getting excessive 8009886Sandreas@sandberg.pp.se // amounts of warnings. 8019884Sandreas@sandberg.pp.se RFLAGS rflags_nocc(tc->readMiscReg(MISCREG_RFLAGS)); 8029884Sandreas@sandberg.pp.se if (!rflags_nocc.vm) { 8039884Sandreas@sandberg.pp.se // Do segment verification if the CPU isn't entering virtual 8049884Sandreas@sandberg.pp.se // 8086 mode. We currently assume that unrestricted guest 8059884Sandreas@sandberg.pp.se // mode is available. 8069884Sandreas@sandberg.pp.se 8079884Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) \ 8089884Sandreas@sandberg.pp.se checkSeg(# kreg, idx + MISCREG_SEG_SEL_BASE, sregs.kreg, sregs) 8099884Sandreas@sandberg.pp.se 8109884Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 8119884Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 8129884Sandreas@sandberg.pp.se } 8139886Sandreas@sandberg.pp.se 8149883Sandreas@sandberg.pp.se setSpecialRegisters(sregs); 8159883Sandreas@sandberg.pp.se} 8169890Sandreas@sandberg.pp.se 8179890Sandreas@sandberg.pp.setemplate <typename T> 8189890Sandreas@sandberg.pp.sestatic void 8199890Sandreas@sandberg.pp.seupdateKvmStateFPUCommon(ThreadContext *tc, T &fpu) 8209890Sandreas@sandberg.pp.se{ 8219890Sandreas@sandberg.pp.se static_assert(sizeof(X86ISA::FloatRegBits) == 8, 8229890Sandreas@sandberg.pp.se "Unexpected size of X86ISA::FloatRegBits"); 8239890Sandreas@sandberg.pp.se 8249890Sandreas@sandberg.pp.se fpu.mxcsr = tc->readMiscRegNoEffect(MISCREG_MXCSR); 8259890Sandreas@sandberg.pp.se fpu.fcw = tc->readMiscRegNoEffect(MISCREG_FCW); 8269890Sandreas@sandberg.pp.se // No need to rebuild from MISCREG_FSW and MISCREG_TOP if we read 8279890Sandreas@sandberg.pp.se // with effects. 8289890Sandreas@sandberg.pp.se fpu.fsw = tc->readMiscReg(MISCREG_FSW); 8299890Sandreas@sandberg.pp.se 8309890Sandreas@sandberg.pp.se uint64_t ftw(tc->readMiscRegNoEffect(MISCREG_FTW)); 8319890Sandreas@sandberg.pp.se fpu.ftwx = X86ISA::convX87TagsToXTags(ftw); 8329890Sandreas@sandberg.pp.se 8339890Sandreas@sandberg.pp.se fpu.last_opcode = tc->readMiscRegNoEffect(MISCREG_FOP); 8349890Sandreas@sandberg.pp.se 8359890Sandreas@sandberg.pp.se const unsigned top((fpu.fsw >> 11) & 0x7); 8369890Sandreas@sandberg.pp.se for (int i = 0; i < 8; ++i) { 8379890Sandreas@sandberg.pp.se const unsigned reg_idx((i + top) & 0x7); 8389890Sandreas@sandberg.pp.se const double value(tc->readFloatReg(FLOATREG_FPR(reg_idx))); 8399890Sandreas@sandberg.pp.se DPRINTF(KvmContext, "Setting KVM FP reg %i (st[%i]) := %f\n", 8409890Sandreas@sandberg.pp.se reg_idx, i, value); 8419890Sandreas@sandberg.pp.se X86ISA::storeFloat80(fpu.fpr[i], value); 8429890Sandreas@sandberg.pp.se } 8439890Sandreas@sandberg.pp.se 8449890Sandreas@sandberg.pp.se // TODO: We should update the MMX state 8459890Sandreas@sandberg.pp.se 8469890Sandreas@sandberg.pp.se for (int i = 0; i < 16; ++i) { 8479890Sandreas@sandberg.pp.se *(X86ISA::FloatRegBits *)&fpu.xmm[i][0] = 8489890Sandreas@sandberg.pp.se tc->readFloatRegBits(FLOATREG_XMM_LOW(i)); 8499890Sandreas@sandberg.pp.se *(X86ISA::FloatRegBits *)&fpu.xmm[i][8] = 8509890Sandreas@sandberg.pp.se tc->readFloatRegBits(FLOATREG_XMM_HIGH(i)); 8519890Sandreas@sandberg.pp.se } 8529890Sandreas@sandberg.pp.se} 8539890Sandreas@sandberg.pp.se 8549890Sandreas@sandberg.pp.sevoid 8559890Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPULegacy() 8569890Sandreas@sandberg.pp.se{ 8579890Sandreas@sandberg.pp.se struct kvm_fpu fpu; 8589890Sandreas@sandberg.pp.se 8599890Sandreas@sandberg.pp.se // There is some padding in the FP registers, so we'd better zero 8609890Sandreas@sandberg.pp.se // the whole struct. 8619890Sandreas@sandberg.pp.se memset(&fpu, 0, sizeof(fpu)); 8629890Sandreas@sandberg.pp.se 8639890Sandreas@sandberg.pp.se updateKvmStateFPUCommon(tc, fpu); 8649890Sandreas@sandberg.pp.se 8659890Sandreas@sandberg.pp.se if (tc->readMiscRegNoEffect(MISCREG_FISEG)) 8669890Sandreas@sandberg.pp.se warn_once("MISCREG_FISEG is non-zero.\n"); 8679890Sandreas@sandberg.pp.se 8689890Sandreas@sandberg.pp.se fpu.last_ip = tc->readMiscRegNoEffect(MISCREG_FIOFF); 8699890Sandreas@sandberg.pp.se 8709890Sandreas@sandberg.pp.se if (tc->readMiscRegNoEffect(MISCREG_FOSEG)) 8719890Sandreas@sandberg.pp.se warn_once("MISCREG_FOSEG is non-zero.\n"); 8729890Sandreas@sandberg.pp.se 8739890Sandreas@sandberg.pp.se fpu.last_dp = tc->readMiscRegNoEffect(MISCREG_FOOFF); 8749890Sandreas@sandberg.pp.se 8759890Sandreas@sandberg.pp.se setFPUState(fpu); 8769890Sandreas@sandberg.pp.se} 8779890Sandreas@sandberg.pp.se 8789890Sandreas@sandberg.pp.sevoid 8799890Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPUXSave() 8809890Sandreas@sandberg.pp.se{ 8819890Sandreas@sandberg.pp.se struct kvm_xsave kxsave; 8829890Sandreas@sandberg.pp.se FXSave &xsave(*(FXSave *)kxsave.region); 8839890Sandreas@sandberg.pp.se 8849890Sandreas@sandberg.pp.se // There is some padding and reserved fields in the structure, so 8859890Sandreas@sandberg.pp.se // we'd better zero the whole thing. 8869890Sandreas@sandberg.pp.se memset(&kxsave, 0, sizeof(kxsave)); 8879890Sandreas@sandberg.pp.se 8889890Sandreas@sandberg.pp.se updateKvmStateFPUCommon(tc, xsave); 8899890Sandreas@sandberg.pp.se 8909890Sandreas@sandberg.pp.se if (tc->readMiscRegNoEffect(MISCREG_FISEG)) 8919890Sandreas@sandberg.pp.se warn_once("MISCREG_FISEG is non-zero.\n"); 8929890Sandreas@sandberg.pp.se 8939890Sandreas@sandberg.pp.se xsave.ctrl64.fpu_ip = tc->readMiscRegNoEffect(MISCREG_FIOFF); 8949890Sandreas@sandberg.pp.se 8959890Sandreas@sandberg.pp.se if (tc->readMiscRegNoEffect(MISCREG_FOSEG)) 8969890Sandreas@sandberg.pp.se warn_once("MISCREG_FOSEG is non-zero.\n"); 8979890Sandreas@sandberg.pp.se 8989890Sandreas@sandberg.pp.se xsave.ctrl64.fpu_dp = tc->readMiscRegNoEffect(MISCREG_FOOFF); 8999890Sandreas@sandberg.pp.se 9009890Sandreas@sandberg.pp.se setXSave(kxsave); 9019890Sandreas@sandberg.pp.se} 9029890Sandreas@sandberg.pp.se 9039883Sandreas@sandberg.pp.sevoid 9049883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPU() 9059883Sandreas@sandberg.pp.se{ 9069890Sandreas@sandberg.pp.se if (useXSave) 9079890Sandreas@sandberg.pp.se updateKvmStateFPUXSave(); 9089890Sandreas@sandberg.pp.se else 9099890Sandreas@sandberg.pp.se updateKvmStateFPULegacy(); 9109883Sandreas@sandberg.pp.se} 9119883Sandreas@sandberg.pp.se 9129883Sandreas@sandberg.pp.sevoid 9139883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateMSRs() 9149883Sandreas@sandberg.pp.se{ 9159883Sandreas@sandberg.pp.se KvmMSRVector msrs; 9169883Sandreas@sandberg.pp.se 9179883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &indices(getMsrIntersection()); 9189883Sandreas@sandberg.pp.se 9199883Sandreas@sandberg.pp.se for (auto it = indices.cbegin(); it != indices.cend(); ++it) { 9209883Sandreas@sandberg.pp.se struct kvm_msr_entry e; 9219883Sandreas@sandberg.pp.se 9229883Sandreas@sandberg.pp.se e.index = *it; 9239883Sandreas@sandberg.pp.se e.reserved = 0; 9249883Sandreas@sandberg.pp.se e.data = tc->readMiscReg(msrMap.at(*it)); 9259883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "Adding MSR: idx: 0x%x, data: 0x%x\n", 9269883Sandreas@sandberg.pp.se e.index, e.data); 9279883Sandreas@sandberg.pp.se 9289883Sandreas@sandberg.pp.se msrs.push_back(e); 9299883Sandreas@sandberg.pp.se } 9309883Sandreas@sandberg.pp.se 9319883Sandreas@sandberg.pp.se setMSRs(msrs); 9329883Sandreas@sandberg.pp.se} 9339883Sandreas@sandberg.pp.se 9349883Sandreas@sandberg.pp.sevoid 9359883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContext() 9369883Sandreas@sandberg.pp.se{ 93710113Sandreas@sandberg.pp.se struct kvm_regs regs; 93810113Sandreas@sandberg.pp.se struct kvm_sregs sregs; 93910113Sandreas@sandberg.pp.se 94010113Sandreas@sandberg.pp.se getRegisters(regs); 94110113Sandreas@sandberg.pp.se getSpecialRegisters(sregs); 94210113Sandreas@sandberg.pp.se 9439883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "X86KvmCPU::updateThreadContext():\n"); 9449883Sandreas@sandberg.pp.se if (DTRACE(KvmContext)) 9459883Sandreas@sandberg.pp.se dump(); 9469883Sandreas@sandberg.pp.se 94710113Sandreas@sandberg.pp.se updateThreadContextRegs(regs, sregs); 94810113Sandreas@sandberg.pp.se updateThreadContextSRegs(sregs); 94910113Sandreas@sandberg.pp.se if (useXSave) { 95010113Sandreas@sandberg.pp.se struct kvm_xsave xsave; 95110113Sandreas@sandberg.pp.se getXSave(xsave); 95210113Sandreas@sandberg.pp.se 95310113Sandreas@sandberg.pp.se updateThreadContextXSave(xsave); 95410113Sandreas@sandberg.pp.se } else { 95510113Sandreas@sandberg.pp.se struct kvm_fpu fpu; 95610113Sandreas@sandberg.pp.se getFPUState(fpu); 95710113Sandreas@sandberg.pp.se 95810113Sandreas@sandberg.pp.se updateThreadContextFPU(fpu); 95910113Sandreas@sandberg.pp.se } 9609883Sandreas@sandberg.pp.se updateThreadContextMSRs(); 9619883Sandreas@sandberg.pp.se 9629883Sandreas@sandberg.pp.se // The M5 misc reg caches some values from other 9639883Sandreas@sandberg.pp.se // registers. Writing to it with side effects causes it to be 9649883Sandreas@sandberg.pp.se // updated from its source registers. 9659883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_M5_REG, 0); 9669883Sandreas@sandberg.pp.se} 9679883Sandreas@sandberg.pp.se 9689883Sandreas@sandberg.pp.sevoid 96910113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextRegs(const struct kvm_regs ®s, 97010113Sandreas@sandberg.pp.se const struct kvm_sregs &sregs) 9719883Sandreas@sandberg.pp.se{ 9729883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg) 9739883Sandreas@sandberg.pp.se 9749883Sandreas@sandberg.pp.se FOREACH_IREG(); 9759883Sandreas@sandberg.pp.se 9769883Sandreas@sandberg.pp.se#undef APPLY_IREG 9779883Sandreas@sandberg.pp.se 97810113Sandreas@sandberg.pp.se tc->pcState(PCState(regs.rip + sregs.cs.base)); 9799883Sandreas@sandberg.pp.se 9809883Sandreas@sandberg.pp.se // Flags are spread out across multiple semi-magic registers so we 9819883Sandreas@sandberg.pp.se // need some special care when updating them. 9829883Sandreas@sandberg.pp.se X86ISA::setRFlags(tc, regs.rflags); 9839883Sandreas@sandberg.pp.se} 9849883Sandreas@sandberg.pp.se 9859883Sandreas@sandberg.pp.se 9869883Sandreas@sandberg.pp.seinline void 9879883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_segment &kvm_seg, 9889883Sandreas@sandberg.pp.se const int index) 9899883Sandreas@sandberg.pp.se{ 9909883Sandreas@sandberg.pp.se SegAttr attr(0); 9919883Sandreas@sandberg.pp.se 9929883Sandreas@sandberg.pp.se attr.type = kvm_seg.type; 9939883Sandreas@sandberg.pp.se attr.present = kvm_seg.present; 9949883Sandreas@sandberg.pp.se attr.dpl = kvm_seg.dpl; 9959883Sandreas@sandberg.pp.se attr.defaultSize = kvm_seg.db; 9969883Sandreas@sandberg.pp.se attr.system = kvm_seg.s; 9979883Sandreas@sandberg.pp.se attr.longMode = kvm_seg.l; 9989883Sandreas@sandberg.pp.se attr.granularity = kvm_seg.g; 9999883Sandreas@sandberg.pp.se attr.avl = kvm_seg.avl; 10009883Sandreas@sandberg.pp.se attr.unusable = kvm_seg.unusable; 10019883Sandreas@sandberg.pp.se 10029883Sandreas@sandberg.pp.se // We need some setMiscReg magic here to keep the effective base 10039883Sandreas@sandberg.pp.se // addresses in sync. We need an up-to-date version of EFER, so 10049883Sandreas@sandberg.pp.se // make sure this is called after the sregs have been synced. 10059883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_seg.base); 10069883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_seg.limit); 10079883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_SEL(index), kvm_seg.selector); 10089883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_ATTR(index), attr); 10099883Sandreas@sandberg.pp.se} 10109883Sandreas@sandberg.pp.se 10119883Sandreas@sandberg.pp.seinline void 10129883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_dtable &kvm_dtable, 10139883Sandreas@sandberg.pp.se const int index) 10149883Sandreas@sandberg.pp.se{ 10159883Sandreas@sandberg.pp.se // We need some setMiscReg magic here to keep the effective base 10169883Sandreas@sandberg.pp.se // addresses in sync. We need an up-to-date version of EFER, so 10179883Sandreas@sandberg.pp.se // make sure this is called after the sregs have been synced. 10189883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_dtable.base); 10199883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_dtable.limit); 10209883Sandreas@sandberg.pp.se} 10219883Sandreas@sandberg.pp.se 10229883Sandreas@sandberg.pp.sevoid 102310113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextSRegs(const struct kvm_sregs &sregs) 10249883Sandreas@sandberg.pp.se{ 10259883Sandreas@sandberg.pp.se assert(getKvmRunState()->apic_base == sregs.apic_base); 10269883Sandreas@sandberg.pp.se assert(getKvmRunState()->cr8 == sregs.cr8); 10279883Sandreas@sandberg.pp.se 10289883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) tc->setMiscRegNoEffect(mreg, sregs.kreg) 10299883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setContextSegment(tc, sregs.kreg, idx) 10309883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setContextSegment(tc, sregs.kreg, idx) 10319883Sandreas@sandberg.pp.se FOREACH_SREG(); 10329883Sandreas@sandberg.pp.se FOREACH_SEGMENT(); 10339883Sandreas@sandberg.pp.se FOREACH_DTABLE(); 10349883Sandreas@sandberg.pp.se#undef APPLY_SREG 10359883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT 10369883Sandreas@sandberg.pp.se#undef APPLY_DTABLE 10379883Sandreas@sandberg.pp.se} 10389883Sandreas@sandberg.pp.se 10399890Sandreas@sandberg.pp.setemplate<typename T> 10409890Sandreas@sandberg.pp.sestatic void 10419890Sandreas@sandberg.pp.seupdateThreadContextFPUCommon(ThreadContext *tc, const T &fpu) 10429890Sandreas@sandberg.pp.se{ 10439890Sandreas@sandberg.pp.se const unsigned top((fpu.fsw >> 11) & 0x7); 10449890Sandreas@sandberg.pp.se 10459890Sandreas@sandberg.pp.se static_assert(sizeof(X86ISA::FloatRegBits) == 8, 10469890Sandreas@sandberg.pp.se "Unexpected size of X86ISA::FloatRegBits"); 10479890Sandreas@sandberg.pp.se 10489890Sandreas@sandberg.pp.se for (int i = 0; i < 8; ++i) { 10499890Sandreas@sandberg.pp.se const unsigned reg_idx((i + top) & 0x7); 10509890Sandreas@sandberg.pp.se const double value(X86ISA::loadFloat80(fpu.fpr[i])); 10519890Sandreas@sandberg.pp.se DPRINTF(KvmContext, "Setting gem5 FP reg %i (st[%i]) := %f\n", 10529890Sandreas@sandberg.pp.se reg_idx, i, value); 10539890Sandreas@sandberg.pp.se tc->setFloatReg(FLOATREG_FPR(reg_idx), value); 10549890Sandreas@sandberg.pp.se } 10559890Sandreas@sandberg.pp.se 10569890Sandreas@sandberg.pp.se // TODO: We should update the MMX state 10579890Sandreas@sandberg.pp.se 10589890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_X87_TOP, top); 10599890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_MXCSR, fpu.mxcsr); 10609890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FCW, fpu.fcw); 10619890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FSW, fpu.fsw); 10629890Sandreas@sandberg.pp.se 10639890Sandreas@sandberg.pp.se uint64_t ftw(convX87XTagsToTags(fpu.ftwx)); 10649890Sandreas@sandberg.pp.se // TODO: Are these registers really the same? 10659890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FTW, ftw); 10669890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FTAG, ftw); 10679890Sandreas@sandberg.pp.se 10689890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FOP, fpu.last_opcode); 10699890Sandreas@sandberg.pp.se 10709890Sandreas@sandberg.pp.se for (int i = 0; i < 16; ++i) { 10719890Sandreas@sandberg.pp.se tc->setFloatRegBits(FLOATREG_XMM_LOW(i), 10729890Sandreas@sandberg.pp.se *(X86ISA::FloatRegBits *)&fpu.xmm[i][0]); 10739890Sandreas@sandberg.pp.se tc->setFloatRegBits(FLOATREG_XMM_HIGH(i), 10749890Sandreas@sandberg.pp.se *(X86ISA::FloatRegBits *)&fpu.xmm[i][8]); 10759890Sandreas@sandberg.pp.se } 10769890Sandreas@sandberg.pp.se} 10779890Sandreas@sandberg.pp.se 10789883Sandreas@sandberg.pp.sevoid 107910113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextFPU(const struct kvm_fpu &fpu) 10809883Sandreas@sandberg.pp.se{ 10819890Sandreas@sandberg.pp.se updateThreadContextFPUCommon(tc, fpu); 10829890Sandreas@sandberg.pp.se 10839890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FISEG, 0); 10849890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FIOFF, fpu.last_ip); 10859890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FOSEG, 0); 10869890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FOOFF, fpu.last_dp); 10879890Sandreas@sandberg.pp.se} 10889890Sandreas@sandberg.pp.se 10899890Sandreas@sandberg.pp.sevoid 109010113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextXSave(const struct kvm_xsave &kxsave) 10919890Sandreas@sandberg.pp.se{ 109210113Sandreas@sandberg.pp.se const FXSave &xsave(*(const FXSave *)kxsave.region); 10939890Sandreas@sandberg.pp.se 10949890Sandreas@sandberg.pp.se updateThreadContextFPUCommon(tc, xsave); 10959890Sandreas@sandberg.pp.se 10969890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FISEG, 0); 10979890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FIOFF, xsave.ctrl64.fpu_ip); 10989890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FOSEG, 0); 10999890Sandreas@sandberg.pp.se tc->setMiscRegNoEffect(MISCREG_FOOFF, xsave.ctrl64.fpu_dp); 11009883Sandreas@sandberg.pp.se} 11019883Sandreas@sandberg.pp.se 11029883Sandreas@sandberg.pp.sevoid 11039883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextMSRs() 11049883Sandreas@sandberg.pp.se{ 11059883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &msrs(getMsrIntersection()); 11069883Sandreas@sandberg.pp.se 11079883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 11089883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size())); 11099883Sandreas@sandberg.pp.se struct kvm_msr_entry *entry; 11109883Sandreas@sandberg.pp.se 11119883Sandreas@sandberg.pp.se // Create a list of MSRs to read 11129883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = msrs.size(); 11139883Sandreas@sandberg.pp.se entry = &kvm_msrs->entries[0]; 11149883Sandreas@sandberg.pp.se for (auto it = msrs.cbegin(); it != msrs.cend(); ++it, ++entry) { 11159883Sandreas@sandberg.pp.se entry->index = *it; 11169883Sandreas@sandberg.pp.se entry->reserved = 0; 11179883Sandreas@sandberg.pp.se entry->data = 0; 11189883Sandreas@sandberg.pp.se } 11199883Sandreas@sandberg.pp.se 11209883Sandreas@sandberg.pp.se getMSRs(*kvm_msrs.get()); 11219883Sandreas@sandberg.pp.se 11229883Sandreas@sandberg.pp.se // Update M5's state 11239883Sandreas@sandberg.pp.se entry = &kvm_msrs->entries[0]; 11249883Sandreas@sandberg.pp.se for (int i = 0; i < kvm_msrs->nmsrs; ++i, ++entry) { 11259883Sandreas@sandberg.pp.se DPRINTF(KvmContext, "Setting M5 MSR: idx: 0x%x, data: 0x%x\n", 11269883Sandreas@sandberg.pp.se entry->index, entry->data); 11279883Sandreas@sandberg.pp.se 11289883Sandreas@sandberg.pp.se tc->setMiscReg(X86ISA::msrMap.at(entry->index), entry->data); 11299883Sandreas@sandberg.pp.se } 11309883Sandreas@sandberg.pp.se} 11319883Sandreas@sandberg.pp.se 11329883Sandreas@sandberg.pp.sevoid 11339883Sandreas@sandberg.pp.seX86KvmCPU::deliverInterrupts() 11349883Sandreas@sandberg.pp.se{ 113510157Sandreas@sandberg.pp.se Fault fault; 113610157Sandreas@sandberg.pp.se 11379883Sandreas@sandberg.pp.se syncThreadContext(); 11389883Sandreas@sandberg.pp.se 113910157Sandreas@sandberg.pp.se { 114010157Sandreas@sandberg.pp.se // Migrate to the interrupt controller's thread to get the 114110157Sandreas@sandberg.pp.se // interrupt. Even though the individual methods are safe to 114210157Sandreas@sandberg.pp.se // call across threads, we might still lose interrupts unless 114310157Sandreas@sandberg.pp.se // they are getInterrupt() and updateIntrInfo() are called 114410157Sandreas@sandberg.pp.se // atomically. 114510157Sandreas@sandberg.pp.se EventQueue::ScopedMigration migrate(interrupts->eventQueue()); 114610157Sandreas@sandberg.pp.se fault = interrupts->getInterrupt(tc); 114710157Sandreas@sandberg.pp.se interrupts->updateIntrInfo(tc); 114810157Sandreas@sandberg.pp.se } 11499883Sandreas@sandberg.pp.se 11509883Sandreas@sandberg.pp.se X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get())); 115110112Sandreas@sandberg.pp.se if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) { 115210112Sandreas@sandberg.pp.se DPRINTF(KvmInt, "Delivering NMI\n"); 115310112Sandreas@sandberg.pp.se kvmNonMaskableInterrupt(); 115410112Sandreas@sandberg.pp.se } else if (dynamic_cast<InitInterrupt *>(fault.get())) { 115510112Sandreas@sandberg.pp.se DPRINTF(KvmInt, "INIT interrupt\n"); 115610112Sandreas@sandberg.pp.se fault.get()->invoke(tc); 115710112Sandreas@sandberg.pp.se // Delay the kvm state update since we won't enter KVM on this 115810112Sandreas@sandberg.pp.se // tick. 115910112Sandreas@sandberg.pp.se threadContextDirty = true; 116010112Sandreas@sandberg.pp.se // HACK: gem5 doesn't actually have any BIOS code, which means 116110112Sandreas@sandberg.pp.se // that we need to halt the thread and wait for a startup 116210112Sandreas@sandberg.pp.se // interrupt before restarting the thread. The simulated CPUs 116310112Sandreas@sandberg.pp.se // use the same kind of hack using a microcode routine. 116410112Sandreas@sandberg.pp.se thread->suspend(); 116510112Sandreas@sandberg.pp.se } else if (dynamic_cast<StartupInterrupt *>(fault.get())) { 116610112Sandreas@sandberg.pp.se DPRINTF(KvmInt, "STARTUP interrupt\n"); 116710112Sandreas@sandberg.pp.se fault.get()->invoke(tc); 116810112Sandreas@sandberg.pp.se // The kvm state is assumed to have been updated when entering 116910112Sandreas@sandberg.pp.se // kvmRun(), so we need to update manually it here. 117010112Sandreas@sandberg.pp.se updateKvmState(); 117110112Sandreas@sandberg.pp.se } else if (x86int) { 11729883Sandreas@sandberg.pp.se struct kvm_interrupt kvm_int; 11739883Sandreas@sandberg.pp.se kvm_int.irq = x86int->getVector(); 11749883Sandreas@sandberg.pp.se 11759883Sandreas@sandberg.pp.se DPRINTF(KvmInt, "Delivering interrupt: %s (%u)\n", 11769883Sandreas@sandberg.pp.se fault->name(), kvm_int.irq); 11779883Sandreas@sandberg.pp.se 11789883Sandreas@sandberg.pp.se kvmInterrupt(kvm_int); 11799883Sandreas@sandberg.pp.se } else { 11809883Sandreas@sandberg.pp.se panic("KVM: Unknown interrupt type\n"); 11819883Sandreas@sandberg.pp.se } 11829883Sandreas@sandberg.pp.se 11839883Sandreas@sandberg.pp.se} 11849883Sandreas@sandberg.pp.se 11859883Sandreas@sandberg.pp.seTick 11869883Sandreas@sandberg.pp.seX86KvmCPU::kvmRun(Tick ticks) 11879883Sandreas@sandberg.pp.se{ 11889883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 11899883Sandreas@sandberg.pp.se 11909883Sandreas@sandberg.pp.se if (interrupts->checkInterruptsRaw()) { 119110112Sandreas@sandberg.pp.se if (interrupts->hasPendingUnmaskable()) { 119210112Sandreas@sandberg.pp.se DPRINTF(KvmInt, 119310112Sandreas@sandberg.pp.se "Delivering unmaskable interrupt.\n"); 119410112Sandreas@sandberg.pp.se syncThreadContext(); 119510112Sandreas@sandberg.pp.se deliverInterrupts(); 119610112Sandreas@sandberg.pp.se } else if (kvm_run.ready_for_interrupt_injection) { 11979883Sandreas@sandberg.pp.se // KVM claims that it is ready for an interrupt. It might 11989883Sandreas@sandberg.pp.se // be lying if we just updated rflags and disabled 11999883Sandreas@sandberg.pp.se // interrupts (e.g., by doing a CPU handover). Let's sync 12009883Sandreas@sandberg.pp.se // the thread context and check if there are /really/ 12019883Sandreas@sandberg.pp.se // interrupts that should be delivered now. 12029883Sandreas@sandberg.pp.se syncThreadContext(); 12039883Sandreas@sandberg.pp.se if (interrupts->checkInterrupts(tc)) { 12049883Sandreas@sandberg.pp.se DPRINTF(KvmInt, 12059883Sandreas@sandberg.pp.se "M5 has pending interrupts, delivering interrupt.\n"); 12069883Sandreas@sandberg.pp.se 12079883Sandreas@sandberg.pp.se deliverInterrupts(); 12089883Sandreas@sandberg.pp.se } else { 12099883Sandreas@sandberg.pp.se DPRINTF(KvmInt, 12109883Sandreas@sandberg.pp.se "Interrupt delivery delayed due to KVM confusion.\n"); 12119883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 1; 12129883Sandreas@sandberg.pp.se } 12139883Sandreas@sandberg.pp.se } else if (!kvm_run.request_interrupt_window) { 12149883Sandreas@sandberg.pp.se DPRINTF(KvmInt, 12159883Sandreas@sandberg.pp.se "M5 has pending interrupts, requesting interrupt " 12169883Sandreas@sandberg.pp.se "window.\n"); 12179883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 1; 12189883Sandreas@sandberg.pp.se } 12199883Sandreas@sandberg.pp.se } else { 12209883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 0; 12219883Sandreas@sandberg.pp.se } 12229883Sandreas@sandberg.pp.se 122310112Sandreas@sandberg.pp.se // The CPU might have been suspended as a result of the INIT 122410112Sandreas@sandberg.pp.se // interrupt delivery hack. In that case, don't enter into KVM. 122510112Sandreas@sandberg.pp.se if (_status == Idle) 122610112Sandreas@sandberg.pp.se return 0; 122710112Sandreas@sandberg.pp.se else 122810112Sandreas@sandberg.pp.se return kvmRunWrapper(ticks); 12299883Sandreas@sandberg.pp.se} 12309883Sandreas@sandberg.pp.se 12319883Sandreas@sandberg.pp.seTick 12329883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunDrain() 12339883Sandreas@sandberg.pp.se{ 12349883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 12359883Sandreas@sandberg.pp.se 12369883Sandreas@sandberg.pp.se if (!archIsDrained()) { 12379883Sandreas@sandberg.pp.se DPRINTF(Drain, "kvmRunDrain: Architecture code isn't drained\n"); 12389883Sandreas@sandberg.pp.se 12399883Sandreas@sandberg.pp.se // Tell KVM to find a suitable place to deliver interrupts. This 12409883Sandreas@sandberg.pp.se // should ensure that pending interrupts have been delivered and 12419883Sandreas@sandberg.pp.se // things are reasonably consistent (i.e., no interrupts pending 12429883Sandreas@sandberg.pp.se // in the guest). 12439883Sandreas@sandberg.pp.se kvm_run.request_interrupt_window = 1; 12449883Sandreas@sandberg.pp.se 12459883Sandreas@sandberg.pp.se // Limit the run to 1 millisecond. That is hopefully enough to 12469883Sandreas@sandberg.pp.se // reach an interrupt window. Otherwise, we'll just try again 12479883Sandreas@sandberg.pp.se // later. 12489883Sandreas@sandberg.pp.se return kvmRunWrapper(1 * SimClock::Float::ms); 12499883Sandreas@sandberg.pp.se } else { 12509883Sandreas@sandberg.pp.se DPRINTF(Drain, "kvmRunDrain: Delivering pending IO\n"); 12519883Sandreas@sandberg.pp.se 12529883Sandreas@sandberg.pp.se return kvmRunWrapper(0); 12539883Sandreas@sandberg.pp.se } 12549883Sandreas@sandberg.pp.se} 12559883Sandreas@sandberg.pp.se 12569883Sandreas@sandberg.pp.seTick 12579883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunWrapper(Tick ticks) 12589883Sandreas@sandberg.pp.se{ 12599883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 12609883Sandreas@sandberg.pp.se 12619883Sandreas@sandberg.pp.se // Synchronize the APIC base and CR8 here since they are present 12629883Sandreas@sandberg.pp.se // in the kvm_run struct, which makes the synchronization really 12639883Sandreas@sandberg.pp.se // cheap. 12649883Sandreas@sandberg.pp.se kvm_run.apic_base = tc->readMiscReg(MISCREG_APIC_BASE); 12659883Sandreas@sandberg.pp.se kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8); 12669883Sandreas@sandberg.pp.se 12679883Sandreas@sandberg.pp.se const Tick run_ticks(BaseKvmCPU::kvmRun(ticks)); 12689883Sandreas@sandberg.pp.se 12699883Sandreas@sandberg.pp.se tc->setMiscReg(MISCREG_APIC_BASE, kvm_run.apic_base); 12709883Sandreas@sandberg.pp.se kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8); 12719883Sandreas@sandberg.pp.se 12729883Sandreas@sandberg.pp.se return run_ticks; 12739883Sandreas@sandberg.pp.se} 12749883Sandreas@sandberg.pp.se 12759883Sandreas@sandberg.pp.seuint64_t 12769883Sandreas@sandberg.pp.seX86KvmCPU::getHostCycles() const 12779883Sandreas@sandberg.pp.se{ 12789883Sandreas@sandberg.pp.se return getMSR(MSR_TSC); 12799883Sandreas@sandberg.pp.se} 12809883Sandreas@sandberg.pp.se 12819883Sandreas@sandberg.pp.sevoid 12829883Sandreas@sandberg.pp.seX86KvmCPU::handleIOMiscReg32(int miscreg) 12839883Sandreas@sandberg.pp.se{ 12849883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 12859883Sandreas@sandberg.pp.se const uint16_t port(kvm_run.io.port); 12869883Sandreas@sandberg.pp.se 12879883Sandreas@sandberg.pp.se assert(kvm_run.exit_reason == KVM_EXIT_IO); 12889883Sandreas@sandberg.pp.se 12899883Sandreas@sandberg.pp.se if (kvm_run.io.size != 4) { 12909883Sandreas@sandberg.pp.se panic("Unexpected IO size (%u) for address 0x%x.\n", 12919883Sandreas@sandberg.pp.se kvm_run.io.size, port); 12929883Sandreas@sandberg.pp.se } 12939883Sandreas@sandberg.pp.se 12949883Sandreas@sandberg.pp.se if (kvm_run.io.count != 1) { 12959883Sandreas@sandberg.pp.se panic("Unexpected IO count (%u) for address 0x%x.\n", 12969883Sandreas@sandberg.pp.se kvm_run.io.count, port); 12979883Sandreas@sandberg.pp.se } 12989883Sandreas@sandberg.pp.se 12999883Sandreas@sandberg.pp.se uint32_t *data((uint32_t *)getGuestData(kvm_run.io.data_offset)); 13009883Sandreas@sandberg.pp.se if (kvm_run.io.direction == KVM_EXIT_IO_OUT) 13019883Sandreas@sandberg.pp.se tc->setMiscReg(miscreg, *data); 13029883Sandreas@sandberg.pp.se else 13039883Sandreas@sandberg.pp.se *data = tc->readMiscRegNoEffect(miscreg); 13049883Sandreas@sandberg.pp.se} 13059883Sandreas@sandberg.pp.se 13069883Sandreas@sandberg.pp.seTick 13079883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIO() 13089883Sandreas@sandberg.pp.se{ 13099883Sandreas@sandberg.pp.se struct kvm_run &kvm_run(*getKvmRunState()); 13109883Sandreas@sandberg.pp.se bool isWrite(kvm_run.io.direction == KVM_EXIT_IO_OUT); 13119883Sandreas@sandberg.pp.se unsigned char *guestData(getGuestData(kvm_run.io.data_offset)); 13129883Sandreas@sandberg.pp.se Tick delay(0); 13139883Sandreas@sandberg.pp.se uint16_t port(kvm_run.io.port); 13149883Sandreas@sandberg.pp.se Addr pAddr; 13159883Sandreas@sandberg.pp.se const int count(kvm_run.io.count); 13169883Sandreas@sandberg.pp.se 13179883Sandreas@sandberg.pp.se assert(kvm_run.io.direction == KVM_EXIT_IO_IN || 13189883Sandreas@sandberg.pp.se kvm_run.io.direction == KVM_EXIT_IO_OUT); 13199883Sandreas@sandberg.pp.se 13209883Sandreas@sandberg.pp.se DPRINTF(KvmIO, "KVM-x86: Handling IO instruction (%s) (port: 0x%x)\n", 13219883Sandreas@sandberg.pp.se (isWrite ? "out" : "in"), kvm_run.io.port); 13229883Sandreas@sandberg.pp.se 13239883Sandreas@sandberg.pp.se /* Vanilla gem5 handles PCI discovery in the TLB(!). Since we 13249883Sandreas@sandberg.pp.se * don't use the TLB component, we need to intercept and handle 13259883Sandreas@sandberg.pp.se * the PCI configuration space IO ports here. 13269883Sandreas@sandberg.pp.se * 13279883Sandreas@sandberg.pp.se * The IO port PCI discovery mechanism uses one address register 13289883Sandreas@sandberg.pp.se * and one data register. We map the address register to a misc 13299883Sandreas@sandberg.pp.se * reg and use that to re-route data register accesses to the 13309883Sandreas@sandberg.pp.se * right location in the PCI configuration space. 13319883Sandreas@sandberg.pp.se */ 13329883Sandreas@sandberg.pp.se if (port == IO_PCI_CONF_ADDR) { 13339883Sandreas@sandberg.pp.se handleIOMiscReg32(MISCREG_PCI_CONFIG_ADDRESS); 13349883Sandreas@sandberg.pp.se return 0; 13359883Sandreas@sandberg.pp.se } else if ((port & ~0x3) == IO_PCI_CONF_DATA_BASE) { 13369883Sandreas@sandberg.pp.se Addr pciConfigAddr(tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS)); 13379883Sandreas@sandberg.pp.se if (pciConfigAddr & 0x80000000) { 13389883Sandreas@sandberg.pp.se pAddr = X86ISA::x86PciConfigAddress((pciConfigAddr & 0x7ffffffc) | 13399883Sandreas@sandberg.pp.se (port & 0x3)); 13409883Sandreas@sandberg.pp.se } else { 13419883Sandreas@sandberg.pp.se pAddr = X86ISA::x86IOAddress(port); 13429883Sandreas@sandberg.pp.se } 13439883Sandreas@sandberg.pp.se } else { 13449883Sandreas@sandberg.pp.se pAddr = X86ISA::x86IOAddress(port); 13459883Sandreas@sandberg.pp.se } 13469883Sandreas@sandberg.pp.se 134710653Sandreas.hansson@arm.com Request io_req(pAddr, kvm_run.io.size, Request::UNCACHEABLE, 13489883Sandreas@sandberg.pp.se dataMasterId()); 134910653Sandreas.hansson@arm.com io_req.setThreadContext(tc->contextId(), 0); 13509883Sandreas@sandberg.pp.se 13519883Sandreas@sandberg.pp.se const MemCmd cmd(isWrite ? MemCmd::WriteReq : MemCmd::ReadReq); 135210157Sandreas@sandberg.pp.se // Temporarily lock and migrate to the event queue of the 135310157Sandreas@sandberg.pp.se // VM. This queue is assumed to "own" all devices we need to 135410157Sandreas@sandberg.pp.se // access if running in multi-core mode. 135510157Sandreas@sandberg.pp.se EventQueue::ScopedMigration migrate(vm.eventQueue()); 13569883Sandreas@sandberg.pp.se for (int i = 0; i < count; ++i) { 13579883Sandreas@sandberg.pp.se Packet pkt(&io_req, cmd); 13589883Sandreas@sandberg.pp.se 13599883Sandreas@sandberg.pp.se pkt.dataStatic(guestData); 13609883Sandreas@sandberg.pp.se delay += dataPort.sendAtomic(&pkt); 13619883Sandreas@sandberg.pp.se 13629883Sandreas@sandberg.pp.se guestData += kvm_run.io.size; 13639883Sandreas@sandberg.pp.se } 13649883Sandreas@sandberg.pp.se 13659883Sandreas@sandberg.pp.se return delay; 13669883Sandreas@sandberg.pp.se} 13679883Sandreas@sandberg.pp.se 13689883Sandreas@sandberg.pp.seTick 13699883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIRQWindowOpen() 13709883Sandreas@sandberg.pp.se{ 13719883Sandreas@sandberg.pp.se // We don't need to do anything here since this is caught the next 13729883Sandreas@sandberg.pp.se // time we execute kvmRun(). We still overload the exit event to 13739883Sandreas@sandberg.pp.se // silence the warning about an unhandled exit event. 13749883Sandreas@sandberg.pp.se return 0; 13759883Sandreas@sandberg.pp.se} 13769883Sandreas@sandberg.pp.se 13779883Sandreas@sandberg.pp.sebool 13789883Sandreas@sandberg.pp.seX86KvmCPU::archIsDrained() const 13799883Sandreas@sandberg.pp.se{ 13809883Sandreas@sandberg.pp.se struct kvm_vcpu_events events; 13819883Sandreas@sandberg.pp.se 13829883Sandreas@sandberg.pp.se getVCpuEvents(events); 13839883Sandreas@sandberg.pp.se 13849883Sandreas@sandberg.pp.se // We could probably handle this in a by re-inserting interrupts 13859883Sandreas@sandberg.pp.se // that are pending into gem5 on a drain. However, that would 13869883Sandreas@sandberg.pp.se // probably be tricky to do reliably, so we'll just prevent a 13879883Sandreas@sandberg.pp.se // drain if there is anything pending in the 13889883Sandreas@sandberg.pp.se // guest. X86KvmCPU::kvmRunDrain() minimizes the amount of code 13899883Sandreas@sandberg.pp.se // executed in the guest by requesting an interrupt window if 13909883Sandreas@sandberg.pp.se // there are pending interrupts. 13919883Sandreas@sandberg.pp.se const bool pending_events(events.exception.injected || 13929883Sandreas@sandberg.pp.se events.interrupt.injected || 13939883Sandreas@sandberg.pp.se events.nmi.injected || events.nmi.pending); 13949883Sandreas@sandberg.pp.se 13959883Sandreas@sandberg.pp.se if (pending_events) { 13969883Sandreas@sandberg.pp.se DPRINTF(Drain, "archIsDrained: Pending events: %s %s %s %s\n", 13979883Sandreas@sandberg.pp.se events.exception.injected ? "exception" : "", 13989883Sandreas@sandberg.pp.se events.interrupt.injected ? "interrupt" : "", 13999883Sandreas@sandberg.pp.se events.nmi.injected ? "nmi[i]" : "", 14009883Sandreas@sandberg.pp.se events.nmi.pending ? "nmi[p]" : ""); 14019883Sandreas@sandberg.pp.se } 14029883Sandreas@sandberg.pp.se 14039883Sandreas@sandberg.pp.se return !pending_events; 14049883Sandreas@sandberg.pp.se} 14059883Sandreas@sandberg.pp.se 14069883Sandreas@sandberg.pp.sestatic struct kvm_cpuid_entry2 14079883Sandreas@sandberg.pp.semakeKvmCpuid(uint32_t function, uint32_t index, 14089883Sandreas@sandberg.pp.se CpuidResult &result) 14099883Sandreas@sandberg.pp.se{ 14109883Sandreas@sandberg.pp.se struct kvm_cpuid_entry2 e; 14119883Sandreas@sandberg.pp.se e.function = function; 14129883Sandreas@sandberg.pp.se e.index = index; 14139883Sandreas@sandberg.pp.se e.flags = 0; 14149883Sandreas@sandberg.pp.se e.eax = (uint32_t)result.rax; 14159883Sandreas@sandberg.pp.se e.ebx = (uint32_t)result.rbx; 14169883Sandreas@sandberg.pp.se e.ecx = (uint32_t)result.rcx; 14179883Sandreas@sandberg.pp.se e.edx = (uint32_t)result.rdx; 14189883Sandreas@sandberg.pp.se 14199883Sandreas@sandberg.pp.se return e; 14209883Sandreas@sandberg.pp.se} 14219883Sandreas@sandberg.pp.se 14229883Sandreas@sandberg.pp.sevoid 14239883Sandreas@sandberg.pp.seX86KvmCPU::updateCPUID() 14249883Sandreas@sandberg.pp.se{ 14259883Sandreas@sandberg.pp.se Kvm::CPUIDVector m5_supported; 14269883Sandreas@sandberg.pp.se 14279883Sandreas@sandberg.pp.se /* TODO: We currently don't support any of the functions that 14289883Sandreas@sandberg.pp.se * iterate through data structures in the CPU using an index. It's 14299883Sandreas@sandberg.pp.se * currently not a problem since M5 doesn't expose any of them at 14309883Sandreas@sandberg.pp.se * the moment. 14319883Sandreas@sandberg.pp.se */ 14329883Sandreas@sandberg.pp.se 14339883Sandreas@sandberg.pp.se /* Basic features */ 14349883Sandreas@sandberg.pp.se CpuidResult func0; 14359883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, 0x0, 0, func0); 14369883Sandreas@sandberg.pp.se for (uint32_t function = 0; function <= func0.rax; ++function) { 14379883Sandreas@sandberg.pp.se CpuidResult cpuid; 14389883Sandreas@sandberg.pp.se uint32_t idx(0); 14399883Sandreas@sandberg.pp.se 14409883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, function, idx, cpuid); 14419883Sandreas@sandberg.pp.se m5_supported.push_back(makeKvmCpuid(function, idx, cpuid)); 14429883Sandreas@sandberg.pp.se } 14439883Sandreas@sandberg.pp.se 14449883Sandreas@sandberg.pp.se /* Extended features */ 14459883Sandreas@sandberg.pp.se CpuidResult efunc0; 14469883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, 0x80000000, 0, efunc0); 14479883Sandreas@sandberg.pp.se for (uint32_t function = 0x80000000; function <= efunc0.rax; ++function) { 14489883Sandreas@sandberg.pp.se CpuidResult cpuid; 14499883Sandreas@sandberg.pp.se uint32_t idx(0); 14509883Sandreas@sandberg.pp.se 14519883Sandreas@sandberg.pp.se X86ISA::doCpuid(tc, function, idx, cpuid); 14529883Sandreas@sandberg.pp.se m5_supported.push_back(makeKvmCpuid(function, idx, cpuid)); 14539883Sandreas@sandberg.pp.se } 14549883Sandreas@sandberg.pp.se 14559883Sandreas@sandberg.pp.se setCPUID(m5_supported); 14569883Sandreas@sandberg.pp.se} 14579883Sandreas@sandberg.pp.se 14589883Sandreas@sandberg.pp.sevoid 14599883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const struct kvm_cpuid2 &cpuid) 14609883Sandreas@sandberg.pp.se{ 14619883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_CPUID2, (void *)&cpuid) == -1) 14629883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest CPUID2 (errno: %i)\n", 14639883Sandreas@sandberg.pp.se errno); 14649883Sandreas@sandberg.pp.se} 14659883Sandreas@sandberg.pp.se 14669883Sandreas@sandberg.pp.sevoid 14679883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const Kvm::CPUIDVector &cpuid) 14689883Sandreas@sandberg.pp.se{ 14699883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_cpuid2> kvm_cpuid( 14709883Sandreas@sandberg.pp.se newVarStruct<struct kvm_cpuid2, struct kvm_cpuid_entry2>(cpuid.size())); 14719883Sandreas@sandberg.pp.se 14729883Sandreas@sandberg.pp.se kvm_cpuid->nent = cpuid.size(); 14739883Sandreas@sandberg.pp.se std::copy(cpuid.begin(), cpuid.end(), kvm_cpuid->entries); 14749883Sandreas@sandberg.pp.se 14759883Sandreas@sandberg.pp.se setCPUID(*kvm_cpuid); 14769883Sandreas@sandberg.pp.se} 14779883Sandreas@sandberg.pp.se 14789883Sandreas@sandberg.pp.sevoid 14799883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const struct kvm_msrs &msrs) 14809883Sandreas@sandberg.pp.se{ 14819883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_MSRS, (void *)&msrs) == -1) 14829883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest MSRs (errno: %i)\n", 14839883Sandreas@sandberg.pp.se errno); 14849883Sandreas@sandberg.pp.se} 14859883Sandreas@sandberg.pp.se 14869883Sandreas@sandberg.pp.sevoid 14879883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const KvmMSRVector &msrs) 14889883Sandreas@sandberg.pp.se{ 14899883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 14909883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size())); 14919883Sandreas@sandberg.pp.se 14929883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = msrs.size(); 14939883Sandreas@sandberg.pp.se std::copy(msrs.begin(), msrs.end(), kvm_msrs->entries); 14949883Sandreas@sandberg.pp.se 14959883Sandreas@sandberg.pp.se setMSRs(*kvm_msrs); 14969883Sandreas@sandberg.pp.se} 14979883Sandreas@sandberg.pp.se 14989883Sandreas@sandberg.pp.sevoid 14999883Sandreas@sandberg.pp.seX86KvmCPU::getMSRs(struct kvm_msrs &msrs) const 15009883Sandreas@sandberg.pp.se{ 15019883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_MSRS, (void *)&msrs) == -1) 15029883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest MSRs (errno: %i)\n", 15039883Sandreas@sandberg.pp.se errno); 15049883Sandreas@sandberg.pp.se} 15059883Sandreas@sandberg.pp.se 15069883Sandreas@sandberg.pp.se 15079883Sandreas@sandberg.pp.sevoid 15089883Sandreas@sandberg.pp.seX86KvmCPU::setMSR(uint32_t index, uint64_t value) 15099883Sandreas@sandberg.pp.se{ 15109883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 15119883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1)); 15129883Sandreas@sandberg.pp.se struct kvm_msr_entry &entry(kvm_msrs->entries[0]); 15139883Sandreas@sandberg.pp.se 15149883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = 1; 15159883Sandreas@sandberg.pp.se entry.index = index; 15169883Sandreas@sandberg.pp.se entry.reserved = 0; 15179883Sandreas@sandberg.pp.se entry.data = value; 15189883Sandreas@sandberg.pp.se 15199883Sandreas@sandberg.pp.se setMSRs(*kvm_msrs.get()); 15209883Sandreas@sandberg.pp.se} 15219883Sandreas@sandberg.pp.se 15229883Sandreas@sandberg.pp.seuint64_t 15239883Sandreas@sandberg.pp.seX86KvmCPU::getMSR(uint32_t index) const 15249883Sandreas@sandberg.pp.se{ 15259883Sandreas@sandberg.pp.se std::unique_ptr<struct kvm_msrs> kvm_msrs( 15269883Sandreas@sandberg.pp.se newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1)); 15279883Sandreas@sandberg.pp.se struct kvm_msr_entry &entry(kvm_msrs->entries[0]); 15289883Sandreas@sandberg.pp.se 15299883Sandreas@sandberg.pp.se kvm_msrs->nmsrs = 1; 15309883Sandreas@sandberg.pp.se entry.index = index; 15319883Sandreas@sandberg.pp.se entry.reserved = 0; 15329883Sandreas@sandberg.pp.se entry.data = 0; 15339883Sandreas@sandberg.pp.se 15349883Sandreas@sandberg.pp.se getMSRs(*kvm_msrs.get()); 15359883Sandreas@sandberg.pp.se return entry.data; 15369883Sandreas@sandberg.pp.se} 15379883Sandreas@sandberg.pp.se 15389883Sandreas@sandberg.pp.seconst Kvm::MSRIndexVector & 15399883Sandreas@sandberg.pp.seX86KvmCPU::getMsrIntersection() const 15409883Sandreas@sandberg.pp.se{ 15419883Sandreas@sandberg.pp.se if (cachedMsrIntersection.empty()) { 15429883Sandreas@sandberg.pp.se const Kvm::MSRIndexVector &kvm_msrs(vm.kvm.getSupportedMSRs()); 15439883Sandreas@sandberg.pp.se 15449883Sandreas@sandberg.pp.se DPRINTF(Kvm, "kvm-x86: Updating MSR intersection\n"); 15459883Sandreas@sandberg.pp.se for (auto it = kvm_msrs.cbegin(); it != kvm_msrs.cend(); ++it) { 15469883Sandreas@sandberg.pp.se if (X86ISA::msrMap.find(*it) != X86ISA::msrMap.end()) { 15479883Sandreas@sandberg.pp.se cachedMsrIntersection.push_back(*it); 15489883Sandreas@sandberg.pp.se DPRINTF(Kvm, "kvm-x86: Adding MSR 0x%x\n", *it); 15499883Sandreas@sandberg.pp.se } else { 15509883Sandreas@sandberg.pp.se warn("kvm-x86: MSR (0x%x) unsupported by gem5. Skipping.\n", 15519883Sandreas@sandberg.pp.se *it); 15529883Sandreas@sandberg.pp.se } 15539883Sandreas@sandberg.pp.se } 15549883Sandreas@sandberg.pp.se } 15559883Sandreas@sandberg.pp.se 15569883Sandreas@sandberg.pp.se return cachedMsrIntersection; 15579883Sandreas@sandberg.pp.se} 15589883Sandreas@sandberg.pp.se 15599883Sandreas@sandberg.pp.sevoid 15609883Sandreas@sandberg.pp.seX86KvmCPU::getDebugRegisters(struct kvm_debugregs ®s) const 15619883Sandreas@sandberg.pp.se{ 15629883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS 15639883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_DEBUGREGS, ®s) == -1) 15649883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 15659883Sandreas@sandberg.pp.se#else 15669883Sandreas@sandberg.pp.se panic("KVM: Unsupported getDebugRegisters call.\n"); 15679883Sandreas@sandberg.pp.se#endif 15689883Sandreas@sandberg.pp.se} 15699883Sandreas@sandberg.pp.se 15709883Sandreas@sandberg.pp.sevoid 15719883Sandreas@sandberg.pp.seX86KvmCPU::setDebugRegisters(const struct kvm_debugregs ®s) 15729883Sandreas@sandberg.pp.se{ 15739883Sandreas@sandberg.pp.se#ifdef KVM_SET_DEBUGREGS 15749883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_DEBUGREGS, (void *)®s) == -1) 15759883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 15769883Sandreas@sandberg.pp.se#else 15779883Sandreas@sandberg.pp.se panic("KVM: Unsupported setDebugRegisters call.\n"); 15789883Sandreas@sandberg.pp.se#endif 15799883Sandreas@sandberg.pp.se} 15809883Sandreas@sandberg.pp.se 15819883Sandreas@sandberg.pp.sevoid 15829883Sandreas@sandberg.pp.seX86KvmCPU::getXCRs(struct kvm_xcrs ®s) const 15839883Sandreas@sandberg.pp.se{ 15849883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_XCRS, ®s) == -1) 15859883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 15869883Sandreas@sandberg.pp.se} 15879883Sandreas@sandberg.pp.se 15889883Sandreas@sandberg.pp.sevoid 15899883Sandreas@sandberg.pp.seX86KvmCPU::setXCRs(const struct kvm_xcrs ®s) 15909883Sandreas@sandberg.pp.se{ 15919883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_XCRS, (void *)®s) == -1) 15929883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 15939883Sandreas@sandberg.pp.se} 15949883Sandreas@sandberg.pp.se 15959883Sandreas@sandberg.pp.sevoid 15969883Sandreas@sandberg.pp.seX86KvmCPU::getXSave(struct kvm_xsave &xsave) const 15979883Sandreas@sandberg.pp.se{ 15989883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_XSAVE, &xsave) == -1) 15999883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 16009883Sandreas@sandberg.pp.se} 16019883Sandreas@sandberg.pp.se 16029883Sandreas@sandberg.pp.sevoid 16039883Sandreas@sandberg.pp.seX86KvmCPU::setXSave(const struct kvm_xsave &xsave) 16049883Sandreas@sandberg.pp.se{ 16059883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_XSAVE, (void *)&xsave) == -1) 16069883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 16079883Sandreas@sandberg.pp.se} 16089883Sandreas@sandberg.pp.se 16099883Sandreas@sandberg.pp.se 16109883Sandreas@sandberg.pp.sevoid 16119883Sandreas@sandberg.pp.seX86KvmCPU::getVCpuEvents(struct kvm_vcpu_events &events) const 16129883Sandreas@sandberg.pp.se{ 16139883Sandreas@sandberg.pp.se if (ioctl(KVM_GET_VCPU_EVENTS, &events) == -1) 16149883Sandreas@sandberg.pp.se panic("KVM: Failed to get guest debug registers\n"); 16159883Sandreas@sandberg.pp.se} 16169883Sandreas@sandberg.pp.se 16179883Sandreas@sandberg.pp.sevoid 16189883Sandreas@sandberg.pp.seX86KvmCPU::setVCpuEvents(const struct kvm_vcpu_events &events) 16199883Sandreas@sandberg.pp.se{ 16209883Sandreas@sandberg.pp.se if (ioctl(KVM_SET_VCPU_EVENTS, (void *)&events) == -1) 16219883Sandreas@sandberg.pp.se panic("KVM: Failed to set guest debug registers\n"); 16229883Sandreas@sandberg.pp.se} 16239883Sandreas@sandberg.pp.se 16249883Sandreas@sandberg.pp.seX86KvmCPU * 16259883Sandreas@sandberg.pp.seX86KvmCPUParams::create() 16269883Sandreas@sandberg.pp.se{ 16279883Sandreas@sandberg.pp.se return new X86KvmCPU(this); 16289883Sandreas@sandberg.pp.se} 1629