hv: vmx: add vpid support

Enable VMX vpid ctrl and assign an unique vpid to each vcpu
so that VMX transitions are not required to invalidate any
linear mappings or combined mappings.

SDM Vol 3 - 28.3.3.3
If EPT is in use, the logical processor associates all mappings
it creates with the value of bits 51:12 of current EPTP.
If a VMM uses different EPTP values for different guests, it may
use the same VPID for those guests. Doing so cannot result in one
guest using translations that pertain to the other.

In our UOS, the trusty world and normal world are using different
EPTP. So we can use the same VPID for it.

Signed-off-by: Li, Fei1 <fei1.li@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Li, Fei1
2018-05-31 16:39:49 +08:00
committed by lijinxia
parent c34f72a0bc
commit 84f4cf3c1d
8 changed files with 96 additions and 0 deletions

View File

@@ -83,6 +83,8 @@ int create_vcpu(int cpu_id, struct vm *vm, struct vcpu **rtn_vcpu_handle)
}
#endif
vcpu->arch_vcpu.vpid = allocate_vpid();
/* Allocate VMCS region for this VCPU */
vcpu->arch_vcpu.vmcs = alloc_page();
ASSERT(vcpu->arch_vcpu.vmcs != NULL, "");
@@ -145,6 +147,15 @@ int start_vcpu(struct vcpu *vcpu)
pr_info("VM %d Starting VCPU %d",
vcpu->vm->attr.id, vcpu->vcpu_id);
if (vcpu->arch_vcpu.vpid)
exec_vmwrite(VMX_VPID, vcpu->arch_vcpu.vpid);
/*
* A power-up or a reset invalidates all linear mappings,
* guest-physical mappings, and combined mappings
*/
flush_vpid_global();
/* Set vcpu launched */
vcpu->launched = true;

View File

@@ -375,6 +375,9 @@ int acrn_handle_pending_request(struct vcpu *vcpu)
if (bitmap_test_and_clear(ACRN_REQUEST_EPT_FLUSH, pending_req_bits))
invept(vcpu);
if (bitmap_test_and_clear(ACRN_REQUEST_VPID_FLUSH, pending_req_bits))
flush_vpid_single(vcpu->arch_vcpu.vpid);
if (bitmap_test_and_clear(ACRN_REQUEST_TMR_UPDATE, pending_req_bits))
vioapic_update_tmr(vcpu);

View File

@@ -44,6 +44,14 @@ static struct vmx_capability {
uint32_t vpid;
} vmx_caps;
/*
* If the logical processor is in VMX non-root operation and
* the “enable VPID” VM-execution control is 1, the current VPID
* is the value of the VPID VM-execution control field in the VMCS.
* (VM entry ensures that this value is never 0000H).
*/
static int vmx_vpid_nr = VMX_MIN_NR_VPID;
#define INVEPT_TYPE_SINGLE_CONTEXT 1UL
#define INVEPT_TYPE_ALL_CONTEXTS 2UL
#define VMFAIL_INVALID_EPT_VPID \
@@ -61,6 +69,25 @@ struct invept_desc {
uint64_t _res;
};
static inline void _invvpid(uint64_t type, int vpid, uint64_t gva)
{
int error = 0;
struct {
uint64_t vpid : 16;
uint64_t rsvd : 48;
uint64_t gva;
} operand = { vpid, 0, gva };
asm volatile ("invvpid %1, %2\n"
VMFAIL_INVALID_EPT_VPID
: "=r" (error)
: "m" (operand), "r" (type)
: "memory");
ASSERT(error == 0, "invvpid error");
}
static inline void _invept(uint64_t type, struct invept_desc desc)
{
int error = 0;
@@ -113,6 +140,38 @@ int check_vmx_mmu_cap(void)
return 0;
}
int allocate_vpid(void)
{
int vpid = atomic_xadd(&vmx_vpid_nr, 1);
/* TODO: vpid overflow */
if (vpid >= VMX_MAX_NR_VPID) {
pr_err("%s, vpid overflow\n", __func__);
/*
* set vmx_vpid_nr to VMX_MAX_NR_VPID to disable vpid
* since next atomic_xadd will always large than
* VMX_MAX_NR_VPID.
*/
vmx_vpid_nr = VMX_MAX_NR_VPID;
vpid = 0;
}
return vpid;
}
void flush_vpid_single(int vpid)
{
if (vpid == 0)
return;
_invvpid(VMX_VPID_TYPE_SINGLE_CONTEXT, vpid, 0);
}
void flush_vpid_global(void)
{
_invvpid(VMX_VPID_TYPE_ALL_CONTEXT, 0, 0);
}
void invept(struct vcpu *vcpu)
{
struct invept_desc desc = {0};

View File

@@ -1085,6 +1085,11 @@ static void init_exec_ctrl(struct vcpu *vcpu)
value32 &= ~(VMX_PROCBASED_CTLS_CR3_LOAD |
VMX_PROCBASED_CTLS_CR3_STORE);
/*
* Disable VM_EXIT for invlpg execution.
*/
value32 &= ~VMX_PROCBASED_CTLS_INVLPG;
if (is_vapic_supported()) {
value32 |= VMX_PROCBASED_CTLS_TPR_SHADOW;
} else {
@@ -1106,6 +1111,11 @@ static void init_exec_ctrl(struct vcpu *vcpu)
VMX_PROCBASED_CTLS2_RDTSCP |
VMX_PROCBASED_CTLS2_UNRESTRICT);
if (vcpu->arch_vcpu.vpid)
value32 |= VMX_PROCBASED_CTLS2_VPID;
else
value32 &= ~VMX_PROCBASED_CTLS2_VPID;
if (is_vapic_supported()) {
value32 |= VMX_PROCBASED_CTLS2_VAPIC;