diff --git a/core/include/cpuid.h b/core/include/cpuid.h index 6536b3d6..9be5e508 100644 --- a/core/include/cpuid.h +++ b/core/include/cpuid.h @@ -232,6 +232,7 @@ enum { #define FEAT(bit) \ FEATURE_KEY_LEAF(4, 0x80000001, CPUID_REG_ECX, bit) X86_FEATURE_LAHF = FEAT(0), /* 0x00000001 LAHF/SAHF Instructions */ + X86_FEATURE_LZCNT = FEAT(5), /* 0x00000020 LZCNT Instruction */ X86_FEATURE_PREFETCHW = FEAT(8), /* 0x00000100 PREFETCH/PREFETCHW instructions */ #undef FEAT diff --git a/core/vcpu.c b/core/vcpu.c index 56e0e83d..67c614e5 100644 --- a/core/vcpu.c +++ b/core/vcpu.c @@ -1189,6 +1189,10 @@ void vcpu_save_host_state(struct vcpu_t *vcpu) vmwrite(vcpu, HOST_EFER, hstate->_efer); } + if (vmx(vcpu, exit_ctls) & EXIT_CONTROL_LOAD_PAT) { + vmwrite(vcpu, HOST_PAT, ia32_rdmsr(IA32_CR_PAT)); + } + #ifdef HAX_ARCH_X86_64 vmwrite(vcpu, HOST_CS_SELECTOR, get_kernel_cs()); #else @@ -1355,15 +1359,15 @@ static void fill_common_vmcs(struct vcpu_t *vcpu) #ifdef HAX_ARCH_X86_64 exit_ctls = EXIT_CONTROL_HOST_ADDR_SPACE_SIZE | EXIT_CONTROL_LOAD_EFER | - EXIT_CONTROL_SAVE_DEBUG_CONTROLS; + EXIT_CONTROL_SAVE_DEBUG_CONTROLS | EXIT_CONTROL_LOAD_PAT; #endif #ifdef HAX_ARCH_X86_32 if (is_compatible()) { exit_ctls = EXIT_CONTROL_HOST_ADDR_SPACE_SIZE | EXIT_CONTROL_LOAD_EFER | - EXIT_CONTROL_SAVE_DEBUG_CONTROLS; + EXIT_CONTROL_SAVE_DEBUG_CONTROLS | EXIT_CONTROL_LOAD_PAT; } else { - exit_ctls = EXIT_CONTROL_SAVE_DEBUG_CONTROLS; + exit_ctls = EXIT_CONTROL_SAVE_DEBUG_CONTROLS | EXIT_CONTROL_LOAD_PAT; } #endif @@ -1433,6 +1437,10 @@ static void fill_common_vmcs(struct vcpu_t *vcpu) if (exit_ctls & EXIT_CONTROL_LOAD_EFER) { vmwrite(vcpu, HOST_EFER, ia32_rdmsr(IA32_EFER)); } + if (exit_ctls & EXIT_CONTROL_LOAD_PAT) { + vmwrite(vcpu, HOST_PAT, ia32_rdmsr(IA32_CR_PAT)); + } + vmwrite(vcpu, GUEST_PAT, vcpu->cr_pat); WRITE_CONTROLS(vcpu, VMX_ENTRY_CONTROLS, entry_ctls); @@ -2014,6 +2022,7 @@ static void vmwrite_cr(struct vcpu_t *vcpu) entry_ctls &= ~ENTRY_CONTROL_LOAD_EFER; vmx(vcpu, entry_ctls) &= ~ENTRY_CONTROL_LOAD_EFER; } + entry_ctls |= ENTRY_CONTROL_LOAD_PAT; vmwrite_efer(vcpu); if (state->_efer & IA32_EFER_LMA) { @@ -2510,8 +2519,8 @@ static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t a, uint32_t c) uint32_t hw_family; uint32_t hw_model; - static uint32_t cpu_features_1 = - // pat is disabled! + uint32_t cpuid_1_features_edx = + FEATURE(PAT) | FEATURE(FPU) | FEATURE(VME) | FEATURE(DE) | @@ -2535,7 +2544,7 @@ static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t a, uint32_t c) FEATURE(PSE) | FEATURE(HTT); - static uint32_t cpu_features_2 = + uint32_t cpuid_1_features_ecx = FEATURE(SSE3) | FEATURE(SSSE3) | FEATURE(SSE41) | @@ -2544,17 +2553,22 @@ static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t a, uint32_t c) FEATURE(MOVBE) | FEATURE(POPCNT); - uint32_t cpu_features_ext = + uint32_t cpuid_8000_0001_features_edx = FEATURE(NX) | FEATURE(SYSCALL) | FEATURE(EM64T); + uint32_t cpuid_8000_0001_features_ecx = + FEATURE(LAHF) | + FEATURE(LZCNT) | + FEATURE(PREFETCHW); + // Conditional features if (cpu_has_feature(X86_FEATURE_AESNI)) { - cpu_features_2 |= FEATURE(AESNI); + cpuid_1_features_ecx |= FEATURE(AESNI); } if (cpu_has_feature(X86_FEATURE_RDTSCP)) { - cpu_features_ext |= FEATURE(RDTSCP); + cpuid_8000_0001_features_edx |= FEATURE(RDTSCP); } uint8_t physical_address_size; @@ -2575,10 +2589,31 @@ static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t a, uint32_t c) * that is an old i7 system, so the emulator can still utilize the * enough extended features of the hardware, but doesn't crash. */ - hw_family = ((state->_eax >> 16) & 0xFF0) | - ((state->_eax >> 8) & 0xF); - hw_model = ((state->_eax >> 12) & 0xF0) | - ((state->_eax >> 4) & 0xF); + union cpuid_1_eax { + uint32_t raw; + struct { + unsigned steppingID : 4; + unsigned model : 4; + unsigned familyID : 4; + unsigned processorType : 2; + unsigned reserved : 2; + unsigned extModelID : 4; + unsigned extFamilyID : 8; + unsigned reserved2 : 4; + }; + } cpuid_eax, cpuid_eax2; + cpuid_eax.raw = state->_eax; + + if (0xF != cpuid_eax.familyID) + hw_family = cpuid_eax.familyID; + else + hw_family = cpuid_eax.familyID + (cpuid_eax.extFamilyID << 4); + + if (0x6 == cpuid_eax.familyID || 0xF == cpuid_eax.familyID) + hw_model = (cpuid_eax.extModelID << 4) + cpuid_eax.model; + else + hw_model = cpuid_eax.model; + if (hw_family == VIRT_FAMILY && hw_model > VIRT_MODEL) { state->_eax = ((VIRT_FAMILY & 0xFF0) << 16) | ((VIRT_FAMILY & 0xF) << 8) | @@ -2612,8 +2647,8 @@ static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t a, uint32_t c) // supported by the host CPU, but including "hypervisor", which is // desirable for VMMs. // TBD: This will need to be changed to emulate new features. - state->_ecx = (cpu_features_2 & state->_ecx) | FEATURE(HYPERVISOR); - state->_edx = cpu_features_1 & state->_edx; + state->_ecx = (cpuid_1_features_ecx & state->_ecx) | FEATURE(HYPERVISOR); + state->_edx = cpuid_1_features_edx & state->_edx; return; } case 2: { // Cache and TLB Information @@ -2677,10 +2712,11 @@ static void handle_cpuid_virtual(struct vcpu_t *vcpu, uint32_t a, uint32_t c) return; } case 0x80000001: { // Extended Signature and Features - state->_eax = state->_ebx = state->_ecx = 0; + state->_eax = state->_ebx = 0; // Report only the features specified but turn off any features // this processor doesn't support. - state->_edx = cpu_features_ext & state->_edx; + state->_ecx = cpuid_8000_0001_features_ecx & state->_ecx; + state->_edx = cpuid_8000_0001_features_edx & state->_edx; return; } /* @@ -3667,6 +3703,7 @@ static int handle_msr_write(struct vcpu_t *vcpu, uint32_t msr, uint64_t val, } case IA32_CR_PAT: { vcpu->cr_pat = val; + vmwrite(vcpu, GUEST_PAT, vcpu->cr_pat); break; } case IA32_MTRR_DEF_TYPE: {