hv: nested: flush L2 VPID only when it could conflict with L1 VPIDs
By changing the way to assign L1 VPID from bottom-up to top-down, the possibilities for VPID conflicts between L1 and L2 guests are small. Then we can flush VPID just in case of conflicting. Tracked-On: #6289 Signed-off-by: Anthony Xu <anthony.xu@intel.com> Signed-off-by: Zide Chen <zide.chen@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
730a275ecc
commit
e9eb72d319
|
@ -238,7 +238,7 @@ int32_t read_vmx_msr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val)
|
|||
return err;
|
||||
}
|
||||
|
||||
#define MAX_SHADOW_VMCS_FIELDS 114U
|
||||
#define MAX_SHADOW_VMCS_FIELDS 113U
|
||||
/*
|
||||
* VMCS fields included in the dual-purpose VMCS: as shadow for L1 and
|
||||
* as hardware VMCS for nested guest (L2).
|
||||
|
@ -254,8 +254,6 @@ int32_t read_vmx_msr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val)
|
|||
*/
|
||||
static const uint32_t vmcs_shadowing_fields[MAX_SHADOW_VMCS_FIELDS] = {
|
||||
/* 16-bits */
|
||||
VMX_VPID,
|
||||
|
||||
VMX_GUEST_ES_SEL,
|
||||
VMX_GUEST_CS_SEL,
|
||||
VMX_GUEST_SS_SEL,
|
||||
|
@ -875,6 +873,7 @@ int32_t vmwrite_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||
|
||||
if ((vmcs_field == VMX_MSR_BITMAP_FULL)
|
||||
|| (vmcs_field == VMX_EPT_POINTER_FULL)
|
||||
|| (vmcs_field == VMX_VPID)
|
||||
|| (vmcs_field == VMX_ENTRY_CONTROLS)
|
||||
|| (vmcs_field == VMX_EXIT_CONTROLS)) {
|
||||
vcpu->arch.nested.control_fields_dirty = true;
|
||||
|
@ -945,6 +944,8 @@ static void merge_and_sync_control_fields(struct acrn_vcpu *vcpu)
|
|||
/* Host is alway runing in 64-bit mode */
|
||||
value64 = vmcs12->vm_exit_controls | VMX_EXIT_CTLS_HOST_ADDR64;
|
||||
exec_vmwrite(VMX_EXIT_CONTROLS, value64);
|
||||
|
||||
exec_vmwrite(VMX_VPID, vmcs12->vpid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1323,6 +1324,17 @@ static void set_vmcs01_guest_state(struct acrn_vcpu *vcpu)
|
|||
vcpu_set_rflags(vcpu, 0x2U);
|
||||
}
|
||||
|
||||
/**
|
||||
* @pre vcpu != NULL
|
||||
*/
|
||||
static void sanitize_l2_vpid(struct acrn_vmcs12 *vmcs12)
|
||||
{
|
||||
/* Flush VPID if the L2 VPID could be conflicted with any L1 VPIDs */
|
||||
if (vmcs12->vpid >= ALLOCATED_MIN_L1_VPID) {
|
||||
flush_vpid_single(vmcs12->vpid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief handler for all VMEXITs from nested guests
|
||||
*
|
||||
|
@ -1331,7 +1343,6 @@ static void set_vmcs01_guest_state(struct acrn_vcpu *vcpu)
|
|||
*/
|
||||
int32_t nested_vmexit_handler(struct acrn_vcpu *vcpu)
|
||||
{
|
||||
struct acrn_vmcs12 *vmcs12 = (struct acrn_vmcs12 *)&vcpu->arch.nested.vmcs12;
|
||||
bool is_l1_vmexit = true;
|
||||
|
||||
if ((vcpu->arch.exit_reason & 0xFFFFU) == VMX_EXIT_REASON_EPT_VIOLATION) {
|
||||
|
@ -1339,13 +1350,7 @@ int32_t nested_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||
}
|
||||
|
||||
if (is_l1_vmexit) {
|
||||
/*
|
||||
* Currerntly VMX_VPID is shadowing to L1, so we flush L2 VPID before
|
||||
* L1 VM entry to avoid conflicting with L1 VPID.
|
||||
*
|
||||
* TODO: emulate VPID for L2 so that we can save this VPID flush
|
||||
*/
|
||||
flush_vpid_single(vmcs12->vpid);
|
||||
sanitize_l2_vpid(&vcpu->arch.nested.vmcs12);
|
||||
|
||||
/*
|
||||
* Clear VMCS02 because: ISDM: Before modifying the shadow-VMCS indicator,
|
||||
|
@ -1411,15 +1416,11 @@ static void nested_vmentry(struct acrn_vcpu *vcpu, bool is_launch)
|
|||
vmcs12->launch_state = VMCS12_LAUNCH_STATE_LAUNCHED;
|
||||
}
|
||||
|
||||
sanitize_l2_vpid(&vcpu->arch.nested.vmcs12);
|
||||
|
||||
/*
|
||||
* There are two reasons to set vcpu->launched to false even for VMRESUME:
|
||||
*
|
||||
* - the launch state of VMCS02 is clear at this moment.
|
||||
* - currently VMX_VPID is shadowing to L1, and it could happens that
|
||||
* L2 VPID will be conflicted with L1 VPID. We rely on run_vcpu() to
|
||||
* flush global vpid in the VMLAUNCH path to resolve this conflict.
|
||||
*
|
||||
* TODO: emulate L2 VPID to avoid VPID flush.
|
||||
* set vcpu->launched to false because the launch state of VMCS02 is
|
||||
* clear at this moment, even for VMRESUME
|
||||
*/
|
||||
vcpu->launched = false;
|
||||
}
|
||||
|
|
|
@ -545,7 +545,7 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn
|
|||
*
|
||||
* This assignment guarantees a unique non-zero per vcpu vpid at runtime.
|
||||
*/
|
||||
vcpu->arch.vpid = 1U + (vm->vm_id * MAX_VCPUS_PER_VM) + vcpu->vcpu_id;
|
||||
vcpu->arch.vpid = ALLOCATED_MIN_L1_VPID + (vm->vm_id * MAX_VCPUS_PER_VM) + vcpu->vcpu_id;
|
||||
|
||||
/*
|
||||
* ACRN uses the following approach to manage VT-d PI notification vectors:
|
||||
|
@ -667,7 +667,9 @@ int32_t run_vcpu(struct acrn_vcpu *vcpu)
|
|||
* A power-up or a reset invalidates all linear mappings,
|
||||
* guest-physical mappings, and combined mappings
|
||||
*/
|
||||
flush_vpid_global();
|
||||
if (!is_vcpu_in_l2_guest(vcpu)) {
|
||||
flush_vpid_global();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HYPERV_ENABLED
|
||||
if (is_vcpu_bsp(vcpu)) {
|
||||
|
|
|
@ -238,6 +238,7 @@ struct acrn_vcpu_arch {
|
|||
/* common MSRs, world_msrs[] is a subset of it */
|
||||
uint64_t guest_msrs[NUM_GUEST_MSRS];
|
||||
|
||||
#define ALLOCATED_MIN_L1_VPID (0x10000U - CONFIG_MAX_VM_NUM * MAX_VCPUS_PER_VM)
|
||||
uint16_t vpid;
|
||||
|
||||
/* Holds the information needed for IRQ/exception handling. */
|
||||
|
|
Loading…
Reference in New Issue