hv: emulate CR0.CD and CR0.NW

This patch makes use of IA32_PAT MSR to emulate cache disabled behaviour

When the guest is requesting to set CR0.CD:
 - Keep guest's CR0.CD and CR0.NW bits unchanged
 - Write IA32_PAT MSR with all-UC entries to change the effective memory
   type for all GPA to UC for the guest VCPU
 - It depends on trapping wrmsr to IA32_PAT to prevent any entry in
   IA32_PAT being changed to non UC type by the guest

When the guest is requesting to clear CR0.CD:
 - restore the content of guest's IA32_PAT MSR

Signed-off-by: Zide Chen <zide.chen@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Zide Chen 2018-06-19 16:36:41 -07:00 committed by lijinxia
parent 6801d826e2
commit d0df39cbb5
3 changed files with 59 additions and 13 deletions

View File

@ -10,15 +10,6 @@
extern struct efi_ctx* efi_ctx;
#endif
#define PAT_POWER_ON_VALUE (PAT_MEM_TYPE_WB + \
((uint64_t)PAT_MEM_TYPE_WT << 8) + \
((uint64_t)PAT_MEM_TYPE_UCM << 16) + \
((uint64_t)PAT_MEM_TYPE_UC << 24) + \
((uint64_t)PAT_MEM_TYPE_WB << 32) + \
((uint64_t)PAT_MEM_TYPE_WT << 40) + \
((uint64_t)PAT_MEM_TYPE_UCM << 48) + \
((uint64_t)PAT_MEM_TYPE_UC << 56))
#define REAL_MODE_BSP_INIT_CODE_SEL (0xf000)
#define REAL_MODE_DATA_SEG_AR (0x0093)
#define REAL_MODE_CODE_SEG_AR (0x009f)
@ -331,7 +322,14 @@ int vmx_wrmsr_pat(struct vcpu *vcpu, uint64_t value)
}
context->ia32_pat = value;
exec_vmwrite(VMX_GUEST_IA32_PAT_FULL, value);
/*
* If context->cr0.CD is set, we defer any further requests to write
* guest's IA32_PAT, until the time when guest's CR0.CD is being cleared
*/
if ((context->cr0 & CR0_CD) == 0U) {
exec_vmwrite(VMX_GUEST_IA32_PAT_FULL, value);
}
return 0;
}
@ -351,8 +349,8 @@ int vmx_wrmsr_pat(struct vcpu *vcpu, uint64_t value)
* - WP (16) Trapped to get if it inhibits supervisor level procedures to
* write into ro-pages.
* - AM (18) Flexible to guest
* - NW (29) Flexible to guest
* - CD (30) Flexible to guest
* - NW (29) Trapped to emulate cache disable situation
* - CD (30) Trapped to emulate cache disable situation
* - PG (31) Trapped to track cpu/paging mode.
* Set the value according to the value from guest.
*/
@ -400,10 +398,40 @@ int vmx_write_cr0(struct vcpu *vcpu, uint64_t cr0)
exec_vmwrite64(VMX_GUEST_IA32_EFER_FULL, context->ia32_efer);
}
/* If CR0.CD or CR0.NW get changed */
if (((context->cr0 ^ cr0) & (CR0_CD | CR0_NW)) != 0U) {
if ((cr0 & CR0_CD) == 0U && ((cr0 & CR0_NW) != 0U)) {
pr_err("not allow to set CR0.NW while clearing CR0.CD");
vcpu_inject_gp(vcpu, 0);
return -EINVAL;
}
/* No action if only CR0.NW is changed */
if (((context->cr0 ^ cr0) & CR0_CD) != 0U) {
if ((cr0 & CR0_CD) != 0U) {
/*
* When the guest requests to set CR0.CD, we don't allow
* guest's CR0.CD to be actually set, instead, we write guest
* IA32_PAT with all-UC entries to emulate the cache
* disabled behavior
*/
exec_vmwrite(VMX_GUEST_IA32_PAT_FULL, PAT_ALL_UC_VALUE);
CACHE_FLUSH_INVALIDATE_ALL();
} else {
/* Restore IA32_PAT to enable cache again */
exec_vmwrite(VMX_GUEST_IA32_PAT_FULL, context->ia32_pat);
}
vcpu_make_request(vcpu, ACRN_REQUEST_EPT_FLUSH);
}
}
/* CR0 has no always off bits, except the always on bits, and reserved
* bits, allow to set according to guest.
*/
cr0_vmx = cr0_always_on_mask | cr0;
/* Don't set CD or NW bit to guest */
cr0_vmx &= ~(CR0_CD | CR0_NW);
exec_vmwrite(VMX_GUEST_CR0, cr0_vmx & 0xFFFFFFFFUL);
exec_vmwrite(VMX_CR0_READ_SHADOW, cr0 & 0xFFFFFFFFUL);
context->cr0 = cr0;

View File

@ -519,6 +519,24 @@
/* 5 high-order bits in every field are reserved */
#define PAT_FIELD_RSV_BITS (0xF8U)
#define PAT_POWER_ON_VALUE (PAT_MEM_TYPE_WB + \
((uint64_t)PAT_MEM_TYPE_WT << 8) + \
((uint64_t)PAT_MEM_TYPE_UCM << 16) + \
((uint64_t)PAT_MEM_TYPE_UC << 24) + \
((uint64_t)PAT_MEM_TYPE_WB << 32) + \
((uint64_t)PAT_MEM_TYPE_WT << 40) + \
((uint64_t)PAT_MEM_TYPE_UCM << 48) + \
((uint64_t)PAT_MEM_TYPE_UC << 56))
#define PAT_ALL_UC_VALUE (PAT_MEM_TYPE_UC + \
((uint64_t)PAT_MEM_TYPE_UC << 8) + \
((uint64_t)PAT_MEM_TYPE_UC << 16) + \
((uint64_t)PAT_MEM_TYPE_UC << 24) + \
((uint64_t)PAT_MEM_TYPE_UC << 32) + \
((uint64_t)PAT_MEM_TYPE_UC << 40) + \
((uint64_t)PAT_MEM_TYPE_UC << 48) + \
((uint64_t)PAT_MEM_TYPE_UC << 56))
/* MTRR memory type definitions */
#define MTRR_MEM_TYPE_UC 0x00U /* uncached */
#define MTRR_MEM_TYPE_WC 0x01U /* write combining */

View File

@ -391,7 +391,7 @@
#define RFLAGS_Z (1U<<6)
/* CR0 bits hv want to trap to track status change */
#define CR0_TRAP_MASK (CR0_PE | CR0_PG | CR0_WP)
#define CR0_TRAP_MASK (CR0_PE | CR0_PG | CR0_WP | CR0_CD | CR0_NW )
#define CR0_RESERVED_MASK ~(CR0_PG | CR0_CD | CR0_NW | CR0_AM | CR0_WP | \
CR0_NE | CR0_ET | CR0_TS | CR0_EM | CR0_MP | CR0_PE)