Changeset 55037 in vbox
- Timestamp:
- Mar 31, 2015 2:09:10 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
-
include/VBox/err.h (modified) (1 diff)
-
include/VBox/vmm/gim.h (modified) (2 diffs)
-
src/VBox/VMM/VMMAll/GIMAll.cpp (modified) (3 diffs)
-
src/VBox/VMM/VMMAll/GIMAllKvm.cpp (modified) (4 diffs)
-
src/VBox/VMM/VMMR0/HMSVMR0.cpp (modified) (9 diffs)
-
src/VBox/VMM/VMMR0/HMVMXR0.cpp (modified) (2 diffs)
-
src/VBox/VMM/VMMR3/GIMKvm.cpp (modified) (1 diff)
-
src/VBox/VMM/include/GIMInternal.h (modified) (1 diff)
-
src/VBox/VMM/include/GIMKvmInternal.h (modified) (3 diffs)
-
src/VBox/VMM/include/HMInternal.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/err.h
r54903 r55037 2622 2622 /** The GIM device is not registered with GIM when it ought to be. */ 2623 2623 #define VERR_GIM_DEVICE_NOT_REGISTERED (-6310) 2624 /** An invalid Guest OS identifier was specified for the GIM provider. */2625 #define VERR_GIM_INVALID_GUESTOS_ID (-6311)2626 2624 /** @} */ 2627 2625 -
trunk/include/VBox/vmm/gim.h
r53615 r55037 98 98 AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0, 8); 99 99 100 101 100 #if 0 102 101 /** … … 175 174 VMM_INT_DECL(bool) GIMAreHypercallsEnabled(PVMCPU pVCpu); 176 175 VMM_INT_DECL(int) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx); 176 VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx); 177 VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVM pVM); 177 178 VMM_INT_DECL(VBOXSTRICTRC) GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); 178 179 VMM_INT_DECL(VBOXSTRICTRC) GIMWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue); 179 180 180 /** @} */ 181 181 -
trunk/src/VBox/VMM/VMMAll/GIMAll.cpp
r54819 r55037 73 73 return gimHvAreHypercallsEnabled(pVCpu); 74 74 75 case GIMPROVIDERID_KVM: 76 return gimKvmAreHypercallsEnabled(pVCpu); 77 75 78 default: 76 79 return false; … … 99 102 return gimHvHypercall(pVCpu, pCtx); 100 103 101 default: 102 AssertMsgFailed(("GIMHypercall: for unknown provider %u\n", pVM->gim.s.enmProviderId)); 103 return VERR_GIM_IPE_3; 104 case GIMPROVIDERID_KVM: 105 return gimKvmHypercall(pVCpu, pCtx); 106 107 default: 108 AssertMsgFailed(("GIMHypercall: for provider %u not available/implemented\n", pVM->gim.s.enmProviderId)); 109 return VERR_GIM_HYPERCALLS_NOT_AVAILABLE; 104 110 } 105 111 } … … 127 133 } 128 134 return false; 135 } 136 137 138 /** 139 * Whether #UD exceptions in the guest needs to be intercepted by the GIM 140 * provider. 141 * 142 * At the moment, the reason why this isn't a more generic interface wrt to 143 * exceptions is because of performance (each VM-exit would have to manually 144 * check whether or not GIM needs to be notified). Left as a todo for later if 145 * really required. 146 * 147 * @returns true if needed, false otherwise. 148 * @param pVM Pointer to the VM. 149 */ 150 VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVM pVM) 151 { 152 if (!GIMIsEnabled(pVM)) 153 return 0; 154 155 switch (pVM->gim.s.enmProviderId) 156 { 157 case GIMPROVIDERID_KVM: 158 return gimKvmShouldTrapXcptUD(pVM); 159 160 default: 161 return 0; 162 } 163 } 164 165 166 /** 167 * Exception handler for #UD when requested by the GIM provider. 168 * 169 * @param pVCpu Pointer to the VMCPU. 170 * @param pCtx Pointer to the guest-CPU context. 171 */ 172 VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx) 173 { 174 PVM pVM = pVCpu->CTX_SUFF(pVM); 175 Assert(GIMIsEnabled(pVM)); 176 177 switch (pVM->gim.s.enmProviderId) 178 { 179 case GIMPROVIDERID_KVM: 180 return gimKvmXcptUD(pVCpu, pCtx); 181 182 default: 183 return VERR_GIM_OPERATION_FAILED; 184 } 129 185 } 130 186 -
trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
r54839 r55037 24 24 25 25 #include <VBox/err.h> 26 #include <VBox/dis.h> 26 27 #include <VBox/vmm/hm.h> 28 #include <VBox/vmm/em.h> 27 29 #include <VBox/vmm/tm.h> 28 30 #include <VBox/vmm/vm.h> … … 30 32 #include <VBox/vmm/pdmdev.h> 31 33 #include <VBox/vmm/pdmapi.h> 34 #include <VBox/sup.h> 32 35 33 36 #include <iprt/asm-amd64-x86.h> … … 43 46 VMM_INT_DECL(int) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx) 44 47 { 45 PVM pVM = pVCpu->CTX_SUFF(pVM); 46 /** @todo Handle hypercalls. Fail for now */ 47 return VERR_GIM_IPE_3; 48 /* 49 * Get the hypercall operation and arguments. 50 */ 51 bool const fIs64BitMode = CPUMIsGuestIn64BitCodeEx(pCtx); 52 uint64_t uHyperOp = pCtx->rax; 53 uint64_t uHyperArg0 = pCtx->rbx; 54 uint64_t uHyperArg1 = pCtx->rcx; 55 uint64_t uHyperArg2 = pCtx->rdi; 56 uint64_t uHyperArg3 = pCtx->rsi; 57 uint64_t uHyperRet = KVM_HYPERCALL_RET_ENOSYS; 58 uint64_t uAndMask = UINT64_C(0xffffffffffffffff); 59 if (!fIs64BitMode) 60 { 61 uAndMask = UINT64_C(0xffffffff); 62 uHyperOp &= UINT64_C(0xffffffff); 63 uHyperArg0 &= UINT64_C(0xffffffff); 64 uHyperArg1 &= UINT64_C(0xffffffff); 65 uHyperArg2 &= UINT64_C(0xffffffff); 66 uHyperArg3 &= UINT64_C(0xffffffff); 67 uHyperRet &= UINT64_C(0xffffffff); 68 } 69 70 /* 71 * Verify that guest ring-0 is the one making the hypercall. 72 */ 73 uint32_t uCpl = CPUMGetGuestCPL(pVCpu); 74 if (uCpl) 75 { 76 pCtx->rax = KVM_HYPERCALL_RET_EPERM & uAndMask; 77 return VINF_SUCCESS; 78 } 79 80 /* 81 * Do the work. 82 */ 83 switch (uHyperOp) 84 { 85 case KVM_HYPERCALL_OP_KICK_CPU: 86 { 87 PVM pVM = pVCpu->CTX_SUFF(pVM); 88 if (uHyperArg1 < pVM->cCpus) 89 { 90 PVMCPU pVCpuTarget = &pVM->aCpus[uHyperArg1]; /** ASSUMES pVCpu index == ApicId of the VCPU. */ 91 VMCPU_FF_SET(pVCpuTarget, VMCPU_FF_UNHALT); 92 #ifdef IN_RING0 93 GVMMR0SchedWakeUp(pVM, pVCpuTarget->idCpu); 94 #elif defined(IN_RING3) 95 int rc2 = SUPR3CallVMMR0(pVM->pVMR0, pVCpuTarget->idCpu, VMMR0_DO_GVMM_SCHED_WAKE_UP, NULL); 96 AssertRC(rc2); 97 #endif 98 uHyperRet = KVM_HYPERCALL_RET_SUCCESS; 99 } 100 break; 101 } 102 103 case KVM_HYPERCALL_OP_VAPIC_POLL_IRQ: 104 uHyperRet = KVM_HYPERCALL_RET_SUCCESS; 105 break; 106 107 default: 108 break; 109 } 110 111 /* 112 * Place the result in rax/eax. 113 */ 114 if (fIs64BitMode) 115 pCtx->rax = uHyperRet; 116 else 117 pCtx->eax = uHyperRet & uAndMask; 118 return VINF_SUCCESS; 48 119 } 49 120 … … 231 302 } 232 303 304 305 /** 306 * Whether we need to trap #UD exceptions in the guest. 307 * 308 * On AMD-V we need to trap them because paravirtualized Linux/KVM guests use 309 * the Intel VMCALL instruction to make hypercalls and we need to trap and 310 * optionally patch them to the AMD-V VMMCALL instruction and handle the 311 * hypercall. 312 * 313 * I guess this was done so that guest teleporation between an AMD and an Intel 314 * machine would working without any changes at the time of teleporation. 315 * However, this also means we -always- need to intercept #UD exceptions on one 316 * of the two CPU models (Intel or AMD). Hyper-V solves this problem more 317 * elegantly by letting the hypervisor supply an opaque hypercall page. 318 * 319 * @param pVM Pointer to the VM. 320 */ 321 VMM_INT_DECL(bool) gimKvmShouldTrapXcptUD(PVM pVM) 322 { 323 pVM->gim.s.u.Kvm.fTrapXcptUD = ASMIsAmdCpu(); 324 return pVM->gim.s.u.Kvm.fTrapXcptUD; 325 } 326 327 328 /** 329 * Exception handler for #UD. 330 * 331 * @param pVCpu Pointer to the VMCPU. 332 * @param pCtx Pointer to the guest-CPU context. 333 */ 334 VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx) 335 { 336 /* 337 * If we didn't ask for #UD to be trapped, bail. 338 */ 339 PVM pVM = pVCpu->CTX_SUFF(pVM); 340 if (RT_UNLIKELY(!pVM->gim.s.u.Kvm.fTrapXcptUD)) 341 return VERR_GIM_OPERATION_FAILED; 342 343 /* 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); 350 if (RT_SUCCESS(rc)) 351 { 352 if (Dis.pCurInstr->uOpcode == OP_VMCALL) 353 { 354 Assert(cbInstr == 3); /* paranoia. */ 355 356 /* 357 * Patch the instruction to so we don't have to spend time disassembling it each time. 358 */ 359 static uint8_t s_abHypercall[3]; 360 size_t cbWritten; 361 rc = HMPatchHypercall(pVM, &s_abHypercall, sizeof(s_abHypercall), &cbWritten); 362 AssertRC(rc); 363 364 if (RT_LIKELY(cbWritten == cbInstr)) 365 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &s_abHypercall, sizeof(s_abHypercall)); 366 if (RT_SUCCESS(rc)) 367 return gimKvmHypercall(pVCpu, pCtx); 368 } 369 } 370 371 return VERR_GIM_OPERATION_FAILED; 372 } 373 -
trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
r55001 r55037 296 296 static FNSVMEXITHANDLER hmR0SvmExitXcptPF; 297 297 static FNSVMEXITHANDLER hmR0SvmExitXcptNM; 298 static FNSVMEXITHANDLER hmR0SvmExitXcptUD; 298 299 static FNSVMEXITHANDLER hmR0SvmExitXcptMF; 299 300 static FNSVMEXITHANDLER hmR0SvmExitXcptDB; … … 669 670 Assert(pVM->hm.s.svm.fSupported); 670 671 672 pVM->hm.s.fTrapXcptUD = GIMShouldTrapXcptUD(pVM); 673 uint32_t const fGimXcptIntercepts = pVM->hm.s.fTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0; 671 674 for (VMCPUID i = 0; i < pVM->cCpus; i++) 672 675 { … … 783 786 pVmcb->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_TASK_SWITCH; 784 787 #endif 788 789 /* Apply the exceptions intercepts needed by the GIM provider. */ 790 pVmcb->ctrl.u32InterceptException |= fGimXcptIntercepts; 785 791 786 792 /* … … 3476 3482 return hmR0SvmExitXcptNM(pVCpu, pCtx, pSvmTransient); 3477 3483 3484 case SVM_EXIT_EXCEPTION_6: /* X86_XCPT_UD */ 3485 return hmR0SvmExitXcptUD(pVCpu, pCtx, pSvmTransient); 3486 3478 3487 case SVM_EXIT_EXCEPTION_10: /* X86_XCPT_MF */ 3479 3488 return hmR0SvmExitXcptMF(pVCpu, pCtx, pSvmTransient); … … 3582 3591 case SVM_EXIT_EXCEPTION_4: /* X86_XCPT_OF */ 3583 3592 case SVM_EXIT_EXCEPTION_5: /* X86_XCPT_BR */ 3584 case SVM_EXIT_EXCEPTION_6: /* X86_XCPT_UD*/3593 /* case SVM_EXIT_EXCEPTION_6: */ /* X86_XCPT_UD - Handled above. */ 3585 3594 /* SVM_EXIT_EXCEPTION_7: */ /* X86_XCPT_NM - Handled above. */ 3586 3595 case SVM_EXIT_EXCEPTION_8: /* X86_XCPT_DF */ … … 3619 3628 /** @todo Investigate this later. */ 3620 3629 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestBP); 3621 break;3622 3623 case X86_XCPT_UD:3624 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);3625 3630 break; 3626 3631 … … 4152 4157 { 4153 4158 PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb; 4159 Assert(pVmcb->ctrl.u64NextRIP - pCtx->rip == cb); 4154 4160 pCtx->rip = pVmcb->ctrl.u64NextRIP; 4155 4161 } … … 5003 5009 if (GIMAreHypercallsEnabled(pVCpu)) 5004 5010 rc = GIMHypercall(pVCpu, pCtx); 5005 } 5006 5007 if (rc != VINF_SUCCESS) 5011 5012 /* If the hypercall changes anything other than guest general-purpose registers, 5013 we would need to reload the guest changed bits on VM-reentry. */ 5014 } 5015 5016 if (RT_SUCCESS(rc)) 5017 hmR0SvmUpdateRip(pVCpu, pCtx, 3); 5018 else 5008 5019 hmR0SvmSetPendingXcptUD(pVCpu); 5009 5020 return VINF_SUCCESS; … … 5202 5213 5203 5214 /** 5215 * #VMEXIT handler for undefined opcode (SVM_EXIT_EXCEPTION_6). 5216 * Conditional #VMEXIT. 5217 */ 5218 HMSVM_EXIT_DECL hmR0SvmExitXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient) 5219 { 5220 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS(); 5221 5222 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY(); 5223 5224 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); 5225 5226 PVM pVM = pVCpu->CTX_SUFF(pVM); 5227 if ( pVM->hm.s.fTrapXcptUD 5228 && GIMAreHypercallsEnabled(pVCpu)) 5229 { 5230 int rc = GIMXcptUD(pVCpu, pCtx); 5231 if (RT_SUCCESS(rc)) 5232 { 5233 /* If the exception handler changes anything other than guest general-purpose registers, 5234 we would need to reload the guest changed bits on VM-reentry. */ 5235 hmR0SvmUpdateRip(pVCpu, pCtx, 3); 5236 return VINF_SUCCESS; 5237 } 5238 } 5239 5240 hmR0SvmSetPendingXcptUD(pVCpu); 5241 return VINF_SUCCESS; 5242 } 5243 5244 5245 /** 5204 5246 * #VMEXIT handler for math-fault exceptions (SVM_EXIT_EXCEPTION_10). 5205 5247 * Conditional #VMEXIT. -
trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
r54908 r55037 7532 7532 else if (uIntType == VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI) 7533 7533 { 7534 bool fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI);7534 bool const fBlockNmi = RT_BOOL(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI); 7535 7535 Assert(!fBlockSti); 7536 7536 Assert(!fBlockMovSS); … … 10250 10250 rc = GIMHypercall(pVCpu, pMixedCtx); 10251 10251 } 10252 if (rc != VINF_SUCCESS) 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 10253 10262 { 10254 10263 hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx); -
trunk/src/VBox/VMM/VMMR3/GIMKvm.cpp
r54845 r55037 98 98 //| GIM_KVM_BASE_FEAT_STEAL_TIME 99 99 //| GIM_KVM_BASE_FEAT_PV_EOI 100 //| GIM_KVM_BASE_FEAT_UNHALT100 | GIM_KVM_BASE_FEAT_PV_UNHALT 101 101 ; 102 102 /* Rest of the features are determined in gimR3KvmInitCompleted(). */ -
trunk/src/VBox/VMM/include/GIMInternal.h
r54819 r55037 73 73 union 74 74 { 75 GIMHV Hv;75 GIMHV Hv; 76 76 GIMKVM Kvm; 77 77 } u; -
trunk/src/VBox/VMM/include/GIMKvmInternal.h
r54839 r55037 117 117 */ 118 118 /** Guest-physical address of the wall-clock struct. */ 119 #define MSR_GIM_KVM_WALL_CLOCK_GUEST_GPA(a) (a) 120 /** @} */ 121 119 #define MSR_GIM_KVM_WALL_CLOCK_GUEST_GPA(a) (a) 120 /** @} */ 121 122 123 /** @name KVM Hypercall operations. 124 * @{ */ 125 #define KVM_HYPERCALL_OP_VAPIC_POLL_IRQ 1 126 #define KVM_HYPERCALL_OP_MMU 2 127 #define KVM_HYPERCALL_OP_FEATURES 3 128 #define KVM_HYPERCALL_OP_KICK_CPU 5 129 /** @} */ 130 131 /** @name KVM Hypercall return values. 132 * @{ */ 133 /* Return values for hypercalls */ 134 #define KVM_HYPERCALL_RET_SUCCESS 0 135 #define KVM_HYPERCALL_RET_ENOSYS (uint64_t)(-1000) 136 #define KVM_HYPERCALL_RET_EFAULT (uint64_t)(-14) 137 #define KVM_HYPERCALL_RET_E2BIG (uint64_t)(-7) 138 #define KVM_HYPERCALL_RET_EPERM (uint64_t)(-1) 139 /** @} */ 122 140 123 141 /** … … 184 202 uint32_t uBaseFeat; 185 203 /** @} */ 204 205 /** Whether we need to trap #UD exceptions. */ 206 bool fTrapXcptUD; 186 207 } GIMKVM; 187 208 /** Pointer to per-VM GIM KVM instance data. */ … … 242 263 VMM_INT_DECL(VBOXSTRICTRC) gimKvmReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); 243 264 VMM_INT_DECL(VBOXSTRICTRC) gimKvmWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue); 265 VMM_INT_DECL(bool) gimKvmShouldTrapXcptUD(PVM pVM); 266 VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx); 267 244 268 245 269 RT_C_DECLS_END -
trunk/src/VBox/VMM/include/HMInternal.h
r54908 r55037 343 343 /** Set when TPR patching is active. */ 344 344 bool fTPRPatchingActive; 345 bool u8Alignment[3]; 345 /** Whether #UD needs to be intercepted (required by certain GIM providers). */ 346 bool fTrapXcptUD; 347 bool u8Alignment[2]; 346 348 347 349 /** Host kernel flags that HM might need to know (SUPKERNELFEATURES_XXX). */
Note:
See TracChangeset
for help on using the changeset viewer.

