Skip to content
This repository has been archived by the owner on Jan 28, 2023. It is now read-only.

Commit

Permalink
Add PAT support and more cpuid features
Browse files Browse the repository at this point in the history
Signed-off-by: Alexey Romko <[email protected]>
  • Loading branch information
nevilad committed May 25, 2019
1 parent e3f02ce commit 8c46c20
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 17 deletions.
1 change: 1 addition & 0 deletions core/include/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
71 changes: 54 additions & 17 deletions core/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) |
Expand All @@ -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) |
Expand All @@ -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;
Expand All @@ -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) |
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
/*
Expand Down Expand Up @@ -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: {
Expand Down

0 comments on commit 8c46c20

Please sign in to comment.