x86_cpu.cc revision 10113
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 &regs)
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 &regs)
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 &regs)
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    io_req.setThreadContext(tc->contextId(), 0);
5589883Sandreas@sandberg.pp.se
5599883Sandreas@sandberg.pp.se    // TODO: Do we need to create an identity mapped TSS area? We
5609883Sandreas@sandberg.pp.se    // should call kvm.vm.setTSSAddress() here in that case. It should
5619883Sandreas@sandberg.pp.se    // only be needed for old versions of the virtualization
5629883Sandreas@sandberg.pp.se    // extensions. We should make sure that the identity range is
5639883Sandreas@sandberg.pp.se    // reserved in the e820 memory map in that case.
5649883Sandreas@sandberg.pp.se}
5659883Sandreas@sandberg.pp.se
5669883Sandreas@sandberg.pp.sevoid
5679883Sandreas@sandberg.pp.seX86KvmCPU::dump()
5689883Sandreas@sandberg.pp.se{
5699883Sandreas@sandberg.pp.se    dumpIntRegs();
5709890Sandreas@sandberg.pp.se    if (useXSave)
5719890Sandreas@sandberg.pp.se        dumpXSave();
5729890Sandreas@sandberg.pp.se    else
5739890Sandreas@sandberg.pp.se        dumpFpuRegs();
5749883Sandreas@sandberg.pp.se    dumpSpecRegs();
5759883Sandreas@sandberg.pp.se    dumpDebugRegs();
5769883Sandreas@sandberg.pp.se    dumpXCRs();
5779883Sandreas@sandberg.pp.se    dumpVCpuEvents();
5789883Sandreas@sandberg.pp.se    dumpMSRs();
5799883Sandreas@sandberg.pp.se}
5809883Sandreas@sandberg.pp.se
5819883Sandreas@sandberg.pp.sevoid
5829883Sandreas@sandberg.pp.seX86KvmCPU::dumpFpuRegs() const
5839883Sandreas@sandberg.pp.se{
5849883Sandreas@sandberg.pp.se    struct kvm_fpu fpu;
5859883Sandreas@sandberg.pp.se    getFPUState(fpu);
5869883Sandreas@sandberg.pp.se    dumpKvm(fpu);
5879883Sandreas@sandberg.pp.se}
5889883Sandreas@sandberg.pp.se
5899883Sandreas@sandberg.pp.sevoid
5909883Sandreas@sandberg.pp.seX86KvmCPU::dumpIntRegs() const
5919883Sandreas@sandberg.pp.se{
5929883Sandreas@sandberg.pp.se    struct kvm_regs regs;
5939883Sandreas@sandberg.pp.se    getRegisters(regs);
5949883Sandreas@sandberg.pp.se    dumpKvm(regs);
5959883Sandreas@sandberg.pp.se}
5969883Sandreas@sandberg.pp.se
5979883Sandreas@sandberg.pp.sevoid
5989883Sandreas@sandberg.pp.seX86KvmCPU::dumpSpecRegs() const
5999883Sandreas@sandberg.pp.se{
6009883Sandreas@sandberg.pp.se    struct kvm_sregs sregs;
6019883Sandreas@sandberg.pp.se    getSpecialRegisters(sregs);
6029883Sandreas@sandberg.pp.se    dumpKvm(sregs);
6039883Sandreas@sandberg.pp.se}
6049883Sandreas@sandberg.pp.se
6059883Sandreas@sandberg.pp.sevoid
6069883Sandreas@sandberg.pp.seX86KvmCPU::dumpDebugRegs() const
6079883Sandreas@sandberg.pp.se{
6089883Sandreas@sandberg.pp.se    if (haveDebugRegs) {
6099883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS
6109883Sandreas@sandberg.pp.se        struct kvm_debugregs dregs;
6119883Sandreas@sandberg.pp.se        getDebugRegisters(dregs);
6129883Sandreas@sandberg.pp.se        dumpKvm(dregs);
6139883Sandreas@sandberg.pp.se#endif
6149883Sandreas@sandberg.pp.se    } else {
6159883Sandreas@sandberg.pp.se        inform("Debug registers not supported by kernel.\n");
6169883Sandreas@sandberg.pp.se    }
6179883Sandreas@sandberg.pp.se}
6189883Sandreas@sandberg.pp.se
6199883Sandreas@sandberg.pp.sevoid
6209883Sandreas@sandberg.pp.seX86KvmCPU::dumpXCRs() const
6219883Sandreas@sandberg.pp.se{
6229883Sandreas@sandberg.pp.se    if (haveXCRs) {
6239883Sandreas@sandberg.pp.se        struct kvm_xcrs xcrs;
6249883Sandreas@sandberg.pp.se        getXCRs(xcrs);
6259883Sandreas@sandberg.pp.se        dumpKvm(xcrs);
6269883Sandreas@sandberg.pp.se    } else {
6279883Sandreas@sandberg.pp.se        inform("XCRs not supported by kernel.\n");
6289883Sandreas@sandberg.pp.se    }
6299883Sandreas@sandberg.pp.se}
6309883Sandreas@sandberg.pp.se
6319883Sandreas@sandberg.pp.sevoid
6329883Sandreas@sandberg.pp.seX86KvmCPU::dumpXSave() const
6339883Sandreas@sandberg.pp.se{
6349883Sandreas@sandberg.pp.se    if (haveXSave) {
6359883Sandreas@sandberg.pp.se        struct kvm_xsave xsave;
6369883Sandreas@sandberg.pp.se        getXSave(xsave);
6379883Sandreas@sandberg.pp.se        dumpKvm(xsave);
6389883Sandreas@sandberg.pp.se    } else {
6399883Sandreas@sandberg.pp.se        inform("XSave not supported by kernel.\n");
6409883Sandreas@sandberg.pp.se    }
6419883Sandreas@sandberg.pp.se}
6429883Sandreas@sandberg.pp.se
6439883Sandreas@sandberg.pp.sevoid
6449883Sandreas@sandberg.pp.seX86KvmCPU::dumpVCpuEvents() const
6459883Sandreas@sandberg.pp.se{
6469883Sandreas@sandberg.pp.se    struct kvm_vcpu_events events;
6479883Sandreas@sandberg.pp.se    getVCpuEvents(events);
6489883Sandreas@sandberg.pp.se    dumpKvm(events);
6499883Sandreas@sandberg.pp.se}
6509883Sandreas@sandberg.pp.se
6519883Sandreas@sandberg.pp.sevoid
6529883Sandreas@sandberg.pp.seX86KvmCPU::dumpMSRs() const
6539883Sandreas@sandberg.pp.se{
6549883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &supported_msrs(vm.kvm.getSupportedMSRs());
6559883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> msrs(
6569883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(
6579883Sandreas@sandberg.pp.se            supported_msrs.size()));
6589883Sandreas@sandberg.pp.se
6599883Sandreas@sandberg.pp.se    msrs->nmsrs = supported_msrs.size();
6609883Sandreas@sandberg.pp.se    for (int i = 0; i < supported_msrs.size(); ++i) {
6619883Sandreas@sandberg.pp.se        struct kvm_msr_entry &e(msrs->entries[i]);
6629883Sandreas@sandberg.pp.se        e.index = supported_msrs[i];
6639883Sandreas@sandberg.pp.se        e.reserved = 0;
6649883Sandreas@sandberg.pp.se        e.data = 0;
6659883Sandreas@sandberg.pp.se    }
6669883Sandreas@sandberg.pp.se    getMSRs(*msrs.get());
6679883Sandreas@sandberg.pp.se
6689883Sandreas@sandberg.pp.se    dumpKvm(*msrs.get());
6699883Sandreas@sandberg.pp.se}
6709883Sandreas@sandberg.pp.se
6719883Sandreas@sandberg.pp.sevoid
6729883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmState()
6739883Sandreas@sandberg.pp.se{
6749883Sandreas@sandberg.pp.se    updateKvmStateRegs();
6759883Sandreas@sandberg.pp.se    updateKvmStateSRegs();
6769883Sandreas@sandberg.pp.se    updateKvmStateFPU();
6779883Sandreas@sandberg.pp.se    updateKvmStateMSRs();
6789883Sandreas@sandberg.pp.se
6799883Sandreas@sandberg.pp.se    DPRINTF(KvmContext, "X86KvmCPU::updateKvmState():\n");
6809883Sandreas@sandberg.pp.se    if (DTRACE(KvmContext))
6819883Sandreas@sandberg.pp.se        dump();
6829883Sandreas@sandberg.pp.se}
6839883Sandreas@sandberg.pp.se
6849883Sandreas@sandberg.pp.sevoid
6859883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateRegs()
6869883Sandreas@sandberg.pp.se{
6879883Sandreas@sandberg.pp.se    struct kvm_regs regs;
6889883Sandreas@sandberg.pp.se
6899883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) regs.kreg = tc->readIntReg(mreg)
6909883Sandreas@sandberg.pp.se    FOREACH_IREG();
6919883Sandreas@sandberg.pp.se#undef APPLY_IREG
6929883Sandreas@sandberg.pp.se
69310113Sandreas@sandberg.pp.se    regs.rip = tc->instAddr() - tc->readMiscReg(MISCREG_CS_BASE);
6949883Sandreas@sandberg.pp.se
6959883Sandreas@sandberg.pp.se    /* You might think that setting regs.rflags to the contents
6969883Sandreas@sandberg.pp.se     * MISCREG_RFLAGS here would suffice. In that case you're
6979883Sandreas@sandberg.pp.se     * mistaken. We need to reconstruct it from a bunch of ucode
6989883Sandreas@sandberg.pp.se     * registers and wave a dead chicken over it (aka mask out and set
6999883Sandreas@sandberg.pp.se     * reserved bits) to get it to work.
7009883Sandreas@sandberg.pp.se     */
7019883Sandreas@sandberg.pp.se    regs.rflags = X86ISA::getRFlags(tc);
7029883Sandreas@sandberg.pp.se
7039883Sandreas@sandberg.pp.se    setRegisters(regs);
7049883Sandreas@sandberg.pp.se}
7059883Sandreas@sandberg.pp.se
7069883Sandreas@sandberg.pp.sestatic inline void
7079883Sandreas@sandberg.pp.sesetKvmSegmentReg(ThreadContext *tc, struct kvm_segment &kvm_seg,
7089883Sandreas@sandberg.pp.se                 const int index)
7099883Sandreas@sandberg.pp.se{
7109883Sandreas@sandberg.pp.se    SegAttr attr(tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(index)));
7119883Sandreas@sandberg.pp.se
7129883Sandreas@sandberg.pp.se    kvm_seg.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index));
7139883Sandreas@sandberg.pp.se    kvm_seg.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index));
7149883Sandreas@sandberg.pp.se    kvm_seg.selector = tc->readMiscRegNoEffect(MISCREG_SEG_SEL(index));
7159883Sandreas@sandberg.pp.se    kvm_seg.type = attr.type;
7169883Sandreas@sandberg.pp.se    kvm_seg.present = attr.present;
7179883Sandreas@sandberg.pp.se    kvm_seg.dpl = attr.dpl;
7189883Sandreas@sandberg.pp.se    kvm_seg.db = attr.defaultSize;
7199883Sandreas@sandberg.pp.se    kvm_seg.s = attr.system;
7209883Sandreas@sandberg.pp.se    kvm_seg.l = attr.longMode;
7219883Sandreas@sandberg.pp.se    kvm_seg.g = attr.granularity;
7229883Sandreas@sandberg.pp.se    kvm_seg.avl = attr.avl;
7239883Sandreas@sandberg.pp.se
72410099Sandreas@sandberg.pp.se    // A segment is normally unusable when the selector is zero. There
72510099Sandreas@sandberg.pp.se    // is a attr.unusable flag in gem5, but it seems unused. qemu
72610099Sandreas@sandberg.pp.se    // seems to set this to 0 all the time, so we just do the same and
72710099Sandreas@sandberg.pp.se    // hope for the best.
72810099Sandreas@sandberg.pp.se    kvm_seg.unusable = 0;
7299883Sandreas@sandberg.pp.se}
7309883Sandreas@sandberg.pp.se
7319883Sandreas@sandberg.pp.sestatic inline void
7329883Sandreas@sandberg.pp.sesetKvmDTableReg(ThreadContext *tc, struct kvm_dtable &kvm_dtable,
7339883Sandreas@sandberg.pp.se                const int index)
7349883Sandreas@sandberg.pp.se{
7359883Sandreas@sandberg.pp.se    kvm_dtable.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index));
7369883Sandreas@sandberg.pp.se    kvm_dtable.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index));
7379883Sandreas@sandberg.pp.se}
7389883Sandreas@sandberg.pp.se
7399886Sandreas@sandberg.pp.sestatic void
7409886Sandreas@sandberg.pp.seforceSegAccessed(struct kvm_segment &seg)
7419886Sandreas@sandberg.pp.se{
7429886Sandreas@sandberg.pp.se    // Intel's VMX requires that (some) usable segments are flagged as
7439886Sandreas@sandberg.pp.se    // 'accessed' (i.e., the lowest bit in the segment type is set)
7449886Sandreas@sandberg.pp.se    // when entering VMX. This wouldn't necessary be the case even if
7459886Sandreas@sandberg.pp.se    // gem5 did set the access bits correctly, so we force it to one
7469886Sandreas@sandberg.pp.se    // in that case.
7479886Sandreas@sandberg.pp.se    if (!seg.unusable)
7489886Sandreas@sandberg.pp.se        seg.type |= SEG_TYPE_BIT_ACCESSED;
7499886Sandreas@sandberg.pp.se}
7509886Sandreas@sandberg.pp.se
7519883Sandreas@sandberg.pp.sevoid
7529883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateSRegs()
7539883Sandreas@sandberg.pp.se{
7549883Sandreas@sandberg.pp.se    struct kvm_sregs sregs;
7559883Sandreas@sandberg.pp.se
7569883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) sregs.kreg = tc->readMiscRegNoEffect(mreg)
7579883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setKvmSegmentReg(tc, sregs.kreg, idx)
7589883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setKvmDTableReg(tc, sregs.kreg, idx)
7599883Sandreas@sandberg.pp.se
7609883Sandreas@sandberg.pp.se    FOREACH_SREG();
7619883Sandreas@sandberg.pp.se    FOREACH_SEGMENT();
7629883Sandreas@sandberg.pp.se    FOREACH_DTABLE();
7639883Sandreas@sandberg.pp.se
7649883Sandreas@sandberg.pp.se#undef APPLY_SREG
7659883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
7669883Sandreas@sandberg.pp.se#undef APPLY_DTABLE
7679883Sandreas@sandberg.pp.se
7689883Sandreas@sandberg.pp.se    // Clear the interrupt bitmap
7699883Sandreas@sandberg.pp.se    memset(&sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
7709883Sandreas@sandberg.pp.se
7719886Sandreas@sandberg.pp.se    // VMX requires CS, SS, DS, ES, FS, and GS to have the accessed
7729886Sandreas@sandberg.pp.se    // bit in the type field set.
7739886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.cs);
7749886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.ss);
7759886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.ds);
7769886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.es);
7779886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.fs);
7789886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.gs);
7799886Sandreas@sandberg.pp.se
7809886Sandreas@sandberg.pp.se    // There are currently some cases where the active task isn't
7819886Sandreas@sandberg.pp.se    // marked as busy. This is illegal in VMX, so we force it to busy.
7829886Sandreas@sandberg.pp.se    if (sregs.tr.type == SEG_SYS_TYPE_TSS_AVAILABLE) {
7839886Sandreas@sandberg.pp.se        hack("tr.type (%i) is not busy. Forcing the busy bit.\n",
7849886Sandreas@sandberg.pp.se             sregs.tr.type);
7859886Sandreas@sandberg.pp.se        sregs.tr.type = SEG_SYS_TYPE_TSS_BUSY;
7869886Sandreas@sandberg.pp.se    }
7879886Sandreas@sandberg.pp.se
7889886Sandreas@sandberg.pp.se    // VMX requires the DPL of SS and CS to be the same for
7899886Sandreas@sandberg.pp.se    // non-conforming code segments. It seems like m5 doesn't set the
7909886Sandreas@sandberg.pp.se    // DPL of SS correctly when taking interrupts, so we need to fix
7919886Sandreas@sandberg.pp.se    // that here.
7929886Sandreas@sandberg.pp.se    if ((sregs.cs.type == SEG_CS_TYPE_ACCESSED ||
7939886Sandreas@sandberg.pp.se         sregs.cs.type == SEG_CS_TYPE_READ_ACCESSED) &&
7949886Sandreas@sandberg.pp.se        sregs.cs.dpl != sregs.ss.dpl) {
7959886Sandreas@sandberg.pp.se
7969886Sandreas@sandberg.pp.se        hack("CS.DPL (%i) != SS.DPL (%i): Forcing SS.DPL to %i\n",
7979886Sandreas@sandberg.pp.se             sregs.cs.dpl, sregs.ss.dpl, sregs.cs.dpl);
7989886Sandreas@sandberg.pp.se        sregs.ss.dpl = sregs.cs.dpl;
7999886Sandreas@sandberg.pp.se    }
8009886Sandreas@sandberg.pp.se
8019886Sandreas@sandberg.pp.se    // Do checks after fixing up the state to avoid getting excessive
8029886Sandreas@sandberg.pp.se    // amounts of warnings.
8039884Sandreas@sandberg.pp.se    RFLAGS rflags_nocc(tc->readMiscReg(MISCREG_RFLAGS));
8049884Sandreas@sandberg.pp.se    if (!rflags_nocc.vm) {
8059884Sandreas@sandberg.pp.se        // Do segment verification if the CPU isn't entering virtual
8069884Sandreas@sandberg.pp.se        // 8086 mode.  We currently assume that unrestricted guest
8079884Sandreas@sandberg.pp.se        // mode is available.
8089884Sandreas@sandberg.pp.se
8099884Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) \
8109884Sandreas@sandberg.pp.se        checkSeg(# kreg, idx + MISCREG_SEG_SEL_BASE, sregs.kreg, sregs)
8119884Sandreas@sandberg.pp.se
8129884Sandreas@sandberg.pp.se        FOREACH_SEGMENT();
8139884Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
8149884Sandreas@sandberg.pp.se    }
8159886Sandreas@sandberg.pp.se
8169883Sandreas@sandberg.pp.se    setSpecialRegisters(sregs);
8179883Sandreas@sandberg.pp.se}
8189890Sandreas@sandberg.pp.se
8199890Sandreas@sandberg.pp.setemplate <typename T>
8209890Sandreas@sandberg.pp.sestatic void
8219890Sandreas@sandberg.pp.seupdateKvmStateFPUCommon(ThreadContext *tc, T &fpu)
8229890Sandreas@sandberg.pp.se{
8239890Sandreas@sandberg.pp.se    static_assert(sizeof(X86ISA::FloatRegBits) == 8,
8249890Sandreas@sandberg.pp.se                  "Unexpected size of X86ISA::FloatRegBits");
8259890Sandreas@sandberg.pp.se
8269890Sandreas@sandberg.pp.se    fpu.mxcsr = tc->readMiscRegNoEffect(MISCREG_MXCSR);
8279890Sandreas@sandberg.pp.se    fpu.fcw = tc->readMiscRegNoEffect(MISCREG_FCW);
8289890Sandreas@sandberg.pp.se    // No need to rebuild from MISCREG_FSW and MISCREG_TOP if we read
8299890Sandreas@sandberg.pp.se    // with effects.
8309890Sandreas@sandberg.pp.se    fpu.fsw = tc->readMiscReg(MISCREG_FSW);
8319890Sandreas@sandberg.pp.se
8329890Sandreas@sandberg.pp.se    uint64_t ftw(tc->readMiscRegNoEffect(MISCREG_FTW));
8339890Sandreas@sandberg.pp.se    fpu.ftwx = X86ISA::convX87TagsToXTags(ftw);
8349890Sandreas@sandberg.pp.se
8359890Sandreas@sandberg.pp.se    fpu.last_opcode = tc->readMiscRegNoEffect(MISCREG_FOP);
8369890Sandreas@sandberg.pp.se
8379890Sandreas@sandberg.pp.se    const unsigned top((fpu.fsw >> 11) & 0x7);
8389890Sandreas@sandberg.pp.se    for (int i = 0; i < 8; ++i) {
8399890Sandreas@sandberg.pp.se        const unsigned reg_idx((i + top) & 0x7);
8409890Sandreas@sandberg.pp.se        const double value(tc->readFloatReg(FLOATREG_FPR(reg_idx)));
8419890Sandreas@sandberg.pp.se        DPRINTF(KvmContext, "Setting KVM FP reg %i (st[%i]) := %f\n",
8429890Sandreas@sandberg.pp.se                reg_idx, i, value);
8439890Sandreas@sandberg.pp.se        X86ISA::storeFloat80(fpu.fpr[i], value);
8449890Sandreas@sandberg.pp.se    }
8459890Sandreas@sandberg.pp.se
8469890Sandreas@sandberg.pp.se    // TODO: We should update the MMX state
8479890Sandreas@sandberg.pp.se
8489890Sandreas@sandberg.pp.se    for (int i = 0; i < 16; ++i) {
8499890Sandreas@sandberg.pp.se        *(X86ISA::FloatRegBits *)&fpu.xmm[i][0] =
8509890Sandreas@sandberg.pp.se            tc->readFloatRegBits(FLOATREG_XMM_LOW(i));
8519890Sandreas@sandberg.pp.se        *(X86ISA::FloatRegBits *)&fpu.xmm[i][8] =
8529890Sandreas@sandberg.pp.se            tc->readFloatRegBits(FLOATREG_XMM_HIGH(i));
8539890Sandreas@sandberg.pp.se    }
8549890Sandreas@sandberg.pp.se}
8559890Sandreas@sandberg.pp.se
8569890Sandreas@sandberg.pp.sevoid
8579890Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPULegacy()
8589890Sandreas@sandberg.pp.se{
8599890Sandreas@sandberg.pp.se    struct kvm_fpu fpu;
8609890Sandreas@sandberg.pp.se
8619890Sandreas@sandberg.pp.se    // There is some padding in the FP registers, so we'd better zero
8629890Sandreas@sandberg.pp.se    // the whole struct.
8639890Sandreas@sandberg.pp.se    memset(&fpu, 0, sizeof(fpu));
8649890Sandreas@sandberg.pp.se
8659890Sandreas@sandberg.pp.se    updateKvmStateFPUCommon(tc, fpu);
8669890Sandreas@sandberg.pp.se
8679890Sandreas@sandberg.pp.se    if (tc->readMiscRegNoEffect(MISCREG_FISEG))
8689890Sandreas@sandberg.pp.se        warn_once("MISCREG_FISEG is non-zero.\n");
8699890Sandreas@sandberg.pp.se
8709890Sandreas@sandberg.pp.se    fpu.last_ip = tc->readMiscRegNoEffect(MISCREG_FIOFF);
8719890Sandreas@sandberg.pp.se
8729890Sandreas@sandberg.pp.se    if (tc->readMiscRegNoEffect(MISCREG_FOSEG))
8739890Sandreas@sandberg.pp.se        warn_once("MISCREG_FOSEG is non-zero.\n");
8749890Sandreas@sandberg.pp.se
8759890Sandreas@sandberg.pp.se    fpu.last_dp = tc->readMiscRegNoEffect(MISCREG_FOOFF);
8769890Sandreas@sandberg.pp.se
8779890Sandreas@sandberg.pp.se    setFPUState(fpu);
8789890Sandreas@sandberg.pp.se}
8799890Sandreas@sandberg.pp.se
8809890Sandreas@sandberg.pp.sevoid
8819890Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPUXSave()
8829890Sandreas@sandberg.pp.se{
8839890Sandreas@sandberg.pp.se    struct kvm_xsave kxsave;
8849890Sandreas@sandberg.pp.se    FXSave &xsave(*(FXSave *)kxsave.region);
8859890Sandreas@sandberg.pp.se
8869890Sandreas@sandberg.pp.se    // There is some padding and reserved fields in the structure, so
8879890Sandreas@sandberg.pp.se    // we'd better zero the whole thing.
8889890Sandreas@sandberg.pp.se    memset(&kxsave, 0, sizeof(kxsave));
8899890Sandreas@sandberg.pp.se
8909890Sandreas@sandberg.pp.se    updateKvmStateFPUCommon(tc, xsave);
8919890Sandreas@sandberg.pp.se
8929890Sandreas@sandberg.pp.se    if (tc->readMiscRegNoEffect(MISCREG_FISEG))
8939890Sandreas@sandberg.pp.se        warn_once("MISCREG_FISEG is non-zero.\n");
8949890Sandreas@sandberg.pp.se
8959890Sandreas@sandberg.pp.se    xsave.ctrl64.fpu_ip = tc->readMiscRegNoEffect(MISCREG_FIOFF);
8969890Sandreas@sandberg.pp.se
8979890Sandreas@sandberg.pp.se    if (tc->readMiscRegNoEffect(MISCREG_FOSEG))
8989890Sandreas@sandberg.pp.se        warn_once("MISCREG_FOSEG is non-zero.\n");
8999890Sandreas@sandberg.pp.se
9009890Sandreas@sandberg.pp.se    xsave.ctrl64.fpu_dp = tc->readMiscRegNoEffect(MISCREG_FOOFF);
9019890Sandreas@sandberg.pp.se
9029890Sandreas@sandberg.pp.se    setXSave(kxsave);
9039890Sandreas@sandberg.pp.se}
9049890Sandreas@sandberg.pp.se
9059883Sandreas@sandberg.pp.sevoid
9069883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPU()
9079883Sandreas@sandberg.pp.se{
9089890Sandreas@sandberg.pp.se    if (useXSave)
9099890Sandreas@sandberg.pp.se        updateKvmStateFPUXSave();
9109890Sandreas@sandberg.pp.se    else
9119890Sandreas@sandberg.pp.se        updateKvmStateFPULegacy();
9129883Sandreas@sandberg.pp.se}
9139883Sandreas@sandberg.pp.se
9149883Sandreas@sandberg.pp.sevoid
9159883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateMSRs()
9169883Sandreas@sandberg.pp.se{
9179883Sandreas@sandberg.pp.se    KvmMSRVector msrs;
9189883Sandreas@sandberg.pp.se
9199883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &indices(getMsrIntersection());
9209883Sandreas@sandberg.pp.se
9219883Sandreas@sandberg.pp.se    for (auto it = indices.cbegin(); it != indices.cend(); ++it) {
9229883Sandreas@sandberg.pp.se        struct kvm_msr_entry e;
9239883Sandreas@sandberg.pp.se
9249883Sandreas@sandberg.pp.se        e.index = *it;
9259883Sandreas@sandberg.pp.se        e.reserved = 0;
9269883Sandreas@sandberg.pp.se        e.data = tc->readMiscReg(msrMap.at(*it));
9279883Sandreas@sandberg.pp.se        DPRINTF(KvmContext, "Adding MSR: idx: 0x%x, data: 0x%x\n",
9289883Sandreas@sandberg.pp.se                e.index, e.data);
9299883Sandreas@sandberg.pp.se
9309883Sandreas@sandberg.pp.se        msrs.push_back(e);
9319883Sandreas@sandberg.pp.se    }
9329883Sandreas@sandberg.pp.se
9339883Sandreas@sandberg.pp.se    setMSRs(msrs);
9349883Sandreas@sandberg.pp.se}
9359883Sandreas@sandberg.pp.se
9369883Sandreas@sandberg.pp.sevoid
9379883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContext()
9389883Sandreas@sandberg.pp.se{
93910113Sandreas@sandberg.pp.se    struct kvm_regs regs;
94010113Sandreas@sandberg.pp.se    struct kvm_sregs sregs;
94110113Sandreas@sandberg.pp.se
94210113Sandreas@sandberg.pp.se    getRegisters(regs);
94310113Sandreas@sandberg.pp.se    getSpecialRegisters(sregs);
94410113Sandreas@sandberg.pp.se
9459883Sandreas@sandberg.pp.se    DPRINTF(KvmContext, "X86KvmCPU::updateThreadContext():\n");
9469883Sandreas@sandberg.pp.se    if (DTRACE(KvmContext))
9479883Sandreas@sandberg.pp.se        dump();
9489883Sandreas@sandberg.pp.se
94910113Sandreas@sandberg.pp.se    updateThreadContextRegs(regs, sregs);
95010113Sandreas@sandberg.pp.se    updateThreadContextSRegs(sregs);
95110113Sandreas@sandberg.pp.se    if (useXSave) {
95210113Sandreas@sandberg.pp.se        struct kvm_xsave xsave;
95310113Sandreas@sandberg.pp.se        getXSave(xsave);
95410113Sandreas@sandberg.pp.se
95510113Sandreas@sandberg.pp.se       updateThreadContextXSave(xsave);
95610113Sandreas@sandberg.pp.se    } else {
95710113Sandreas@sandberg.pp.se        struct kvm_fpu fpu;
95810113Sandreas@sandberg.pp.se        getFPUState(fpu);
95910113Sandreas@sandberg.pp.se
96010113Sandreas@sandberg.pp.se        updateThreadContextFPU(fpu);
96110113Sandreas@sandberg.pp.se    }
9629883Sandreas@sandberg.pp.se    updateThreadContextMSRs();
9639883Sandreas@sandberg.pp.se
9649883Sandreas@sandberg.pp.se    // The M5 misc reg caches some values from other
9659883Sandreas@sandberg.pp.se    // registers. Writing to it with side effects causes it to be
9669883Sandreas@sandberg.pp.se    // updated from its source registers.
9679883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_M5_REG, 0);
9689883Sandreas@sandberg.pp.se}
9699883Sandreas@sandberg.pp.se
9709883Sandreas@sandberg.pp.sevoid
97110113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextRegs(const struct kvm_regs &regs,
97210113Sandreas@sandberg.pp.se                                   const struct kvm_sregs &sregs)
9739883Sandreas@sandberg.pp.se{
9749883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg)
9759883Sandreas@sandberg.pp.se
9769883Sandreas@sandberg.pp.se    FOREACH_IREG();
9779883Sandreas@sandberg.pp.se
9789883Sandreas@sandberg.pp.se#undef APPLY_IREG
9799883Sandreas@sandberg.pp.se
98010113Sandreas@sandberg.pp.se    tc->pcState(PCState(regs.rip + sregs.cs.base));
9819883Sandreas@sandberg.pp.se
9829883Sandreas@sandberg.pp.se    // Flags are spread out across multiple semi-magic registers so we
9839883Sandreas@sandberg.pp.se    // need some special care when updating them.
9849883Sandreas@sandberg.pp.se    X86ISA::setRFlags(tc, regs.rflags);
9859883Sandreas@sandberg.pp.se}
9869883Sandreas@sandberg.pp.se
9879883Sandreas@sandberg.pp.se
9889883Sandreas@sandberg.pp.seinline void
9899883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_segment &kvm_seg,
9909883Sandreas@sandberg.pp.se                  const int index)
9919883Sandreas@sandberg.pp.se{
9929883Sandreas@sandberg.pp.se    SegAttr attr(0);
9939883Sandreas@sandberg.pp.se
9949883Sandreas@sandberg.pp.se    attr.type = kvm_seg.type;
9959883Sandreas@sandberg.pp.se    attr.present = kvm_seg.present;
9969883Sandreas@sandberg.pp.se    attr.dpl = kvm_seg.dpl;
9979883Sandreas@sandberg.pp.se    attr.defaultSize = kvm_seg.db;
9989883Sandreas@sandberg.pp.se    attr.system = kvm_seg.s;
9999883Sandreas@sandberg.pp.se    attr.longMode = kvm_seg.l;
10009883Sandreas@sandberg.pp.se    attr.granularity = kvm_seg.g;
10019883Sandreas@sandberg.pp.se    attr.avl = kvm_seg.avl;
10029883Sandreas@sandberg.pp.se    attr.unusable = kvm_seg.unusable;
10039883Sandreas@sandberg.pp.se
10049883Sandreas@sandberg.pp.se    // We need some setMiscReg magic here to keep the effective base
10059883Sandreas@sandberg.pp.se    // addresses in sync. We need an up-to-date version of EFER, so
10069883Sandreas@sandberg.pp.se    // make sure this is called after the sregs have been synced.
10079883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_seg.base);
10089883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_seg.limit);
10099883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_SEL(index), kvm_seg.selector);
10109883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_ATTR(index), attr);
10119883Sandreas@sandberg.pp.se}
10129883Sandreas@sandberg.pp.se
10139883Sandreas@sandberg.pp.seinline void
10149883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_dtable &kvm_dtable,
10159883Sandreas@sandberg.pp.se                  const int index)
10169883Sandreas@sandberg.pp.se{
10179883Sandreas@sandberg.pp.se    // We need some setMiscReg magic here to keep the effective base
10189883Sandreas@sandberg.pp.se    // addresses in sync. We need an up-to-date version of EFER, so
10199883Sandreas@sandberg.pp.se    // make sure this is called after the sregs have been synced.
10209883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_dtable.base);
10219883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_dtable.limit);
10229883Sandreas@sandberg.pp.se}
10239883Sandreas@sandberg.pp.se
10249883Sandreas@sandberg.pp.sevoid
102510113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextSRegs(const struct kvm_sregs &sregs)
10269883Sandreas@sandberg.pp.se{
10279883Sandreas@sandberg.pp.se    assert(getKvmRunState()->apic_base == sregs.apic_base);
10289883Sandreas@sandberg.pp.se    assert(getKvmRunState()->cr8 == sregs.cr8);
10299883Sandreas@sandberg.pp.se
10309883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) tc->setMiscRegNoEffect(mreg, sregs.kreg)
10319883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setContextSegment(tc, sregs.kreg, idx)
10329883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setContextSegment(tc, sregs.kreg, idx)
10339883Sandreas@sandberg.pp.se    FOREACH_SREG();
10349883Sandreas@sandberg.pp.se    FOREACH_SEGMENT();
10359883Sandreas@sandberg.pp.se    FOREACH_DTABLE();
10369883Sandreas@sandberg.pp.se#undef APPLY_SREG
10379883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
10389883Sandreas@sandberg.pp.se#undef APPLY_DTABLE
10399883Sandreas@sandberg.pp.se}
10409883Sandreas@sandberg.pp.se
10419890Sandreas@sandberg.pp.setemplate<typename T>
10429890Sandreas@sandberg.pp.sestatic void
10439890Sandreas@sandberg.pp.seupdateThreadContextFPUCommon(ThreadContext *tc, const T &fpu)
10449890Sandreas@sandberg.pp.se{
10459890Sandreas@sandberg.pp.se    const unsigned top((fpu.fsw >> 11) & 0x7);
10469890Sandreas@sandberg.pp.se
10479890Sandreas@sandberg.pp.se    static_assert(sizeof(X86ISA::FloatRegBits) == 8,
10489890Sandreas@sandberg.pp.se                  "Unexpected size of X86ISA::FloatRegBits");
10499890Sandreas@sandberg.pp.se
10509890Sandreas@sandberg.pp.se    for (int i = 0; i < 8; ++i) {
10519890Sandreas@sandberg.pp.se        const unsigned reg_idx((i + top) & 0x7);
10529890Sandreas@sandberg.pp.se        const double value(X86ISA::loadFloat80(fpu.fpr[i]));
10539890Sandreas@sandberg.pp.se        DPRINTF(KvmContext, "Setting gem5 FP reg %i (st[%i]) := %f\n",
10549890Sandreas@sandberg.pp.se                reg_idx, i, value);
10559890Sandreas@sandberg.pp.se        tc->setFloatReg(FLOATREG_FPR(reg_idx), value);
10569890Sandreas@sandberg.pp.se    }
10579890Sandreas@sandberg.pp.se
10589890Sandreas@sandberg.pp.se    // TODO: We should update the MMX state
10599890Sandreas@sandberg.pp.se
10609890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_X87_TOP, top);
10619890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_MXCSR, fpu.mxcsr);
10629890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FCW, fpu.fcw);
10639890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FSW, fpu.fsw);
10649890Sandreas@sandberg.pp.se
10659890Sandreas@sandberg.pp.se    uint64_t ftw(convX87XTagsToTags(fpu.ftwx));
10669890Sandreas@sandberg.pp.se    // TODO: Are these registers really the same?
10679890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FTW, ftw);
10689890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FTAG, ftw);
10699890Sandreas@sandberg.pp.se
10709890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FOP, fpu.last_opcode);
10719890Sandreas@sandberg.pp.se
10729890Sandreas@sandberg.pp.se    for (int i = 0; i < 16; ++i) {
10739890Sandreas@sandberg.pp.se        tc->setFloatRegBits(FLOATREG_XMM_LOW(i),
10749890Sandreas@sandberg.pp.se                            *(X86ISA::FloatRegBits *)&fpu.xmm[i][0]);
10759890Sandreas@sandberg.pp.se        tc->setFloatRegBits(FLOATREG_XMM_HIGH(i),
10769890Sandreas@sandberg.pp.se                            *(X86ISA::FloatRegBits *)&fpu.xmm[i][8]);
10779890Sandreas@sandberg.pp.se    }
10789890Sandreas@sandberg.pp.se}
10799890Sandreas@sandberg.pp.se
10809883Sandreas@sandberg.pp.sevoid
108110113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextFPU(const struct kvm_fpu &fpu)
10829883Sandreas@sandberg.pp.se{
10839890Sandreas@sandberg.pp.se    updateThreadContextFPUCommon(tc, fpu);
10849890Sandreas@sandberg.pp.se
10859890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FISEG, 0);
10869890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FIOFF, fpu.last_ip);
10879890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FOSEG, 0);
10889890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FOOFF, fpu.last_dp);
10899890Sandreas@sandberg.pp.se}
10909890Sandreas@sandberg.pp.se
10919890Sandreas@sandberg.pp.sevoid
109210113Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextXSave(const struct kvm_xsave &kxsave)
10939890Sandreas@sandberg.pp.se{
109410113Sandreas@sandberg.pp.se    const FXSave &xsave(*(const FXSave *)kxsave.region);
10959890Sandreas@sandberg.pp.se
10969890Sandreas@sandberg.pp.se    updateThreadContextFPUCommon(tc, xsave);
10979890Sandreas@sandberg.pp.se
10989890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FISEG, 0);
10999890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FIOFF, xsave.ctrl64.fpu_ip);
11009890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FOSEG, 0);
11019890Sandreas@sandberg.pp.se    tc->setMiscRegNoEffect(MISCREG_FOOFF, xsave.ctrl64.fpu_dp);
11029883Sandreas@sandberg.pp.se}
11039883Sandreas@sandberg.pp.se
11049883Sandreas@sandberg.pp.sevoid
11059883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextMSRs()
11069883Sandreas@sandberg.pp.se{
11079883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &msrs(getMsrIntersection());
11089883Sandreas@sandberg.pp.se
11099883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
11109883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size()));
11119883Sandreas@sandberg.pp.se    struct kvm_msr_entry *entry;
11129883Sandreas@sandberg.pp.se
11139883Sandreas@sandberg.pp.se    // Create a list of MSRs to read
11149883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = msrs.size();
11159883Sandreas@sandberg.pp.se    entry = &kvm_msrs->entries[0];
11169883Sandreas@sandberg.pp.se    for (auto it = msrs.cbegin(); it != msrs.cend(); ++it, ++entry) {
11179883Sandreas@sandberg.pp.se        entry->index = *it;
11189883Sandreas@sandberg.pp.se        entry->reserved = 0;
11199883Sandreas@sandberg.pp.se        entry->data = 0;
11209883Sandreas@sandberg.pp.se    }
11219883Sandreas@sandberg.pp.se
11229883Sandreas@sandberg.pp.se    getMSRs(*kvm_msrs.get());
11239883Sandreas@sandberg.pp.se
11249883Sandreas@sandberg.pp.se    // Update M5's state
11259883Sandreas@sandberg.pp.se    entry = &kvm_msrs->entries[0];
11269883Sandreas@sandberg.pp.se    for (int i = 0; i < kvm_msrs->nmsrs; ++i, ++entry) {
11279883Sandreas@sandberg.pp.se        DPRINTF(KvmContext, "Setting M5 MSR: idx: 0x%x, data: 0x%x\n",
11289883Sandreas@sandberg.pp.se                entry->index, entry->data);
11299883Sandreas@sandberg.pp.se
11309883Sandreas@sandberg.pp.se        tc->setMiscReg(X86ISA::msrMap.at(entry->index), entry->data);
11319883Sandreas@sandberg.pp.se    }
11329883Sandreas@sandberg.pp.se}
11339883Sandreas@sandberg.pp.se
11349883Sandreas@sandberg.pp.sevoid
11359883Sandreas@sandberg.pp.seX86KvmCPU::deliverInterrupts()
11369883Sandreas@sandberg.pp.se{
11379883Sandreas@sandberg.pp.se    syncThreadContext();
11389883Sandreas@sandberg.pp.se
11399883Sandreas@sandberg.pp.se    Fault fault(interrupts->getInterrupt(tc));
11409883Sandreas@sandberg.pp.se    interrupts->updateIntrInfo(tc);
11419883Sandreas@sandberg.pp.se
11429883Sandreas@sandberg.pp.se    X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get()));
114310112Sandreas@sandberg.pp.se    if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) {
114410112Sandreas@sandberg.pp.se        DPRINTF(KvmInt, "Delivering NMI\n");
114510112Sandreas@sandberg.pp.se        kvmNonMaskableInterrupt();
114610112Sandreas@sandberg.pp.se    } else if (dynamic_cast<InitInterrupt *>(fault.get())) {
114710112Sandreas@sandberg.pp.se        DPRINTF(KvmInt, "INIT interrupt\n");
114810112Sandreas@sandberg.pp.se        fault.get()->invoke(tc);
114910112Sandreas@sandberg.pp.se        // Delay the kvm state update since we won't enter KVM on this
115010112Sandreas@sandberg.pp.se        // tick.
115110112Sandreas@sandberg.pp.se        threadContextDirty = true;
115210112Sandreas@sandberg.pp.se        // HACK: gem5 doesn't actually have any BIOS code, which means
115310112Sandreas@sandberg.pp.se        // that we need to halt the thread and wait for a startup
115410112Sandreas@sandberg.pp.se        // interrupt before restarting the thread. The simulated CPUs
115510112Sandreas@sandberg.pp.se        // use the same kind of hack using a microcode routine.
115610112Sandreas@sandberg.pp.se        thread->suspend();
115710112Sandreas@sandberg.pp.se    } else if (dynamic_cast<StartupInterrupt *>(fault.get())) {
115810112Sandreas@sandberg.pp.se        DPRINTF(KvmInt, "STARTUP interrupt\n");
115910112Sandreas@sandberg.pp.se        fault.get()->invoke(tc);
116010112Sandreas@sandberg.pp.se        // The kvm state is assumed to have been updated when entering
116110112Sandreas@sandberg.pp.se        // kvmRun(), so we need to update manually it here.
116210112Sandreas@sandberg.pp.se        updateKvmState();
116310112Sandreas@sandberg.pp.se    } else if (x86int) {
11649883Sandreas@sandberg.pp.se        struct kvm_interrupt kvm_int;
11659883Sandreas@sandberg.pp.se        kvm_int.irq = x86int->getVector();
11669883Sandreas@sandberg.pp.se
11679883Sandreas@sandberg.pp.se        DPRINTF(KvmInt, "Delivering interrupt: %s (%u)\n",
11689883Sandreas@sandberg.pp.se                fault->name(), kvm_int.irq);
11699883Sandreas@sandberg.pp.se
11709883Sandreas@sandberg.pp.se        kvmInterrupt(kvm_int);
11719883Sandreas@sandberg.pp.se    } else {
11729883Sandreas@sandberg.pp.se        panic("KVM: Unknown interrupt type\n");
11739883Sandreas@sandberg.pp.se    }
11749883Sandreas@sandberg.pp.se
11759883Sandreas@sandberg.pp.se}
11769883Sandreas@sandberg.pp.se
11779883Sandreas@sandberg.pp.seTick
11789883Sandreas@sandberg.pp.seX86KvmCPU::kvmRun(Tick ticks)
11799883Sandreas@sandberg.pp.se{
11809883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
11819883Sandreas@sandberg.pp.se
11829883Sandreas@sandberg.pp.se    if (interrupts->checkInterruptsRaw()) {
118310112Sandreas@sandberg.pp.se        if (interrupts->hasPendingUnmaskable()) {
118410112Sandreas@sandberg.pp.se            DPRINTF(KvmInt,
118510112Sandreas@sandberg.pp.se                    "Delivering unmaskable interrupt.\n");
118610112Sandreas@sandberg.pp.se            syncThreadContext();
118710112Sandreas@sandberg.pp.se            deliverInterrupts();
118810112Sandreas@sandberg.pp.se        } else if (kvm_run.ready_for_interrupt_injection) {
11899883Sandreas@sandberg.pp.se            // KVM claims that it is ready for an interrupt. It might
11909883Sandreas@sandberg.pp.se            // be lying if we just updated rflags and disabled
11919883Sandreas@sandberg.pp.se            // interrupts (e.g., by doing a CPU handover). Let's sync
11929883Sandreas@sandberg.pp.se            // the thread context and check if there are /really/
11939883Sandreas@sandberg.pp.se            // interrupts that should be delivered now.
11949883Sandreas@sandberg.pp.se            syncThreadContext();
11959883Sandreas@sandberg.pp.se            if (interrupts->checkInterrupts(tc)) {
11969883Sandreas@sandberg.pp.se                DPRINTF(KvmInt,
11979883Sandreas@sandberg.pp.se                        "M5 has pending interrupts, delivering interrupt.\n");
11989883Sandreas@sandberg.pp.se
11999883Sandreas@sandberg.pp.se                deliverInterrupts();
12009883Sandreas@sandberg.pp.se            } else {
12019883Sandreas@sandberg.pp.se                DPRINTF(KvmInt,
12029883Sandreas@sandberg.pp.se                        "Interrupt delivery delayed due to KVM confusion.\n");
12039883Sandreas@sandberg.pp.se                kvm_run.request_interrupt_window = 1;
12049883Sandreas@sandberg.pp.se            }
12059883Sandreas@sandberg.pp.se        } else if (!kvm_run.request_interrupt_window) {
12069883Sandreas@sandberg.pp.se            DPRINTF(KvmInt,
12079883Sandreas@sandberg.pp.se                    "M5 has pending interrupts, requesting interrupt "
12089883Sandreas@sandberg.pp.se                    "window.\n");
12099883Sandreas@sandberg.pp.se            kvm_run.request_interrupt_window = 1;
12109883Sandreas@sandberg.pp.se        }
12119883Sandreas@sandberg.pp.se    } else {
12129883Sandreas@sandberg.pp.se        kvm_run.request_interrupt_window = 0;
12139883Sandreas@sandberg.pp.se    }
12149883Sandreas@sandberg.pp.se
121510112Sandreas@sandberg.pp.se    // The CPU might have been suspended as a result of the INIT
121610112Sandreas@sandberg.pp.se    // interrupt delivery hack. In that case, don't enter into KVM.
121710112Sandreas@sandberg.pp.se    if (_status == Idle)
121810112Sandreas@sandberg.pp.se        return 0;
121910112Sandreas@sandberg.pp.se    else
122010112Sandreas@sandberg.pp.se        return kvmRunWrapper(ticks);
12219883Sandreas@sandberg.pp.se}
12229883Sandreas@sandberg.pp.se
12239883Sandreas@sandberg.pp.seTick
12249883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunDrain()
12259883Sandreas@sandberg.pp.se{
12269883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
12279883Sandreas@sandberg.pp.se
12289883Sandreas@sandberg.pp.se    if (!archIsDrained()) {
12299883Sandreas@sandberg.pp.se        DPRINTF(Drain, "kvmRunDrain: Architecture code isn't drained\n");
12309883Sandreas@sandberg.pp.se
12319883Sandreas@sandberg.pp.se        // Tell KVM to find a suitable place to deliver interrupts. This
12329883Sandreas@sandberg.pp.se        // should ensure that pending interrupts have been delivered and
12339883Sandreas@sandberg.pp.se        // things are reasonably consistent (i.e., no interrupts pending
12349883Sandreas@sandberg.pp.se        // in the guest).
12359883Sandreas@sandberg.pp.se        kvm_run.request_interrupt_window = 1;
12369883Sandreas@sandberg.pp.se
12379883Sandreas@sandberg.pp.se        // Limit the run to 1 millisecond. That is hopefully enough to
12389883Sandreas@sandberg.pp.se        // reach an interrupt window. Otherwise, we'll just try again
12399883Sandreas@sandberg.pp.se        // later.
12409883Sandreas@sandberg.pp.se        return kvmRunWrapper(1 * SimClock::Float::ms);
12419883Sandreas@sandberg.pp.se    } else {
12429883Sandreas@sandberg.pp.se        DPRINTF(Drain, "kvmRunDrain: Delivering pending IO\n");
12439883Sandreas@sandberg.pp.se
12449883Sandreas@sandberg.pp.se        return kvmRunWrapper(0);
12459883Sandreas@sandberg.pp.se    }
12469883Sandreas@sandberg.pp.se}
12479883Sandreas@sandberg.pp.se
12489883Sandreas@sandberg.pp.seTick
12499883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunWrapper(Tick ticks)
12509883Sandreas@sandberg.pp.se{
12519883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
12529883Sandreas@sandberg.pp.se
12539883Sandreas@sandberg.pp.se    // Synchronize the APIC base and CR8 here since they are present
12549883Sandreas@sandberg.pp.se    // in the kvm_run struct, which makes the synchronization really
12559883Sandreas@sandberg.pp.se    // cheap.
12569883Sandreas@sandberg.pp.se    kvm_run.apic_base = tc->readMiscReg(MISCREG_APIC_BASE);
12579883Sandreas@sandberg.pp.se    kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8);
12589883Sandreas@sandberg.pp.se
12599883Sandreas@sandberg.pp.se    const Tick run_ticks(BaseKvmCPU::kvmRun(ticks));
12609883Sandreas@sandberg.pp.se
12619883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_APIC_BASE, kvm_run.apic_base);
12629883Sandreas@sandberg.pp.se    kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8);
12639883Sandreas@sandberg.pp.se
12649883Sandreas@sandberg.pp.se    return run_ticks;
12659883Sandreas@sandberg.pp.se}
12669883Sandreas@sandberg.pp.se
12679883Sandreas@sandberg.pp.seuint64_t
12689883Sandreas@sandberg.pp.seX86KvmCPU::getHostCycles() const
12699883Sandreas@sandberg.pp.se{
12709883Sandreas@sandberg.pp.se    return getMSR(MSR_TSC);
12719883Sandreas@sandberg.pp.se}
12729883Sandreas@sandberg.pp.se
12739883Sandreas@sandberg.pp.sevoid
12749883Sandreas@sandberg.pp.seX86KvmCPU::handleIOMiscReg32(int miscreg)
12759883Sandreas@sandberg.pp.se{
12769883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
12779883Sandreas@sandberg.pp.se    const uint16_t port(kvm_run.io.port);
12789883Sandreas@sandberg.pp.se
12799883Sandreas@sandberg.pp.se    assert(kvm_run.exit_reason == KVM_EXIT_IO);
12809883Sandreas@sandberg.pp.se
12819883Sandreas@sandberg.pp.se    if (kvm_run.io.size != 4) {
12829883Sandreas@sandberg.pp.se        panic("Unexpected IO size (%u) for address 0x%x.\n",
12839883Sandreas@sandberg.pp.se              kvm_run.io.size, port);
12849883Sandreas@sandberg.pp.se    }
12859883Sandreas@sandberg.pp.se
12869883Sandreas@sandberg.pp.se    if (kvm_run.io.count != 1) {
12879883Sandreas@sandberg.pp.se        panic("Unexpected IO count (%u) for address 0x%x.\n",
12889883Sandreas@sandberg.pp.se              kvm_run.io.count, port);
12899883Sandreas@sandberg.pp.se    }
12909883Sandreas@sandberg.pp.se
12919883Sandreas@sandberg.pp.se    uint32_t *data((uint32_t *)getGuestData(kvm_run.io.data_offset));
12929883Sandreas@sandberg.pp.se    if (kvm_run.io.direction == KVM_EXIT_IO_OUT)
12939883Sandreas@sandberg.pp.se        tc->setMiscReg(miscreg, *data);
12949883Sandreas@sandberg.pp.se    else
12959883Sandreas@sandberg.pp.se        *data = tc->readMiscRegNoEffect(miscreg);
12969883Sandreas@sandberg.pp.se}
12979883Sandreas@sandberg.pp.se
12989883Sandreas@sandberg.pp.seTick
12999883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIO()
13009883Sandreas@sandberg.pp.se{
13019883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
13029883Sandreas@sandberg.pp.se    bool isWrite(kvm_run.io.direction == KVM_EXIT_IO_OUT);
13039883Sandreas@sandberg.pp.se    unsigned char *guestData(getGuestData(kvm_run.io.data_offset));
13049883Sandreas@sandberg.pp.se    Tick delay(0);
13059883Sandreas@sandberg.pp.se    uint16_t port(kvm_run.io.port);
13069883Sandreas@sandberg.pp.se    Addr pAddr;
13079883Sandreas@sandberg.pp.se    const int count(kvm_run.io.count);
13089883Sandreas@sandberg.pp.se
13099883Sandreas@sandberg.pp.se    assert(kvm_run.io.direction == KVM_EXIT_IO_IN ||
13109883Sandreas@sandberg.pp.se           kvm_run.io.direction == KVM_EXIT_IO_OUT);
13119883Sandreas@sandberg.pp.se
13129883Sandreas@sandberg.pp.se    DPRINTF(KvmIO, "KVM-x86: Handling IO instruction (%s) (port: 0x%x)\n",
13139883Sandreas@sandberg.pp.se            (isWrite ? "out" : "in"), kvm_run.io.port);
13149883Sandreas@sandberg.pp.se
13159883Sandreas@sandberg.pp.se    /* Vanilla gem5 handles PCI discovery in the TLB(!). Since we
13169883Sandreas@sandberg.pp.se     * don't use the TLB component, we need to intercept and handle
13179883Sandreas@sandberg.pp.se     * the PCI configuration space IO ports here.
13189883Sandreas@sandberg.pp.se     *
13199883Sandreas@sandberg.pp.se     * The IO port PCI discovery mechanism uses one address register
13209883Sandreas@sandberg.pp.se     * and one data register. We map the address register to a misc
13219883Sandreas@sandberg.pp.se     * reg and use that to re-route data register accesses to the
13229883Sandreas@sandberg.pp.se     * right location in the PCI configuration space.
13239883Sandreas@sandberg.pp.se     */
13249883Sandreas@sandberg.pp.se    if (port == IO_PCI_CONF_ADDR) {
13259883Sandreas@sandberg.pp.se        handleIOMiscReg32(MISCREG_PCI_CONFIG_ADDRESS);
13269883Sandreas@sandberg.pp.se        return 0;
13279883Sandreas@sandberg.pp.se    } else if ((port & ~0x3) == IO_PCI_CONF_DATA_BASE) {
13289883Sandreas@sandberg.pp.se        Addr pciConfigAddr(tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS));
13299883Sandreas@sandberg.pp.se        if (pciConfigAddr & 0x80000000) {
13309883Sandreas@sandberg.pp.se            pAddr = X86ISA::x86PciConfigAddress((pciConfigAddr & 0x7ffffffc) |
13319883Sandreas@sandberg.pp.se                                                (port & 0x3));
13329883Sandreas@sandberg.pp.se        } else {
13339883Sandreas@sandberg.pp.se            pAddr = X86ISA::x86IOAddress(port);
13349883Sandreas@sandberg.pp.se        }
13359883Sandreas@sandberg.pp.se    } else {
13369883Sandreas@sandberg.pp.se        pAddr = X86ISA::x86IOAddress(port);
13379883Sandreas@sandberg.pp.se    }
13389883Sandreas@sandberg.pp.se
13399883Sandreas@sandberg.pp.se    io_req.setPhys(pAddr, kvm_run.io.size, Request::UNCACHEABLE,
13409883Sandreas@sandberg.pp.se                   dataMasterId());
13419883Sandreas@sandberg.pp.se
13429883Sandreas@sandberg.pp.se    const MemCmd cmd(isWrite ? MemCmd::WriteReq : MemCmd::ReadReq);
13439883Sandreas@sandberg.pp.se    for (int i = 0; i < count; ++i) {
13449883Sandreas@sandberg.pp.se        Packet pkt(&io_req, cmd);
13459883Sandreas@sandberg.pp.se
13469883Sandreas@sandberg.pp.se        pkt.dataStatic(guestData);
13479883Sandreas@sandberg.pp.se        delay += dataPort.sendAtomic(&pkt);
13489883Sandreas@sandberg.pp.se
13499883Sandreas@sandberg.pp.se        guestData += kvm_run.io.size;
13509883Sandreas@sandberg.pp.se    }
13519883Sandreas@sandberg.pp.se
13529883Sandreas@sandberg.pp.se    return delay;
13539883Sandreas@sandberg.pp.se}
13549883Sandreas@sandberg.pp.se
13559883Sandreas@sandberg.pp.seTick
13569883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIRQWindowOpen()
13579883Sandreas@sandberg.pp.se{
13589883Sandreas@sandberg.pp.se    // We don't need to do anything here since this is caught the next
13599883Sandreas@sandberg.pp.se    // time we execute kvmRun(). We still overload the exit event to
13609883Sandreas@sandberg.pp.se    // silence the warning about an unhandled exit event.
13619883Sandreas@sandberg.pp.se    return 0;
13629883Sandreas@sandberg.pp.se}
13639883Sandreas@sandberg.pp.se
13649883Sandreas@sandberg.pp.sebool
13659883Sandreas@sandberg.pp.seX86KvmCPU::archIsDrained() const
13669883Sandreas@sandberg.pp.se{
13679883Sandreas@sandberg.pp.se    struct kvm_vcpu_events events;
13689883Sandreas@sandberg.pp.se
13699883Sandreas@sandberg.pp.se    getVCpuEvents(events);
13709883Sandreas@sandberg.pp.se
13719883Sandreas@sandberg.pp.se    // We could probably handle this in a by re-inserting interrupts
13729883Sandreas@sandberg.pp.se    // that are pending into gem5 on a drain. However, that would
13739883Sandreas@sandberg.pp.se    // probably be tricky to do reliably, so we'll just prevent a
13749883Sandreas@sandberg.pp.se    // drain if there is anything pending in the
13759883Sandreas@sandberg.pp.se    // guest. X86KvmCPU::kvmRunDrain() minimizes the amount of code
13769883Sandreas@sandberg.pp.se    // executed in the guest by requesting an interrupt window if
13779883Sandreas@sandberg.pp.se    // there are pending interrupts.
13789883Sandreas@sandberg.pp.se    const bool pending_events(events.exception.injected ||
13799883Sandreas@sandberg.pp.se                              events.interrupt.injected ||
13809883Sandreas@sandberg.pp.se                              events.nmi.injected || events.nmi.pending);
13819883Sandreas@sandberg.pp.se
13829883Sandreas@sandberg.pp.se    if (pending_events) {
13839883Sandreas@sandberg.pp.se        DPRINTF(Drain, "archIsDrained: Pending events: %s %s %s %s\n",
13849883Sandreas@sandberg.pp.se                events.exception.injected ? "exception" : "",
13859883Sandreas@sandberg.pp.se                events.interrupt.injected ? "interrupt" : "",
13869883Sandreas@sandberg.pp.se                events.nmi.injected ? "nmi[i]" : "",
13879883Sandreas@sandberg.pp.se                events.nmi.pending ? "nmi[p]" : "");
13889883Sandreas@sandberg.pp.se    }
13899883Sandreas@sandberg.pp.se
13909883Sandreas@sandberg.pp.se    return !pending_events;
13919883Sandreas@sandberg.pp.se}
13929883Sandreas@sandberg.pp.se
13939883Sandreas@sandberg.pp.sestatic struct kvm_cpuid_entry2
13949883Sandreas@sandberg.pp.semakeKvmCpuid(uint32_t function, uint32_t index,
13959883Sandreas@sandberg.pp.se             CpuidResult &result)
13969883Sandreas@sandberg.pp.se{
13979883Sandreas@sandberg.pp.se    struct kvm_cpuid_entry2 e;
13989883Sandreas@sandberg.pp.se    e.function = function;
13999883Sandreas@sandberg.pp.se    e.index = index;
14009883Sandreas@sandberg.pp.se    e.flags = 0;
14019883Sandreas@sandberg.pp.se    e.eax = (uint32_t)result.rax;
14029883Sandreas@sandberg.pp.se    e.ebx = (uint32_t)result.rbx;
14039883Sandreas@sandberg.pp.se    e.ecx = (uint32_t)result.rcx;
14049883Sandreas@sandberg.pp.se    e.edx = (uint32_t)result.rdx;
14059883Sandreas@sandberg.pp.se
14069883Sandreas@sandberg.pp.se    return e;
14079883Sandreas@sandberg.pp.se}
14089883Sandreas@sandberg.pp.se
14099883Sandreas@sandberg.pp.sevoid
14109883Sandreas@sandberg.pp.seX86KvmCPU::updateCPUID()
14119883Sandreas@sandberg.pp.se{
14129883Sandreas@sandberg.pp.se    Kvm::CPUIDVector m5_supported;
14139883Sandreas@sandberg.pp.se
14149883Sandreas@sandberg.pp.se    /* TODO: We currently don't support any of the functions that
14159883Sandreas@sandberg.pp.se     * iterate through data structures in the CPU using an index. It's
14169883Sandreas@sandberg.pp.se     * currently not a problem since M5 doesn't expose any of them at
14179883Sandreas@sandberg.pp.se     * the moment.
14189883Sandreas@sandberg.pp.se     */
14199883Sandreas@sandberg.pp.se
14209883Sandreas@sandberg.pp.se    /* Basic features */
14219883Sandreas@sandberg.pp.se    CpuidResult func0;
14229883Sandreas@sandberg.pp.se    X86ISA::doCpuid(tc, 0x0, 0, func0);
14239883Sandreas@sandberg.pp.se    for (uint32_t function = 0; function <= func0.rax; ++function) {
14249883Sandreas@sandberg.pp.se        CpuidResult cpuid;
14259883Sandreas@sandberg.pp.se        uint32_t idx(0);
14269883Sandreas@sandberg.pp.se
14279883Sandreas@sandberg.pp.se        X86ISA::doCpuid(tc, function, idx, cpuid);
14289883Sandreas@sandberg.pp.se        m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
14299883Sandreas@sandberg.pp.se    }
14309883Sandreas@sandberg.pp.se
14319883Sandreas@sandberg.pp.se    /* Extended features */
14329883Sandreas@sandberg.pp.se    CpuidResult efunc0;
14339883Sandreas@sandberg.pp.se    X86ISA::doCpuid(tc, 0x80000000, 0, efunc0);
14349883Sandreas@sandberg.pp.se    for (uint32_t function = 0x80000000; function <= efunc0.rax; ++function) {
14359883Sandreas@sandberg.pp.se        CpuidResult cpuid;
14369883Sandreas@sandberg.pp.se        uint32_t idx(0);
14379883Sandreas@sandberg.pp.se
14389883Sandreas@sandberg.pp.se        X86ISA::doCpuid(tc, function, idx, cpuid);
14399883Sandreas@sandberg.pp.se        m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
14409883Sandreas@sandberg.pp.se    }
14419883Sandreas@sandberg.pp.se
14429883Sandreas@sandberg.pp.se    setCPUID(m5_supported);
14439883Sandreas@sandberg.pp.se}
14449883Sandreas@sandberg.pp.se
14459883Sandreas@sandberg.pp.sevoid
14469883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const struct kvm_cpuid2 &cpuid)
14479883Sandreas@sandberg.pp.se{
14489883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_CPUID2, (void *)&cpuid) == -1)
14499883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest CPUID2 (errno: %i)\n",
14509883Sandreas@sandberg.pp.se              errno);
14519883Sandreas@sandberg.pp.se}
14529883Sandreas@sandberg.pp.se
14539883Sandreas@sandberg.pp.sevoid
14549883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const Kvm::CPUIDVector &cpuid)
14559883Sandreas@sandberg.pp.se{
14569883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_cpuid2> kvm_cpuid(
14579883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_cpuid2, struct kvm_cpuid_entry2>(cpuid.size()));
14589883Sandreas@sandberg.pp.se
14599883Sandreas@sandberg.pp.se    kvm_cpuid->nent = cpuid.size();
14609883Sandreas@sandberg.pp.se    std::copy(cpuid.begin(), cpuid.end(), kvm_cpuid->entries);
14619883Sandreas@sandberg.pp.se
14629883Sandreas@sandberg.pp.se    setCPUID(*kvm_cpuid);
14639883Sandreas@sandberg.pp.se}
14649883Sandreas@sandberg.pp.se
14659883Sandreas@sandberg.pp.sevoid
14669883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const struct kvm_msrs &msrs)
14679883Sandreas@sandberg.pp.se{
14689883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_MSRS, (void *)&msrs) == -1)
14699883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest MSRs (errno: %i)\n",
14709883Sandreas@sandberg.pp.se              errno);
14719883Sandreas@sandberg.pp.se}
14729883Sandreas@sandberg.pp.se
14739883Sandreas@sandberg.pp.sevoid
14749883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const KvmMSRVector &msrs)
14759883Sandreas@sandberg.pp.se{
14769883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
14779883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size()));
14789883Sandreas@sandberg.pp.se
14799883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = msrs.size();
14809883Sandreas@sandberg.pp.se    std::copy(msrs.begin(), msrs.end(), kvm_msrs->entries);
14819883Sandreas@sandberg.pp.se
14829883Sandreas@sandberg.pp.se    setMSRs(*kvm_msrs);
14839883Sandreas@sandberg.pp.se}
14849883Sandreas@sandberg.pp.se
14859883Sandreas@sandberg.pp.sevoid
14869883Sandreas@sandberg.pp.seX86KvmCPU::getMSRs(struct kvm_msrs &msrs) const
14879883Sandreas@sandberg.pp.se{
14889883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_MSRS, (void *)&msrs) == -1)
14899883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest MSRs (errno: %i)\n",
14909883Sandreas@sandberg.pp.se              errno);
14919883Sandreas@sandberg.pp.se}
14929883Sandreas@sandberg.pp.se
14939883Sandreas@sandberg.pp.se
14949883Sandreas@sandberg.pp.sevoid
14959883Sandreas@sandberg.pp.seX86KvmCPU::setMSR(uint32_t index, uint64_t value)
14969883Sandreas@sandberg.pp.se{
14979883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
14989883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1));
14999883Sandreas@sandberg.pp.se    struct kvm_msr_entry &entry(kvm_msrs->entries[0]);
15009883Sandreas@sandberg.pp.se
15019883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = 1;
15029883Sandreas@sandberg.pp.se    entry.index = index;
15039883Sandreas@sandberg.pp.se    entry.reserved = 0;
15049883Sandreas@sandberg.pp.se    entry.data = value;
15059883Sandreas@sandberg.pp.se
15069883Sandreas@sandberg.pp.se    setMSRs(*kvm_msrs.get());
15079883Sandreas@sandberg.pp.se}
15089883Sandreas@sandberg.pp.se
15099883Sandreas@sandberg.pp.seuint64_t
15109883Sandreas@sandberg.pp.seX86KvmCPU::getMSR(uint32_t index) const
15119883Sandreas@sandberg.pp.se{
15129883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
15139883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1));
15149883Sandreas@sandberg.pp.se    struct kvm_msr_entry &entry(kvm_msrs->entries[0]);
15159883Sandreas@sandberg.pp.se
15169883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = 1;
15179883Sandreas@sandberg.pp.se    entry.index = index;
15189883Sandreas@sandberg.pp.se    entry.reserved = 0;
15199883Sandreas@sandberg.pp.se    entry.data = 0;
15209883Sandreas@sandberg.pp.se
15219883Sandreas@sandberg.pp.se    getMSRs(*kvm_msrs.get());
15229883Sandreas@sandberg.pp.se    return entry.data;
15239883Sandreas@sandberg.pp.se}
15249883Sandreas@sandberg.pp.se
15259883Sandreas@sandberg.pp.seconst Kvm::MSRIndexVector &
15269883Sandreas@sandberg.pp.seX86KvmCPU::getMsrIntersection() const
15279883Sandreas@sandberg.pp.se{
15289883Sandreas@sandberg.pp.se    if (cachedMsrIntersection.empty()) {
15299883Sandreas@sandberg.pp.se        const Kvm::MSRIndexVector &kvm_msrs(vm.kvm.getSupportedMSRs());
15309883Sandreas@sandberg.pp.se
15319883Sandreas@sandberg.pp.se        DPRINTF(Kvm, "kvm-x86: Updating MSR intersection\n");
15329883Sandreas@sandberg.pp.se        for (auto it = kvm_msrs.cbegin(); it != kvm_msrs.cend(); ++it) {
15339883Sandreas@sandberg.pp.se            if (X86ISA::msrMap.find(*it) != X86ISA::msrMap.end()) {
15349883Sandreas@sandberg.pp.se                cachedMsrIntersection.push_back(*it);
15359883Sandreas@sandberg.pp.se                DPRINTF(Kvm, "kvm-x86: Adding MSR 0x%x\n", *it);
15369883Sandreas@sandberg.pp.se            } else {
15379883Sandreas@sandberg.pp.se                warn("kvm-x86: MSR (0x%x) unsupported by gem5. Skipping.\n",
15389883Sandreas@sandberg.pp.se                     *it);
15399883Sandreas@sandberg.pp.se            }
15409883Sandreas@sandberg.pp.se        }
15419883Sandreas@sandberg.pp.se    }
15429883Sandreas@sandberg.pp.se
15439883Sandreas@sandberg.pp.se    return cachedMsrIntersection;
15449883Sandreas@sandberg.pp.se}
15459883Sandreas@sandberg.pp.se
15469883Sandreas@sandberg.pp.sevoid
15479883Sandreas@sandberg.pp.seX86KvmCPU::getDebugRegisters(struct kvm_debugregs &regs) const
15489883Sandreas@sandberg.pp.se{
15499883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS
15509883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_DEBUGREGS, &regs) == -1)
15519883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
15529883Sandreas@sandberg.pp.se#else
15539883Sandreas@sandberg.pp.se    panic("KVM: Unsupported getDebugRegisters call.\n");
15549883Sandreas@sandberg.pp.se#endif
15559883Sandreas@sandberg.pp.se}
15569883Sandreas@sandberg.pp.se
15579883Sandreas@sandberg.pp.sevoid
15589883Sandreas@sandberg.pp.seX86KvmCPU::setDebugRegisters(const struct kvm_debugregs &regs)
15599883Sandreas@sandberg.pp.se{
15609883Sandreas@sandberg.pp.se#ifdef KVM_SET_DEBUGREGS
15619883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_DEBUGREGS, (void *)&regs) == -1)
15629883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
15639883Sandreas@sandberg.pp.se#else
15649883Sandreas@sandberg.pp.se    panic("KVM: Unsupported setDebugRegisters call.\n");
15659883Sandreas@sandberg.pp.se#endif
15669883Sandreas@sandberg.pp.se}
15679883Sandreas@sandberg.pp.se
15689883Sandreas@sandberg.pp.sevoid
15699883Sandreas@sandberg.pp.seX86KvmCPU::getXCRs(struct kvm_xcrs &regs) const
15709883Sandreas@sandberg.pp.se{
15719883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_XCRS, &regs) == -1)
15729883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
15739883Sandreas@sandberg.pp.se}
15749883Sandreas@sandberg.pp.se
15759883Sandreas@sandberg.pp.sevoid
15769883Sandreas@sandberg.pp.seX86KvmCPU::setXCRs(const struct kvm_xcrs &regs)
15779883Sandreas@sandberg.pp.se{
15789883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_XCRS, (void *)&regs) == -1)
15799883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
15809883Sandreas@sandberg.pp.se}
15819883Sandreas@sandberg.pp.se
15829883Sandreas@sandberg.pp.sevoid
15839883Sandreas@sandberg.pp.seX86KvmCPU::getXSave(struct kvm_xsave &xsave) const
15849883Sandreas@sandberg.pp.se{
15859883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_XSAVE, &xsave) == -1)
15869883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
15879883Sandreas@sandberg.pp.se}
15889883Sandreas@sandberg.pp.se
15899883Sandreas@sandberg.pp.sevoid
15909883Sandreas@sandberg.pp.seX86KvmCPU::setXSave(const struct kvm_xsave &xsave)
15919883Sandreas@sandberg.pp.se{
15929883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_XSAVE, (void *)&xsave) == -1)
15939883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
15949883Sandreas@sandberg.pp.se}
15959883Sandreas@sandberg.pp.se
15969883Sandreas@sandberg.pp.se
15979883Sandreas@sandberg.pp.sevoid
15989883Sandreas@sandberg.pp.seX86KvmCPU::getVCpuEvents(struct kvm_vcpu_events &events) const
15999883Sandreas@sandberg.pp.se{
16009883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_VCPU_EVENTS, &events) == -1)
16019883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
16029883Sandreas@sandberg.pp.se}
16039883Sandreas@sandberg.pp.se
16049883Sandreas@sandberg.pp.sevoid
16059883Sandreas@sandberg.pp.seX86KvmCPU::setVCpuEvents(const struct kvm_vcpu_events &events)
16069883Sandreas@sandberg.pp.se{
16079883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_VCPU_EVENTS, (void *)&events) == -1)
16089883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
16099883Sandreas@sandberg.pp.se}
16109883Sandreas@sandberg.pp.se
16119883Sandreas@sandberg.pp.seX86KvmCPU *
16129883Sandreas@sandberg.pp.seX86KvmCPUParams::create()
16139883Sandreas@sandberg.pp.se{
16149883Sandreas@sandberg.pp.se    return new X86KvmCPU(this);
16159883Sandreas@sandberg.pp.se}
1616