x86_cpu.cc revision 9886
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
709886Sandreas@sandberg.pp.se
719883Sandreas@sandberg.pp.se#define FOREACH_IREG()                          \
729883Sandreas@sandberg.pp.se    do {                                        \
739883Sandreas@sandberg.pp.se        APPLY_IREG(rax, INTREG_RAX);            \
749883Sandreas@sandberg.pp.se        APPLY_IREG(rbx, INTREG_RBX);            \
759883Sandreas@sandberg.pp.se        APPLY_IREG(rcx, INTREG_RCX);            \
769883Sandreas@sandberg.pp.se        APPLY_IREG(rdx, INTREG_RDX);            \
779883Sandreas@sandberg.pp.se        APPLY_IREG(rsi, INTREG_RSI);            \
789883Sandreas@sandberg.pp.se        APPLY_IREG(rdi, INTREG_RDI);            \
799883Sandreas@sandberg.pp.se        APPLY_IREG(rsp, INTREG_RSP);            \
809883Sandreas@sandberg.pp.se        APPLY_IREG(rbp, INTREG_RBP);            \
819883Sandreas@sandberg.pp.se        APPLY_IREG(r8, INTREG_R8);              \
829883Sandreas@sandberg.pp.se        APPLY_IREG(r9, INTREG_R9);              \
839883Sandreas@sandberg.pp.se        APPLY_IREG(r10, INTREG_R10);            \
849883Sandreas@sandberg.pp.se        APPLY_IREG(r11, INTREG_R11);            \
859883Sandreas@sandberg.pp.se        APPLY_IREG(r12, INTREG_R12);            \
869883Sandreas@sandberg.pp.se        APPLY_IREG(r13, INTREG_R13);            \
879883Sandreas@sandberg.pp.se        APPLY_IREG(r14, INTREG_R14);            \
889883Sandreas@sandberg.pp.se        APPLY_IREG(r15, INTREG_R15);            \
899883Sandreas@sandberg.pp.se    } while(0)
909883Sandreas@sandberg.pp.se
919883Sandreas@sandberg.pp.se#define FOREACH_SREG()                                  \
929883Sandreas@sandberg.pp.se    do {                                                \
939883Sandreas@sandberg.pp.se        APPLY_SREG(cr0, MISCREG_CR0);                   \
949883Sandreas@sandberg.pp.se        APPLY_SREG(cr2, MISCREG_CR2);                   \
959883Sandreas@sandberg.pp.se        APPLY_SREG(cr3, MISCREG_CR3);                   \
969883Sandreas@sandberg.pp.se        APPLY_SREG(cr4, MISCREG_CR4);                   \
979883Sandreas@sandberg.pp.se        APPLY_SREG(cr8, MISCREG_CR8);                   \
989883Sandreas@sandberg.pp.se        APPLY_SREG(efer, MISCREG_EFER);                 \
999883Sandreas@sandberg.pp.se        APPLY_SREG(apic_base, MISCREG_APIC_BASE);       \
1009883Sandreas@sandberg.pp.se    } while(0)
1019883Sandreas@sandberg.pp.se
1029883Sandreas@sandberg.pp.se#define FOREACH_DREG()                          \
1039883Sandreas@sandberg.pp.se    do {                                        \
1049883Sandreas@sandberg.pp.se        APPLY_DREG(db[0], MISCREG_DR0);         \
1059883Sandreas@sandberg.pp.se        APPLY_DREG(db[1], MISCREG_DR1);         \
1069883Sandreas@sandberg.pp.se        APPLY_DREG(db[2], MISCREG_DR2);         \
1079883Sandreas@sandberg.pp.se        APPLY_DREG(db[3], MISCREG_DR3);         \
1089883Sandreas@sandberg.pp.se        APPLY_DREG(dr6, MISCREG_DR6);           \
1099883Sandreas@sandberg.pp.se        APPLY_DREG(dr7, MISCREG_DR7);           \
1109883Sandreas@sandberg.pp.se    } while(0)
1119883Sandreas@sandberg.pp.se
1129883Sandreas@sandberg.pp.se#define FOREACH_SEGMENT()                                       \
1139883Sandreas@sandberg.pp.se    do {                                                        \
1149883Sandreas@sandberg.pp.se        APPLY_SEGMENT(cs, MISCREG_CS - MISCREG_SEG_SEL_BASE);   \
1159883Sandreas@sandberg.pp.se        APPLY_SEGMENT(ds, MISCREG_DS - MISCREG_SEG_SEL_BASE);   \
1169883Sandreas@sandberg.pp.se        APPLY_SEGMENT(es, MISCREG_ES - MISCREG_SEG_SEL_BASE);   \
1179883Sandreas@sandberg.pp.se        APPLY_SEGMENT(fs, MISCREG_FS - MISCREG_SEG_SEL_BASE);   \
1189883Sandreas@sandberg.pp.se        APPLY_SEGMENT(gs, MISCREG_GS - MISCREG_SEG_SEL_BASE);   \
1199883Sandreas@sandberg.pp.se        APPLY_SEGMENT(ss, MISCREG_SS - MISCREG_SEG_SEL_BASE);   \
1209883Sandreas@sandberg.pp.se        APPLY_SEGMENT(tr, MISCREG_TR - MISCREG_SEG_SEL_BASE);   \
1219883Sandreas@sandberg.pp.se        APPLY_SEGMENT(ldt, MISCREG_TSL - MISCREG_SEG_SEL_BASE); \
1229883Sandreas@sandberg.pp.se    } while(0)
1239883Sandreas@sandberg.pp.se
1249883Sandreas@sandberg.pp.se#define FOREACH_DTABLE()                                        \
1259883Sandreas@sandberg.pp.se    do {                                                        \
1269883Sandreas@sandberg.pp.se        APPLY_DTABLE(gdt, MISCREG_TSG - MISCREG_SEG_SEL_BASE);  \
1279883Sandreas@sandberg.pp.se        APPLY_DTABLE(idt, MISCREG_IDTR - MISCREG_SEG_SEL_BASE); \
1289883Sandreas@sandberg.pp.se    } while(0)
1299883Sandreas@sandberg.pp.se
1309883Sandreas@sandberg.pp.setemplate<typename STRUCT, typename ENTRY>
1319883Sandreas@sandberg.pp.sestatic STRUCT *newVarStruct(size_t entries)
1329883Sandreas@sandberg.pp.se{
1339883Sandreas@sandberg.pp.se    return (STRUCT *)operator new(sizeof(STRUCT) + entries * sizeof(ENTRY));
1349883Sandreas@sandberg.pp.se}
1359883Sandreas@sandberg.pp.se
1369883Sandreas@sandberg.pp.sestatic void
1379883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_regs &regs)
1389883Sandreas@sandberg.pp.se{
1399883Sandreas@sandberg.pp.se    inform("KVM register state:\n");
1409883Sandreas@sandberg.pp.se
1419883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg)                  \
1429883Sandreas@sandberg.pp.se    inform("\t" # kreg ": 0x%llx\n", regs.kreg)
1439883Sandreas@sandberg.pp.se
1449883Sandreas@sandberg.pp.se    FOREACH_IREG();
1459883Sandreas@sandberg.pp.se
1469883Sandreas@sandberg.pp.se#undef APPLY_IREG
1479883Sandreas@sandberg.pp.se
1489883Sandreas@sandberg.pp.se    inform("\trip: 0x%llx\n", regs.rip);
1499883Sandreas@sandberg.pp.se    inform("\trflags: 0x%llx\n", regs.rflags);
1509883Sandreas@sandberg.pp.se}
1519883Sandreas@sandberg.pp.se
1529883Sandreas@sandberg.pp.sestatic void
1539883Sandreas@sandberg.pp.sedumpKvm(const char *reg_name, const struct kvm_segment &seg)
1549883Sandreas@sandberg.pp.se{
1559883Sandreas@sandberg.pp.se    inform("\t%s: @0x%llx+%x [sel: 0x%x, type: 0x%x]\n"
1569883Sandreas@sandberg.pp.se           "\t\tpres.: %u, dpl: %u, db: %u, s: %u, l: %u, g: %u, avl: %u, unus.: %u\n",
1579883Sandreas@sandberg.pp.se           reg_name,
1589883Sandreas@sandberg.pp.se           seg.base, seg.limit, seg.selector, seg.type,
1599883Sandreas@sandberg.pp.se           seg.present, seg.dpl, seg.db, seg.s, seg.l, seg.g, seg.avl, seg.unusable);
1609883Sandreas@sandberg.pp.se}
1619883Sandreas@sandberg.pp.se
1629883Sandreas@sandberg.pp.sestatic void
1639883Sandreas@sandberg.pp.sedumpKvm(const char *reg_name, const struct kvm_dtable &dtable)
1649883Sandreas@sandberg.pp.se{
1659883Sandreas@sandberg.pp.se    inform("\t%s: @0x%llx+%x\n",
1669883Sandreas@sandberg.pp.se           reg_name, dtable.base, dtable.limit);
1679883Sandreas@sandberg.pp.se}
1689883Sandreas@sandberg.pp.se
1699883Sandreas@sandberg.pp.sestatic void
1709883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_sregs &sregs)
1719883Sandreas@sandberg.pp.se{
1729883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg)                          \
1739883Sandreas@sandberg.pp.se    inform("\t" # kreg ": 0x%llx\n", sregs.kreg);
1749883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx)                \
1759883Sandreas@sandberg.pp.se    dumpKvm(# kreg, sregs.kreg);
1769883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx)                 \
1779883Sandreas@sandberg.pp.se    dumpKvm(# kreg, sregs.kreg);
1789883Sandreas@sandberg.pp.se
1799883Sandreas@sandberg.pp.se    inform("Special registers:\n");
1809883Sandreas@sandberg.pp.se    FOREACH_SEGMENT();
1819883Sandreas@sandberg.pp.se    FOREACH_SREG();
1829883Sandreas@sandberg.pp.se    FOREACH_DTABLE();
1839883Sandreas@sandberg.pp.se
1849883Sandreas@sandberg.pp.se    inform("Interrupt Bitmap:");
1859883Sandreas@sandberg.pp.se    for (int i = 0; i < KVM_NR_INTERRUPTS; i += 64)
1869883Sandreas@sandberg.pp.se        inform("  0x%.8x", sregs.interrupt_bitmap[i / 64]);
1879883Sandreas@sandberg.pp.se
1889883Sandreas@sandberg.pp.se#undef APPLY_SREG
1899883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
1909883Sandreas@sandberg.pp.se#undef APPLY_DTABLE
1919883Sandreas@sandberg.pp.se}
1929883Sandreas@sandberg.pp.se
1939883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS
1949883Sandreas@sandberg.pp.sestatic void
1959883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_debugregs &regs)
1969883Sandreas@sandberg.pp.se{
1979883Sandreas@sandberg.pp.se    inform("KVM debug state:\n");
1989883Sandreas@sandberg.pp.se
1999883Sandreas@sandberg.pp.se#define APPLY_DREG(kreg, mreg)                  \
2009883Sandreas@sandberg.pp.se    inform("\t" # kreg ": 0x%llx\n", regs.kreg)
2019883Sandreas@sandberg.pp.se
2029883Sandreas@sandberg.pp.se    FOREACH_DREG();
2039883Sandreas@sandberg.pp.se
2049883Sandreas@sandberg.pp.se#undef APPLY_DREG
2059883Sandreas@sandberg.pp.se
2069883Sandreas@sandberg.pp.se    inform("\tflags: 0x%llx\n", regs.flags);
2079883Sandreas@sandberg.pp.se}
2089883Sandreas@sandberg.pp.se#endif
2099883Sandreas@sandberg.pp.se
2109883Sandreas@sandberg.pp.sestatic void
2119883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_fpu &fpu)
2129883Sandreas@sandberg.pp.se{
2139883Sandreas@sandberg.pp.se    inform("FPU registers:\n");
2149883Sandreas@sandberg.pp.se    inform("\tfcw: 0x%x\n", fpu.fcw);
2159883Sandreas@sandberg.pp.se    inform("\tfsw: 0x%x\n", fpu.fsw);
2169883Sandreas@sandberg.pp.se    inform("\tftwx: 0x%x\n", fpu.ftwx);
2179883Sandreas@sandberg.pp.se    inform("\tlast_opcode: 0x%x\n", fpu.last_opcode);
2189883Sandreas@sandberg.pp.se    inform("\tlast_ip: 0x%x\n", fpu.last_ip);
2199883Sandreas@sandberg.pp.se    inform("\tlast_dp: 0x%x\n", fpu.last_dp);
2209883Sandreas@sandberg.pp.se    inform("\tmxcsr: 0x%x\n", fpu.mxcsr);
2219883Sandreas@sandberg.pp.se    inform("\tFP Stack:\n");
2229883Sandreas@sandberg.pp.se    for (int i = 0; i < 8; ++i) {
2239883Sandreas@sandberg.pp.se        const bool empty(!((fpu.ftwx >> i) & 0x1));
2249883Sandreas@sandberg.pp.se        char hex[33];
2259883Sandreas@sandberg.pp.se        for (int j = 0; j < 16; ++j)
2269883Sandreas@sandberg.pp.se            snprintf(&hex[j*2], 3, "%.2x", fpu.fpr[i][j]);
2279883Sandreas@sandberg.pp.se        inform("\t\t%i: 0x%s%s\n", i, hex, empty ? " (e)" : "");
2289883Sandreas@sandberg.pp.se    }
2299883Sandreas@sandberg.pp.se    inform("\tXMM registers:\n");
2309883Sandreas@sandberg.pp.se    for (int i = 0; i < 16; ++i) {
2319883Sandreas@sandberg.pp.se        char hex[33];
2329883Sandreas@sandberg.pp.se        for (int j = 0; j < 16; ++j)
2339883Sandreas@sandberg.pp.se            snprintf(&hex[j*2], 3, "%.2x", fpu.xmm[i][j]);
2349883Sandreas@sandberg.pp.se        inform("\t\t%i: 0x%s\n", i, hex);
2359883Sandreas@sandberg.pp.se    }
2369883Sandreas@sandberg.pp.se}
2379883Sandreas@sandberg.pp.se
2389883Sandreas@sandberg.pp.sestatic void
2399883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_msrs &msrs)
2409883Sandreas@sandberg.pp.se{
2419883Sandreas@sandberg.pp.se    inform("MSRs:\n");
2429883Sandreas@sandberg.pp.se
2439883Sandreas@sandberg.pp.se    for (int i = 0; i < msrs.nmsrs; ++i) {
2449883Sandreas@sandberg.pp.se        const struct kvm_msr_entry &e(msrs.entries[i]);
2459883Sandreas@sandberg.pp.se
2469883Sandreas@sandberg.pp.se        inform("\t0x%x: 0x%x\n", e.index, e.data);
2479883Sandreas@sandberg.pp.se    }
2489883Sandreas@sandberg.pp.se}
2499883Sandreas@sandberg.pp.se
2509883Sandreas@sandberg.pp.sestatic void
2519883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_xcrs &regs)
2529883Sandreas@sandberg.pp.se{
2539883Sandreas@sandberg.pp.se    inform("KVM XCR registers:\n");
2549883Sandreas@sandberg.pp.se
2559883Sandreas@sandberg.pp.se    inform("\tFlags: 0x%x\n", regs.flags);
2569883Sandreas@sandberg.pp.se    for (int i = 0; i < regs.nr_xcrs; ++i) {
2579883Sandreas@sandberg.pp.se        inform("\tXCR[0x%x]: 0x%x\n",
2589883Sandreas@sandberg.pp.se               regs.xcrs[i].xcr,
2599883Sandreas@sandberg.pp.se               regs.xcrs[i].value);
2609883Sandreas@sandberg.pp.se    }
2619883Sandreas@sandberg.pp.se}
2629883Sandreas@sandberg.pp.se
2639883Sandreas@sandberg.pp.sestatic void
2649883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_xsave &xsave)
2659883Sandreas@sandberg.pp.se{
2669883Sandreas@sandberg.pp.se    inform("KVM XSAVE:\n");
2679883Sandreas@sandberg.pp.se
2689883Sandreas@sandberg.pp.se    Trace::dump((Tick)-1, "xsave.region",
2699883Sandreas@sandberg.pp.se                xsave.region, sizeof(xsave.region));
2709883Sandreas@sandberg.pp.se}
2719883Sandreas@sandberg.pp.se
2729883Sandreas@sandberg.pp.sestatic void
2739883Sandreas@sandberg.pp.sedumpKvm(const struct kvm_vcpu_events &events)
2749883Sandreas@sandberg.pp.se{
2759883Sandreas@sandberg.pp.se    inform("vCPU events:\n");
2769883Sandreas@sandberg.pp.se
2779883Sandreas@sandberg.pp.se    inform("\tException: [inj: %i, nr: %i, has_ec: %i, ec: %i]\n",
2789883Sandreas@sandberg.pp.se           events.exception.injected, events.exception.nr,
2799883Sandreas@sandberg.pp.se           events.exception.has_error_code, events.exception.error_code);
2809883Sandreas@sandberg.pp.se
2819883Sandreas@sandberg.pp.se    inform("\tInterrupt: [inj: %i, nr: %i, soft: %i]\n",
2829883Sandreas@sandberg.pp.se           events.interrupt.injected, events.interrupt.nr,
2839883Sandreas@sandberg.pp.se           events.interrupt.soft);
2849883Sandreas@sandberg.pp.se
2859883Sandreas@sandberg.pp.se    inform("\tNMI: [inj: %i, pending: %i, masked: %i]\n",
2869883Sandreas@sandberg.pp.se           events.nmi.injected, events.nmi.pending,
2879883Sandreas@sandberg.pp.se           events.nmi.masked);
2889883Sandreas@sandberg.pp.se
2899883Sandreas@sandberg.pp.se    inform("\tSIPI vector: 0x%x\n", events.sipi_vector);
2909883Sandreas@sandberg.pp.se    inform("\tFlags: 0x%x\n", events.flags);
2919883Sandreas@sandberg.pp.se}
2929883Sandreas@sandberg.pp.se
2939884Sandreas@sandberg.pp.sestatic bool
2949884Sandreas@sandberg.pp.seisCanonicalAddress(uint64_t addr)
2959884Sandreas@sandberg.pp.se{
2969884Sandreas@sandberg.pp.se    // x86-64 doesn't currently use the full 64-bit virtual address
2979884Sandreas@sandberg.pp.se    // space, instead it uses signed 48 bit addresses that are
2989884Sandreas@sandberg.pp.se    // sign-extended to 64 bits.  Such addresses are known as
2999884Sandreas@sandberg.pp.se    // "canonical".
3009884Sandreas@sandberg.pp.se    uint64_t upper_half(addr & 0xffff800000000000ULL);
3019884Sandreas@sandberg.pp.se    return upper_half == 0 || upper_half == 0xffff800000000000;
3029884Sandreas@sandberg.pp.se}
3039884Sandreas@sandberg.pp.se
3049884Sandreas@sandberg.pp.sestatic void
3059884Sandreas@sandberg.pp.secheckSeg(const char *name, const int idx, const struct kvm_segment &seg,
3069884Sandreas@sandberg.pp.se         struct kvm_sregs sregs)
3079884Sandreas@sandberg.pp.se{
3089884Sandreas@sandberg.pp.se    // Check the register base
3099884Sandreas@sandberg.pp.se    switch (idx) {
3109884Sandreas@sandberg.pp.se      case MISCREG_TSL:
3119884Sandreas@sandberg.pp.se      case MISCREG_TR:
3129884Sandreas@sandberg.pp.se      case MISCREG_FS:
3139884Sandreas@sandberg.pp.se      case MISCREG_GS:
3149884Sandreas@sandberg.pp.se        if (!isCanonicalAddress(seg.base))
3159884Sandreas@sandberg.pp.se            warn("Illegal %s base: 0x%x\n", name, seg.base);
3169884Sandreas@sandberg.pp.se        break;
3179884Sandreas@sandberg.pp.se
3189884Sandreas@sandberg.pp.se      case MISCREG_SS:
3199884Sandreas@sandberg.pp.se      case MISCREG_DS:
3209884Sandreas@sandberg.pp.se      case MISCREG_ES:
3219884Sandreas@sandberg.pp.se        if (seg.unusable)
3229884Sandreas@sandberg.pp.se            break;
3239884Sandreas@sandberg.pp.se      case MISCREG_CS:
3249884Sandreas@sandberg.pp.se        if (seg.base & 0xffffffff00000000ULL)
3259884Sandreas@sandberg.pp.se            warn("Illegal %s base: 0x%x\n", name, seg.base);
3269884Sandreas@sandberg.pp.se        break;
3279884Sandreas@sandberg.pp.se    }
3289884Sandreas@sandberg.pp.se
3299884Sandreas@sandberg.pp.se    // Check the type
3309884Sandreas@sandberg.pp.se    switch (idx) {
3319884Sandreas@sandberg.pp.se      case MISCREG_CS:
3329884Sandreas@sandberg.pp.se        switch (seg.type) {
3339884Sandreas@sandberg.pp.se          case 3:
3349884Sandreas@sandberg.pp.se            if (seg.dpl != 0)
3359884Sandreas@sandberg.pp.se                warn("CS type is 3 but dpl != 0.\n");
3369884Sandreas@sandberg.pp.se            break;
3379884Sandreas@sandberg.pp.se          case 9:
3389884Sandreas@sandberg.pp.se          case 11:
3399884Sandreas@sandberg.pp.se            if (seg.dpl != sregs.ss.dpl)
3409884Sandreas@sandberg.pp.se                warn("CS type is %i but CS DPL != SS DPL\n", seg.type);
3419884Sandreas@sandberg.pp.se            break;
3429884Sandreas@sandberg.pp.se          case 13:
3439884Sandreas@sandberg.pp.se          case 15:
3449884Sandreas@sandberg.pp.se            if (seg.dpl > sregs.ss.dpl)
3459884Sandreas@sandberg.pp.se                warn("CS type is %i but CS DPL > SS DPL\n", seg.type);
3469884Sandreas@sandberg.pp.se            break;
3479884Sandreas@sandberg.pp.se          default:
3489884Sandreas@sandberg.pp.se            warn("Illegal CS type: %i\n", seg.type);
3499884Sandreas@sandberg.pp.se            break;
3509884Sandreas@sandberg.pp.se        }
3519884Sandreas@sandberg.pp.se        break;
3529884Sandreas@sandberg.pp.se
3539884Sandreas@sandberg.pp.se      case MISCREG_SS:
3549884Sandreas@sandberg.pp.se        if (seg.unusable)
3559884Sandreas@sandberg.pp.se            break;
3569884Sandreas@sandberg.pp.se        switch (seg.type) {
3579884Sandreas@sandberg.pp.se          case 3:
3589884Sandreas@sandberg.pp.se            if (sregs.cs.type == 3 && seg.dpl != 0)
3599884Sandreas@sandberg.pp.se                warn("CS type is 3, but SS DPL is != 0.\n");
3609884Sandreas@sandberg.pp.se            /* FALLTHROUGH */
3619884Sandreas@sandberg.pp.se          case 7:
3629884Sandreas@sandberg.pp.se            if (!(sregs.cr0 & 1) && seg.dpl != 0)
3639884Sandreas@sandberg.pp.se                warn("SS DPL is %i, but CR0 PE is 0\n", seg.dpl);
3649884Sandreas@sandberg.pp.se            break;
3659884Sandreas@sandberg.pp.se          default:
3669884Sandreas@sandberg.pp.se            warn("Illegal SS type: %i\n", seg.type);
3679884Sandreas@sandberg.pp.se            break;
3689884Sandreas@sandberg.pp.se        }
3699884Sandreas@sandberg.pp.se        break;
3709884Sandreas@sandberg.pp.se
3719884Sandreas@sandberg.pp.se      case MISCREG_DS:
3729884Sandreas@sandberg.pp.se      case MISCREG_ES:
3739884Sandreas@sandberg.pp.se      case MISCREG_FS:
3749884Sandreas@sandberg.pp.se      case MISCREG_GS:
3759884Sandreas@sandberg.pp.se        if (seg.unusable)
3769884Sandreas@sandberg.pp.se            break;
3779884Sandreas@sandberg.pp.se        if (!(seg.type & 0x1) ||
3789884Sandreas@sandberg.pp.se            ((seg.type & 0x8) && !(seg.type & 0x2)))
3799884Sandreas@sandberg.pp.se            warn("%s has an illegal type field: %i\n", name, seg.type);
3809884Sandreas@sandberg.pp.se        break;
3819884Sandreas@sandberg.pp.se
3829884Sandreas@sandberg.pp.se      case MISCREG_TR:
3839884Sandreas@sandberg.pp.se        // TODO: We should check the CPU mode
3849884Sandreas@sandberg.pp.se        if (seg.type != 3 && seg.type != 11)
3859884Sandreas@sandberg.pp.se            warn("%s: Illegal segment type (%i)\n", name, seg.type);
3869884Sandreas@sandberg.pp.se        break;
3879884Sandreas@sandberg.pp.se
3889884Sandreas@sandberg.pp.se      case MISCREG_TSL:
3899884Sandreas@sandberg.pp.se        if (seg.unusable)
3909884Sandreas@sandberg.pp.se            break;
3919884Sandreas@sandberg.pp.se        if (seg.type != 2)
3929884Sandreas@sandberg.pp.se            warn("%s: Illegal segment type (%i)\n", name, seg.type);
3939884Sandreas@sandberg.pp.se        break;
3949884Sandreas@sandberg.pp.se    }
3959884Sandreas@sandberg.pp.se
3969884Sandreas@sandberg.pp.se    switch (idx) {
3979884Sandreas@sandberg.pp.se      case MISCREG_SS:
3989884Sandreas@sandberg.pp.se      case MISCREG_DS:
3999884Sandreas@sandberg.pp.se      case MISCREG_ES:
4009884Sandreas@sandberg.pp.se      case MISCREG_FS:
4019884Sandreas@sandberg.pp.se      case MISCREG_GS:
4029884Sandreas@sandberg.pp.se        if (seg.unusable)
4039884Sandreas@sandberg.pp.se            break;
4049884Sandreas@sandberg.pp.se      case MISCREG_CS:
4059884Sandreas@sandberg.pp.se        if (!seg.s)
4069884Sandreas@sandberg.pp.se            warn("%s: S flag not set\n", name);
4079884Sandreas@sandberg.pp.se        break;
4089884Sandreas@sandberg.pp.se
4099884Sandreas@sandberg.pp.se      case MISCREG_TSL:
4109884Sandreas@sandberg.pp.se        if (seg.unusable)
4119884Sandreas@sandberg.pp.se            break;
4129884Sandreas@sandberg.pp.se      case MISCREG_TR:
4139884Sandreas@sandberg.pp.se        if (seg.s)
4149884Sandreas@sandberg.pp.se            warn("%s: S flag is set\n", name);
4159884Sandreas@sandberg.pp.se        break;
4169884Sandreas@sandberg.pp.se    }
4179884Sandreas@sandberg.pp.se
4189884Sandreas@sandberg.pp.se    switch (idx) {
4199884Sandreas@sandberg.pp.se      case MISCREG_SS:
4209884Sandreas@sandberg.pp.se      case MISCREG_DS:
4219884Sandreas@sandberg.pp.se      case MISCREG_ES:
4229884Sandreas@sandberg.pp.se      case MISCREG_FS:
4239884Sandreas@sandberg.pp.se      case MISCREG_GS:
4249884Sandreas@sandberg.pp.se      case MISCREG_TSL:
4259884Sandreas@sandberg.pp.se        if (seg.unusable)
4269884Sandreas@sandberg.pp.se            break;
4279884Sandreas@sandberg.pp.se      case MISCREG_TR:
4289884Sandreas@sandberg.pp.se      case MISCREG_CS:
4299884Sandreas@sandberg.pp.se        if (!seg.present)
4309884Sandreas@sandberg.pp.se            warn("%s: P flag not set\n", name);
4319884Sandreas@sandberg.pp.se
4329884Sandreas@sandberg.pp.se        if (((seg.limit & 0xFFF) == 0 && seg.g) ||
4339884Sandreas@sandberg.pp.se            ((seg.limit & 0xFFF00000) != 0 && !seg.g)) {
4349884Sandreas@sandberg.pp.se            warn("%s limit (0x%x) and g (%i) combination is illegal.\n",
4359884Sandreas@sandberg.pp.se                 name, seg.limit, seg.g);
4369884Sandreas@sandberg.pp.se        }
4379884Sandreas@sandberg.pp.se        break;
4389884Sandreas@sandberg.pp.se    }
4399884Sandreas@sandberg.pp.se
4409884Sandreas@sandberg.pp.se    // TODO: Check CS DB
4419884Sandreas@sandberg.pp.se}
4429884Sandreas@sandberg.pp.se
4439883Sandreas@sandberg.pp.seX86KvmCPU::X86KvmCPU(X86KvmCPUParams *params)
4449883Sandreas@sandberg.pp.se    : BaseKvmCPU(params)
4459883Sandreas@sandberg.pp.se{
4469883Sandreas@sandberg.pp.se    Kvm &kvm(vm.kvm);
4479883Sandreas@sandberg.pp.se
4489883Sandreas@sandberg.pp.se    if (!kvm.capSetTSSAddress())
4499883Sandreas@sandberg.pp.se        panic("KVM: Missing capability (KVM_CAP_SET_TSS_ADDR)\n");
4509883Sandreas@sandberg.pp.se    if (!kvm.capExtendedCPUID())
4519883Sandreas@sandberg.pp.se        panic("KVM: Missing capability (KVM_CAP_EXT_CPUID)\n");
4529883Sandreas@sandberg.pp.se    if (!kvm.capUserNMI())
4539883Sandreas@sandberg.pp.se        warn("KVM: Missing capability (KVM_CAP_USER_NMI)\n");
4549883Sandreas@sandberg.pp.se    if (!kvm.capVCPUEvents())
4559883Sandreas@sandberg.pp.se        warn("KVM: Missing capability (KVM_CAP_VCPU_EVENTS)\n");
4569883Sandreas@sandberg.pp.se
4579883Sandreas@sandberg.pp.se    haveDebugRegs = kvm.capDebugRegs();
4589883Sandreas@sandberg.pp.se    haveXSave = kvm.capXSave();
4599883Sandreas@sandberg.pp.se    haveXCRs = kvm.capXCRs();
4609883Sandreas@sandberg.pp.se}
4619883Sandreas@sandberg.pp.se
4629883Sandreas@sandberg.pp.seX86KvmCPU::~X86KvmCPU()
4639883Sandreas@sandberg.pp.se{
4649883Sandreas@sandberg.pp.se}
4659883Sandreas@sandberg.pp.se
4669883Sandreas@sandberg.pp.sevoid
4679883Sandreas@sandberg.pp.seX86KvmCPU::startup()
4689883Sandreas@sandberg.pp.se{
4699883Sandreas@sandberg.pp.se    BaseKvmCPU::startup();
4709883Sandreas@sandberg.pp.se
4719883Sandreas@sandberg.pp.se    updateCPUID();
4729883Sandreas@sandberg.pp.se
4739883Sandreas@sandberg.pp.se    io_req.setThreadContext(tc->contextId(), 0);
4749883Sandreas@sandberg.pp.se
4759883Sandreas@sandberg.pp.se    // TODO: Do we need to create an identity mapped TSS area? We
4769883Sandreas@sandberg.pp.se    // should call kvm.vm.setTSSAddress() here in that case. It should
4779883Sandreas@sandberg.pp.se    // only be needed for old versions of the virtualization
4789883Sandreas@sandberg.pp.se    // extensions. We should make sure that the identity range is
4799883Sandreas@sandberg.pp.se    // reserved in the e820 memory map in that case.
4809883Sandreas@sandberg.pp.se}
4819883Sandreas@sandberg.pp.se
4829883Sandreas@sandberg.pp.sevoid
4839883Sandreas@sandberg.pp.seX86KvmCPU::dump()
4849883Sandreas@sandberg.pp.se{
4859883Sandreas@sandberg.pp.se    dumpIntRegs();
4869883Sandreas@sandberg.pp.se    dumpFpuRegs();
4879883Sandreas@sandberg.pp.se    dumpSpecRegs();
4889883Sandreas@sandberg.pp.se    dumpDebugRegs();
4899883Sandreas@sandberg.pp.se    dumpXCRs();
4909883Sandreas@sandberg.pp.se    dumpVCpuEvents();
4919883Sandreas@sandberg.pp.se    dumpMSRs();
4929883Sandreas@sandberg.pp.se    dumpXSave();
4939883Sandreas@sandberg.pp.se}
4949883Sandreas@sandberg.pp.se
4959883Sandreas@sandberg.pp.sevoid
4969883Sandreas@sandberg.pp.seX86KvmCPU::dumpFpuRegs() const
4979883Sandreas@sandberg.pp.se{
4989883Sandreas@sandberg.pp.se    struct kvm_fpu fpu;
4999883Sandreas@sandberg.pp.se    getFPUState(fpu);
5009883Sandreas@sandberg.pp.se    dumpKvm(fpu);
5019883Sandreas@sandberg.pp.se}
5029883Sandreas@sandberg.pp.se
5039883Sandreas@sandberg.pp.sevoid
5049883Sandreas@sandberg.pp.seX86KvmCPU::dumpIntRegs() const
5059883Sandreas@sandberg.pp.se{
5069883Sandreas@sandberg.pp.se    struct kvm_regs regs;
5079883Sandreas@sandberg.pp.se    getRegisters(regs);
5089883Sandreas@sandberg.pp.se    dumpKvm(regs);
5099883Sandreas@sandberg.pp.se}
5109883Sandreas@sandberg.pp.se
5119883Sandreas@sandberg.pp.sevoid
5129883Sandreas@sandberg.pp.seX86KvmCPU::dumpSpecRegs() const
5139883Sandreas@sandberg.pp.se{
5149883Sandreas@sandberg.pp.se    struct kvm_sregs sregs;
5159883Sandreas@sandberg.pp.se    getSpecialRegisters(sregs);
5169883Sandreas@sandberg.pp.se    dumpKvm(sregs);
5179883Sandreas@sandberg.pp.se}
5189883Sandreas@sandberg.pp.se
5199883Sandreas@sandberg.pp.sevoid
5209883Sandreas@sandberg.pp.seX86KvmCPU::dumpDebugRegs() const
5219883Sandreas@sandberg.pp.se{
5229883Sandreas@sandberg.pp.se    if (haveDebugRegs) {
5239883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS
5249883Sandreas@sandberg.pp.se        struct kvm_debugregs dregs;
5259883Sandreas@sandberg.pp.se        getDebugRegisters(dregs);
5269883Sandreas@sandberg.pp.se        dumpKvm(dregs);
5279883Sandreas@sandberg.pp.se#endif
5289883Sandreas@sandberg.pp.se    } else {
5299883Sandreas@sandberg.pp.se        inform("Debug registers not supported by kernel.\n");
5309883Sandreas@sandberg.pp.se    }
5319883Sandreas@sandberg.pp.se}
5329883Sandreas@sandberg.pp.se
5339883Sandreas@sandberg.pp.sevoid
5349883Sandreas@sandberg.pp.seX86KvmCPU::dumpXCRs() const
5359883Sandreas@sandberg.pp.se{
5369883Sandreas@sandberg.pp.se    if (haveXCRs) {
5379883Sandreas@sandberg.pp.se        struct kvm_xcrs xcrs;
5389883Sandreas@sandberg.pp.se        getXCRs(xcrs);
5399883Sandreas@sandberg.pp.se        dumpKvm(xcrs);
5409883Sandreas@sandberg.pp.se    } else {
5419883Sandreas@sandberg.pp.se        inform("XCRs not supported by kernel.\n");
5429883Sandreas@sandberg.pp.se    }
5439883Sandreas@sandberg.pp.se}
5449883Sandreas@sandberg.pp.se
5459883Sandreas@sandberg.pp.sevoid
5469883Sandreas@sandberg.pp.seX86KvmCPU::dumpXSave() const
5479883Sandreas@sandberg.pp.se{
5489883Sandreas@sandberg.pp.se    if (haveXSave) {
5499883Sandreas@sandberg.pp.se        struct kvm_xsave xsave;
5509883Sandreas@sandberg.pp.se        getXSave(xsave);
5519883Sandreas@sandberg.pp.se        dumpKvm(xsave);
5529883Sandreas@sandberg.pp.se    } else {
5539883Sandreas@sandberg.pp.se        inform("XSave not supported by kernel.\n");
5549883Sandreas@sandberg.pp.se    }
5559883Sandreas@sandberg.pp.se}
5569883Sandreas@sandberg.pp.se
5579883Sandreas@sandberg.pp.sevoid
5589883Sandreas@sandberg.pp.seX86KvmCPU::dumpVCpuEvents() const
5599883Sandreas@sandberg.pp.se{
5609883Sandreas@sandberg.pp.se    struct kvm_vcpu_events events;
5619883Sandreas@sandberg.pp.se    getVCpuEvents(events);
5629883Sandreas@sandberg.pp.se    dumpKvm(events);
5639883Sandreas@sandberg.pp.se}
5649883Sandreas@sandberg.pp.se
5659883Sandreas@sandberg.pp.sevoid
5669883Sandreas@sandberg.pp.seX86KvmCPU::dumpMSRs() const
5679883Sandreas@sandberg.pp.se{
5689883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &supported_msrs(vm.kvm.getSupportedMSRs());
5699883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> msrs(
5709883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(
5719883Sandreas@sandberg.pp.se            supported_msrs.size()));
5729883Sandreas@sandberg.pp.se
5739883Sandreas@sandberg.pp.se    msrs->nmsrs = supported_msrs.size();
5749883Sandreas@sandberg.pp.se    for (int i = 0; i < supported_msrs.size(); ++i) {
5759883Sandreas@sandberg.pp.se        struct kvm_msr_entry &e(msrs->entries[i]);
5769883Sandreas@sandberg.pp.se        e.index = supported_msrs[i];
5779883Sandreas@sandberg.pp.se        e.reserved = 0;
5789883Sandreas@sandberg.pp.se        e.data = 0;
5799883Sandreas@sandberg.pp.se    }
5809883Sandreas@sandberg.pp.se    getMSRs(*msrs.get());
5819883Sandreas@sandberg.pp.se
5829883Sandreas@sandberg.pp.se    dumpKvm(*msrs.get());
5839883Sandreas@sandberg.pp.se}
5849883Sandreas@sandberg.pp.se
5859883Sandreas@sandberg.pp.sevoid
5869883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmState()
5879883Sandreas@sandberg.pp.se{
5889883Sandreas@sandberg.pp.se    updateKvmStateRegs();
5899883Sandreas@sandberg.pp.se    updateKvmStateSRegs();
5909883Sandreas@sandberg.pp.se    updateKvmStateFPU();
5919883Sandreas@sandberg.pp.se    updateKvmStateMSRs();
5929883Sandreas@sandberg.pp.se
5939883Sandreas@sandberg.pp.se    DPRINTF(KvmContext, "X86KvmCPU::updateKvmState():\n");
5949883Sandreas@sandberg.pp.se    if (DTRACE(KvmContext))
5959883Sandreas@sandberg.pp.se        dump();
5969883Sandreas@sandberg.pp.se}
5979883Sandreas@sandberg.pp.se
5989883Sandreas@sandberg.pp.sevoid
5999883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateRegs()
6009883Sandreas@sandberg.pp.se{
6019883Sandreas@sandberg.pp.se    struct kvm_regs regs;
6029883Sandreas@sandberg.pp.se
6039883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) regs.kreg = tc->readIntReg(mreg)
6049883Sandreas@sandberg.pp.se    FOREACH_IREG();
6059883Sandreas@sandberg.pp.se#undef APPLY_IREG
6069883Sandreas@sandberg.pp.se
6079883Sandreas@sandberg.pp.se    regs.rip = tc->instAddr();
6089883Sandreas@sandberg.pp.se
6099883Sandreas@sandberg.pp.se    /* You might think that setting regs.rflags to the contents
6109883Sandreas@sandberg.pp.se     * MISCREG_RFLAGS here would suffice. In that case you're
6119883Sandreas@sandberg.pp.se     * mistaken. We need to reconstruct it from a bunch of ucode
6129883Sandreas@sandberg.pp.se     * registers and wave a dead chicken over it (aka mask out and set
6139883Sandreas@sandberg.pp.se     * reserved bits) to get it to work.
6149883Sandreas@sandberg.pp.se     */
6159883Sandreas@sandberg.pp.se    regs.rflags = X86ISA::getRFlags(tc);
6169883Sandreas@sandberg.pp.se
6179883Sandreas@sandberg.pp.se    setRegisters(regs);
6189883Sandreas@sandberg.pp.se}
6199883Sandreas@sandberg.pp.se
6209883Sandreas@sandberg.pp.sestatic inline void
6219883Sandreas@sandberg.pp.sesetKvmSegmentReg(ThreadContext *tc, struct kvm_segment &kvm_seg,
6229883Sandreas@sandberg.pp.se                 const int index)
6239883Sandreas@sandberg.pp.se{
6249883Sandreas@sandberg.pp.se    SegAttr attr(tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(index)));
6259883Sandreas@sandberg.pp.se
6269883Sandreas@sandberg.pp.se    kvm_seg.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index));
6279883Sandreas@sandberg.pp.se    kvm_seg.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index));
6289883Sandreas@sandberg.pp.se    kvm_seg.selector = tc->readMiscRegNoEffect(MISCREG_SEG_SEL(index));
6299883Sandreas@sandberg.pp.se    kvm_seg.type = attr.type;
6309883Sandreas@sandberg.pp.se    kvm_seg.present = attr.present;
6319883Sandreas@sandberg.pp.se    kvm_seg.dpl = attr.dpl;
6329883Sandreas@sandberg.pp.se    kvm_seg.db = attr.defaultSize;
6339883Sandreas@sandberg.pp.se    kvm_seg.s = attr.system;
6349883Sandreas@sandberg.pp.se    kvm_seg.l = attr.longMode;
6359883Sandreas@sandberg.pp.se    kvm_seg.g = attr.granularity;
6369883Sandreas@sandberg.pp.se    kvm_seg.avl = attr.avl;
6379883Sandreas@sandberg.pp.se
6389883Sandreas@sandberg.pp.se    // A segment is unusable when the selector is zero. There is a
6399883Sandreas@sandberg.pp.se    // attr.unusable flag in gem5, but it seems unused.
6409883Sandreas@sandberg.pp.se    //
6419883Sandreas@sandberg.pp.se    // TODO: Are there corner cases where this doesn't work?
6429883Sandreas@sandberg.pp.se    kvm_seg.unusable = (kvm_seg.selector == 0);
6439883Sandreas@sandberg.pp.se}
6449883Sandreas@sandberg.pp.se
6459883Sandreas@sandberg.pp.sestatic inline void
6469883Sandreas@sandberg.pp.sesetKvmDTableReg(ThreadContext *tc, struct kvm_dtable &kvm_dtable,
6479883Sandreas@sandberg.pp.se                const int index)
6489883Sandreas@sandberg.pp.se{
6499883Sandreas@sandberg.pp.se    kvm_dtable.base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(index));
6509883Sandreas@sandberg.pp.se    kvm_dtable.limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(index));
6519883Sandreas@sandberg.pp.se}
6529883Sandreas@sandberg.pp.se
6539886Sandreas@sandberg.pp.sestatic void
6549886Sandreas@sandberg.pp.seforceSegAccessed(struct kvm_segment &seg)
6559886Sandreas@sandberg.pp.se{
6569886Sandreas@sandberg.pp.se    // Intel's VMX requires that (some) usable segments are flagged as
6579886Sandreas@sandberg.pp.se    // 'accessed' (i.e., the lowest bit in the segment type is set)
6589886Sandreas@sandberg.pp.se    // when entering VMX. This wouldn't necessary be the case even if
6599886Sandreas@sandberg.pp.se    // gem5 did set the access bits correctly, so we force it to one
6609886Sandreas@sandberg.pp.se    // in that case.
6619886Sandreas@sandberg.pp.se    if (!seg.unusable)
6629886Sandreas@sandberg.pp.se        seg.type |= SEG_TYPE_BIT_ACCESSED;
6639886Sandreas@sandberg.pp.se}
6649886Sandreas@sandberg.pp.se
6659883Sandreas@sandberg.pp.sevoid
6669883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateSRegs()
6679883Sandreas@sandberg.pp.se{
6689883Sandreas@sandberg.pp.se    struct kvm_sregs sregs;
6699883Sandreas@sandberg.pp.se
6709883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) sregs.kreg = tc->readMiscRegNoEffect(mreg)
6719883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setKvmSegmentReg(tc, sregs.kreg, idx)
6729883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setKvmDTableReg(tc, sregs.kreg, idx)
6739883Sandreas@sandberg.pp.se
6749883Sandreas@sandberg.pp.se    FOREACH_SREG();
6759883Sandreas@sandberg.pp.se    FOREACH_SEGMENT();
6769883Sandreas@sandberg.pp.se    FOREACH_DTABLE();
6779883Sandreas@sandberg.pp.se
6789883Sandreas@sandberg.pp.se#undef APPLY_SREG
6799883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
6809883Sandreas@sandberg.pp.se#undef APPLY_DTABLE
6819883Sandreas@sandberg.pp.se
6829883Sandreas@sandberg.pp.se    // Clear the interrupt bitmap
6839883Sandreas@sandberg.pp.se    memset(&sregs.interrupt_bitmap, 0, sizeof(sregs.interrupt_bitmap));
6849883Sandreas@sandberg.pp.se
6859886Sandreas@sandberg.pp.se    // VMX requires CS, SS, DS, ES, FS, and GS to have the accessed
6869886Sandreas@sandberg.pp.se    // bit in the type field set.
6879886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.cs);
6889886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.ss);
6899886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.ds);
6909886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.es);
6919886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.fs);
6929886Sandreas@sandberg.pp.se    forceSegAccessed(sregs.gs);
6939886Sandreas@sandberg.pp.se
6949886Sandreas@sandberg.pp.se    // There are currently some cases where the active task isn't
6959886Sandreas@sandberg.pp.se    // marked as busy. This is illegal in VMX, so we force it to busy.
6969886Sandreas@sandberg.pp.se    if (sregs.tr.type == SEG_SYS_TYPE_TSS_AVAILABLE) {
6979886Sandreas@sandberg.pp.se        hack("tr.type (%i) is not busy. Forcing the busy bit.\n",
6989886Sandreas@sandberg.pp.se             sregs.tr.type);
6999886Sandreas@sandberg.pp.se        sregs.tr.type = SEG_SYS_TYPE_TSS_BUSY;
7009886Sandreas@sandberg.pp.se    }
7019886Sandreas@sandberg.pp.se
7029886Sandreas@sandberg.pp.se    // VMX requires the DPL of SS and CS to be the same for
7039886Sandreas@sandberg.pp.se    // non-conforming code segments. It seems like m5 doesn't set the
7049886Sandreas@sandberg.pp.se    // DPL of SS correctly when taking interrupts, so we need to fix
7059886Sandreas@sandberg.pp.se    // that here.
7069886Sandreas@sandberg.pp.se    if ((sregs.cs.type == SEG_CS_TYPE_ACCESSED ||
7079886Sandreas@sandberg.pp.se         sregs.cs.type == SEG_CS_TYPE_READ_ACCESSED) &&
7089886Sandreas@sandberg.pp.se        sregs.cs.dpl != sregs.ss.dpl) {
7099886Sandreas@sandberg.pp.se
7109886Sandreas@sandberg.pp.se        hack("CS.DPL (%i) != SS.DPL (%i): Forcing SS.DPL to %i\n",
7119886Sandreas@sandberg.pp.se             sregs.cs.dpl, sregs.ss.dpl, sregs.cs.dpl);
7129886Sandreas@sandberg.pp.se        sregs.ss.dpl = sregs.cs.dpl;
7139886Sandreas@sandberg.pp.se    }
7149886Sandreas@sandberg.pp.se
7159886Sandreas@sandberg.pp.se    // Do checks after fixing up the state to avoid getting excessive
7169886Sandreas@sandberg.pp.se    // amounts of warnings.
7179884Sandreas@sandberg.pp.se    RFLAGS rflags_nocc(tc->readMiscReg(MISCREG_RFLAGS));
7189884Sandreas@sandberg.pp.se    if (!rflags_nocc.vm) {
7199884Sandreas@sandberg.pp.se        // Do segment verification if the CPU isn't entering virtual
7209884Sandreas@sandberg.pp.se        // 8086 mode.  We currently assume that unrestricted guest
7219884Sandreas@sandberg.pp.se        // mode is available.
7229884Sandreas@sandberg.pp.se
7239884Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) \
7249884Sandreas@sandberg.pp.se        checkSeg(# kreg, idx + MISCREG_SEG_SEL_BASE, sregs.kreg, sregs)
7259884Sandreas@sandberg.pp.se
7269884Sandreas@sandberg.pp.se        FOREACH_SEGMENT();
7279884Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
7289884Sandreas@sandberg.pp.se    }
7299886Sandreas@sandberg.pp.se
7309883Sandreas@sandberg.pp.se    setSpecialRegisters(sregs);
7319883Sandreas@sandberg.pp.se}
7329883Sandreas@sandberg.pp.sevoid
7339883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateFPU()
7349883Sandreas@sandberg.pp.se{
7359883Sandreas@sandberg.pp.se    warn_once("X86KvmCPU::updateKvmStateFPU not implemented\n");
7369883Sandreas@sandberg.pp.se}
7379883Sandreas@sandberg.pp.se
7389883Sandreas@sandberg.pp.sevoid
7399883Sandreas@sandberg.pp.seX86KvmCPU::updateKvmStateMSRs()
7409883Sandreas@sandberg.pp.se{
7419883Sandreas@sandberg.pp.se    KvmMSRVector msrs;
7429883Sandreas@sandberg.pp.se
7439883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &indices(getMsrIntersection());
7449883Sandreas@sandberg.pp.se
7459883Sandreas@sandberg.pp.se    for (auto it = indices.cbegin(); it != indices.cend(); ++it) {
7469883Sandreas@sandberg.pp.se        struct kvm_msr_entry e;
7479883Sandreas@sandberg.pp.se
7489883Sandreas@sandberg.pp.se        e.index = *it;
7499883Sandreas@sandberg.pp.se        e.reserved = 0;
7509883Sandreas@sandberg.pp.se        e.data = tc->readMiscReg(msrMap.at(*it));
7519883Sandreas@sandberg.pp.se        DPRINTF(KvmContext, "Adding MSR: idx: 0x%x, data: 0x%x\n",
7529883Sandreas@sandberg.pp.se                e.index, e.data);
7539883Sandreas@sandberg.pp.se
7549883Sandreas@sandberg.pp.se        msrs.push_back(e);
7559883Sandreas@sandberg.pp.se    }
7569883Sandreas@sandberg.pp.se
7579883Sandreas@sandberg.pp.se    setMSRs(msrs);
7589883Sandreas@sandberg.pp.se}
7599883Sandreas@sandberg.pp.se
7609883Sandreas@sandberg.pp.sevoid
7619883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContext()
7629883Sandreas@sandberg.pp.se{
7639883Sandreas@sandberg.pp.se    DPRINTF(KvmContext, "X86KvmCPU::updateThreadContext():\n");
7649883Sandreas@sandberg.pp.se    if (DTRACE(KvmContext))
7659883Sandreas@sandberg.pp.se        dump();
7669883Sandreas@sandberg.pp.se
7679883Sandreas@sandberg.pp.se    updateThreadContextRegs();
7689883Sandreas@sandberg.pp.se    updateThreadContextSRegs();
7699883Sandreas@sandberg.pp.se    updateThreadContextFPU();
7709883Sandreas@sandberg.pp.se    updateThreadContextMSRs();
7719883Sandreas@sandberg.pp.se
7729883Sandreas@sandberg.pp.se    // The M5 misc reg caches some values from other
7739883Sandreas@sandberg.pp.se    // registers. Writing to it with side effects causes it to be
7749883Sandreas@sandberg.pp.se    // updated from its source registers.
7759883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_M5_REG, 0);
7769883Sandreas@sandberg.pp.se}
7779883Sandreas@sandberg.pp.se
7789883Sandreas@sandberg.pp.sevoid
7799883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextRegs()
7809883Sandreas@sandberg.pp.se{
7819883Sandreas@sandberg.pp.se    struct kvm_regs regs;
7829883Sandreas@sandberg.pp.se    getRegisters(regs);
7839883Sandreas@sandberg.pp.se
7849883Sandreas@sandberg.pp.se#define APPLY_IREG(kreg, mreg) tc->setIntReg(mreg, regs.kreg)
7859883Sandreas@sandberg.pp.se
7869883Sandreas@sandberg.pp.se    FOREACH_IREG();
7879883Sandreas@sandberg.pp.se
7889883Sandreas@sandberg.pp.se#undef APPLY_IREG
7899883Sandreas@sandberg.pp.se
7909883Sandreas@sandberg.pp.se    tc->pcState(PCState(regs.rip));
7919883Sandreas@sandberg.pp.se
7929883Sandreas@sandberg.pp.se    // Flags are spread out across multiple semi-magic registers so we
7939883Sandreas@sandberg.pp.se    // need some special care when updating them.
7949883Sandreas@sandberg.pp.se    X86ISA::setRFlags(tc, regs.rflags);
7959883Sandreas@sandberg.pp.se}
7969883Sandreas@sandberg.pp.se
7979883Sandreas@sandberg.pp.se
7989883Sandreas@sandberg.pp.seinline void
7999883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_segment &kvm_seg,
8009883Sandreas@sandberg.pp.se                  const int index)
8019883Sandreas@sandberg.pp.se{
8029883Sandreas@sandberg.pp.se    SegAttr attr(0);
8039883Sandreas@sandberg.pp.se
8049883Sandreas@sandberg.pp.se    attr.type = kvm_seg.type;
8059883Sandreas@sandberg.pp.se    attr.present = kvm_seg.present;
8069883Sandreas@sandberg.pp.se    attr.dpl = kvm_seg.dpl;
8079883Sandreas@sandberg.pp.se    attr.defaultSize = kvm_seg.db;
8089883Sandreas@sandberg.pp.se    attr.system = kvm_seg.s;
8099883Sandreas@sandberg.pp.se    attr.longMode = kvm_seg.l;
8109883Sandreas@sandberg.pp.se    attr.granularity = kvm_seg.g;
8119883Sandreas@sandberg.pp.se    attr.avl = kvm_seg.avl;
8129883Sandreas@sandberg.pp.se    attr.unusable = kvm_seg.unusable;
8139883Sandreas@sandberg.pp.se
8149883Sandreas@sandberg.pp.se    // We need some setMiscReg magic here to keep the effective base
8159883Sandreas@sandberg.pp.se    // addresses in sync. We need an up-to-date version of EFER, so
8169883Sandreas@sandberg.pp.se    // make sure this is called after the sregs have been synced.
8179883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_seg.base);
8189883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_seg.limit);
8199883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_SEL(index), kvm_seg.selector);
8209883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_ATTR(index), attr);
8219883Sandreas@sandberg.pp.se}
8229883Sandreas@sandberg.pp.se
8239883Sandreas@sandberg.pp.seinline void
8249883Sandreas@sandberg.pp.sesetContextSegment(ThreadContext *tc, const struct kvm_dtable &kvm_dtable,
8259883Sandreas@sandberg.pp.se                  const int index)
8269883Sandreas@sandberg.pp.se{
8279883Sandreas@sandberg.pp.se    // We need some setMiscReg magic here to keep the effective base
8289883Sandreas@sandberg.pp.se    // addresses in sync. We need an up-to-date version of EFER, so
8299883Sandreas@sandberg.pp.se    // make sure this is called after the sregs have been synced.
8309883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_BASE(index), kvm_dtable.base);
8319883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_SEG_LIMIT(index), kvm_dtable.limit);
8329883Sandreas@sandberg.pp.se}
8339883Sandreas@sandberg.pp.se
8349883Sandreas@sandberg.pp.sevoid
8359883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextSRegs()
8369883Sandreas@sandberg.pp.se{
8379883Sandreas@sandberg.pp.se    struct kvm_sregs sregs;
8389883Sandreas@sandberg.pp.se    getSpecialRegisters(sregs);
8399883Sandreas@sandberg.pp.se
8409883Sandreas@sandberg.pp.se    assert(getKvmRunState()->apic_base == sregs.apic_base);
8419883Sandreas@sandberg.pp.se    assert(getKvmRunState()->cr8 == sregs.cr8);
8429883Sandreas@sandberg.pp.se
8439883Sandreas@sandberg.pp.se#define APPLY_SREG(kreg, mreg) tc->setMiscRegNoEffect(mreg, sregs.kreg)
8449883Sandreas@sandberg.pp.se#define APPLY_SEGMENT(kreg, idx) setContextSegment(tc, sregs.kreg, idx)
8459883Sandreas@sandberg.pp.se#define APPLY_DTABLE(kreg, idx) setContextSegment(tc, sregs.kreg, idx)
8469883Sandreas@sandberg.pp.se    FOREACH_SREG();
8479883Sandreas@sandberg.pp.se    FOREACH_SEGMENT();
8489883Sandreas@sandberg.pp.se    FOREACH_DTABLE();
8499883Sandreas@sandberg.pp.se#undef APPLY_SREG
8509883Sandreas@sandberg.pp.se#undef APPLY_SEGMENT
8519883Sandreas@sandberg.pp.se#undef APPLY_DTABLE
8529883Sandreas@sandberg.pp.se}
8539883Sandreas@sandberg.pp.se
8549883Sandreas@sandberg.pp.sevoid
8559883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextFPU()
8569883Sandreas@sandberg.pp.se{
8579883Sandreas@sandberg.pp.se    warn_once("X86KvmCPU::updateThreadContextFPU not implemented\n");
8589883Sandreas@sandberg.pp.se}
8599883Sandreas@sandberg.pp.se
8609883Sandreas@sandberg.pp.sevoid
8619883Sandreas@sandberg.pp.seX86KvmCPU::updateThreadContextMSRs()
8629883Sandreas@sandberg.pp.se{
8639883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &msrs(getMsrIntersection());
8649883Sandreas@sandberg.pp.se
8659883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
8669883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size()));
8679883Sandreas@sandberg.pp.se    struct kvm_msr_entry *entry;
8689883Sandreas@sandberg.pp.se
8699883Sandreas@sandberg.pp.se    // Create a list of MSRs to read
8709883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = msrs.size();
8719883Sandreas@sandberg.pp.se    entry = &kvm_msrs->entries[0];
8729883Sandreas@sandberg.pp.se    for (auto it = msrs.cbegin(); it != msrs.cend(); ++it, ++entry) {
8739883Sandreas@sandberg.pp.se        entry->index = *it;
8749883Sandreas@sandberg.pp.se        entry->reserved = 0;
8759883Sandreas@sandberg.pp.se        entry->data = 0;
8769883Sandreas@sandberg.pp.se    }
8779883Sandreas@sandberg.pp.se
8789883Sandreas@sandberg.pp.se    getMSRs(*kvm_msrs.get());
8799883Sandreas@sandberg.pp.se
8809883Sandreas@sandberg.pp.se    // Update M5's state
8819883Sandreas@sandberg.pp.se    entry = &kvm_msrs->entries[0];
8829883Sandreas@sandberg.pp.se    for (int i = 0; i < kvm_msrs->nmsrs; ++i, ++entry) {
8839883Sandreas@sandberg.pp.se        DPRINTF(KvmContext, "Setting M5 MSR: idx: 0x%x, data: 0x%x\n",
8849883Sandreas@sandberg.pp.se                entry->index, entry->data);
8859883Sandreas@sandberg.pp.se
8869883Sandreas@sandberg.pp.se        tc->setMiscReg(X86ISA::msrMap.at(entry->index), entry->data);
8879883Sandreas@sandberg.pp.se    }
8889883Sandreas@sandberg.pp.se}
8899883Sandreas@sandberg.pp.se
8909883Sandreas@sandberg.pp.sevoid
8919883Sandreas@sandberg.pp.seX86KvmCPU::deliverInterrupts()
8929883Sandreas@sandberg.pp.se{
8939883Sandreas@sandberg.pp.se    syncThreadContext();
8949883Sandreas@sandberg.pp.se
8959883Sandreas@sandberg.pp.se    Fault fault(interrupts->getInterrupt(tc));
8969883Sandreas@sandberg.pp.se    interrupts->updateIntrInfo(tc);
8979883Sandreas@sandberg.pp.se
8989883Sandreas@sandberg.pp.se    X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get()));
8999883Sandreas@sandberg.pp.se    if (x86int) {
9009883Sandreas@sandberg.pp.se        struct kvm_interrupt kvm_int;
9019883Sandreas@sandberg.pp.se        kvm_int.irq = x86int->getVector();
9029883Sandreas@sandberg.pp.se
9039883Sandreas@sandberg.pp.se        DPRINTF(KvmInt, "Delivering interrupt: %s (%u)\n",
9049883Sandreas@sandberg.pp.se                fault->name(), kvm_int.irq);
9059883Sandreas@sandberg.pp.se
9069883Sandreas@sandberg.pp.se        kvmInterrupt(kvm_int);
9079883Sandreas@sandberg.pp.se    } else if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) {
9089883Sandreas@sandberg.pp.se        DPRINTF(KvmInt, "Delivering NMI\n");
9099883Sandreas@sandberg.pp.se        kvmNonMaskableInterrupt();
9109883Sandreas@sandberg.pp.se    } else {
9119883Sandreas@sandberg.pp.se        panic("KVM: Unknown interrupt type\n");
9129883Sandreas@sandberg.pp.se    }
9139883Sandreas@sandberg.pp.se
9149883Sandreas@sandberg.pp.se}
9159883Sandreas@sandberg.pp.se
9169883Sandreas@sandberg.pp.seTick
9179883Sandreas@sandberg.pp.seX86KvmCPU::kvmRun(Tick ticks)
9189883Sandreas@sandberg.pp.se{
9199883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
9209883Sandreas@sandberg.pp.se
9219883Sandreas@sandberg.pp.se    if (interrupts->checkInterruptsRaw()) {
9229883Sandreas@sandberg.pp.se        if (kvm_run.ready_for_interrupt_injection) {
9239883Sandreas@sandberg.pp.se            // KVM claims that it is ready for an interrupt. It might
9249883Sandreas@sandberg.pp.se            // be lying if we just updated rflags and disabled
9259883Sandreas@sandberg.pp.se            // interrupts (e.g., by doing a CPU handover). Let's sync
9269883Sandreas@sandberg.pp.se            // the thread context and check if there are /really/
9279883Sandreas@sandberg.pp.se            // interrupts that should be delivered now.
9289883Sandreas@sandberg.pp.se            syncThreadContext();
9299883Sandreas@sandberg.pp.se            if (interrupts->checkInterrupts(tc)) {
9309883Sandreas@sandberg.pp.se                DPRINTF(KvmInt,
9319883Sandreas@sandberg.pp.se                        "M5 has pending interrupts, delivering interrupt.\n");
9329883Sandreas@sandberg.pp.se
9339883Sandreas@sandberg.pp.se                deliverInterrupts();
9349883Sandreas@sandberg.pp.se            } else {
9359883Sandreas@sandberg.pp.se                DPRINTF(KvmInt,
9369883Sandreas@sandberg.pp.se                        "Interrupt delivery delayed due to KVM confusion.\n");
9379883Sandreas@sandberg.pp.se                kvm_run.request_interrupt_window = 1;
9389883Sandreas@sandberg.pp.se            }
9399883Sandreas@sandberg.pp.se        } else if (!kvm_run.request_interrupt_window) {
9409883Sandreas@sandberg.pp.se            DPRINTF(KvmInt,
9419883Sandreas@sandberg.pp.se                    "M5 has pending interrupts, requesting interrupt "
9429883Sandreas@sandberg.pp.se                    "window.\n");
9439883Sandreas@sandberg.pp.se            kvm_run.request_interrupt_window = 1;
9449883Sandreas@sandberg.pp.se        }
9459883Sandreas@sandberg.pp.se    } else {
9469883Sandreas@sandberg.pp.se        kvm_run.request_interrupt_window = 0;
9479883Sandreas@sandberg.pp.se    }
9489883Sandreas@sandberg.pp.se
9499883Sandreas@sandberg.pp.se    return kvmRunWrapper(ticks);
9509883Sandreas@sandberg.pp.se}
9519883Sandreas@sandberg.pp.se
9529883Sandreas@sandberg.pp.seTick
9539883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunDrain()
9549883Sandreas@sandberg.pp.se{
9559883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
9569883Sandreas@sandberg.pp.se
9579883Sandreas@sandberg.pp.se    if (!archIsDrained()) {
9589883Sandreas@sandberg.pp.se        DPRINTF(Drain, "kvmRunDrain: Architecture code isn't drained\n");
9599883Sandreas@sandberg.pp.se
9609883Sandreas@sandberg.pp.se        // Tell KVM to find a suitable place to deliver interrupts. This
9619883Sandreas@sandberg.pp.se        // should ensure that pending interrupts have been delivered and
9629883Sandreas@sandberg.pp.se        // things are reasonably consistent (i.e., no interrupts pending
9639883Sandreas@sandberg.pp.se        // in the guest).
9649883Sandreas@sandberg.pp.se        kvm_run.request_interrupt_window = 1;
9659883Sandreas@sandberg.pp.se
9669883Sandreas@sandberg.pp.se        // Limit the run to 1 millisecond. That is hopefully enough to
9679883Sandreas@sandberg.pp.se        // reach an interrupt window. Otherwise, we'll just try again
9689883Sandreas@sandberg.pp.se        // later.
9699883Sandreas@sandberg.pp.se        return kvmRunWrapper(1 * SimClock::Float::ms);
9709883Sandreas@sandberg.pp.se    } else {
9719883Sandreas@sandberg.pp.se        DPRINTF(Drain, "kvmRunDrain: Delivering pending IO\n");
9729883Sandreas@sandberg.pp.se
9739883Sandreas@sandberg.pp.se        return kvmRunWrapper(0);
9749883Sandreas@sandberg.pp.se    }
9759883Sandreas@sandberg.pp.se}
9769883Sandreas@sandberg.pp.se
9779883Sandreas@sandberg.pp.seTick
9789883Sandreas@sandberg.pp.seX86KvmCPU::kvmRunWrapper(Tick ticks)
9799883Sandreas@sandberg.pp.se{
9809883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
9819883Sandreas@sandberg.pp.se
9829883Sandreas@sandberg.pp.se    // Synchronize the APIC base and CR8 here since they are present
9839883Sandreas@sandberg.pp.se    // in the kvm_run struct, which makes the synchronization really
9849883Sandreas@sandberg.pp.se    // cheap.
9859883Sandreas@sandberg.pp.se    kvm_run.apic_base = tc->readMiscReg(MISCREG_APIC_BASE);
9869883Sandreas@sandberg.pp.se    kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8);
9879883Sandreas@sandberg.pp.se
9889883Sandreas@sandberg.pp.se    const Tick run_ticks(BaseKvmCPU::kvmRun(ticks));
9899883Sandreas@sandberg.pp.se
9909883Sandreas@sandberg.pp.se    tc->setMiscReg(MISCREG_APIC_BASE, kvm_run.apic_base);
9919883Sandreas@sandberg.pp.se    kvm_run.cr8 = tc->readMiscReg(MISCREG_CR8);
9929883Sandreas@sandberg.pp.se
9939883Sandreas@sandberg.pp.se    return run_ticks;
9949883Sandreas@sandberg.pp.se}
9959883Sandreas@sandberg.pp.se
9969883Sandreas@sandberg.pp.seuint64_t
9979883Sandreas@sandberg.pp.seX86KvmCPU::getHostCycles() const
9989883Sandreas@sandberg.pp.se{
9999883Sandreas@sandberg.pp.se    return getMSR(MSR_TSC);
10009883Sandreas@sandberg.pp.se}
10019883Sandreas@sandberg.pp.se
10029883Sandreas@sandberg.pp.sevoid
10039883Sandreas@sandberg.pp.seX86KvmCPU::handleIOMiscReg32(int miscreg)
10049883Sandreas@sandberg.pp.se{
10059883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
10069883Sandreas@sandberg.pp.se    const uint16_t port(kvm_run.io.port);
10079883Sandreas@sandberg.pp.se
10089883Sandreas@sandberg.pp.se    assert(kvm_run.exit_reason == KVM_EXIT_IO);
10099883Sandreas@sandberg.pp.se
10109883Sandreas@sandberg.pp.se    if (kvm_run.io.size != 4) {
10119883Sandreas@sandberg.pp.se        panic("Unexpected IO size (%u) for address 0x%x.\n",
10129883Sandreas@sandberg.pp.se              kvm_run.io.size, port);
10139883Sandreas@sandberg.pp.se    }
10149883Sandreas@sandberg.pp.se
10159883Sandreas@sandberg.pp.se    if (kvm_run.io.count != 1) {
10169883Sandreas@sandberg.pp.se        panic("Unexpected IO count (%u) for address 0x%x.\n",
10179883Sandreas@sandberg.pp.se              kvm_run.io.count, port);
10189883Sandreas@sandberg.pp.se    }
10199883Sandreas@sandberg.pp.se
10209883Sandreas@sandberg.pp.se    uint32_t *data((uint32_t *)getGuestData(kvm_run.io.data_offset));
10219883Sandreas@sandberg.pp.se    if (kvm_run.io.direction == KVM_EXIT_IO_OUT)
10229883Sandreas@sandberg.pp.se        tc->setMiscReg(miscreg, *data);
10239883Sandreas@sandberg.pp.se    else
10249883Sandreas@sandberg.pp.se        *data = tc->readMiscRegNoEffect(miscreg);
10259883Sandreas@sandberg.pp.se}
10269883Sandreas@sandberg.pp.se
10279883Sandreas@sandberg.pp.seTick
10289883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIO()
10299883Sandreas@sandberg.pp.se{
10309883Sandreas@sandberg.pp.se    struct kvm_run &kvm_run(*getKvmRunState());
10319883Sandreas@sandberg.pp.se    bool isWrite(kvm_run.io.direction == KVM_EXIT_IO_OUT);
10329883Sandreas@sandberg.pp.se    unsigned char *guestData(getGuestData(kvm_run.io.data_offset));
10339883Sandreas@sandberg.pp.se    Tick delay(0);
10349883Sandreas@sandberg.pp.se    uint16_t port(kvm_run.io.port);
10359883Sandreas@sandberg.pp.se    Addr pAddr;
10369883Sandreas@sandberg.pp.se    const int count(kvm_run.io.count);
10379883Sandreas@sandberg.pp.se
10389883Sandreas@sandberg.pp.se    assert(kvm_run.io.direction == KVM_EXIT_IO_IN ||
10399883Sandreas@sandberg.pp.se           kvm_run.io.direction == KVM_EXIT_IO_OUT);
10409883Sandreas@sandberg.pp.se
10419883Sandreas@sandberg.pp.se    DPRINTF(KvmIO, "KVM-x86: Handling IO instruction (%s) (port: 0x%x)\n",
10429883Sandreas@sandberg.pp.se            (isWrite ? "out" : "in"), kvm_run.io.port);
10439883Sandreas@sandberg.pp.se
10449883Sandreas@sandberg.pp.se    /* Vanilla gem5 handles PCI discovery in the TLB(!). Since we
10459883Sandreas@sandberg.pp.se     * don't use the TLB component, we need to intercept and handle
10469883Sandreas@sandberg.pp.se     * the PCI configuration space IO ports here.
10479883Sandreas@sandberg.pp.se     *
10489883Sandreas@sandberg.pp.se     * The IO port PCI discovery mechanism uses one address register
10499883Sandreas@sandberg.pp.se     * and one data register. We map the address register to a misc
10509883Sandreas@sandberg.pp.se     * reg and use that to re-route data register accesses to the
10519883Sandreas@sandberg.pp.se     * right location in the PCI configuration space.
10529883Sandreas@sandberg.pp.se     */
10539883Sandreas@sandberg.pp.se    if (port == IO_PCI_CONF_ADDR) {
10549883Sandreas@sandberg.pp.se        handleIOMiscReg32(MISCREG_PCI_CONFIG_ADDRESS);
10559883Sandreas@sandberg.pp.se        return 0;
10569883Sandreas@sandberg.pp.se    } else if ((port & ~0x3) == IO_PCI_CONF_DATA_BASE) {
10579883Sandreas@sandberg.pp.se        Addr pciConfigAddr(tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS));
10589883Sandreas@sandberg.pp.se        if (pciConfigAddr & 0x80000000) {
10599883Sandreas@sandberg.pp.se            pAddr = X86ISA::x86PciConfigAddress((pciConfigAddr & 0x7ffffffc) |
10609883Sandreas@sandberg.pp.se                                                (port & 0x3));
10619883Sandreas@sandberg.pp.se        } else {
10629883Sandreas@sandberg.pp.se            pAddr = X86ISA::x86IOAddress(port);
10639883Sandreas@sandberg.pp.se        }
10649883Sandreas@sandberg.pp.se    } else {
10659883Sandreas@sandberg.pp.se        pAddr = X86ISA::x86IOAddress(port);
10669883Sandreas@sandberg.pp.se    }
10679883Sandreas@sandberg.pp.se
10689883Sandreas@sandberg.pp.se    io_req.setPhys(pAddr, kvm_run.io.size, Request::UNCACHEABLE,
10699883Sandreas@sandberg.pp.se                   dataMasterId());
10709883Sandreas@sandberg.pp.se
10719883Sandreas@sandberg.pp.se    const MemCmd cmd(isWrite ? MemCmd::WriteReq : MemCmd::ReadReq);
10729883Sandreas@sandberg.pp.se    for (int i = 0; i < count; ++i) {
10739883Sandreas@sandberg.pp.se        Packet pkt(&io_req, cmd);
10749883Sandreas@sandberg.pp.se
10759883Sandreas@sandberg.pp.se        pkt.dataStatic(guestData);
10769883Sandreas@sandberg.pp.se        delay += dataPort.sendAtomic(&pkt);
10779883Sandreas@sandberg.pp.se
10789883Sandreas@sandberg.pp.se        guestData += kvm_run.io.size;
10799883Sandreas@sandberg.pp.se    }
10809883Sandreas@sandberg.pp.se
10819883Sandreas@sandberg.pp.se    return delay;
10829883Sandreas@sandberg.pp.se}
10839883Sandreas@sandberg.pp.se
10849883Sandreas@sandberg.pp.seTick
10859883Sandreas@sandberg.pp.seX86KvmCPU::handleKvmExitIRQWindowOpen()
10869883Sandreas@sandberg.pp.se{
10879883Sandreas@sandberg.pp.se    // We don't need to do anything here since this is caught the next
10889883Sandreas@sandberg.pp.se    // time we execute kvmRun(). We still overload the exit event to
10899883Sandreas@sandberg.pp.se    // silence the warning about an unhandled exit event.
10909883Sandreas@sandberg.pp.se    return 0;
10919883Sandreas@sandberg.pp.se}
10929883Sandreas@sandberg.pp.se
10939883Sandreas@sandberg.pp.sebool
10949883Sandreas@sandberg.pp.seX86KvmCPU::archIsDrained() const
10959883Sandreas@sandberg.pp.se{
10969883Sandreas@sandberg.pp.se    struct kvm_vcpu_events events;
10979883Sandreas@sandberg.pp.se
10989883Sandreas@sandberg.pp.se    getVCpuEvents(events);
10999883Sandreas@sandberg.pp.se
11009883Sandreas@sandberg.pp.se    // We could probably handle this in a by re-inserting interrupts
11019883Sandreas@sandberg.pp.se    // that are pending into gem5 on a drain. However, that would
11029883Sandreas@sandberg.pp.se    // probably be tricky to do reliably, so we'll just prevent a
11039883Sandreas@sandberg.pp.se    // drain if there is anything pending in the
11049883Sandreas@sandberg.pp.se    // guest. X86KvmCPU::kvmRunDrain() minimizes the amount of code
11059883Sandreas@sandberg.pp.se    // executed in the guest by requesting an interrupt window if
11069883Sandreas@sandberg.pp.se    // there are pending interrupts.
11079883Sandreas@sandberg.pp.se    const bool pending_events(events.exception.injected ||
11089883Sandreas@sandberg.pp.se                              events.interrupt.injected ||
11099883Sandreas@sandberg.pp.se                              events.nmi.injected || events.nmi.pending);
11109883Sandreas@sandberg.pp.se
11119883Sandreas@sandberg.pp.se    if (pending_events) {
11129883Sandreas@sandberg.pp.se        DPRINTF(Drain, "archIsDrained: Pending events: %s %s %s %s\n",
11139883Sandreas@sandberg.pp.se                events.exception.injected ? "exception" : "",
11149883Sandreas@sandberg.pp.se                events.interrupt.injected ? "interrupt" : "",
11159883Sandreas@sandberg.pp.se                events.nmi.injected ? "nmi[i]" : "",
11169883Sandreas@sandberg.pp.se                events.nmi.pending ? "nmi[p]" : "");
11179883Sandreas@sandberg.pp.se    }
11189883Sandreas@sandberg.pp.se
11199883Sandreas@sandberg.pp.se    return !pending_events;
11209883Sandreas@sandberg.pp.se}
11219883Sandreas@sandberg.pp.se
11229883Sandreas@sandberg.pp.sestatic struct kvm_cpuid_entry2
11239883Sandreas@sandberg.pp.semakeKvmCpuid(uint32_t function, uint32_t index,
11249883Sandreas@sandberg.pp.se             CpuidResult &result)
11259883Sandreas@sandberg.pp.se{
11269883Sandreas@sandberg.pp.se    struct kvm_cpuid_entry2 e;
11279883Sandreas@sandberg.pp.se    e.function = function;
11289883Sandreas@sandberg.pp.se    e.index = index;
11299883Sandreas@sandberg.pp.se    e.flags = 0;
11309883Sandreas@sandberg.pp.se    e.eax = (uint32_t)result.rax;
11319883Sandreas@sandberg.pp.se    e.ebx = (uint32_t)result.rbx;
11329883Sandreas@sandberg.pp.se    e.ecx = (uint32_t)result.rcx;
11339883Sandreas@sandberg.pp.se    e.edx = (uint32_t)result.rdx;
11349883Sandreas@sandberg.pp.se
11359883Sandreas@sandberg.pp.se    return e;
11369883Sandreas@sandberg.pp.se}
11379883Sandreas@sandberg.pp.se
11389883Sandreas@sandberg.pp.sevoid
11399883Sandreas@sandberg.pp.seX86KvmCPU::updateCPUID()
11409883Sandreas@sandberg.pp.se{
11419883Sandreas@sandberg.pp.se    Kvm::CPUIDVector m5_supported;
11429883Sandreas@sandberg.pp.se
11439883Sandreas@sandberg.pp.se    /* TODO: We currently don't support any of the functions that
11449883Sandreas@sandberg.pp.se     * iterate through data structures in the CPU using an index. It's
11459883Sandreas@sandberg.pp.se     * currently not a problem since M5 doesn't expose any of them at
11469883Sandreas@sandberg.pp.se     * the moment.
11479883Sandreas@sandberg.pp.se     */
11489883Sandreas@sandberg.pp.se
11499883Sandreas@sandberg.pp.se    /* Basic features */
11509883Sandreas@sandberg.pp.se    CpuidResult func0;
11519883Sandreas@sandberg.pp.se    X86ISA::doCpuid(tc, 0x0, 0, func0);
11529883Sandreas@sandberg.pp.se    for (uint32_t function = 0; function <= func0.rax; ++function) {
11539883Sandreas@sandberg.pp.se        CpuidResult cpuid;
11549883Sandreas@sandberg.pp.se        uint32_t idx(0);
11559883Sandreas@sandberg.pp.se
11569883Sandreas@sandberg.pp.se        X86ISA::doCpuid(tc, function, idx, cpuid);
11579883Sandreas@sandberg.pp.se        m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
11589883Sandreas@sandberg.pp.se    }
11599883Sandreas@sandberg.pp.se
11609883Sandreas@sandberg.pp.se    /* Extended features */
11619883Sandreas@sandberg.pp.se    CpuidResult efunc0;
11629883Sandreas@sandberg.pp.se    X86ISA::doCpuid(tc, 0x80000000, 0, efunc0);
11639883Sandreas@sandberg.pp.se    for (uint32_t function = 0x80000000; function <= efunc0.rax; ++function) {
11649883Sandreas@sandberg.pp.se        CpuidResult cpuid;
11659883Sandreas@sandberg.pp.se        uint32_t idx(0);
11669883Sandreas@sandberg.pp.se
11679883Sandreas@sandberg.pp.se        X86ISA::doCpuid(tc, function, idx, cpuid);
11689883Sandreas@sandberg.pp.se        m5_supported.push_back(makeKvmCpuid(function, idx, cpuid));
11699883Sandreas@sandberg.pp.se    }
11709883Sandreas@sandberg.pp.se
11719883Sandreas@sandberg.pp.se    setCPUID(m5_supported);
11729883Sandreas@sandberg.pp.se}
11739883Sandreas@sandberg.pp.se
11749883Sandreas@sandberg.pp.sevoid
11759883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const struct kvm_cpuid2 &cpuid)
11769883Sandreas@sandberg.pp.se{
11779883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_CPUID2, (void *)&cpuid) == -1)
11789883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest CPUID2 (errno: %i)\n",
11799883Sandreas@sandberg.pp.se              errno);
11809883Sandreas@sandberg.pp.se}
11819883Sandreas@sandberg.pp.se
11829883Sandreas@sandberg.pp.sevoid
11839883Sandreas@sandberg.pp.seX86KvmCPU::setCPUID(const Kvm::CPUIDVector &cpuid)
11849883Sandreas@sandberg.pp.se{
11859883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_cpuid2> kvm_cpuid(
11869883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_cpuid2, struct kvm_cpuid_entry2>(cpuid.size()));
11879883Sandreas@sandberg.pp.se
11889883Sandreas@sandberg.pp.se    kvm_cpuid->nent = cpuid.size();
11899883Sandreas@sandberg.pp.se    std::copy(cpuid.begin(), cpuid.end(), kvm_cpuid->entries);
11909883Sandreas@sandberg.pp.se
11919883Sandreas@sandberg.pp.se    setCPUID(*kvm_cpuid);
11929883Sandreas@sandberg.pp.se}
11939883Sandreas@sandberg.pp.se
11949883Sandreas@sandberg.pp.sevoid
11959883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const struct kvm_msrs &msrs)
11969883Sandreas@sandberg.pp.se{
11979883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_MSRS, (void *)&msrs) == -1)
11989883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest MSRs (errno: %i)\n",
11999883Sandreas@sandberg.pp.se              errno);
12009883Sandreas@sandberg.pp.se}
12019883Sandreas@sandberg.pp.se
12029883Sandreas@sandberg.pp.sevoid
12039883Sandreas@sandberg.pp.seX86KvmCPU::setMSRs(const KvmMSRVector &msrs)
12049883Sandreas@sandberg.pp.se{
12059883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
12069883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(msrs.size()));
12079883Sandreas@sandberg.pp.se
12089883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = msrs.size();
12099883Sandreas@sandberg.pp.se    std::copy(msrs.begin(), msrs.end(), kvm_msrs->entries);
12109883Sandreas@sandberg.pp.se
12119883Sandreas@sandberg.pp.se    setMSRs(*kvm_msrs);
12129883Sandreas@sandberg.pp.se}
12139883Sandreas@sandberg.pp.se
12149883Sandreas@sandberg.pp.sevoid
12159883Sandreas@sandberg.pp.seX86KvmCPU::getMSRs(struct kvm_msrs &msrs) const
12169883Sandreas@sandberg.pp.se{
12179883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_MSRS, (void *)&msrs) == -1)
12189883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest MSRs (errno: %i)\n",
12199883Sandreas@sandberg.pp.se              errno);
12209883Sandreas@sandberg.pp.se}
12219883Sandreas@sandberg.pp.se
12229883Sandreas@sandberg.pp.se
12239883Sandreas@sandberg.pp.sevoid
12249883Sandreas@sandberg.pp.seX86KvmCPU::setMSR(uint32_t index, uint64_t value)
12259883Sandreas@sandberg.pp.se{
12269883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
12279883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1));
12289883Sandreas@sandberg.pp.se    struct kvm_msr_entry &entry(kvm_msrs->entries[0]);
12299883Sandreas@sandberg.pp.se
12309883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = 1;
12319883Sandreas@sandberg.pp.se    entry.index = index;
12329883Sandreas@sandberg.pp.se    entry.reserved = 0;
12339883Sandreas@sandberg.pp.se    entry.data = value;
12349883Sandreas@sandberg.pp.se
12359883Sandreas@sandberg.pp.se    setMSRs(*kvm_msrs.get());
12369883Sandreas@sandberg.pp.se}
12379883Sandreas@sandberg.pp.se
12389883Sandreas@sandberg.pp.seuint64_t
12399883Sandreas@sandberg.pp.seX86KvmCPU::getMSR(uint32_t index) const
12409883Sandreas@sandberg.pp.se{
12419883Sandreas@sandberg.pp.se    std::unique_ptr<struct kvm_msrs> kvm_msrs(
12429883Sandreas@sandberg.pp.se        newVarStruct<struct kvm_msrs, struct kvm_msr_entry>(1));
12439883Sandreas@sandberg.pp.se    struct kvm_msr_entry &entry(kvm_msrs->entries[0]);
12449883Sandreas@sandberg.pp.se
12459883Sandreas@sandberg.pp.se    kvm_msrs->nmsrs = 1;
12469883Sandreas@sandberg.pp.se    entry.index = index;
12479883Sandreas@sandberg.pp.se    entry.reserved = 0;
12489883Sandreas@sandberg.pp.se    entry.data = 0;
12499883Sandreas@sandberg.pp.se
12509883Sandreas@sandberg.pp.se    getMSRs(*kvm_msrs.get());
12519883Sandreas@sandberg.pp.se    return entry.data;
12529883Sandreas@sandberg.pp.se}
12539883Sandreas@sandberg.pp.se
12549883Sandreas@sandberg.pp.seconst Kvm::MSRIndexVector &
12559883Sandreas@sandberg.pp.seX86KvmCPU::getMsrIntersection() const
12569883Sandreas@sandberg.pp.se{
12579883Sandreas@sandberg.pp.se    if (cachedMsrIntersection.empty()) {
12589883Sandreas@sandberg.pp.se        const Kvm::MSRIndexVector &kvm_msrs(vm.kvm.getSupportedMSRs());
12599883Sandreas@sandberg.pp.se
12609883Sandreas@sandberg.pp.se        DPRINTF(Kvm, "kvm-x86: Updating MSR intersection\n");
12619883Sandreas@sandberg.pp.se        for (auto it = kvm_msrs.cbegin(); it != kvm_msrs.cend(); ++it) {
12629883Sandreas@sandberg.pp.se            if (X86ISA::msrMap.find(*it) != X86ISA::msrMap.end()) {
12639883Sandreas@sandberg.pp.se                cachedMsrIntersection.push_back(*it);
12649883Sandreas@sandberg.pp.se                DPRINTF(Kvm, "kvm-x86: Adding MSR 0x%x\n", *it);
12659883Sandreas@sandberg.pp.se            } else {
12669883Sandreas@sandberg.pp.se                warn("kvm-x86: MSR (0x%x) unsupported by gem5. Skipping.\n",
12679883Sandreas@sandberg.pp.se                     *it);
12689883Sandreas@sandberg.pp.se            }
12699883Sandreas@sandberg.pp.se        }
12709883Sandreas@sandberg.pp.se    }
12719883Sandreas@sandberg.pp.se
12729883Sandreas@sandberg.pp.se    return cachedMsrIntersection;
12739883Sandreas@sandberg.pp.se}
12749883Sandreas@sandberg.pp.se
12759883Sandreas@sandberg.pp.sevoid
12769883Sandreas@sandberg.pp.seX86KvmCPU::getDebugRegisters(struct kvm_debugregs &regs) const
12779883Sandreas@sandberg.pp.se{
12789883Sandreas@sandberg.pp.se#ifdef KVM_GET_DEBUGREGS
12799883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_DEBUGREGS, &regs) == -1)
12809883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
12819883Sandreas@sandberg.pp.se#else
12829883Sandreas@sandberg.pp.se    panic("KVM: Unsupported getDebugRegisters call.\n");
12839883Sandreas@sandberg.pp.se#endif
12849883Sandreas@sandberg.pp.se}
12859883Sandreas@sandberg.pp.se
12869883Sandreas@sandberg.pp.sevoid
12879883Sandreas@sandberg.pp.seX86KvmCPU::setDebugRegisters(const struct kvm_debugregs &regs)
12889883Sandreas@sandberg.pp.se{
12899883Sandreas@sandberg.pp.se#ifdef KVM_SET_DEBUGREGS
12909883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_DEBUGREGS, (void *)&regs) == -1)
12919883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
12929883Sandreas@sandberg.pp.se#else
12939883Sandreas@sandberg.pp.se    panic("KVM: Unsupported setDebugRegisters call.\n");
12949883Sandreas@sandberg.pp.se#endif
12959883Sandreas@sandberg.pp.se}
12969883Sandreas@sandberg.pp.se
12979883Sandreas@sandberg.pp.sevoid
12989883Sandreas@sandberg.pp.seX86KvmCPU::getXCRs(struct kvm_xcrs &regs) const
12999883Sandreas@sandberg.pp.se{
13009883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_XCRS, &regs) == -1)
13019883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
13029883Sandreas@sandberg.pp.se}
13039883Sandreas@sandberg.pp.se
13049883Sandreas@sandberg.pp.sevoid
13059883Sandreas@sandberg.pp.seX86KvmCPU::setXCRs(const struct kvm_xcrs &regs)
13069883Sandreas@sandberg.pp.se{
13079883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_XCRS, (void *)&regs) == -1)
13089883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
13099883Sandreas@sandberg.pp.se}
13109883Sandreas@sandberg.pp.se
13119883Sandreas@sandberg.pp.sevoid
13129883Sandreas@sandberg.pp.seX86KvmCPU::getXSave(struct kvm_xsave &xsave) const
13139883Sandreas@sandberg.pp.se{
13149883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_XSAVE, &xsave) == -1)
13159883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
13169883Sandreas@sandberg.pp.se}
13179883Sandreas@sandberg.pp.se
13189883Sandreas@sandberg.pp.sevoid
13199883Sandreas@sandberg.pp.seX86KvmCPU::setXSave(const struct kvm_xsave &xsave)
13209883Sandreas@sandberg.pp.se{
13219883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_XSAVE, (void *)&xsave) == -1)
13229883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
13239883Sandreas@sandberg.pp.se}
13249883Sandreas@sandberg.pp.se
13259883Sandreas@sandberg.pp.se
13269883Sandreas@sandberg.pp.sevoid
13279883Sandreas@sandberg.pp.seX86KvmCPU::getVCpuEvents(struct kvm_vcpu_events &events) const
13289883Sandreas@sandberg.pp.se{
13299883Sandreas@sandberg.pp.se    if (ioctl(KVM_GET_VCPU_EVENTS, &events) == -1)
13309883Sandreas@sandberg.pp.se        panic("KVM: Failed to get guest debug registers\n");
13319883Sandreas@sandberg.pp.se}
13329883Sandreas@sandberg.pp.se
13339883Sandreas@sandberg.pp.sevoid
13349883Sandreas@sandberg.pp.seX86KvmCPU::setVCpuEvents(const struct kvm_vcpu_events &events)
13359883Sandreas@sandberg.pp.se{
13369883Sandreas@sandberg.pp.se    if (ioctl(KVM_SET_VCPU_EVENTS, (void *)&events) == -1)
13379883Sandreas@sandberg.pp.se        panic("KVM: Failed to set guest debug registers\n");
13389883Sandreas@sandberg.pp.se}
13399883Sandreas@sandberg.pp.se
13409883Sandreas@sandberg.pp.seX86KvmCPU *
13419883Sandreas@sandberg.pp.seX86KvmCPUParams::create()
13429883Sandreas@sandberg.pp.se{
13439883Sandreas@sandberg.pp.se    return new X86KvmCPU(this);
13449883Sandreas@sandberg.pp.se}
1345