| 167 | | HWACCMR0Globals.vmx.hostCR4 = ASMGetCR4(); |
|---|
| 168 | | |
|---|
| 169 | | #if HC_ARCH_BITS == 64 |
|---|
| 170 | | RTR0MEMOBJ pScatchMemObj; |
|---|
| 171 | | void *pvScatchPage; |
|---|
| 172 | | RTHCPHYS pScatchPagePhys; |
|---|
| 173 | | |
|---|
| 174 | | rc = RTR0MemObjAllocCont(&pScatchMemObj, 1 << PAGE_SHIFT, true /* executable R0 mapping */); |
|---|
| 175 | | if (RT_FAILURE(rc)) |
|---|
| 176 | | return rc; |
|---|
| 177 | | |
|---|
| 178 | | pvScatchPage = RTR0MemObjAddress(pScatchMemObj); |
|---|
| 179 | | pScatchPagePhys = RTR0MemObjGetPagePhysAddr(pScatchMemObj, 0); |
|---|
| 180 | | memset(pvScatchPage, 0, PAGE_SIZE); |
|---|
| 181 | | |
|---|
| 182 | | /* Set revision dword at the beginning of the structure. */ |
|---|
| 183 | | *(uint32_t *)pvScatchPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(HWACCMR0Globals.vmx.msr.vmx_basic_info); |
|---|
| 184 | | |
|---|
| 185 | | /* Make sure we don't get rescheduled to another cpu during this probe. */ |
|---|
| 186 | | RTCCUINTREG fFlags = ASMIntDisableFlags(); |
|---|
| 187 | | |
|---|
| 188 | | /* |
|---|
| 189 | | * Check CR4.VMXE |
|---|
| 190 | | */ |
|---|
| 191 | | if (!(HWACCMR0Globals.vmx.hostCR4 & X86_CR4_VMXE)) |
|---|
| 192 | | { |
|---|
| 193 | | /* In theory this bit could be cleared behind our back. Which would cause #UD faults when we |
|---|
| 194 | | * try to execute the VMX instructions... |
|---|
| 195 | | */ |
|---|
| 196 | | ASMSetCR4(HWACCMR0Globals.vmx.hostCR4 | X86_CR4_VMXE); |
|---|
| 197 | | } |
|---|
| 198 | | |
|---|
| 199 | | /* Enter VMX Root Mode */ |
|---|
| 200 | | rc = VMXEnable(pScatchPagePhys); |
|---|
| 201 | | if (VBOX_FAILURE(rc)) |
|---|
| 202 | | { |
|---|
| 203 | | /* KVM leaves the CPU in VMX root mode. Not only is this not allowed, it will crash the host when we enter raw mode, because |
|---|
| 204 | | * (a) clearing X86_CR4_VMXE in CR4 causes a #GP (we no longer modify this bit) |
|---|
| 205 | | * (b) turning off paging causes a #GP (unavoidable when switching from long to 32 bits mode) |
|---|
| 206 | | * |
|---|
| 207 | | * They should fix their code, but until they do we simply refuse to run. |
|---|
| 208 | | */ |
|---|
| 209 | | HWACCMR0Globals.lLastError = VERR_VMX_IN_VMX_ROOT_MODE; |
|---|
| 210 | | HWACCMR0Globals.vmx.fSupported = false; |
|---|
| 211 | | } |
|---|
| 212 | | else |
|---|
| 213 | | VMXDisable(); |
|---|
| 214 | | |
|---|
| 215 | | /* Restore CR4 again; don't leave the X86_CR4_VMXE flag set if it wasn't so before (some software could incorrectly think it's in VMX mode) */ |
|---|
| 216 | | ASMSetCR4(HWACCMR0Globals.vmx.hostCR4); |
|---|
| 217 | | ASMSetFlags(fFlags); |
|---|
| 218 | | |
|---|
| 219 | | RTR0MemObjFree(pScatchMemObj, false); |
|---|
| 220 | | if (VBOX_FAILURE(HWACCMR0Globals.lLastError)) |
|---|
| 221 | | return HWACCMR0Globals.lLastError ; |
|---|
| 222 | | #endif |
|---|
| | 196 | HWACCMR0Globals.vmx.hostCR4 = ASMGetCR4(); |
|---|
| | 197 | |
|---|
| | 198 | #if HC_ARCH_BITS == 64 |
|---|
| | 199 | RTR0MEMOBJ pScatchMemObj; |
|---|
| | 200 | void *pvScatchPage; |
|---|
| | 201 | RTHCPHYS pScatchPagePhys; |
|---|
| | 202 | |
|---|
| | 203 | rc = RTR0MemObjAllocCont(&pScatchMemObj, 1 << PAGE_SHIFT, true /* executable R0 mapping */); |
|---|
| | 204 | if (RT_FAILURE(rc)) |
|---|
| | 205 | return rc; |
|---|
| | 206 | |
|---|
| | 207 | pvScatchPage = RTR0MemObjAddress(pScatchMemObj); |
|---|
| | 208 | pScatchPagePhys = RTR0MemObjGetPagePhysAddr(pScatchMemObj, 0); |
|---|
| | 209 | memset(pvScatchPage, 0, PAGE_SIZE); |
|---|
| | 210 | |
|---|
| | 211 | /* Set revision dword at the beginning of the structure. */ |
|---|
| | 212 | *(uint32_t *)pvScatchPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(HWACCMR0Globals.vmx.msr.vmx_basic_info); |
|---|
| | 213 | |
|---|
| | 214 | /* Make sure we don't get rescheduled to another cpu during this probe. */ |
|---|
| | 215 | RTCCUINTREG fFlags = ASMIntDisableFlags(); |
|---|
| | 216 | |
|---|
| | 217 | /* |
|---|
| | 218 | * Check CR4.VMXE |
|---|
| | 219 | */ |
|---|
| | 220 | if (!(HWACCMR0Globals.vmx.hostCR4 & X86_CR4_VMXE)) |
|---|
| | 221 | { |
|---|
| | 222 | /* In theory this bit could be cleared behind our back. Which would cause #UD faults when we |
|---|
| | 223 | * try to execute the VMX instructions... |
|---|
| | 224 | */ |
|---|
| | 225 | ASMSetCR4(HWACCMR0Globals.vmx.hostCR4 | X86_CR4_VMXE); |
|---|
| | 226 | } |
|---|
| | 227 | |
|---|
| | 228 | /* Enter VMX Root Mode */ |
|---|
| | 229 | rc = VMXEnable(pScatchPagePhys); |
|---|
| | 230 | if (VBOX_FAILURE(rc)) |
|---|
| | 231 | { |
|---|
| | 232 | /* KVM leaves the CPU in VMX root mode. Not only is this not allowed, it will crash the host when we enter raw mode, because |
|---|
| | 233 | * (a) clearing X86_CR4_VMXE in CR4 causes a #GP (we no longer modify this bit) |
|---|
| | 234 | * (b) turning off paging causes a #GP (unavoidable when switching from long to 32 bits mode) |
|---|
| | 235 | * |
|---|
| | 236 | * They should fix their code, but until they do we simply refuse to run. |
|---|
| | 237 | */ |
|---|
| | 238 | HWACCMR0Globals.lLastError = VERR_VMX_IN_VMX_ROOT_MODE; |
|---|
| | 239 | HWACCMR0Globals.vmx.fSupported = false; |
|---|
| | 240 | } |
|---|
| | 241 | else |
|---|
| | 242 | VMXDisable(); |
|---|
| | 243 | |
|---|
| | 244 | /* Restore CR4 again; don't leave the X86_CR4_VMXE flag set if it wasn't so before (some software could incorrectly think it's in VMX mode) */ |
|---|
| | 245 | ASMSetCR4(HWACCMR0Globals.vmx.hostCR4); |
|---|
| | 246 | ASMSetFlags(fFlags); |
|---|
| | 247 | |
|---|
| | 248 | RTR0MemObjFree(pScatchMemObj, false); |
|---|
| | 249 | if (VBOX_FAILURE(HWACCMR0Globals.lLastError)) |
|---|
| | 250 | return HWACCMR0Globals.lLastError ; |
|---|
| | 251 | #endif |
|---|