diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index 6d13412a3..dd0b242a3 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -13,6 +13,7 @@ static const uint32_t emulated_msrs[] = { MSR_IA32_BIOS_UPDT_TRIG, /* Enable MSR_IA32_BIOS_UPDT_TRIG */ MSR_IA32_BIOS_SIGN_ID, /* Enable MSR_IA32_BIOS_SIGN_ID */ MSR_IA32_TIME_STAMP_COUNTER, + MSR_IA32_PAT, /* following MSR not emulated now */ /* @@ -205,6 +206,11 @@ int rdmsr_vmexit_handler(struct vcpu *vcpu) v = exec_vmread(VMX_GUEST_IA32_SYSENTER_EIP); break; } + case MSR_IA32_PAT: + { + v = vmx_rdmsr_pat(vcpu); + break; + } case MSR_IA32_TSC_AUX: { v = vcpu->arch_vcpu.msr_tsc_aux; @@ -330,6 +336,11 @@ int wrmsr_vmexit_handler(struct vcpu *vcpu) exec_vmwrite(VMX_GUEST_IA32_SYSENTER_EIP, v); break; } + case MSR_IA32_PAT: + { + vmx_wrmsr_pat(vcpu, v); + break; + } case MSR_IA32_GS_BASE: { exec_vmwrite(VMX_GUEST_GS_BASE, v); diff --git a/hypervisor/arch/x86/vmx.c b/hypervisor/arch/x86/vmx.c index 7cafcace8..edfa72e8a 100644 --- a/hypervisor/arch/x86/vmx.c +++ b/hypervisor/arch/x86/vmx.c @@ -299,7 +299,40 @@ static void init_cr0_cr4_host_mask(__unused struct vcpu *vcpu) exec_vmwrite(VMX_CR4_MASK, cr4_host_mask); /* Output CR4 mask value */ pr_dbg("CR4 mask value: 0x%x", cr4_host_mask); +} +uint64_t vmx_rdmsr_pat(struct vcpu *vcpu) +{ + struct run_context *context = + &vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context]; + + /* + * note: if context->cr0.CD is set, the actual value in guest's + * IA32_PAT MSR is PAT_ALL_UC_VALUE, which may be different from + * the saved value context->ia32_pat + */ + return context->ia32_pat; +} + +int vmx_wrmsr_pat(struct vcpu *vcpu, uint64_t value) +{ + uint32_t field, i; + struct run_context *context = + &vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context]; + + for (i = 0; i < 8; i++) { + field = (value >> (i * 8)) & 0xffU; + if ((PAT_MEM_TYPE_INVALID(field) || + (PAT_FIELD_RSV_BITS & field) != 0U)) { + pr_err("invalid guest IA32_PAT: 0x%016llx", value); + vcpu_inject_gp(vcpu, 0); + return -EINVAL; + } + } + + context->ia32_pat = value; + exec_vmwrite(VMX_GUEST_IA32_PAT_FULL, value); + return 0; } /* @@ -875,6 +908,7 @@ static void init_guest_state(struct vcpu *vcpu) value32); value64 = PAT_POWER_ON_VALUE; + cur_context->ia32_pat = value64; exec_vmwrite64(VMX_GUEST_IA32_PAT_FULL, value64); pr_dbg("VMX_GUEST_IA32_PAT: 0x%016llx ", value64); diff --git a/hypervisor/include/arch/x86/guest/guest.h b/hypervisor/include/arch/x86/guest/guest.h index 5c424c8f3..bbe628d6f 100644 --- a/hypervisor/include/arch/x86/guest/guest.h +++ b/hypervisor/include/arch/x86/guest/guest.h @@ -28,6 +28,7 @@ enum { IDX_BIOS_UPDT_TRIG, IDX_BIOS_SIGN_ID, IDX_TSC, + IDX_PAT, IDX_MAX_MSR }; diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index 20da573af..9b8845444 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -509,6 +509,15 @@ #define PAT_MEM_TYPE_WP 0x05U /* write protected */ #define PAT_MEM_TYPE_WB 0x06U /* writeback */ #define PAT_MEM_TYPE_UCM 0x07U /* uncached minus */ +#define PAT_MEM_TYPE_INVALID(x) (((x) != PAT_MEM_TYPE_UC) && \ + ((x) != PAT_MEM_TYPE_WC) && \ + ((x) != PAT_MEM_TYPE_WT) && \ + ((x) != PAT_MEM_TYPE_WP) && \ + ((x) != PAT_MEM_TYPE_WB) && \ + ((x) != PAT_MEM_TYPE_UCM)) + +/* 5 high-order bits in every field are reserved */ +#define PAT_FIELD_RSV_BITS (0xF8U) /* MTRR memory type definitions */ #define MTRR_MEM_TYPE_UC 0x00U /* uncached */ diff --git a/hypervisor/include/arch/x86/vmx.h b/hypervisor/include/arch/x86/vmx.h index 571b58808..16494ddad 100644 --- a/hypervisor/include/arch/x86/vmx.h +++ b/hypervisor/include/arch/x86/vmx.h @@ -414,6 +414,9 @@ int vmx_restart(uint16_t pcpu_id); int exec_vmclear(void *addr); int exec_vmptrld(void *addr); +uint64_t vmx_rdmsr_pat(struct vcpu *vcpu); +int vmx_wrmsr_pat(struct vcpu *vcpu, uint64_t value); + int vmx_write_cr0(struct vcpu *vcpu, uint64_t cr0); int vmx_write_cr3(struct vcpu *vcpu, uint64_t cr3); int vmx_write_cr4(struct vcpu *vcpu, uint64_t cr4);