VirtualBox

Changeset 55118 in vbox


Ignore:
Timestamp:
Apr 7, 2015 3:21:45 PM (9 years ago)
Author:
vboxsync
Message:

VMM: GIM raw-mode support.

Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/err.h

    r55037 r55118  
    26222622/** The GIM device is not registered with GIM when it ought to be. */
    26232623#define VERR_GIM_DEVICE_NOT_REGISTERED              (-6310)
     2624/** Hypercall cannot be enabled/performed due to access/permissions/CPL. */
     2625#define VERR_GIM_HYPERCALL_ACCESS_DENIED            (-6311)
    26242626/** @} */
    26252627
  • trunk/include/VBox/vmm/gim.h

    r55037 r55118  
    174174VMM_INT_DECL(bool)          GIMAreHypercallsEnabled(PVMCPU pVCpu);
    175175VMM_INT_DECL(int)           GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
    176 VMM_INT_DECL(int)           GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx);
     176VMM_INT_DECL(int)           GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
    177177VMM_INT_DECL(bool)          GIMShouldTrapXcptUD(PVM pVM);
    178178VMM_INT_DECL(VBOXSTRICTRC)  GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
  • trunk/include/VBox/vmm/hm.h

    r54878 r55118  
    144144VMM_INT_DECL(int)               HMAmdIsSubjectToErratum170(uint32_t *pu32Family, uint32_t *pu32Model, uint32_t *pu32Stepping);
    145145VMM_INT_DECL(bool)              HMSetSingleInstruction(PVMCPU pVCpu, bool fEnable);
    146 VMM_INT_DECL(int)               HMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
     146VMM_INT_DECL(void)              HMHypercallsEnable(PVM pVM);
     147VMM_INT_DECL(void)              HMHypercallsDisable(PVM pVM);
    147148
    148149#ifndef IN_RC
  • trunk/include/VBox/vmm/vmm.h

    r54720 r55118  
    268268VMM_INT_DECL(bool)          VMMIsInRing3Call(PVMCPU pVCpu);
    269269VMM_INT_DECL(void)          VMMTrashVolatileXMMRegs(void);
     270VMM_INT_DECL(int)           VMMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
     271VMM_INT_DECL(void)          VMMHypercallsEnable(PVM pVM);
     272VMM_INT_DECL(void)          VMMHypercallsDisable(PVM pVM);
    270273
    271274
  • trunk/src/VBox/VMM/VMMAll/GIMAll.cpp

    r55037 r55118  
    129129            return gimHvIsParavirtTscEnabled(pVM);
    130130
     131        case GIMPROVIDERID_KVM:
     132            return gimKvmIsParavirtTscEnabled(pVM);
     133
    131134        default:
    132135            break;
     
    151154{
    152155    if (!GIMIsEnabled(pVM))
    153         return 0;
     156        return false;
    154157
    155158    switch (pVM->gim.s.enmProviderId)
     
    159162
    160163        default:
    161             return 0;
     164            return false;
    162165    }
    163166}
     
    169172 * @param   pVCpu       Pointer to the VMCPU.
    170173 * @param   pCtx        Pointer to the guest-CPU context.
    171  */
    172 VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx)
     174 * @param   pDis        Pointer to the disassembled instruction state at RIP.
     175 *                      Optional, can be NULL.
     176 */
     177VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
    173178{
    174179    PVM pVM = pVCpu->CTX_SUFF(pVM);
     
    178183    {
    179184        case GIMPROVIDERID_KVM:
    180             return gimKvmXcptUD(pVCpu, pCtx);
     185            return gimKvmXcptUD(pVCpu, pCtx, pDis);
    181186
    182187        default:
  • trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp

    r55039 r55118  
    112112     * Place the result in rax/eax.
    113113     */
    114     if (fIs64BitMode)
    115         pCtx->rax = uHyperRet;
    116     else
    117         pCtx->eax = uHyperRet & uAndMask;
     114    pCtx->rax = uHyperRet & uAndMask;
    118115    return VINF_SUCCESS;
    119116}
     
    144141VMM_INT_DECL(bool) gimKvmIsParavirtTscEnabled(PVM pVM)
    145142{
    146     return false;   /** @todo implement this! */
     143    uint32_t cCpus = pVM->cCpus;
     144    for (uint32_t i = 0; i < cCpus; i++)
     145    {
     146        PVMCPU     pVCpu      = &pVM->aCpus[i];
     147        PGIMKVMCPU pGimKvmCpu = &pVCpu->gim.s.u.KvmCpu;
     148        if (MSR_GIM_KVM_SYSTEM_TIME_IS_ENABLED(pGimKvmCpu->u64SystemTimeMsr))
     149            return true;
     150    }
     151    return false;
    147152}
    148153
     
    223228            if (fEnable)
    224229            {
    225                 RTCCUINTREG fEFlags = ASMIntDisableFlags();
     230                RTCCUINTREG fEFlags  = ASMIntDisableFlags();
    226231                pKvmCpu->uTsc        = TMCpuTickGetNoCheck(pVCpu);
    227232                pKvmCpu->uVirtNanoTS = TMVirtualGetNoCheck(pVM);
     
    317322 * elegantly by letting the hypervisor supply an opaque hypercall page.
    318323 *
     324 * For raw-mode VMs, this function will always return true. See gimR3KvmInit().
     325 *
    319326 * @param   pVM         Pointer to the VM.
    320327 */
    321328VMM_INT_DECL(bool) gimKvmShouldTrapXcptUD(PVM pVM)
    322329{
    323     pVM->gim.s.u.Kvm.fTrapXcptUD = ASMIsAmdCpu();
    324330    return pVM->gim.s.u.Kvm.fTrapXcptUD;
    325331}
     
    331337 * @param   pVCpu       Pointer to the VMCPU.
    332338 * @param   pCtx        Pointer to the guest-CPU context.
    333  */
    334 VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx)
     339 * @param   pDis        Pointer to the disassembled instruction state at RIP.
     340 *                      Optional, can be NULL.
     341 */
     342VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
    335343{
    336344    /*
    337345     * If we didn't ask for #UD to be trapped, bail.
    338346     */
    339     PVM pVM = pVCpu->CTX_SUFF(pVM);
     347    PVM     pVM  = pVCpu->CTX_SUFF(pVM);
     348    PGIMKVM pKvm = &pVM->gim.s.u.Kvm;
    340349    if (RT_UNLIKELY(!pVM->gim.s.u.Kvm.fTrapXcptUD))
    341350        return VERR_GIM_OPERATION_FAILED;
    342351
    343352    /*
    344      * Disassemble the instruction at RIP to figure out if it's the Intel
    345      * VMCALL instruction and if so, handle it as a hypercall.
    346      */
    347     DISCPUSTATE Dis;
    348     unsigned    cbInstr;
    349     int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, &cbInstr);
     353     * Make sure guest ring-0 is the one making the hypercall.
     354     */
     355    if (CPUMGetGuestCPL(pVCpu))
     356        return VERR_GIM_HYPERCALL_ACCESS_DENIED;
     357
     358    int rc = VINF_SUCCESS;
     359    if (!pDis)
     360    {
     361        /*
     362         * Disassemble the instruction at RIP to figure out if it's the Intel
     363         * VMCALL instruction and if so, handle it as a hypercall.
     364         */
     365        DISCPUSTATE Dis;
     366        rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, NULL /* pcbInstr */);
     367        pDis = &Dis;
     368    }
     369
    350370    if (RT_SUCCESS(rc))
    351371    {
    352         if (Dis.pCurInstr->uOpcode == OP_VMCALL)
    353         {
     372        /*
     373         * Patch the instruction to so we don't have to spend time disassembling it each time.
     374         * Makes sense only for HM as with raw-mode we will be getting a #UD regardless.
     375         */
     376        if (   pDis->pCurInstr->uOpcode == OP_VMCALL
     377            || pDis->pCurInstr->uOpcode == OP_VMMCALL)
     378        {
     379            uint8_t abHypercall[3];
     380            if (   pDis->pCurInstr->uOpcode != pKvm->uOpCodeNative
     381                && HMIsEnabled(pVM))
     382            {
     383                size_t  cbWritten = 0;
     384                rc = VMMPatchHypercall(pVM, &abHypercall, sizeof(abHypercall), &cbWritten);
     385                AssertRC(rc);
     386                Assert(sizeof(abHypercall) == pDis->cbInstr);
     387                Assert(sizeof(abHypercall) == cbWritten);
     388
     389                rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &abHypercall, sizeof(abHypercall));
     390            }
     391
    354392            /*
    355              * Patch the instruction to so we don't have to spend time disassembling it each time.
     393             * Perform the hypercall and update RIP.
     394             *
     395             * For HM, we can simply resume guest execution without perform the hypercall now and
     396             * do it on the next VMCALL/VMMCALL exit handler on the patched instruction.
     397             *
     398             * For raw-mode we need to do this now anyway. So we do it here regardless with an added
     399             * advantage is that it saves one world-switch for the HM case.
    356400             */
    357             static uint8_t s_abHypercall[3] = { 0x0F, 0x01, 0x00 };
    358             Assert(sizeof(s_abHypercall) == cbInstr);
    359             if (!s_abHypercall[2])
    360                 s_abHypercall[2] = ASMIsAmdCpu() ? 0xD9 /* VMMCALL */ : 0xC1 /* VMCALL */;
    361             rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &s_abHypercall, sizeof(s_abHypercall));
    362             return VINF_SUCCESS;
     401            if (RT_SUCCESS(rc))
     402            {
     403                int rc2 = gimKvmHypercall(pVCpu, pCtx);
     404                AssertRC(rc2);
     405                pCtx->rip += pDis->cbInstr;
     406            }
     407            return rc;
    363408        }
    364409    }
  • trunk/src/VBox/VMM/VMMAll/HMAll.cpp

    r54878 r55118  
    508508
    509509/**
    510  * Patches the instructions necessary for making a hypercall to the hypervisor.
    511  * Used by GIM.
    512  *
    513  * @returns VBox status code.
    514  * @param   pVM         Pointer to the VM.
    515  * @param   pvBuf       The buffer in the hypercall page(s) to be patched.
    516  * @param   cbBuf       The size of the buffer.
    517  * @param   pcbWritten  Where to store the number of bytes patched. This
    518  *                      is reliably updated only when this function returns
    519  *                      VINF_SUCCESS.
    520  */
    521 VMM_INT_DECL(int) HMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
    522 {
    523     AssertReturn(pvBuf, VERR_INVALID_POINTER);
    524     AssertReturn(pcbWritten, VERR_INVALID_POINTER);
    525     AssertReturn(HMIsEnabled(pVM), VERR_HM_IPE_5);
    526 
    527     if (pVM->hm.s.vmx.fSupported)
    528     {
    529         uint8_t abHypercall[] = { 0x0F, 0x01, 0xC1 };   /* VMCALL */
    530         if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
    531         {
    532             memcpy(pvBuf, abHypercall, sizeof(abHypercall));
    533             *pcbWritten = sizeof(abHypercall);
    534             return VINF_SUCCESS;
    535         }
    536         return VERR_BUFFER_OVERFLOW;
    537     }
    538     else
    539     {
    540         Assert(pVM->hm.s.svm.fSupported);
    541         uint8_t abHypercall[] = { 0x0F, 0x01, 0xD9 };   /* VMMCALL */
    542         if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
    543         {
    544             memcpy(pvBuf, abHypercall, sizeof(abHypercall));
    545             *pcbWritten = sizeof(abHypercall);
    546             return VINF_SUCCESS;
    547         }
    548         return VERR_BUFFER_OVERFLOW;
    549     }
    550 }
    551 
     510 * Notifies HM that paravirtualized hypercalls are now enabled.
     511 *
     512 * @param   pVM     Pointer to the VM.
     513 */
     514VMM_INT_DECL(void) HMHypercallsEnable(PVM pVM)
     515{
     516    pVM->hm.s.fHypercallsEnabled = true;
     517}
     518
     519
     520/**
     521 * Notifies HM that paravirtualized hypercalls are now disabled.
     522 *
     523 * @param   pVM     Pointer to the VM.
     524 */
     525VMM_INT_DECL(void) HMHypercallsDisable(PVM pVM)
     526{
     527    pVM->hm.s.fHypercallsEnabled = false;
     528}
     529
  • trunk/src/VBox/VMM/VMMAll/VMMAll.cpp

    r54467 r55118  
    2424#include "VMMInternal.h"
    2525#include <VBox/vmm/vm.h>
     26#include <VBox/vmm/hm.h>
    2627#include <VBox/vmm/vmcpuset.h>
    2728#include <VBox/param.h>
     
    391392}
    392393
     394
     395/**
     396 * Patches the instructions necessary for making a hypercall to the hypervisor.
     397 * Used by GIM.
     398 *
     399 * @returns VBox status code.
     400 * @param   pVM         Pointer to the VM.
     401 * @param   pvBuf       The buffer in the hypercall page(s) to be patched.
     402 * @param   cbBuf       The size of the buffer.
     403 * @param   pcbWritten  Where to store the number of bytes patched. This
     404 *                      is reliably updated only when this function returns
     405 *                      VINF_SUCCESS.
     406 */
     407VMM_INT_DECL(int) VMMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
     408{
     409    AssertReturn(pvBuf, VERR_INVALID_POINTER);
     410    AssertReturn(pcbWritten, VERR_INVALID_POINTER);
     411
     412    if (ASMIsAmdCpu())
     413    {
     414        uint8_t abHypercall[] = { 0x0F, 0x01, 0xD9 };   /* VMMCALL */
     415        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
     416        {
     417            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
     418            *pcbWritten = sizeof(abHypercall);
     419            return VINF_SUCCESS;
     420        }
     421        return VERR_BUFFER_OVERFLOW;
     422    }
     423    else
     424    {
     425        AssertReturn(ASMIsIntelCpu() || ASMIsViaCentaurCpu(), VERR_UNSUPPORTED_CPU);
     426        uint8_t abHypercall[] = { 0x0F, 0x01, 0xC1 };   /* VMCALL */
     427        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
     428        {
     429            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
     430            *pcbWritten = sizeof(abHypercall);
     431            return VINF_SUCCESS;
     432        }
     433        return VERR_BUFFER_OVERFLOW;
     434    }
     435}
     436
     437
     438/**
     439 * Notifies VMM that paravirtualized hypercalls are now enabled.
     440 *
     441 * @param   pVM     Pointer to the VM.
     442 */
     443VMM_INT_DECL(void) VMMHypercallsEnable(PVM pVM)
     444{
     445    /* If there is anything to do for raw-mode, do it here. */
     446#ifndef IN_RC
     447    if (HMIsEnabled(pVM))
     448        HMHypercallsEnable(pVM);
     449#endif
     450}
     451
     452
     453/**
     454 * Notifies VMM that paravirtualized hypercalls are now disabled.
     455 *
     456 * @param   pVM     Pointer to the VM.
     457 */
     458VMM_INT_DECL(void) VMMHypercallsDisable(PVM pVM)
     459{
     460    /* If there is anything to do for raw-mode, do it here. */
     461#ifndef IN_RC
     462    if (HMIsEnabled(pVM))
     463        HMHypercallsDisable(pVM);
     464#endif
     465}
     466
  • trunk/src/VBox/VMM/VMMR0/HMR0.cpp

    r55048 r55118  
    55
    66/*
    7  * Copyright (C) 2006-2014 Oracle Corporation
     7 * Copyright (C) 2006-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2626#include <VBox/vmm/hm_vmx.h>
    2727#include <VBox/vmm/hm_svm.h>
     28#include <VBox/vmm/gim.h>
    2829#include <VBox/err.h>
    2930#include <VBox/log.h>
     
    12111212    pVM->hm.s.cpuid.u32AMDFeatureEDX    = g_HvmR0.cpuid.u32AMDFeatureEDX;
    12121213    pVM->hm.s.lLastError                = g_HvmR0.lLastError;
    1213 
    12141214    pVM->hm.s.uMaxAsid                  = g_HvmR0.uMaxAsid;
    12151215
     1216    pVM->hm.s.fGIMTrapXcptUD            = GIMShouldTrapXcptUD(pVM);
    12161217
    12171218    if (!pVM->hm.s.cMaxResumeLoops) /* allow ring-3 overrides */
  • trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp

    r55040 r55118  
    670670    Assert(pVM->hm.s.svm.fSupported);
    671671
    672     pVM->hm.s.fTrapXcptUD             = GIMShouldTrapXcptUD(pVM);
    673     uint32_t const fGimXcptIntercepts = pVM->hm.s.fTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
     672    uint32_t const fGimXcptIntercepts = pVM->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
    674673    for (VMCPUID i = 0; i < pVM->cCpus; i++)
    675674    {
     
    35113510            return hmR0SvmExitWriteCRx(pVCpu, pCtx, pSvmTransient);
    35123511
     3512        case SVM_EXIT_VMMCALL:
     3513            return hmR0SvmExitVmmCall(pVCpu, pCtx, pSvmTransient);
     3514
    35133515        case SVM_EXIT_VINTR:
    35143516            return hmR0SvmExitVIntr(pVCpu, pCtx, pSvmTransient);
     
    35523554                case SVM_EXIT_TASK_SWITCH:
    35533555                    return hmR0SvmExitTaskSwitch(pVCpu, pCtx, pSvmTransient);
    3554 
    3555                 case SVM_EXIT_VMMCALL:
    3556                     return hmR0SvmExitVmmCall(pVCpu, pCtx, pSvmTransient);
    35573556
    35583557                case SVM_EXIT_IRET:
     
    38993898 * @returns VBox status code.
    39003899 * @retval VINF_SUCCESS if the access was handled successfully.
    3901  * @retval VERR_NOT_FOUND if no patch record for this eip could be found.
     3900 * @retval VERR_NOT_FOUND if no patch record for this RIP could be found.
    39023901 * @retval VERR_SVM_UNEXPECTED_PATCH_TYPE if the found patch type is invalid.
    39033902 *
     
    49984997{
    49994998    HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
     4999    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
    50005000
    50015001    /* First check if this is a patched VMMCALL for mov TPR */
     
    50085008    else if (rc == VERR_NOT_FOUND)
    50095009    {
    5010         /* Handle GIM provider hypercalls. */
    5011         if (GIMAreHypercallsEnabled(pVCpu))
     5010        PVM pVM = pVCpu->CTX_SUFF(pVM);
     5011        if (pVM->hm.s.fHypercallsEnabled)
    50125012        {
    50135013            rc = GIMHypercall(pVCpu, pCtx);
    5014             /* If the hypercall changes anything other than guest general-purpose registers,
    5015                we would need to reload the guest changed bits on VM-reentry. */
    50165014            if (RT_SUCCESS(rc))
    50175015            {
     5016                /* If the hypercall changes anything other than guest general-purpose registers,
     5017                   we would need to reload the guest changed bits here before VM-reentry. */
    50185018                hmR0SvmUpdateRip(pVCpu, pCtx, 3);
    50195019                return VINF_SUCCESS;
     
    52285228
    52295229    PVM pVM = pVCpu->CTX_SUFF(pVM);
    5230     if (   pVM->hm.s.fTrapXcptUD
    5231         && GIMAreHypercallsEnabled(pVCpu))
    5232         GIMXcptUD(pVCpu, pCtx);
     5230    if (pVM->hm.s.fGIMTrapXcptUD)
     5231        GIMXcptUD(pVCpu, pCtx, NULL /* pDis */);
    52335232    else
    52345233        hmR0SvmSetPendingXcptUD(pVCpu);
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r55037 r55118  
    1024110241{
    1024210242    HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
    10243 
    10244     int rc = VERR_NOT_SUPPORTED;
    10245     if (GIMAreHypercallsEnabled(pVCpu))
    10246     {
    10247         rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
     10243    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
     10244
     10245    PVM pVM = pVCpu->CTX_SUFF(pVM);
     10246    if (pVM->hm.s.fHypercallsEnabled)
     10247    {
     10248#if 0
     10249        int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
    1024810250        AssertRCReturn(rc, rc);
     10251#else
     10252        /* Aggressive state sync. for now. */
     10253        int rc  = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
     10254        rc     |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);    /* For long-mode checks in gimKvmHypercall(). */
     10255#endif
     10256        AssertRCReturn(rc, rc);
    1024910257
    1025010258        rc = GIMHypercall(pVCpu, pMixedCtx);
    10251     }
    10252 
    10253     if (RT_SUCCESS(rc))
    10254     {
    10255         rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
    10256         Assert(pVmxTransient->cbInstr == 3);
    10257 
    10258         /* If the hypercall changes anything other than guest general-purpose registers,
    10259            we would need to reload the guest changed bits on VM-reentry. */
    10260     }
    10261     else
    10262     {
    10263         hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
    10264         rc = VINF_SUCCESS;
    10265     }
    10266 
    10267     STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
    10268     return rc;
     10259        if (RT_SUCCESS(rc))
     10260        {
     10261            /* If the hypercall changes anything other than guest general-purpose registers,
     10262               we would need to reload the guest changed bits here before VM-reentry. */
     10263            hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
     10264            return VINF_SUCCESS;
     10265        }
     10266    }
     10267
     10268    hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
     10269    return VINF_SUCCESS;
    1026910270}
    1027010271
  • trunk/src/VBox/VMM/VMMR3/GIMHv.cpp

    r54819 r55118  
    633633        GIMR3Mmio2Unmap(pVM, pRegion);
    634634        Assert(!pRegion->fMapped);
     635        VMMHypercallsDisable(pVM);
    635636        LogRel(("GIM: HyperV: Disabled Hypercall-page\n"));
    636637        return VINF_SUCCESS;
     
    680681         * Patch the hypercall-page.
    681682         */
    682         if (HMIsEnabled(pVM))
     683        size_t cbWritten = 0;
     684        rc = VMMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
     685        if (   RT_SUCCESS(rc)
     686            && cbWritten < PAGE_SIZE)
    683687        {
    684             size_t cbWritten = 0;
    685             rc = HMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
    686             if (   RT_SUCCESS(rc)
    687                 && cbWritten < PAGE_SIZE)
    688             {
    689                 uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
    690                 *pbLast = 0xc3;  /* RET */
    691 
    692                 LogRel(("GIM: HyperV: Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
    693                 return VINF_SUCCESS;
    694             }
    695             else
    696             {
    697                 if (rc == VINF_SUCCESS)
    698                     rc = VERR_GIM_OPERATION_FAILED;
    699                 LogRelFunc(("HMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
    700             }
     688            uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
     689            *pbLast = 0xc3;  /* RET */
     690
     691            /*
     692             * Notify VMM that hypercalls are now enabled.
     693             */
     694            VMMHypercallsEnable(pVM);
     695
     696            LogRel(("GIM: HyperV: Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
     697            return VINF_SUCCESS;
    701698        }
    702699        else
    703700        {
    704             /** @todo Handle raw-mode hypercall page patching. */
    705             LogRel(("GIM: HyperV: Raw-mode hypercalls not yet implemented!\n"));
     701            if (rc == VINF_SUCCESS)
     702                rc = VERR_GIM_OPERATION_FAILED;
     703            LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
    706704        }
     705
    707706        GIMR3Mmio2Unmap(pVM, pRegion);
    708707    }
    709     else
    710         LogRelFunc(("GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
    711 
     708
     709    LogRel(("GIM: HyperV: GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
    712710    return rc;
    713711}
  • trunk/src/VBox/VMM/VMMR3/GIMKvm.cpp

    r55037 r55118  
    3030
    3131#include <VBox/vmm/cpum.h>
     32#include <VBox/disopcode.h>
    3233#include <VBox/vmm/ssm.h>
    3334#include <VBox/vmm/vm.h>
     
    141142    }
    142143
     144    /*
     145     * Setup #UD and hypercall behaviour.
     146     */
     147    VMMHypercallsEnable(pVM);
     148    if (ASMIsAmdCpu())
     149    {
     150        pKvm->fTrapXcptUD   = true;
     151        pKvm->uOpCodeNative = OP_VMMCALL;
     152    }
     153    else
     154    {
     155        Assert(ASMIsIntelCpu() || ASMIsViaCentaurCpu());
     156        pKvm->fTrapXcptUD   = false;
     157        pKvm->uOpCodeNative = OP_VMCALL;
     158    }
     159    /* We always need to trap VMCALL/VMMCALL hypercall using #UDs for raw-mode VMs. */
     160    if (!HMIsEnabled(pVM))
     161        pKvm->fTrapXcptUD = true;
     162
    143163    return VINF_SUCCESS;
    144164}
     
    368388     * time = ((tsc * SysTime.u32TscScale) >> 32) + SysTime.u64NanoTS
    369389     */
    370     uint64_t u64TscFreq = TMCpuTicksPerSecond(pVM);
    371     SystemTime.i8TscShift  = 0;
     390    uint64_t u64TscFreq   = TMCpuTicksPerSecond(pVM);
     391    SystemTime.i8TscShift = 0;
    372392    while (u64TscFreq > 2 * RT_NS_1SEC_64)
    373393    {
  • trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp

    r55001 r55118  
    2727#include <VBox/vmm/dbgf.h>
    2828#include <VBox/vmm/em.h>
     29#include <VBox/vmm/gim.h>
    2930#include <VBox/vmm/csam.h>
    3031#include <VBox/vmm/patm.h>
     
    595596#ifdef DTRACE_EXPERIMENT /** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
    596597            Assert(!PATMIsPatchGCAddr(pVM, pRegFrame->eip));
    597             rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6);
     598            rc = TRPMForwardTrap(pVCpu, pRegFrame, X86_XCPT_UD, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, X86_XCPT_UD);
    598599            Assert(rc == VINF_EM_RAW_GUEST_TRAP);
    599600#else
     
    609610            rc = EMInterpretInstructionDisasState(pVCpu, &Cpu, pRegFrame, PC, EMCODETYPE_SUPERVISOR);
    610611        }
     612        else if (GIMShouldTrapXcptUD(pVM))
     613        {
     614            LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD\n"));
     615            rc = GIMXcptUD(pVCpu, CPUMCTX_FROM_CORE(pRegFrame), &Cpu);
     616            if (RT_FAILURE(rc))
     617            {
     618                LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD -> VINF_EM_RAW_EMULATE_INSTR\n"));
     619                rc = VINF_EM_RAW_EMULATE_INSTR;
     620            }
     621        }
    611622        /* Never generate a raw trap here; it might be an instruction, that requires emulation. */
    612623        else
     
    619630    {
    620631        LogFlow(("TRPMGCTrap06Handler: -> TRPMForwardTrap\n"));
    621         rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6);
     632        rc = TRPMForwardTrap(pVCpu, pRegFrame, X86_XCPT_UD, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, X86_XCPT_UD);
    622633        Assert(rc == VINF_EM_RAW_GUEST_TRAP);
    623634    }
  • trunk/src/VBox/VMM/include/GIMKvmInternal.h

    r55037 r55118  
    193193typedef struct GIMKVM
    194194{
    195     /** @name MSRs. */
    196195    /** Wall-clock MSR. */
    197196    uint64_t                    u64WallClockMsr;
    198     /** @} */
    199 
    200     /** @name CPUID features. */
    201     /** Basic features. */
     197
     198    /**  CPUID features: Basic. */
    202199    uint32_t                    uBaseFeat;
    203     /** @} */
    204 
    205     /** Whether we need to trap #UD exceptions. */
     200
     201    /** Whether GIM needs to trap #UD exceptions. */
    206202    bool                        fTrapXcptUD;
     203    /** Disassembler opcode of hypercall instruction native for this host CPU. */
     204    uint16_t                    uOpCodeNative;
    207205} GIMKVM;
    208206/** Pointer to per-VM GIM KVM instance data. */
     
    264262VMM_INT_DECL(VBOXSTRICTRC)      gimKvmWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue);
    265263VMM_INT_DECL(bool)              gimKvmShouldTrapXcptUD(PVM pVM);
    266 VMM_INT_DECL(int)               gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx);
     264VMM_INT_DECL(int)               gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
    267265
    268266
  • trunk/src/VBox/VMM/include/HMInternal.h

    r55037 r55118  
    344344    bool                        fTPRPatchingActive;
    345345    /** Whether #UD needs to be intercepted (required by certain GIM providers). */
    346     bool                        fTrapXcptUD;
    347     bool                        u8Alignment[2];
     346    bool                        fGIMTrapXcptUD;
     347    /** Whether paravirt. hypercalls are enabled. */
     348    bool                        fHypercallsEnabled;
     349    bool                        u8Alignment[1];
    348350
    349351    /** Host kernel flags that HM might need to know (SUPKERNELFEATURES_XXX). */
Note: See TracChangeset for help on using the changeset viewer.

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