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