| | 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 | | #endif |
|---|