VirtualBox

Changeset 92578 in vbox


Ignore:
Timestamp:
Nov 24, 2021 1:51:03 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
148460
Message:

VMM/NEM-linux: Started work on handling all non-common MSRs ourselves. bugref:9044

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/NEMR3Native-linux.cpp

    r92555 r92578  
    3434#include <iprt/string.h>
    3535#include <iprt/system.h>
     36#include <iprt/x86.h>
    3637
    3738#include <errno.h>
     
    417418
    418419    /*
     420     * Enable user space MSRs and let us check everything KVM cannot handle.
     421     * We will set up filtering later when ring-3 init has completed.
     422     */
     423    struct kvm_enable_cap CapEn =
     424    {
     425        KVM_CAP_X86_USER_SPACE_MSR, 0,
     426        { KVM_MSR_EXIT_REASON_FILTER | KVM_MSR_EXIT_REASON_UNKNOWN | KVM_MSR_EXIT_REASON_INVAL, 0, 0, 0}
     427    };
     428    int rcLnx = ioctl(pVM->nem.s.fdVm, KVM_ENABLE_CAP, &CapEn);
     429    if (rcLnx == -1)
     430        return RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, "Failed to enable KVM_CAP_X86_USER_SPACE_MSR failed: %u", errno);
     431
     432    /*
    419433     * Create the VCpus.
    420434     */
     
    426440        pVCpu->nem.s.fdVCpu = ioctl(pVM->nem.s.fdVm, KVM_CREATE_VCPU, (unsigned long)idCpu);
    427441        if (pVCpu->nem.s.fdVCpu < 0)
    428             return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    429                               "KVM_CREATE_VCPU failed for VCpu #%u: %d", idCpu, errno);
     442            return RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, "KVM_CREATE_VCPU failed for VCpu #%u: %d", idCpu, errno);
    430443
    431444        /* Map the KVM_RUN area. */
     
    433446                                                   pVCpu->nem.s.fdVCpu, 0 /*offset*/);
    434447        if ((void *)pVCpu->nem.s.pRun == MAP_FAILED)
    435             return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "mmap failed for VCpu #%u: %d", idCpu, errno);
     448            return RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, "mmap failed for VCpu #%u: %d", idCpu, errno);
    436449
    437450        /* We want all x86 registers and events on each exit. */
     
    672685            AssertRCReturn(rc, rc);
    673686        }
     687    }
     688
     689    /*
     690     * Configure MSRs after ring-3 init is done.
     691     *
     692     * We only need to tell KVM which MSRs it can handle, as we already
     693     * requested KVM_MSR_EXIT_REASON_FILTER, KVM_MSR_EXIT_REASON_UNKNOWN
     694     * and KVM_MSR_EXIT_REASON_INVAL in nemR3LnxInitSetupVm, and here we
     695     * will use KVM_MSR_FILTER_DEFAULT_DENY.  So, all MSRs w/o a 1 in the
     696     * bitmaps should be deferred to ring-3.
     697     */
     698    if (enmWhat == VMINITCOMPLETED_RING3)
     699    {
     700        struct kvm_msr_filter MsrFilters = {0}; /* Structure with a couple of implicit paddings on 64-bit systems. */
     701        MsrFilters.flags = KVM_MSR_FILTER_DEFAULT_DENY;
     702
     703        unsigned iRange = 0;
     704#define MSR_RANGE_BEGIN(a_uBase, a_uEnd, a_fFlags) \
     705        AssertCompile(0x3000 <= KVM_MSR_FILTER_MAX_BITMAP_SIZE * 8); \
     706        uint64_t RT_CONCAT(bm, a_uBase)[0x3000 / 64] = {0}; \
     707        do { \
     708            uint64_t * const pbm = RT_CONCAT(bm, a_uBase); \
     709            uint32_t   const uBase = UINT32_C(a_uBase); \
     710            uint32_t   const cMsrs = UINT32_C(a_uEnd) - UINT32_C(a_uBase); \
     711            MsrFilters.ranges[iRange].base   = UINT32_C(a_uBase); \
     712            MsrFilters.ranges[iRange].nmsrs  = cMsrs; \
     713            MsrFilters.ranges[iRange].flags  = (a_fFlags); \
     714            MsrFilters.ranges[iRange].bitmap = (uint8_t *)&RT_CONCAT(bm, a_uBase)[0]
     715#define MSR_RANGE_ADD(a_Msr) \
     716        do { Assert((uint32_t)(a_Msr) - uBase < cMsrs); ASMBitSet(pbm, (uint32_t)(a_Msr) - uBase); } while (0)
     717#define MSR_RANGE_END(a_cMinMsrs) \
     718            /* optimize the range size before closing: */ \
     719            uint32_t cBitmap = cMsrs / 64; \
     720            while (cBitmap > ((a_cMinMsrs) + 63 / 64) && pbm[cBitmap - 1] == 0) \
     721                cBitmap -= 1; \
     722            MsrFilters.ranges[iRange].nmsrs = cBitmap * 64; \
     723            iRange++; \
     724        } while (0)
     725
     726        /* 1st Intel range: 0000_0000 to 0000_3000. */
     727        MSR_RANGE_BEGIN(0x00000000, 0x00003000, KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE);
     728        MSR_RANGE_ADD(MSR_IA32_TSC);
     729        MSR_RANGE_ADD(MSR_IA32_SYSENTER_CS);
     730        MSR_RANGE_ADD(MSR_IA32_SYSENTER_ESP);
     731        MSR_RANGE_ADD(MSR_IA32_SYSENTER_EIP);
     732        MSR_RANGE_ADD(MSR_IA32_CR_PAT);
     733        /** @todo more? */
     734        MSR_RANGE_END(64);
     735
     736        /* 1st AMD range: c000_0000 to c000_3000 */
     737        MSR_RANGE_BEGIN(0xc0000000, 0xc0003000, KVM_MSR_FILTER_READ | KVM_MSR_FILTER_WRITE);
     738        MSR_RANGE_ADD(MSR_K6_EFER);
     739        MSR_RANGE_ADD(MSR_K6_STAR);
     740        MSR_RANGE_ADD(MSR_K8_GS_BASE);
     741        MSR_RANGE_ADD(MSR_K8_KERNEL_GS_BASE);
     742        MSR_RANGE_ADD(MSR_K8_LSTAR);
     743        MSR_RANGE_ADD(MSR_K8_CSTAR);
     744        MSR_RANGE_ADD(MSR_K8_SF_MASK);
     745        MSR_RANGE_ADD(MSR_K8_TSC_AUX);
     746        /** @todo add more? */
     747        MSR_RANGE_END(64);
     748
     749        /** @todo Specify other ranges too? Like hyper-V and KVM to make sure we get
     750         *        the MSR requests instead of KVM. */
     751
     752        int rcLnx = ioctl(pVM->nem.s.fdVm, KVM_X86_SET_MSR_FILTER, &MsrFilters);
     753        if (rcLnx == -1)
     754            return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
     755                              "Failed to enable KVM_X86_SET_MSR_FILTER failed: %u", errno);
    674756    }
    675757
     
    21392221
    21402222    /*
    2141      * We cannot actually act on the exit history here, because the I/O port
     2223     * We cannot easily act on the exit history here, because the I/O port
    21422224     * exit is stateful and the instruction will be completed in the next
    21432225     * KVM_RUN call.  There seems no way to avoid this.
     
    22242306
    22252307    /*
    2226      * We cannot actually act on the exit history here, because the MMIO port
     2308     * We cannot easily act on the exit history here, because the MMIO port
    22272309     * exit is stateful and the instruction will be completed in the next
    22282310     * KVM_RUN call.  There seems no way to circumvent this.
     
    22542336    return rcStrict;
    22552337}
     2338
     2339
     2340/**
     2341 * Handles KVM_EXIT_RDMSR
     2342 */
     2343static VBOXSTRICTRC nemHCLnxHandleExitRdMsr(PVMCPUCC pVCpu, struct kvm_run *pRun)
     2344{
     2345    /*
     2346     * Input validation.
     2347     */
     2348    Assert(   pRun->msr.reason == KVM_MSR_EXIT_REASON_INVAL
     2349           || pRun->msr.reason == KVM_MSR_EXIT_REASON_UNKNOWN
     2350           || pRun->msr.reason == KVM_MSR_EXIT_REASON_FILTER);
     2351
     2352    /*
     2353     * We cannot easily act on the exit history here, because the MSR exit is
     2354     * stateful and the instruction will be completed in the next KVM_RUN call.
     2355     * There seems no way to circumvent this.
     2356     */
     2357    EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_READ),
     2358                     pRun->s.regs.regs.rip + pRun->s.regs.sregs.cs.base, ASMReadTSC());
     2359
     2360    /*
     2361     * Do the requested job.
     2362     */
     2363    uint64_t uValue = 0;
     2364    VBOXSTRICTRC rcStrict = CPUMQueryGuestMsr(pVCpu, pRun->msr.index, &uValue);
     2365    pRun->msr.data = uValue;
     2366    if (rcStrict != VERR_CPUM_RAISE_GP_0)
     2367    {
     2368        Log3(("MsrRead/%u: %04x:%08RX64: msr=%#010x (reason=%#x) -> %#RX64 rcStrict=%Rrc\n", pVCpu->idCpu,
     2369              pRun->s.regs.sregs.cs.selector, pRun->s.regs.regs.rip, pRun->msr.index, pRun->msr.reason, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2370        pRun->msr.error = 0;
     2371    }
     2372    else
     2373    {
     2374        Log3(("MsrRead/%u: %04x:%08RX64: msr=%#010x (reason%#x)-> %#RX64 rcStrict=#GP!\n", pVCpu->idCpu,
     2375              pRun->s.regs.sregs.cs.selector, pRun->s.regs.regs.rip, pRun->msr.index, pRun->msr.reason, uValue));
     2376        pRun->msr.error = 1;
     2377        rcStrict = VINF_SUCCESS;
     2378    }
     2379    return rcStrict;
     2380}
     2381
     2382
     2383/**
     2384 * Handles KVM_EXIT_WRMSR
     2385 */
     2386static VBOXSTRICTRC nemHCLnxHandleExitWrMsr(PVMCPUCC pVCpu, struct kvm_run *pRun)
     2387{
     2388    /*
     2389     * Input validation.
     2390     */
     2391    Assert(   pRun->msr.reason == KVM_MSR_EXIT_REASON_INVAL
     2392           || pRun->msr.reason == KVM_MSR_EXIT_REASON_UNKNOWN
     2393           || pRun->msr.reason == KVM_MSR_EXIT_REASON_FILTER);
     2394
     2395    /*
     2396     * We cannot easily act on the exit history here, because the MSR exit is
     2397     * stateful and the instruction will be completed in the next KVM_RUN call.
     2398     * There seems no way to circumvent this.
     2399     */
     2400    EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FT(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_WRITE),
     2401                     pRun->s.regs.regs.rip + pRun->s.regs.sregs.cs.base, ASMReadTSC());
     2402
     2403    /*
     2404     * Do the requested job.
     2405     */
     2406    VBOXSTRICTRC rcStrict = CPUMSetGuestMsr(pVCpu, pRun->msr.index, pRun->msr.data);
     2407    if (rcStrict != VERR_CPUM_RAISE_GP_0)
     2408    {
     2409        Log3(("MsrWrite/%u: %04x:%08RX64: msr=%#010x := %#RX64 (reason=%#x) -> rcStrict=%Rrc\n", pVCpu->idCpu,
     2410              pRun->s.regs.sregs.cs.selector, pRun->s.regs.regs.rip, pRun->msr.index, pRun->msr.data, pRun->msr.reason, VBOXSTRICTRC_VAL(rcStrict) ));
     2411        pRun->msr.error = 0;
     2412    }
     2413    else
     2414    {
     2415        Log3(("MsrWrite/%u: %04x:%08RX64: msr=%#010x := %#RX64 (reason%#x)-> rcStrict=#GP!\n", pVCpu->idCpu,
     2416              pRun->s.regs.sregs.cs.selector, pRun->s.regs.regs.rip, pRun->msr.index, pRun->msr.data, pRun->msr.reason));
     2417        pRun->msr.error = 1;
     2418        rcStrict = VINF_SUCCESS;
     2419    }
     2420    return rcStrict;
     2421}
     2422
    22562423
    22572424
     
    22952462        case KVM_EXIT_X86_RDMSR:
    22962463            STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatExitRdMsr);
    2297             AssertFailed();
    2298             break;
     2464            *pfStatefulExit = true;
     2465            return nemHCLnxHandleExitRdMsr(pVCpu, pRun);
    22992466
    23002467        case KVM_EXIT_X86_WRMSR:
    23012468            STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatExitWrMsr);
    2302             AssertFailed();
    2303             break;
     2469            *pfStatefulExit = true;
     2470            return nemHCLnxHandleExitWrMsr(pVCpu, pRun);
    23042471
    23052472        case KVM_EXIT_HLT:
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette