Changeset 61544 in vbox for trunk/src/VBox
- Timestamp:
- Jun 7, 2016 2:42:20 PM (9 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/GIMAll.cpp
r61489 r61544 23 23 #include "GIMInternal.h" 24 24 #include <VBox/err.h> 25 #include <VBox/dis.h> /* For DISCPUSTATE */ 26 #include <VBox/vmm/em.h> /* For EMInterpretDisasCurrent */ 25 27 #include <VBox/vmm/vm.h> 26 28 … … 85 87 * Implements a GIM hypercall with the provider configured for the VM. 86 88 * 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 * 88 101 * @param pVCpu The cross context virtual CPU structure. 89 102 * @param pCtx Pointer to the guest-CPU context. … … 91 104 * @thread EMT. 92 105 */ 93 VMM_INT_DECL( int) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)106 VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx) 94 107 { 95 108 PVM pVM = pVCpu->CTX_SUFF(pVM); … … 99 112 return VERR_GIM_NOT_ENABLED; 100 113 101 STAM_REL_COUNTER_INC(&pVM->gim.s.StatHypercalls);102 114 switch (pVM->gim.s.enmProviderId) 103 115 { … … 112 124 return VERR_GIM_HYPERCALLS_NOT_AVAILABLE; 113 125 } 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 */ 142 VMM_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; 114 173 } 115 174 … … 177 236 * Exception handler for \#UD when requested by the GIM provider. 178 237 * 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 * 179 248 * @param pVCpu The cross context virtual CPU structure. 180 249 * @param pCtx Pointer to the guest-CPU context. 181 250 * @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 */ 259 VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr) 185 260 { 186 261 PVM pVM = pVCpu->CTX_SUFF(pVM); 187 262 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); 196 272 197 273 default: -
trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
r61125 r61544 126 126 * Handles all Hyper-V hypercalls. 127 127 * 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 * 129 140 * @param pVCpu The cross context virtual CPU structure. 130 141 * @param pCtx Pointer to the guest-CPU context. 131 142 * 132 * @thread EMT .133 */ 134 VMM_INT_DECL( int) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)143 * @thread EMT(pVCpu). 144 */ 145 VMM_INT_DECL(VBOXSTRICTRC) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx) 135 146 { 147 VMCPU_ASSERT_EMT(pVCpu); 148 136 149 #ifndef IN_RING3 137 150 return VINF_GIM_R3_HYPERCALL; 138 151 #else 139 152 PVM pVM = pVCpu->CTX_SUFF(pVM); 153 STAM_REL_COUNTER_INC(&pVM->gim.s.StatHypercalls); 140 154 141 155 /* 142 * Verify that hypercalls are enabled .156 * Verify that hypercalls are enabled by the guest. 143 157 */ 144 158 if (!gimHvAreHypercallsEnabled(pVCpu)) … … 975 989 976 990 /** 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 */ 1003 VMM_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 /** 977 1026 * 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. 978 1037 * 979 1038 * @param pVCpu The cross context virtual CPU structure. … … 981 1040 * @param pDis Pointer to the disassembled instruction state at RIP. 982 1041 * 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 */ 1047 VMM_INT_DECL(VBOXSTRICTRC) gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr) 987 1048 { 1049 VMCPU_ASSERT_EMT(pVCpu); 1050 988 1051 /* 989 1052 * If we didn't ask for #UD to be trapped, bail. 990 1053 */ 991 PVM pVM = pVCpu->CTX_SUFF(pVM);992 1054 if (!gimHvShouldTrapXcptUD(pVCpu)) 993 return VERR_GIM_OPERATION_FAILED; 994 995 int rc = VINF_SUCCESS; 1055 return VERR_GIM_IPE_1; 1056 996 1057 if (!pDis) 997 1058 { … … 1000 1061 * or the AMD VMMCALL instruction and if so, handle it as a hypercall. 1001 1062 */ 1063 unsigned cbInstr; 1002 1064 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); 1033 1078 } 1034 1079 -
trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
r58123 r61544 42 42 * Handles the KVM hypercall. 43 43 * 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 * 45 50 * @param pVCpu The cross context virtual CPU structure. 46 51 * @param pCtx Pointer to the guest-CPU context. 47 52 * 48 * @thread EMT. 49 */ 50 VMM_INT_DECL(int) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx) 51 { 53 * @thread EMT(pVCpu). 54 */ 55 VMM_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 52 62 /* 53 63 * Get the hypercall operation and arguments. … … 76 86 */ 77 87 uint32_t uCpl = CPUMGetGuestCPL(pVCpu); 78 if ( uCpl)88 if (RT_UNLIKELY(uCpl)) 79 89 { 80 90 pCtx->rax = KVM_HYPERCALL_RET_EPERM & uAndMask; 81 return V INF_SUCCESS;91 return VERR_GIM_HYPERCALL_ACCESS_DENIED; 82 92 } 83 93 … … 85 95 * Do the work. 86 96 */ 97 int rc = VINF_SUCCESS; 87 98 switch (uHyperOp) 88 99 { 89 100 case KVM_HYPERCALL_OP_KICK_CPU: 90 101 { 91 PVM pVM = pVCpu->CTX_SUFF(pVM);92 102 if (uHyperArg1 < pVM->cCpus) 93 103 { … … 101 111 GVMMR0SchedWakeUpEx(pVM, pVCpuTarget->idCpu, false /* fTakeUsedLock */); 102 112 #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 */); 104 114 AssertRC(rc2); 105 115 #elif defined(IN_RC) … … 109 119 uHyperRet = KVM_HYPERCALL_RET_SUCCESS; 110 120 } 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 } 111 126 break; 112 127 } … … 124 139 */ 125 140 pCtx->rax = uHyperRet & uAndMask; 126 return VINF_SUCCESS;141 return rc; 127 142 } 128 143 … … 349 364 350 365 /** 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 */ 378 VMM_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 /** 351 450 * 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. 352 459 * 353 460 * @param pVCpu The cross context virtual CPU structure. … … 355 462 * @param pDis Pointer to the disassembled instruction state at RIP. 356 463 * 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 */ 469 VMM_INT_DECL(VBOXSTRICTRC) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr) 470 { 471 VMCPU_ASSERT_EMT(pVCpu); 472 362 473 /* 363 474 * If we didn't ask for #UD to be trapped, bail. 364 475 */ 365 PVM pVM = pVCpu->CTX_SUFF(pVM);366 P GIMKVM pKvm = &pVM->gim.s.u.Kvm;367 if (RT_UNLIKELY(!p VM->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; 371 482 if (!pDis) 372 483 { 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; 377 485 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 4126 4126 } 4127 4127 #endif 4128 4128 4129 4129 if ( uIdtVector == X86_XCPT_BP 4130 4130 || uIdtVector == X86_XCPT_OF) … … 5198 5198 return VINF_SUCCESS; 5199 5199 } 5200 else if (rc == VERR_NOT_FOUND) 5200 5201 if (rc == VERR_NOT_FOUND) 5201 5202 { 5202 5203 if (pVCpu->hm.s.fHypercallsEnabled) 5203 5204 { 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); 5212 5218 } 5213 5219 else … … 5215 5221 } 5216 5222 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; 5219 5231 } 5220 5232 … … 5423 5435 5424 5436 /** 5425 * \#VMEXIT handler for undefined opcode (SVM_EXIT_EXCEPTION_6). Conditional5426 * \#VMEXIT.5437 * \#VMEXIT handler for undefined opcode (SVM_EXIT_EXCEPTION_6). 5438 * Conditional \#VMEXIT. 5427 5439 */ 5428 5440 HMSVM_EXIT_DECL hmR0SvmExitXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient) … … 5432 5444 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY(); 5433 5445 5446 int rc = VERR_SVM_UNEXPECTED_XCPT_EXIT; 5434 5447 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 { 5437 5467 hmR0SvmSetPendingXcptUD(pVCpu); 5468 rc = VINF_SUCCESS; 5469 } 5438 5470 5439 5471 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD); 5440 return VINF_SUCCESS;5472 return rc; 5441 5473 } 5442 5474 -
trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
r61455 r61544 11441 11441 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall); 11442 11442 11443 VBOXSTRICTRC rcStrict = VERR_VMX_IPE_3; 11443 11444 if (pVCpu->hm.s.fHypercallsEnabled) 11444 11445 { … … 11449 11450 int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx); 11450 11451 rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* For long-mode checks in gimKvmHypercall(). */ 11452 AssertRCReturn(rc, rc); 11451 11453 #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, 11464 11468 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; 11471 11481 } 11472 11482 -
trunk/src/VBox/VMM/VMMR3/GIM.cpp
r58564 r61544 434 434 if (ASMAtomicReadBool(&pDbg->fDbgRecvBufRead) == true) 435 435 { 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); 438 438 439 439 memcpy(pvRead, pDbg->pvDbgRecvBuf, pDbg->cbDbgRecvBufRead); … … 477 477 && *pcbWrite == cbWrite) 478 478 { 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); 481 481 } 482 482 return rc; -
trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
r61008 r61544 1712 1712 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED; 1713 1713 } 1714 else 1715 Assert(rc == VINF_SUCCESS); 1714 1716 1715 1717 *prcHv = rcHv; … … 1791 1793 rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED; 1792 1794 } 1795 else 1796 Assert(rc == VINF_SUCCESS); 1793 1797 1794 1798 *prcHv = rcHv; -
trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp
r61144 r61544 643 643 { 644 644 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) 647 647 { 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)); 649 660 rc = VINF_EM_RAW_EMULATE_INSTR; 650 661 } -
trunk/src/VBox/VMM/include/EMHandleRCTmpl.h
r60847 r61544 236 236 */ 237 237 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 } 240 262 241 263 #ifdef EMHANDLERC_WITH_HM -
trunk/src/VBox/VMM/include/GIMHvInternal.h
r58392 r61544 1139 1139 VMM_INT_DECL(bool) gimHvAreHypercallsEnabled(PVMCPU pVCpu); 1140 1140 VMM_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); 1141 VMM_INT_DECL(VBOXSTRICTRC) gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); 1142 VMM_INT_DECL(VBOXSTRICTRC) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx); 1143 VMM_INT_DECL(VBOXSTRICTRC) gimHvExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis); 1143 1144 VMM_INT_DECL(VBOXSTRICTRC) gimHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); 1144 1145 VMM_INT_DECL(VBOXSTRICTRC) gimHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue); -
trunk/src/VBox/VMM/include/GIMKvmInternal.h
r58127 r61544 261 261 VMM_INT_DECL(bool) gimKvmIsParavirtTscEnabled(PVM pVM); 262 262 VMM_INT_DECL(bool) gimKvmAreHypercallsEnabled(PVMCPU pVCpu); 263 VMM_INT_DECL( int)gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);263 VMM_INT_DECL(VBOXSTRICTRC) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx); 264 264 VMM_INT_DECL(VBOXSTRICTRC) gimKvmReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); 265 265 VMM_INT_DECL(VBOXSTRICTRC) gimKvmWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue); 266 266 VMM_INT_DECL(bool) gimKvmShouldTrapXcptUD(PVMCPU pVCpu); 267 VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis); 267 VMM_INT_DECL(VBOXSTRICTRC) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); 268 VMM_INT_DECL(VBOXSTRICTRC) gimKvmExecHypercallInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis); 268 269 269 270
Note:
See TracChangeset
for help on using the changeset viewer.