hv: nested: support for VMPTRLD emulation

This patch emulates the VMPTRLD instruction. L0 hypervisor (ACRN) caches
the VMCS12 that is passed down from the VMPTRLD instruction, and merges it
with VMCS01 to create VMCS02 to run the nested VM.

- Currently ACRN can't cache multiple VMCS12 on one vCPU, so it needs to
  flushes active but not current VMCS12s to L1 guest.
- ACRN creates VMCS02 to run nested VM based on VMCS12:
  1) copy VMCS12 from guest memory to the per vCPU cache VMCS12
  2) initialize VMCS02 revision ID and host-state area
  3) load shadow fields from cache VMCS12 to VMCS02
  4) enable VMCS shadowing before L1 Vm entry

Tracked-On: #5923
Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
Signed-off-by: Zide Chen <zide.chen@intel.com>
This commit is contained in:
Zide Chen
2021-05-08 20:45:28 -07:00
committed by wenlingz
parent 0a1ac2f4a0
commit f5744174b5
8 changed files with 262 additions and 3 deletions

View File

@@ -66,7 +66,12 @@ union value_64 {
#define VMX_II_BASE_REG_VALID(v) ((((v) >> 27U) & 0x1U) == 0U)
#define VMX_II_REG2(v) (((v) >> 28U) & 0xfU)
#define VMCS_SHADOW_BIT_INDICATOR (1U << 31U)
/* refer to ISDM: Table 30-1. VM-Instruction Error Numbers */
#define VMXERR_VMPTRLD_INVALID_ADDRESS (9)
#define VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID (10)
#define VMXERR_VMPTRLD_VMXON_POINTER (11)
#define VMXERR_VMXON_IN_VMX_ROOT_OPERATION (15)
/*
@@ -75,6 +80,9 @@ union value_64 {
*/
#define VMCS12_REVISION_ID 0x15407E12U
/* Implemented in next patch */
struct acrn_vmcs12 {};
enum VMXResult {
VMsucceed,
VMfailValid,
@@ -83,19 +91,25 @@ enum VMXResult {
void nested_vmx_result(enum VMXResult, int error_number);
int32_t vmxon_vmexit_handler(struct acrn_vcpu *vcpu);
int32_t vmxoff_vmexit_handler(struct acrn_vcpu *vcpu);
int32_t vmptrld_vmexit_handler(struct acrn_vcpu *vcpu);
#ifdef CONFIG_NVMX_ENABLED
struct acrn_nested {
uint8_t vmcs02[PAGE_SIZE]; /* VMCS to run L2 and as Link Pointer in VMCS01 */
struct acrn_vmcs12 vmcs12; /* To cache L1's VMCS12*/
uint64_t current_vmcs12_ptr; /* GPA */
uint64_t vmxon_ptr; /* GPA */
bool vmxon; /* To indicate if vCPU entered VMX operation */
} __aligned(PAGE_SIZE);
void init_nested_vmx(__unused struct acrn_vm *vm);
bool is_vmx_msr(uint32_t msr);
void init_vmx_msrs(struct acrn_vcpu *vcpu);
int32_t read_vmx_msr(__unused struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val);
#else
struct acrn_nested {};
static inline void init_nested_vmx(__unused struct acrn_vm *vm) {}
static inline bool is_vmx_msr(__unused uint32_t msr)
{
/*

View File

@@ -42,6 +42,7 @@ static inline uint64_t apic_access_offset(uint64_t qual)
}
void init_vmcs(struct acrn_vcpu *vcpu);
void load_vmcs(const struct acrn_vcpu *vcpu);
void init_host_state(void);
void switch_apicv_mode_x2apic(struct acrn_vcpu *vcpu);
#endif /* ASSEMBLER */

View File

@@ -61,6 +61,10 @@
#define VMX_EOI_EXIT2_HIGH 0x00002021U
#define VMX_EOI_EXIT3_FULL 0x00002022U
#define VMX_EOI_EXIT3_HIGH 0x00002023U
#define VMX_VMREAD_BITMAP_FULL 0x00002026U
#define VMX_VMREAD_BITMAP_HIGH 0x00002027U
#define VMX_VMWRITE_BITMAP_FULL 0x00002028U
#define VMX_VMWRITE_BITMAP_HIGH 0x00002029U
#define VMX_XSS_EXITING_BITMAP_FULL 0x0000202CU
#define VMX_XSS_EXITING_BITMAP_HIGH 0x0000202DU
@@ -443,6 +447,8 @@ void exec_vmwrite64(uint32_t field_full, uint64_t value);
void exec_vmclear(void *addr);
void exec_vmptrld(void *addr);
void clear_va_vmcs(const uint8_t *vmcs_va);
void load_va_vmcs(const uint8_t *vmcs_va);
void init_cr0_cr4_flexible_bits(void);
bool is_valid_cr0_cr4(uint64_t cr0, uint64_t cr4);