VirtualBox

Changeset 61544 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 7, 2016 2:42:20 PM (9 years ago)
Author:
vboxsync
Message:

VMM/GIM: Fix up hypercall rc handling and also a bug while disassembling hypercalls. IEM/REM being able to handle VMCALL/VMMCALL to hook into GIM is still a todo but this change temporarily works around by adding new GIM and GIM provider interfaces to kinda do the same work. The Xcpt handlers were not re-used as they check for whether or not the provider requested UD trapping in the first place.

Location:
trunk/src/VBox/VMM
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/GIMAll.cpp

    r61489 r61544  
    2323#include "GIMInternal.h"
    2424#include <VBox/err.h>
     25#include <VBox/dis.h>       /* For DISCPUSTATE */
     26#include <VBox/vmm/em.h>    /* For EMInterpretDisasCurrent */
    2527#include <VBox/vmm/vm.h>
    2628
     
    8587 * Implements a GIM hypercall with the provider configured for the VM.
    8688 *
    87  * @returns VBox status code.
     89 * @returns Strict VBox status code.
     90 * @retval  VINF_SUCCESS if the hypercall succeeded (even if its operation
     91 *          failed).
     92 * @retval  VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
     93 * @retval  VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
     94 * @retval  VERR_GIM_HYPERCALLS_NOT_AVAILABLE hypercalls unavailable.
     95 * @retval  VERR_GIM_NOT_ENABLED GIM is not enabled (shouldn't really happen)
     96 * @retval  VERR_GIM_HYPERCALL_MEMORY_READ_FAILED hypercall failed while reading
     97 *          memory.
     98 * @retval  VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED hypercall failed while
     99 *          writing memory.
     100 *
    88101 * @param   pVCpu       The cross context virtual CPU structure.
    89102 * @param   pCtx        Pointer to the guest-CPU context.
     
    91104 * @thread  EMT.
    92105 */
    93 VMM_INT_DECL(int) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
     106VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
    94107{
    95108    PVM pVM = pVCpu->CTX_SUFF(pVM);
     
    99112        return VERR_GIM_NOT_ENABLED;
    100113
    101     STAM_REL_COUNTER_INC(&pVM->gim.s.StatHypercalls);
    102114    switch (pVM->gim.s.enmProviderId)
    103115    {
     
    112124            return VERR_GIM_HYPERCALLS_NOT_AVAILABLE;
    113125    }
     126}
     127
     128
     129/**
     130 * Disassembles the current instruction at RIP and if it's a hypercall
     131 * instruction, performs the hypercall.
     132 *
     133 * @param   pVCpu       The cross context virtual CPU structure.
     134 * @param   pCtx        Pointer to the guest-CPU context.
     135 * @param   pcbInstr    Where to store the disassembled instruction length.
     136 *                      Optional, can be NULL.
     137 *
     138 * @todo    This interface should disappear when IEM/REM execution engines
     139 *          handle VMCALL/VMMCALL instrunctions to call into GIM when
     140 *          required. See @bugref{7270#c168}.
     141 */
     142VMM_INT_DECL(VBOXSTRICTRC) GIMExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t *pcbInstr)
     143{
     144    PVM pVM = pVCpu->CTX_SUFF(pVM);
     145    VMCPU_ASSERT_EMT(pVCpu);
     146
     147    if (RT_UNLIKELY(!GIMIsEnabled(pVM)))
     148        return VERR_GIM_NOT_ENABLED;
     149
     150    unsigned    cbInstr;
     151    DISCPUSTATE Dis;
     152    int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, &cbInstr);
     153    if (RT_SUCCESS(rc))
     154    {
     155        if (pcbInstr)
     156            *pcbInstr = (uint8_t)cbInstr;
     157        switch (pVM->gim.s.enmProviderId)
     158        {
     159            case GIMPROVIDERID_HYPERV:
     160                return gimHvExecHypercallInstr(pVCpu, pCtx, &Dis);
     161
     162            case GIMPROVIDERID_KVM:
     163                return gimKvmExecHypercallInstr(pVCpu, pCtx, &Dis);
     164
     165            default:
     166                AssertMsgFailed(("GIMExecHypercallInstr: for provider %u not available/implemented\n", pVM->gim.s.enmProviderId));
     167                return VERR_GIM_HYPERCALLS_NOT_AVAILABLE;
     168        }
     169    }
     170
     171    Log(("GIM: GIMExecHypercallInstr: Failed to disassemble CS:RIP=%04x:%08RX64. rc=%Rrc\n", pCtx->cs.Sel, pCtx->rip, rc));
     172    return rc;
    114173}
    115174
     
    177236 * Exception handler for \#UD when requested by the GIM provider.
    178237 *
     238 * @returns Strict VBox status code.
     239 * @retval  VINF_SUCCESS if the hypercall succeeded (even if its operation
     240 *          failed).
     241 * @retval  VINF_GIM_R3_HYPERCALL restart the hypercall from ring-3.
     242 * @retval  VINF_GIM_HYPERCALL_CONTINUING continue hypercall without updating
     243 *          RIP.
     244 * @retval  VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
     245 * @retval  VERR_GIM_INVALID_HYPERCALL_INSTR instruction at RIP is not a valid
     246 *          hypercall instruction.
     247 *
    179248 * @param   pVCpu       The cross context virtual CPU structure.
    180249 * @param   pCtx        Pointer to the guest-CPU context.
    181250 * @param   pDis        Pointer to the disassembled instruction state at RIP.
    182  *                      Optional, can be NULL.
    183  */
    184 VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
     251 *                      If NULL is passed, it implies the disassembly of the
     252 *                      the instruction at RIP is the responsibility of the
     253 *                      GIM provider.
     254 * @param   pcbInstr    Where to store the instruction length of the hypercall
     255 *                      instruction. Optional, can be NULL.
     256 *
     257 * @thread  EMT(pVCpu).
     258 */
     259VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr)
    185260{
    186261    PVM pVM = pVCpu->CTX_SUFF(pVM);
    187262    Assert(GIMIsEnabled(pVM));
    188 
    189     switch (pVM->gim.s.enmProviderId)
    190     {
    191         case GIMPROVIDERID_KVM:
    192             return gimKvmXcptUD(pVCpu, pCtx, pDis);
    193 
    194         case GIMPROVIDERID_HYPERV:
    195             return gimHvXcptUD(pVCpu, pCtx, pDis);
     263    Assert(pDis || pcbInstr);
     264
     265    switch (pVM->gim.s.enmProviderId)
     266    {
     267        case GIMPROVIDERID_KVM:
     268            return gimKvmXcptUD(pVCpu, pCtx, pDis, pcbInstr);
     269
     270        case GIMPROVIDERID_HYPERV:
     271            return gimHvXcptUD(pVCpu, pCtx, pDis, pcbInstr);
    196272
    197273        default:
  • trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp

    r61125 r61544  
    126126 * Handles all Hyper-V hypercalls.
    127127 *
    128  * @returns VBox status code.
     128 * @returns Strict VBox status code.
     129 * @retval  VINF_SUCCESS if the hypercall succeeded (even if its operation
     130 *          failed).
     131 * @retval  VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
     132 * @retval  VERR_GIM_HYPERCALLS_NOT_ENABLED hypercalls are disabled by the
     133 *          guest.
     134 * @retval  VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
     135 * @retval  VERR_GIM_HYPERCALL_MEMORY_READ_FAILED hypercall failed while reading
     136 *          memory.
     137 * @retval  VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED hypercall failed while
     138 *          writing memory.
     139 *
    129140 * @param   pVCpu           The cross context virtual CPU structure.
    130141 * @param   pCtx            Pointer to the guest-CPU context.
    131142 *
    132  * @thread  EMT.
    133  */
    134 VMM_INT_DECL(int) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
     143 * @thread  EMT(pVCpu).
     144 */
     145VMM_INT_DECL(VBOXSTRICTRC) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
    135146{
     147    VMCPU_ASSERT_EMT(pVCpu);
     148
    136149#ifndef IN_RING3
    137150    return VINF_GIM_R3_HYPERCALL;
    138151#else
    139152    PVM pVM = pVCpu->CTX_SUFF(pVM);
     153    STAM_REL_COUNTER_INC(&pVM->gim.s.StatHypercalls);
    140154
    141155    /*
    142      * Verify that hypercalls are enabled.
     156     * Verify that hypercalls are enabled by the guest.
    143157     */
    144158    if (!gimHvAreHypercallsEnabled(pVCpu))
     
    975989
    976990/**
     991 * Checks the currently disassembled instrunction and executes the hypercall if
     992 * it's a hypercall instruction.
     993 *
     994 * @returns Strict VBox status code.
     995 * @param   pVCpu       The cross context virtual CPU structure.
     996 * @param   pCtx        Pointer to the guest-CPU context.
     997 * @param   pDis        Pointer to the disassembled instruction state at RIP.
     998 *
     999 * @thread  EMT(pVCpu).
     1000 *
     1001 * @todo    Make this function static when @bugref{7270#c168} is addressed.
     1002 */
     1003VMM_INT_DECL(VBOXSTRICTRC) gimHvExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
     1004{
     1005    Assert(pVCpu);
     1006    Assert(pCtx);
     1007    Assert(pDis);
     1008    VMCPU_ASSERT_EMT(pVCpu);
     1009
     1010    PVM pVM = pVCpu->CTX_SUFF(pVM);
     1011    CPUMCPUVENDOR const enmGuestCpuVendor = CPUMGetGuestCpuVendor(pVM);
     1012    if (   (   pDis->pCurInstr->uOpcode == OP_VMCALL
     1013            && (   enmGuestCpuVendor == CPUMCPUVENDOR_INTEL
     1014                || enmGuestCpuVendor == CPUMCPUVENDOR_VIA))
     1015        || (   pDis->pCurInstr->uOpcode == OP_VMMCALL
     1016            && enmGuestCpuVendor == CPUMCPUVENDOR_AMD))
     1017    {
     1018        return gimHvHypercall(pVCpu, pCtx);
     1019    }
     1020
     1021    return VERR_GIM_INVALID_HYPERCALL_INSTR;
     1022}
     1023
     1024
     1025/**
    9771026 * Exception handler for \#UD.
     1027 *
     1028 * @returns Strict VBox status code.
     1029 * @retval  VINF_SUCCESS if the hypercall succeeded (even if its operation
     1030 *          failed).
     1031 * @retval  VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
     1032 * @retval  VINF_GIM_HYPERCALL_CONTINUING continue hypercall without updating
     1033 *          RIP.
     1034 * @retval  VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
     1035 * @retval  VERR_GIM_INVALID_HYPERCALL_INSTR instruction at RIP is not a valid
     1036 *          hypercall instruction.
    9781037 *
    9791038 * @param   pVCpu       The cross context virtual CPU structure.
     
    9811040 * @param   pDis        Pointer to the disassembled instruction state at RIP.
    9821041 *                      Optional, can be NULL.
    983  *
    984  * @thread  EMT.
    985  */
    986 VMM_INT_DECL(int) gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
     1042 * @param   pcbInstr    Where to store the instruction length of the hypercall
     1043 *                      instruction. Optional, can be NULL.
     1044 *
     1045 * @thread  EMT(pVCpu).
     1046 */
     1047VMM_INT_DECL(VBOXSTRICTRC) gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr)
    9871048{
     1049    VMCPU_ASSERT_EMT(pVCpu);
     1050
    9881051    /*
    9891052     * If we didn't ask for #UD to be trapped, bail.
    9901053     */
    991     PVM pVM = pVCpu->CTX_SUFF(pVM);
    9921054    if (!gimHvShouldTrapXcptUD(pVCpu))
    993         return VERR_GIM_OPERATION_FAILED;
    994 
    995     int rc = VINF_SUCCESS;
     1055        return VERR_GIM_IPE_1;
     1056
    9961057    if (!pDis)
    9971058    {
     
    10001061         * or the AMD VMMCALL instruction and if so, handle it as a hypercall.
    10011062         */
     1063        unsigned    cbInstr;
    10021064        DISCPUSTATE Dis;
    1003         rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, NULL /* pcbInstr */);
    1004         pDis = &Dis;
    1005     }
    1006 
    1007     if (RT_SUCCESS(rc))
    1008     {
    1009         CPUMCPUVENDOR enmGuestCpuVendor = CPUMGetGuestCpuVendor(pVM);
    1010         if (   (   pDis->pCurInstr->uOpcode == OP_VMCALL
    1011                 && (   enmGuestCpuVendor == CPUMCPUVENDOR_INTEL
    1012                     || enmGuestCpuVendor == CPUMCPUVENDOR_VIA))
    1013             || (   pDis->pCurInstr->uOpcode == OP_VMMCALL
    1014                 && enmGuestCpuVendor == CPUMCPUVENDOR_AMD))
    1015         {
    1016             /*
    1017              * Make sure guest ring-0 is the one making the hypercall.
    1018              */
    1019             if (CPUMGetGuestCPL(pVCpu))
    1020                 return VERR_GIM_HYPERCALL_ACCESS_DENIED;
    1021 
    1022             /*
    1023              * Update RIP and perform the hypercall.
    1024              */
    1025             /** @todo pre-incrementing of RIP will break when we implement continuing hypercalls. */
    1026             pCtx->rip += pDis->cbInstr;
    1027             rc = gimHvHypercall(pVCpu, pCtx);
    1028         }
    1029         else
    1030             rc = VERR_GIM_OPERATION_FAILED;
    1031     }
    1032     return rc;
     1065        int rc = EMInterpretDisasCurrent(pVCpu->CTX_SUFF(pVM), pVCpu, &Dis, &cbInstr);
     1066        if (RT_SUCCESS(rc))
     1067        {
     1068            if (pcbInstr)
     1069                *pcbInstr = (uint8_t)cbInstr;
     1070            return gimHvExecHypercallInstr(pVCpu, pCtx, &Dis);
     1071        }
     1072
     1073        Log(("GIM: HyperV: Failed to disassemble instruction at CS:RIP=%04x:%08RX64. rc=%Rrc\n", pCtx->cs.Sel, pCtx->rip, rc));
     1074        return rc;
     1075    }
     1076
     1077    return gimHvExecHypercallInstr(pVCpu, pCtx, pDis);
    10331078}
    10341079
  • trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp

    r58123 r61544  
    4242 * Handles the KVM hypercall.
    4343 *
    44  * @returns VBox status code.
     44 * @returns Strict VBox status code.
     45 * @retval  VINF_SUCCESS if the hypercall succeeded (even if its operation
     46 *          failed).
     47 * @retval  VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
     48 * @retval  VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
     49 *
    4550 * @param   pVCpu           The cross context virtual CPU structure.
    4651 * @param   pCtx            Pointer to the guest-CPU context.
    4752 *
    48  * @thread  EMT.
    49  */
    50 VMM_INT_DECL(int) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
    51 {
     53 * @thread  EMT(pVCpu).
     54 */
     55VMM_INT_DECL(VBOXSTRICTRC) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
     56{
     57    VMCPU_ASSERT_EMT(pVCpu);
     58
     59    PVM pVM = pVCpu->CTX_SUFF(pVM);
     60    STAM_REL_COUNTER_INC(&pVM->gim.s.StatHypercalls);
     61
    5262    /*
    5363     * Get the hypercall operation and arguments.
     
    7686     */
    7787    uint32_t uCpl = CPUMGetGuestCPL(pVCpu);
    78     if (uCpl)
     88    if (RT_UNLIKELY(uCpl))
    7989    {
    8090        pCtx->rax = KVM_HYPERCALL_RET_EPERM & uAndMask;
    81         return VINF_SUCCESS;
     91        return VERR_GIM_HYPERCALL_ACCESS_DENIED;
    8292    }
    8393
     
    8595     * Do the work.
    8696     */
     97    int rc = VINF_SUCCESS;
    8798    switch (uHyperOp)
    8899    {
    89100        case KVM_HYPERCALL_OP_KICK_CPU:
    90101        {
    91             PVM pVM = pVCpu->CTX_SUFF(pVM);
    92102            if (uHyperArg1 < pVM->cCpus)
    93103            {
     
    101111                GVMMR0SchedWakeUpEx(pVM, pVCpuTarget->idCpu, false /* fTakeUsedLock */);
    102112#elif defined(IN_RING3)
    103                 int rc2 = SUPR3CallVMMR0(pVM->pVMR0, pVCpuTarget->idCpu, VMMR0_DO_GVMM_SCHED_WAKE_UP, NULL);
     113                int rc2 = SUPR3CallVMMR0(pVM->pVMR0, pVCpuTarget->idCpu, VMMR0_DO_GVMM_SCHED_WAKE_UP, NULL /* pvArg */);
    104114                AssertRC(rc2);
    105115#elif defined(IN_RC)
     
    109119                uHyperRet = KVM_HYPERCALL_RET_SUCCESS;
    110120            }
     121            else
     122            {
     123                /* Shouldn't ever happen! If it does, throw a guru, as otherwise it'll lead to deadlocks in the guest anyway! */
     124                rc = VERR_GIM_HYPERCALL_FAILED;
     125            }
    111126            break;
    112127        }
     
    124139     */
    125140    pCtx->rax = uHyperRet & uAndMask;
    126     return VINF_SUCCESS;
     141    return rc;
    127142}
    128143
     
    349364
    350365/**
     366 * Checks the currently disassembled instrunction and executes the hypercall if
     367 * it's a hypercall instruction.
     368 *
     369 * @returns Strict VBox status code.
     370 * @param   pVCpu       The cross context virtual CPU structure.
     371 * @param   pCtx        Pointer to the guest-CPU context.
     372 * @param   pDis        Pointer to the disassembled instruction state at RIP.
     373 *
     374 * @thread  EMT(pVCpu).
     375 *
     376 * @todo    Make this function static when @bugref{7270#c168} is addressed.
     377 */
     378VMM_INT_DECL(VBOXSTRICTRC) gimKvmExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
     379{
     380    Assert(pVCpu);
     381    Assert(pCtx);
     382    Assert(pDis);
     383    VMCPU_ASSERT_EMT(pVCpu);
     384
     385    /*
     386     * If the instruction at RIP is the Intel VMCALL instruction or
     387     * the AMD VMMCALL instruction handle it as a hypercall.
     388     *
     389     * Linux/KVM guests always uses the Intel VMCALL instruction but we patch
     390     * it to the host-native one whenever we encounter it so subsequent calls
     391     * will not require disassembly (when coming from HM).
     392     */
     393    if (   pDis->pCurInstr->uOpcode == OP_VMCALL
     394        || pDis->pCurInstr->uOpcode == OP_VMMCALL)
     395    {
     396        /*
     397         * Perform the hypercall.
     398         *
     399         * For HM, we can simply resume guest execution without performing the hypercall now and
     400         * do it on the next VMCALL/VMMCALL exit handler on the patched instruction.
     401         *
     402         * For raw-mode we need to do this now anyway. So we do it here regardless with an added
     403         * advantage is that it saves one world-switch for the HM case.
     404         */
     405        VBOXSTRICTRC rcStrict = gimKvmHypercall(pVCpu, pCtx);
     406        if (rcStrict == VINF_SUCCESS)
     407        {
     408            /*
     409             * Patch the instruction to so we don't have to spend time disassembling it each time.
     410             * Makes sense only for HM as with raw-mode we will be getting a #UD regardless.
     411             */
     412            PVM      pVM  = pVCpu->CTX_SUFF(pVM);
     413            PCGIMKVM pKvm = &pVM->gim.s.u.Kvm;
     414            if (   pDis->pCurInstr->uOpcode != pKvm->uOpCodeNative
     415                && HMIsEnabled(pVM))
     416            {
     417                /** @todo r=ramshankar: we probably should be doing this in an
     418                 *        EMT rendezvous and using proper AVL-tree patching to
     419                 *        keep track at RIP so that non-patched VMCALL's still
     420                 *        produce \#UD. */
     421                uint8_t abHypercall[3];
     422                size_t  cbWritten = 0;
     423                int rc = VMMPatchHypercall(pVM, &abHypercall, sizeof(abHypercall), &cbWritten);
     424                AssertRC(rc);
     425                Assert(sizeof(abHypercall) == pDis->cbInstr);
     426                Assert(sizeof(abHypercall) == cbWritten);
     427
     428                rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &abHypercall, sizeof(abHypercall));
     429                AssertRC(rc);
     430
     431                /** @todo Add stats for patching. */
     432            }
     433        }
     434        else
     435        {
     436            /* The KVM provider doesn't have any concept of continuing hypercalls. */
     437            Assert(rcStrict != VINF_GIM_HYPERCALL_CONTINUING);
     438#ifdef IN_RING3
     439            Assert(rcStrict != VINF_GIM_R3_HYPERCALL);
     440#endif
     441        }
     442        return rcStrict;
     443    }
     444
     445    return VERR_GIM_INVALID_HYPERCALL_INSTR;
     446}
     447
     448
     449/**
    351450 * Exception handler for \#UD.
     451 *
     452 * @returns Strict VBox status code.
     453 * @retval  VINF_SUCCESS if the hypercall succeeded (even if its operation
     454 *          failed).
     455 * @retval  VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
     456 * @retval  VERR_GIM_HYPERCALL_ACCESS_DENIED CPL is insufficient.
     457 * @retval  VERR_GIM_INVALID_HYPERCALL_INSTR instruction at RIP is not a valid
     458 *          hypercall instruction.
    352459 *
    353460 * @param   pVCpu       The cross context virtual CPU structure.
     
    355462 * @param   pDis        Pointer to the disassembled instruction state at RIP.
    356463 *                      Optional, can be NULL.
    357  *
    358  * @thread  EMT.
    359  */
    360 VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
    361 {
     464 * @param   pcbInstr    Where to store the instruction length of the hypercall
     465 *                      instruction. Optional, can be NULL.
     466 *
     467 * @thread  EMT(pVCpu).
     468 */
     469VMM_INT_DECL(VBOXSTRICTRC) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr)
     470{
     471    VMCPU_ASSERT_EMT(pVCpu);
     472
    362473    /*
    363474     * If we didn't ask for #UD to be trapped, bail.
    364475     */
    365     PVM     pVM  = pVCpu->CTX_SUFF(pVM);
    366     PGIMKVM pKvm = &pVM->gim.s.u.Kvm;
    367     if (RT_UNLIKELY(!pVM->gim.s.u.Kvm.fTrapXcptUD))
    368         return VERR_GIM_OPERATION_FAILED;
    369 
    370     int rc = VINF_SUCCESS;
     476    PVM      pVM  = pVCpu->CTX_SUFF(pVM);
     477    PCGIMKVM pKvm = &pVM->gim.s.u.Kvm;
     478    if (RT_UNLIKELY(!pKvm->fTrapXcptUD))
     479        return VERR_GIM_IPE_3;
     480
     481    VBOXSTRICTRC rcStrict = VINF_SUCCESS;
    371482    if (!pDis)
    372483    {
    373         /*
    374          * Disassemble the instruction at RIP to figure out if it's the Intel VMCALL instruction
    375          * or the AMD VMMCALL instruction and if so, handle it as a hypercall.
    376          */
     484        unsigned    cbInstr;
    377485        DISCPUSTATE Dis;
    378         rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, NULL /* pcbInstr */);
    379         pDis = &Dis;
    380     }
    381 
    382     if (RT_SUCCESS(rc))
    383     {
    384         /*
    385          * Patch the instruction to so we don't have to spend time disassembling it each time.
    386          * Makes sense only for HM as with raw-mode we will be getting a #UD regardless.
    387          */
    388         if (   pDis->pCurInstr->uOpcode == OP_VMCALL
    389             || pDis->pCurInstr->uOpcode == OP_VMMCALL)
    390         {
    391             /*
    392              * Make sure guest ring-0 is the one making the hypercall.
    393              */
    394             if (CPUMGetGuestCPL(pVCpu))
    395                 return VERR_GIM_HYPERCALL_ACCESS_DENIED;
    396 
    397             if (   pDis->pCurInstr->uOpcode != pKvm->uOpCodeNative
    398                 && HMIsEnabled(pVM))
    399             {
    400                 uint8_t abHypercall[3];
    401                 size_t  cbWritten = 0;
    402                 rc = VMMPatchHypercall(pVM, &abHypercall, sizeof(abHypercall), &cbWritten);
    403                 AssertRC(rc);
    404                 Assert(sizeof(abHypercall) == pDis->cbInstr);
    405                 Assert(sizeof(abHypercall) == cbWritten);
    406 
    407                 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &abHypercall, sizeof(abHypercall));
    408             }
    409 
    410             /*
    411              * Update RIP and perform the hypercall.
    412              *
    413              * For HM, we can simply resume guest execution without performing the hypercall now and
    414              * do it on the next VMCALL/VMMCALL exit handler on the patched instruction.
    415              *
    416              * For raw-mode we need to do this now anyway. So we do it here regardless with an added
    417              * advantage is that it saves one world-switch for the HM case.
    418              */
    419             if (RT_SUCCESS(rc))
    420             {
    421                 pCtx->rip += pDis->cbInstr;
    422                 rc = gimKvmHypercall(pVCpu, pCtx);
    423             }
    424         }
    425         else
    426             rc = VERR_GIM_OPERATION_FAILED;
    427     }
    428     return rc;
    429 }
    430 
     486        int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, &cbInstr);
     487        if (RT_SUCCESS(rc))
     488        {
     489            if (pcbInstr)
     490                *pcbInstr = (uint8_t)cbInstr;
     491            return gimKvmExecHypercallInstr(pVCpu, pCtx, &Dis);
     492        }
     493
     494        Log(("GIM: KVM: Failed to disassemble instruction at CS:RIP=%04x:%08RX64. rc=%Rrc\n", pCtx->cs.Sel, pCtx->rip, rc));
     495        return rc;
     496    }
     497
     498    return gimKvmExecHypercallInstr(pVCpu, pCtx, pDis);
     499}
     500
  • trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp

    r61534 r61544  
    41264126                }
    41274127#endif
    4128                
     4128
    41294129                if (   uIdtVector == X86_XCPT_BP
    41304130                    || uIdtVector == X86_XCPT_OF)
     
    51985198        return VINF_SUCCESS;
    51995199    }
    5200     else if (rc == VERR_NOT_FOUND)
     5200
     5201    if (rc == VERR_NOT_FOUND)
    52015202    {
    52025203        if (pVCpu->hm.s.fHypercallsEnabled)
    52035204        {
    5204             hmR0SvmUpdateRip(pVCpu, pCtx, 3);
    5205 
    5206             /** @todo pre-increment RIP before hypercall will break when we have to implement
    5207              *  continuing hypercalls (e.g. Hyper-V). */
    5208             rc = GIMHypercall(pVCpu, pCtx);
    5209             /* If the hypercall changes anything other than guest general-purpose registers,
    5210                we would need to reload the guest changed bits here before VM-entry. */
    5211             return rc;
     5205            VBOXSTRICTRC rcStrict = GIMHypercall(pVCpu, pCtx);
     5206            if (RT_SUCCESS(VBOXSTRICTRC_VAL(rcStrict)))
     5207            {
     5208                if (rcStrict == VINF_SUCCESS)
     5209                    hmR0SvmUpdateRip(pVCpu, pCtx, 3 /* cbInstr */);
     5210                else
     5211                    Assert(   rcStrict == VINF_GIM_HYPERCALL_CONTINUING
     5212                           || rcStrict == VINF_GIM_R3_HYPERCALL);
     5213
     5214                /* If the hypercall changes anything other than guest's general-purpose registers,
     5215                   we would need to reload the guest changed bits here before VM-entry. */
     5216            }
     5217            rc = VBOXSTRICTRC_VAL(rcStrict);
    52125218        }
    52135219        else
     
    52155221    }
    52165222
    5217     hmR0SvmSetPendingXcptUD(pVCpu);
    5218     return VINF_SUCCESS;
     5223    /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
     5224    if (RT_FAILURE(rc))
     5225    {
     5226        hmR0SvmSetPendingXcptUD(pVCpu);
     5227        rc = VINF_SUCCESS;
     5228    }
     5229
     5230    return rc;
    52195231}
    52205232
     
    54235435
    54245436/**
    5425  * \#VMEXIT handler for undefined opcode (SVM_EXIT_EXCEPTION_6). Conditional
    5426  * \#VMEXIT.
     5437 * \#VMEXIT handler for undefined opcode (SVM_EXIT_EXCEPTION_6).
     5438 * Conditional \#VMEXIT.
    54275439 */
    54285440HMSVM_EXIT_DECL hmR0SvmExitXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
     
    54325444    HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
    54335445
     5446    int rc = VERR_SVM_UNEXPECTED_XCPT_EXIT;
    54345447    if (pVCpu->hm.s.fGIMTrapXcptUD)
    5435         GIMXcptUD(pVCpu, pCtx, NULL /* pDis */);
    5436     else
     5448    {
     5449        uint8_t cbInstr = 0;
     5450        VBOXSTRICTRC rcStrict = GIMXcptUD(pVCpu, pCtx, NULL /* pDis */, &cbInstr);
     5451        if (rcStrict == VINF_SUCCESS)
     5452        {
     5453            hmR0SvmUpdateRip(pVCpu, pCtx, cbInstr);
     5454            rc = VINF_SUCCESS;
     5455        }
     5456        else if (rcStrict == VINF_GIM_HYPERCALL_CONTINUING)
     5457            rc = VINF_SUCCESS;
     5458        else if (rcStrict == VINF_GIM_R3_HYPERCALL)
     5459            rc = VINF_GIM_R3_HYPERCALL;
     5460        else
     5461            Assert(RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
     5462    }
     5463
     5464    /* If the GIM #UD exception handler didn't succeed for some reason or wasn't needed, raise #UD. */
     5465    if (RT_FAILURE(rc))
     5466    {
    54375467        hmR0SvmSetPendingXcptUD(pVCpu);
     5468        rc = VINF_SUCCESS;
     5469    }
    54385470
    54395471    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
    5440     return VINF_SUCCESS;
     5472    return rc;
    54415473}
    54425474
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r61455 r61544  
    1144111441    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
    1144211442
     11443    VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3;
    1144311444    if (pVCpu->hm.s.fHypercallsEnabled)
    1144411445    {
     
    1144911450        int rc  = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
    1145011451        rc     |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);    /* For long-mode checks in gimKvmHypercall(). */
     11452        AssertRCReturn(rc, rc);
    1145111453#endif
    11452         rc     |= hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
    11453         AssertRCReturn(rc, rc);
    11454 
    11455         /** @todo pre-increment RIP before hypercall will break when we have to implement
    11456          *  continuing hypercalls (e.g. Hyper-V). */
    11457         /** @todo r=bird: GIMHypercall will probably have to be able to return
    11458          *        informational status codes, so it should be made VBOXSTRICTRC. Not
    11459          *        doing that now because the status code handling isn't clean (i.e.
    11460          *        if you use RT_SUCCESS(rc) on the result of something, you don't
    11461          *        return rc in the success case, you return VINF_SUCCESS). */
    11462         rc = GIMHypercall(pVCpu, pMixedCtx);
    11463         /* If the hypercall changes anything other than guest general-purpose registers,
     11454
     11455        /* Perform the hypercall. */
     11456        rcStrict = GIMHypercall(pVCpu, pMixedCtx);
     11457        if (rcStrict == VINF_SUCCESS)
     11458        {
     11459            rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
     11460            AssertRCReturn(rc, rc);
     11461        }
     11462        else
     11463            Assert(   rcStrict == VINF_GIM_R3_HYPERCALL
     11464                   || rcStrict == VINF_GIM_HYPERCALL_CONTINUING
     11465                   || RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
     11466
     11467        /* If the hypercall changes anything other than guest's general-purpose registers,
    1146411468           we would need to reload the guest changed bits here before VM-entry. */
    11465         return rc;
    11466     }
    11467 
    11468     Log4(("hmR0VmxExitVmcall: Hypercalls not enabled\n"));
    11469     hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
    11470     return VINF_SUCCESS;
     11469    }
     11470    else
     11471        Log4(("hmR0VmxExitVmcall: Hypercalls not enabled\n"));
     11472
     11473    /* If hypercalls are disabled or the hypercall failed for some reason, raise #UD and continue. */
     11474    if (RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)))
     11475    {
     11476        hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
     11477        rcStrict = VINF_SUCCESS;
     11478    }
     11479
     11480    return rcStrict;
    1147111481}
    1147211482
  • trunk/src/VBox/VMM/VMMR3/GIM.cpp

    r58564 r61544  
    434434        if (ASMAtomicReadBool(&pDbg->fDbgRecvBufRead) == true)
    435435        {
    436             STAM_COUNTER_INC(&pVM->gim.s.StatDbgRecv);
    437             STAM_COUNTER_ADD(&pVM->gim.s.StatDbgRecvBytes, pDbg->cbDbgRecvBufRead);
     436            STAM_REL_COUNTER_INC(&pVM->gim.s.StatDbgRecv);
     437            STAM_REL_COUNTER_ADD(&pVM->gim.s.StatDbgRecvBytes, pDbg->cbDbgRecvBufRead);
    438438
    439439            memcpy(pvRead, pDbg->pvDbgRecvBuf, pDbg->cbDbgRecvBufRead);
     
    477477                && *pcbWrite == cbWrite)
    478478            {
    479                 STAM_COUNTER_INC(&pVM->gim.s.StatDbgXmit);
    480                 STAM_COUNTER_ADD(&pVM->gim.s.StatDbgXmitBytes, *pcbWrite);
     479                STAM_REL_COUNTER_INC(&pVM->gim.s.StatDbgXmit);
     480                STAM_REL_COUNTER_ADD(&pVM->gim.s.StatDbgXmitBytes, *pcbWrite);
    481481            }
    482482            return rc;
  • trunk/src/VBox/VMM/VMMR3/GIMHv.cpp

    r61008 r61544  
    17121712        rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
    17131713    }
     1714    else
     1715        Assert(rc == VINF_SUCCESS);
    17141716
    17151717    *prcHv = rcHv;
     
    17911793        rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
    17921794    }
     1795    else
     1796        Assert(rc == VINF_SUCCESS);
    17931797
    17941798    *prcHv = rcHv;
  • trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp

    r61144 r61544  
    643643        {
    644644            LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD\n"));
    645             rc = GIMXcptUD(pVCpu, CPUMCTX_FROM_CORE(pRegFrame), &Cpu);
    646             if (RT_FAILURE(rc))
     645            VBOXSTRICTRC rcStrict = GIMXcptUD(pVCpu, CPUMCTX_FROM_CORE(pRegFrame), &Cpu, NULL /* pcbInstr */);
     646            if (rcStrict == VINF_SUCCESS)
    647647            {
    648                 LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD -> VINF_EM_RAW_EMULATE_INSTR\n"));
     648                /* The interrupt inhibition wrt to EIP will be handled by trpmGCExitTrap() below. */
     649                pRegFrame->eip += Cpu.cbInstr;
     650                Assert(Cpu.cbInstr);
     651            }
     652            else if (rcStrict == VINF_GIM_HYPERCALL_CONTINUING)
     653                rc = VINF_SUCCESS;
     654            else if (rcStrict == VINF_GIM_R3_HYPERCALL)
     655                rc = VINF_GIM_R3_HYPERCALL;
     656            else
     657            {
     658                Assert(RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
     659                LogFlow(("TRPMGCTrap06Handler: GIMXcptUD returns %Rrc -> VINF_EM_RAW_EMULATE_INSTR\n", rc));
    649660                rc = VINF_EM_RAW_EMULATE_INSTR;
    650661            }
  • trunk/src/VBox/VMM/include/EMHandleRCTmpl.h

    r60847 r61544  
    236236         */
    237237        case VINF_GIM_R3_HYPERCALL:
    238             rc = GIMHypercall(pVCpu, pCtx);
    239             break;
     238        {
     239            /** @todo IEM/REM need to handle VMCALL/VMMCALL, see
     240             *        @bugref{7270#c168}. */
     241            uint8_t cbInstr = 0;
     242            VBOXSTRICTRC rcStrict = GIMExecHypercallInstr(pVCpu, pCtx, &cbInstr);
     243            if (rcStrict == VINF_SUCCESS)
     244            {
     245                Assert(cbInstr);
     246                pCtx->rip += cbInstr;
     247                /* Update interrupt inhibition. */
     248                if (   VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)
     249                    && pCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
     250                    VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
     251                rc = VINF_SUCCESS;
     252            }
     253            else if (rcStrict == VINF_GIM_HYPERCALL_CONTINUING)
     254                rc = VINF_SUCCESS;
     255            else
     256            {
     257                Assert(rcStrict != VINF_GIM_R3_HYPERCALL);
     258                rc = VBOXSTRICTRC_VAL(rcStrict);
     259            }
     260            break;
     261        }
    240262
    241263#ifdef EMHANDLERC_WITH_HM
  • trunk/src/VBox/VMM/include/GIMHvInternal.h

    r58392 r61544  
    11391139VMM_INT_DECL(bool)              gimHvAreHypercallsEnabled(PVMCPU pVCpu);
    11401140VMM_INT_DECL(bool)              gimHvShouldTrapXcptUD(PVMCPU pVCpu);
    1141 VMM_INT_DECL(int)               gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
    1142 VMM_INT_DECL(int)               gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
     1141VMM_INT_DECL(VBOXSTRICTRC)      gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr);
     1142VMM_INT_DECL(VBOXSTRICTRC)      gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
     1143VMM_INT_DECL(VBOXSTRICTRC)      gimHvExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
    11431144VMM_INT_DECL(VBOXSTRICTRC)      gimHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
    11441145VMM_INT_DECL(VBOXSTRICTRC)      gimHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue);
  • trunk/src/VBox/VMM/include/GIMKvmInternal.h

    r58127 r61544  
    261261VMM_INT_DECL(bool)              gimKvmIsParavirtTscEnabled(PVM pVM);
    262262VMM_INT_DECL(bool)              gimKvmAreHypercallsEnabled(PVMCPU pVCpu);
    263 VMM_INT_DECL(int)               gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
     263VMM_INT_DECL(VBOXSTRICTRC)      gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
    264264VMM_INT_DECL(VBOXSTRICTRC)      gimKvmReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
    265265VMM_INT_DECL(VBOXSTRICTRC)      gimKvmWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue);
    266266VMM_INT_DECL(bool)              gimKvmShouldTrapXcptUD(PVMCPU pVCpu);
    267 VMM_INT_DECL(int)               gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
     267VMM_INT_DECL(VBOXSTRICTRC)      gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr);
     268VMM_INT_DECL(VBOXSTRICTRC)      gimKvmExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
    268269
    269270
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