From 5379b14108946b340fa5eb705b308f77a0d5ac9f Mon Sep 17 00:00:00 2001 From: Zide Chen Date: Tue, 11 May 2021 13:37:20 -0700 Subject: [PATCH] hv: nested: define VMCS shadow fields Enable VMCS shadowing for most of the VMCS fields, so that execution of the VMREAD or VMWRITE on these shadow VMCS fields from L1 hypervisor won't cause VM exits, but read from or write to the shadow VMCS. Tracked-On: #5923 Signed-off-by: Sainath Grandhi Signed-off-by: Alexander Merritt Signed-off-by: Zide Chen --- hypervisor/arch/x86/guest/nested.c | 150 +++++++++++++++++++++++++- hypervisor/include/arch/x86/asm/vmx.h | 11 ++ 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/hypervisor/arch/x86/guest/nested.c b/hypervisor/arch/x86/guest/nested.c index af1b2720b..bfc587b5f 100644 --- a/hypervisor/arch/x86/guest/nested.c +++ b/hypervisor/arch/x86/guest/nested.c @@ -228,8 +228,7 @@ int32_t read_vmx_msr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val) return err; } -/* make it 1 to be able to build. correctly initialize it in next patch */ -#define MAX_SHADOW_VMCS_FIELDS 1 +#define MAX_SHADOW_VMCS_FIELDS 117U /* * VMCS fields included in the dual-purpose VMCS: as shadow for L1 and * as hardware VMCS for nested guest (L2). @@ -244,11 +243,157 @@ int32_t read_vmx_msr(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val) * for all platforms. */ 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, + VMX_GUEST_DS_SEL, + VMX_GUEST_FS_SEL, + VMX_GUEST_GS_SEL, + VMX_GUEST_LDTR_SEL, + VMX_GUEST_TR_SEL, + VMX_GUEST_PML_INDEX, + + /* 64-bits */ + VMX_IO_BITMAP_A_FULL, + VMX_IO_BITMAP_B_FULL, + VMX_EXIT_MSR_STORE_ADDR_FULL, + VMX_EXIT_MSR_LOAD_ADDR_FULL, + VMX_ENTRY_MSR_LOAD_ADDR_FULL, + VMX_EXECUTIVE_VMCS_PTR_FULL, + VMX_TSC_OFFSET_FULL, + VMX_VIRTUAL_APIC_PAGE_ADDR_FULL, + VMX_APIC_ACCESS_ADDR_FULL, + VMX_EPT_POINTER_FULL, + VMX_VMREAD_BITMAP_FULL, + VMX_VMWRITE_BITMAP_FULL, + VMX_XSS_EXITING_BITMAP_FULL, + VMX_TSC_MULTIPLIER_FULL, + VMX_GUEST_PHYSICAL_ADDR_FULL, + VMX_VMS_LINK_PTR_FULL, + VMX_GUEST_IA32_DEBUGCTL_FULL, + VMX_GUEST_IA32_PAT_FULL, + VMX_GUEST_IA32_EFER_FULL, + VMX_GUEST_IA32_PERF_CTL_FULL, + VMX_GUEST_PDPTE0_FULL, + VMX_GUEST_PDPTE1_FULL, + VMX_GUEST_PDPTE2_FULL, + VMX_GUEST_PDPTE3_FULL, + + /* 32-bits */ + VMX_PIN_VM_EXEC_CONTROLS, + VMX_PROC_VM_EXEC_CONTROLS, + VMX_EXCEPTION_BITMAP, + VMX_PF_ERROR_CODE_MASK, + VMX_PF_ERROR_CODE_MATCH, + VMX_CR3_TARGET_COUNT, + VMX_EXIT_CONTROLS, + VMX_EXIT_MSR_STORE_COUNT, + VMX_EXIT_MSR_LOAD_COUNT, + VMX_ENTRY_CONTROLS, + VMX_ENTRY_MSR_LOAD_COUNT, + VMX_ENTRY_INT_INFO_FIELD, + VMX_ENTRY_EXCEPTION_ERROR_CODE, + VMX_ENTRY_INSTR_LENGTH, + VMX_TPR_THRESHOLD, + VMX_PROC_VM_EXEC_CONTROLS2, + VMX_PLE_GAP, + VMX_PLE_WINDOW, + VMX_INSTR_ERROR, + VMX_EXIT_REASON, + VMX_EXIT_INT_INFO, + VMX_EXIT_INT_ERROR_CODE, + VMX_IDT_VEC_INFO_FIELD, + VMX_IDT_VEC_ERROR_CODE, + VMX_EXIT_INSTR_LEN, + VMX_INSTR_INFO, + VMX_GUEST_ES_LIMIT, + VMX_GUEST_CS_LIMIT, + VMX_GUEST_SS_LIMIT, + VMX_GUEST_DS_LIMIT, + VMX_GUEST_FS_LIMIT, + VMX_GUEST_GS_LIMIT, + VMX_GUEST_LDTR_LIMIT, + VMX_GUEST_TR_LIMIT, + VMX_GUEST_GDTR_LIMIT, + VMX_GUEST_IDTR_LIMIT, + VMX_GUEST_ES_ATTR, + VMX_GUEST_CS_ATTR, + VMX_GUEST_SS_ATTR, + VMX_GUEST_DS_ATTR, + VMX_GUEST_FS_ATTR, + VMX_GUEST_GS_ATTR, + VMX_GUEST_LDTR_ATTR, + VMX_GUEST_TR_ATTR, + VMX_GUEST_INTERRUPTIBILITY_INFO, + VMX_GUEST_ACTIVITY_STATE, + VMX_GUEST_SMBASE, + VMX_GUEST_IA32_SYSENTER_CS, + VMX_GUEST_TIMER, + VMX_CR0_GUEST_HOST_MASK, + VMX_CR4_GUEST_HOST_MASK, + VMX_CR0_READ_SHADOW, + VMX_CR4_READ_SHADOW, + VMX_CR3_TARGET_0, + VMX_CR3_TARGET_1, + VMX_CR3_TARGET_2, + VMX_CR3_TARGET_3, + VMX_EXIT_QUALIFICATION, + VMX_IO_RCX, + VMX_IO_RSI, + VMX_IO_RDI, + VMX_IO_RIP, + VMX_GUEST_LINEAR_ADDR, + VMX_GUEST_CR0, + VMX_GUEST_CR3, + VMX_GUEST_CR4, + VMX_GUEST_ES_BASE, + VMX_GUEST_CS_BASE, + VMX_GUEST_SS_BASE, + VMX_GUEST_DS_BASE, + VMX_GUEST_FS_BASE, + VMX_GUEST_GS_BASE, + VMX_GUEST_LDTR_BASE, + VMX_GUEST_TR_BASE, + VMX_GUEST_GDTR_BASE, + VMX_GUEST_IDTR_BASE, + VMX_GUEST_DR7, + VMX_GUEST_RSP, + VMX_GUEST_RIP, + VMX_GUEST_RFLAGS, + VMX_GUEST_PENDING_DEBUG_EXCEPT, + VMX_GUEST_IA32_SYSENTER_ESP, + VMX_GUEST_IA32_SYSENTER_EIP }; /* to be shared by all vCPUs for all nested guests */ static uint64_t vmcs_shadowing_bitmap[PAGE_SIZE / sizeof(uint64_t)] __aligned(PAGE_SIZE); +static void setup_vmcs_shadowing_bitmap(void) +{ + uint16_t field_index; + uint32_t array_index; + uint16_t bit_pos; + + /* + * Set all the bits to 1s first and clear out the bits for + * the corresponding fields that ACRN lets its guest to access Shadow VMCS + */ + memset((void *)vmcs_shadowing_bitmap, 0xFFU, PAGE_SIZE); + + /* + * Refer to ISDM Section 24.6.15 VMCS Shadowing Bitmap Addresses + * and Section 30.3 VMX Instructions - VMWRITE/VMREAD + */ + for (field_index = 0U; field_index < MAX_SHADOW_VMCS_FIELDS; field_index++) { + bit_pos = vmcs_shadowing_fields[field_index] % 64U; + array_index = vmcs_shadowing_fields[field_index] / 64U; + bitmap_clear_nolock(bit_pos, &vmcs_shadowing_bitmap[array_index]); + } +} + /* * This is an array of offsets into a structure of type "struct acrn_vmcs12" * 16 offsets for a total of 16 GROUPs. 4 "field widths" by 4 "field types". @@ -848,5 +993,6 @@ void init_nested_vmx(__unused struct acrn_vm *vm) /* Cache the value of physical MSR_IA32_VMX_BASIC */ vmx_basic = (uint32_t)msr_read(MSR_IA32_VMX_BASIC); + setup_vmcs_shadowing_bitmap(); } } diff --git a/hypervisor/include/arch/x86/asm/vmx.h b/hypervisor/include/arch/x86/asm/vmx.h index 87c3022ca..2404f2cc6 100644 --- a/hypervisor/include/arch/x86/asm/vmx.h +++ b/hypervisor/include/arch/x86/asm/vmx.h @@ -20,6 +20,7 @@ #define VMX_GUEST_LDTR_SEL 0x0000080cU #define VMX_GUEST_TR_SEL 0x0000080eU #define VMX_GUEST_INTR_STATUS 0x00000810U +#define VMX_GUEST_PML_INDEX 0x00000812U /* 16-bit host-state fields */ #define VMX_HOST_ES_SEL 0x00000c00U #define VMX_HOST_CS_SEL 0x00000c02U @@ -43,6 +44,7 @@ #define VMX_ENTRY_MSR_LOAD_ADDR_HIGH 0x0000200bU #define VMX_EXECUTIVE_VMCS_PTR_FULL 0x0000200cU #define VMX_EXECUTIVE_VMCS_PTR_HIGH 0x0000200dU +#define VMX_PML_ADDR_FULL 0x0000200EU #define VMX_TSC_OFFSET_FULL 0x00002010U #define VMX_TSC_OFFSET_HIGH 0x00002011U #define VMX_VIRTUAL_APIC_PAGE_ADDR_FULL 0x00002012U @@ -51,6 +53,7 @@ #define VMX_APIC_ACCESS_ADDR_HIGH 0x00002015U #define VMX_PIR_DESC_ADDR_FULL 0x00002016U #define VMX_PIR_DESC_ADDR_HIGH 0x00002017U +#define VMX_VM_FUNCTION_CTL_FULL 0x00002018U #define VMX_EPT_POINTER_FULL 0x0000201AU #define VMX_EPT_POINTER_HIGH 0x0000201BU #define VMX_EOI_EXIT0_FULL 0x0000201CU @@ -61,13 +64,16 @@ #define VMX_EOI_EXIT2_HIGH 0x00002021U #define VMX_EOI_EXIT3_FULL 0x00002022U #define VMX_EOI_EXIT3_HIGH 0x00002023U +#define VMX_EPT_LIST_ADDR_FULL 0x00002024U #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_VIR_EXCEPTION_INFO_FULL 0x0000202AU #define VMX_XSS_EXITING_BITMAP_FULL 0x0000202CU #define VMX_XSS_EXITING_BITMAP_HIGH 0x0000202DU +#define VMX_TSC_MULTIPLIER_FULL 0x00002032U #define VMX_PROC_VM_EXEC_CONTROLS3_FULL 0x00002034U #define VMX_PROC_VM_EXEC_CONTROLS3_HIGH 0x00002035U @@ -94,6 +100,9 @@ #define VMX_GUEST_PDPTE2_HIGH 0x0000280FU #define VMX_GUEST_PDPTE3_FULL 0x00002810U #define VMX_GUEST_PDPTE3_HIGH 0x00002811U +#define VMX_GUEST_IA32_BNDCFGS_FULL 0x00002812U +#define VMX_GUEST_IA32_BNDCFGS_HIGH 0x00002813U + /* 64-bit host-state fields */ #define VMX_HOST_IA32_PAT_FULL 0x00002C00U #define VMX_HOST_IA32_PAT_HIGH 0x00002C01U @@ -167,7 +176,9 @@ /* natural-width read-only data fields */ #define VMX_EXIT_QUALIFICATION 0x00006400U #define VMX_IO_RCX 0x00006402U +#define VMX_IO_RSI 0x00006404U #define VMX_IO_RDI 0x00006406U +#define VMX_IO_RIP 0x00006408U #define VMX_GUEST_LINEAR_ADDR 0x0000640aU /* natural-width guest-state fields */ #define VMX_GUEST_CR0 0x00006800U