For vmcs shadow fields, Host VM directly access through VMREAD/WMWRITE without vmexit. Meanwhile for other vmcs fields, the VMREAD/WMWRITE from host VM cause vmread/wmwrite vmexit, pKVM need to handle them. Such fields can be divided into two categories: one is host fields, pKVM just need to record them as the value host VM set, the other one is emulated fields which pKVM need to do emulation to ensure the isolation/security. Introduce a MACRO EMULATED_FIELD_RW in pkvm_nested_vmcs_fields.h to help pre-define the emulated fields for vmcs emulation, based on it, initialize emulated_fields[] array for future emulation. Signed-off-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx> --- arch/x86/kvm/vmx/pkvm/hyp/nested.c | 23 +++++++++++ .../vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h | 41 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/pkvm/hyp/nested.c b/arch/x86/kvm/vmx/pkvm/hyp/nested.c index 8ae37feda5ff..8e6d0f01819a 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/nested.c +++ b/arch/x86/kvm/vmx/pkvm/hyp/nested.c @@ -149,6 +149,12 @@ static struct shadow_vmcs_field shadow_read_write_fields[] = { }; static int max_shadow_read_write_fields = ARRAY_SIZE(shadow_read_write_fields); +static struct shadow_vmcs_field emulated_fields[] = { +#define EMULATED_FIELD_RW(x, y) { x, offsetof(struct vmcs12, y) }, +#include "pkvm_nested_vmcs_fields.h" +}; +static int max_emulated_fields = + ARRAY_SIZE(emulated_fields); static void init_vmcs_shadow_fields(void) { @@ -201,6 +207,22 @@ static void init_vmcs_shadow_fields(void) max_shadow_read_write_fields = j; } +static void init_emulated_vmcs_fields(void) +{ + int i, j; + + for (i = j = 0; i < max_emulated_fields; i++) { + struct shadow_vmcs_field entry = emulated_fields[i]; + u16 field = entry.encoding; + + if (!has_vmcs_field(field)) + continue; + + emulated_fields[j++] = entry; + } + max_emulated_fields = j; +} + static void nested_vmx_result(enum VMXResult result, int error_number) { u64 rflags = vmcs_readl(GUEST_RFLAGS); @@ -384,4 +406,5 @@ int handle_vmxoff(struct kvm_vcpu *vcpu) void pkvm_init_nest(void) { init_vmcs_shadow_fields(); + init_emulated_vmcs_fields(); } diff --git a/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h b/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h index 4380d415428f..8666cda4ee6d 100644 --- a/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h +++ b/arch/x86/kvm/vmx/pkvm/hyp/pkvm_nested_vmcs_fields.h @@ -2,10 +2,13 @@ /* * Copyright (C) 2022 Intel Corporation */ -#if !defined(SHADOW_FIELD_RW) && !defined(SHADOW_FIELD_RO) +#if !defined(EMULATED_FIELD_RW) && !defined(SHADOW_FIELD_RW) && !defined(SHADOW_FIELD_RO) BUILD_BUG_ON(1) #endif +#ifndef EMULATED_FIELD_RW +#define EMULATED_FIELD_RW(x, y) +#endif #ifndef SHADOW_FIELD_RW #define SHADOW_FIELD_RW(x, y) #endif @@ -13,6 +16,41 @@ BUILD_BUG_ON(1) #define SHADOW_FIELD_RO(x, y) #endif +/* + * Emulated fields for vmcs02: + * + * These fields are recorded in cached_vmcs12, and should be emulated to + * real value in vmcs02 before vmcs01 active. + */ +/* 16-bits */ +EMULATED_FIELD_RW(VIRTUAL_PROCESSOR_ID, virtual_processor_id) + +/* 32-bits */ +EMULATED_FIELD_RW(VM_EXIT_CONTROLS, vm_exit_controls) +EMULATED_FIELD_RW(VM_ENTRY_CONTROLS, vm_entry_controls) + +/* 64-bits, what about their HIGH 32 fields? */ +EMULATED_FIELD_RW(IO_BITMAP_A, io_bitmap_a) +EMULATED_FIELD_RW(IO_BITMAP_B, io_bitmap_b) +EMULATED_FIELD_RW(MSR_BITMAP, msr_bitmap) +EMULATED_FIELD_RW(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr) +EMULATED_FIELD_RW(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr) +EMULATED_FIELD_RW(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr) +EMULATED_FIELD_RW(XSS_EXIT_BITMAP, xss_exit_bitmap) +EMULATED_FIELD_RW(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr) +EMULATED_FIELD_RW(PML_ADDRESS, pml_address) +EMULATED_FIELD_RW(VM_FUNCTION_CONTROL, vm_function_control) +EMULATED_FIELD_RW(EPT_POINTER, ept_pointer) +EMULATED_FIELD_RW(EOI_EXIT_BITMAP0, eoi_exit_bitmap0) +EMULATED_FIELD_RW(EOI_EXIT_BITMAP1, eoi_exit_bitmap1) +EMULATED_FIELD_RW(EOI_EXIT_BITMAP2, eoi_exit_bitmap2) +EMULATED_FIELD_RW(EOI_EXIT_BITMAP3, eoi_exit_bitmap3) +EMULATED_FIELD_RW(EPTP_LIST_ADDRESS, eptp_list_address) +EMULATED_FIELD_RW(VMREAD_BITMAP, vmread_bitmap) +EMULATED_FIELD_RW(VMWRITE_BITMAP, vmwrite_bitmap) +EMULATED_FIELD_RW(ENCLS_EXITING_BITMAP, encls_exiting_bitmap) +EMULATED_FIELD_RW(VMCS_LINK_POINTER, vmcs_link_pointer) + /* * Shadow fields for vmcs02: * @@ -152,5 +190,6 @@ SHADOW_FIELD_RO(GUEST_LINEAR_ADDRESS, guest_linear_address) SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS, guest_physical_address) SHADOW_FIELD_RO(GUEST_PHYSICAL_ADDRESS_HIGH, guest_physical_address) +#undef EMULATED_FIELD_RW #undef SHADOW_FIELD_RW #undef SHADOW_FIELD_RO -- 2.25.1