The vmcs_field_to_offset_table was a rather sparse table of short integers with a maximum index of 0x6c16, amounting to 55342 bytes. Now that we are considering support for multiple VMCS12 formats, it would be unfortunate to replicate that large, sparse table. Using a three-dimensional table indexed by VMCS field index, VMCS field type, and VMCS field width, it's relatively easy to reduce that table to 768 bytes. Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx> --- arch/x86/kvm/vmx.c | 145 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 57 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 1847000fbb0c..bd601b0984d1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -714,11 +714,15 @@ static struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu) return &(to_vmx(vcpu)->pi_desc); } -#define VMCS12_OFFSET(x) offsetof(struct vmcs12, x) -#define FIELD(number, name) [number] = VMCS12_OFFSET(name) -#define FIELD64(number, name) [number] = VMCS12_OFFSET(name), \ - [number##_HIGH] = VMCS12_OFFSET(name)+4 +#define VMCS_FIELD_HIGH(field) ((field) & 1) +#define VMCS_FIELD_INDEX(field) (((field) >> 1) & 0x1ff) +#define VMCS_FIELD_TYPE(field) (((field) >> 10) & 3) +#define VMCS_FIELD_WIDTH(field) (((field) >> 13) & 3) +#define VMCS12_OFFSET(x) offsetof(struct vmcs12, x) +#define FIELD(n, name) \ + [VMCS_FIELD_INDEX(n)][VMCS_FIELD_TYPE(n)][VMCS_FIELD_WIDTH(n)] = \ + VMCS12_OFFSET(name) static unsigned long shadow_read_only_fields[] = { /* @@ -779,7 +783,7 @@ static unsigned long shadow_read_write_fields[] = { static int max_shadow_read_write_fields = ARRAY_SIZE(shadow_read_write_fields); -static const unsigned short vmcs_field_to_offset_table[] = { +static const unsigned short vmcs_field_to_offset_table[][4][4] = { FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id), FIELD(POSTED_INTR_NV, posted_intr_nv), FIELD(GUEST_ES_SELECTOR, guest_es_selector), @@ -799,39 +803,39 @@ static const unsigned short vmcs_field_to_offset_table[] = { FIELD(HOST_FS_SELECTOR, host_fs_selector), FIELD(HOST_GS_SELECTOR, host_gs_selector), FIELD(HOST_TR_SELECTOR, host_tr_selector), - FIELD64(IO_BITMAP_A, io_bitmap_a), - FIELD64(IO_BITMAP_B, io_bitmap_b), - FIELD64(MSR_BITMAP, msr_bitmap), - FIELD64(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr), - FIELD64(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr), - FIELD64(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr), - FIELD64(TSC_OFFSET, tsc_offset), - FIELD64(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr), - FIELD64(APIC_ACCESS_ADDR, apic_access_addr), - FIELD64(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr), - FIELD64(VM_FUNCTION_CONTROL, vm_function_control), - FIELD64(EPT_POINTER, ept_pointer), - FIELD64(EOI_EXIT_BITMAP0, eoi_exit_bitmap0), - FIELD64(EOI_EXIT_BITMAP1, eoi_exit_bitmap1), - FIELD64(EOI_EXIT_BITMAP2, eoi_exit_bitmap2), - FIELD64(EOI_EXIT_BITMAP3, eoi_exit_bitmap3), - FIELD64(EPTP_LIST_ADDRESS, eptp_list_address), - FIELD64(XSS_EXIT_BITMAP, xss_exit_bitmap), - FIELD64(GUEST_PHYSICAL_ADDRESS, guest_physical_address), - FIELD64(VMCS_LINK_POINTER, vmcs_link_pointer), - FIELD64(PML_ADDRESS, pml_address), - FIELD64(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl), - FIELD64(GUEST_IA32_PAT, guest_ia32_pat), - FIELD64(GUEST_IA32_EFER, guest_ia32_efer), - FIELD64(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl), - FIELD64(GUEST_PDPTR0, guest_pdptr0), - FIELD64(GUEST_PDPTR1, guest_pdptr1), - FIELD64(GUEST_PDPTR2, guest_pdptr2), - FIELD64(GUEST_PDPTR3, guest_pdptr3), - FIELD64(GUEST_BNDCFGS, guest_bndcfgs), - FIELD64(HOST_IA32_PAT, host_ia32_pat), - FIELD64(HOST_IA32_EFER, host_ia32_efer), - FIELD64(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl), + FIELD(IO_BITMAP_A, io_bitmap_a), + FIELD(IO_BITMAP_B, io_bitmap_b), + FIELD(MSR_BITMAP, msr_bitmap), + FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr), + FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr), + FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr), + FIELD(TSC_OFFSET, tsc_offset), + FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr), + FIELD(APIC_ACCESS_ADDR, apic_access_addr), + FIELD(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr), + FIELD(VM_FUNCTION_CONTROL, vm_function_control), + FIELD(EPT_POINTER, ept_pointer), + FIELD(EOI_EXIT_BITMAP0, eoi_exit_bitmap0), + FIELD(EOI_EXIT_BITMAP1, eoi_exit_bitmap1), + FIELD(EOI_EXIT_BITMAP2, eoi_exit_bitmap2), + FIELD(EOI_EXIT_BITMAP3, eoi_exit_bitmap3), + FIELD(EPTP_LIST_ADDRESS, eptp_list_address), + FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap), + FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address), + FIELD(VMCS_LINK_POINTER, vmcs_link_pointer), + FIELD(PML_ADDRESS, pml_address), + FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl), + FIELD(GUEST_IA32_PAT, guest_ia32_pat), + FIELD(GUEST_IA32_EFER, guest_ia32_efer), + FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl), + FIELD(GUEST_PDPTR0, guest_pdptr0), + FIELD(GUEST_PDPTR1, guest_pdptr1), + FIELD(GUEST_PDPTR2, guest_pdptr2), + FIELD(GUEST_PDPTR3, guest_pdptr3), + FIELD(GUEST_BNDCFGS, guest_bndcfgs), + FIELD(HOST_IA32_PAT, host_ia32_pat), + FIELD(HOST_IA32_EFER, host_ia32_efer), + FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl), FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control), FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control), FIELD(EXCEPTION_BITMAP, exception_bitmap), @@ -923,15 +927,56 @@ static const unsigned short vmcs_field_to_offset_table[] = { FIELD(HOST_RIP, host_rip), }; +enum vmcs_field_width { + VMCS_FIELD_WIDTH_U16 = 0, + VMCS_FIELD_WIDTH_U64 = 1, + VMCS_FIELD_WIDTH_U32 = 2, + VMCS_FIELD_WIDTH_NATURAL_WIDTH = 3 +}; + +static inline int vmcs_field_width(unsigned long field) +{ + if (VMCS_FIELD_HIGH(field)) /* the *_HIGH fields are all 32 bit */ + return VMCS_FIELD_WIDTH_U32; + return VMCS_FIELD_WIDTH(field); +} + +enum vmcs_field_type { + VMCS_FIELD_TYPE_CONTROL = 0, + VMCS_FIELD_TYPE_INFO = 1, + VMCS_FIELD_TYPE_GUEST = 2, + VMCS_FIELD_TYPE_HOST = 3 +}; + +static inline int vmcs_field_type(unsigned long field) +{ + return VMCS_FIELD_TYPE(field); +} + static inline short vmcs_field_to_offset(unsigned long field) { - BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX); + unsigned index = VMCS_FIELD_INDEX(field); + unsigned type = VMCS_FIELD_TYPE(field); + unsigned width = VMCS_FIELD_WIDTH(field); + short offset; - if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) || - vmcs_field_to_offset_table[field] == 0) + BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > + VMCS12_MAX_FIELD_INDEX + 1); + if (VMCS_FIELD_HIGH(field) && width != VMCS_FIELD_WIDTH_U64) return -ENOENT; - return vmcs_field_to_offset_table[field]; + if (index >= ARRAY_SIZE(vmcs_field_to_offset_table)) + return -ENOENT; + + offset = vmcs_field_to_offset_table[index][type][width]; + + if (offset == 0) + return -ENOENT; + + if (VMCS_FIELD_HIGH(field)) + offset += sizeof(u32); + + return offset; } static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu) @@ -4050,23 +4095,9 @@ static void free_kvm_area(void) } } -enum vmcs_field_width { - VMCS_FIELD_WIDTH_U16 = 0, - VMCS_FIELD_WIDTH_U64 = 1, - VMCS_FIELD_WIDTH_U32 = 2, - VMCS_FIELD_WIDTH_NATURAL_WIDTH = 3 -}; - -static inline int vmcs_field_width(unsigned long field) -{ - if (0x1 & field) /* the *_HIGH fields are all 32 bit */ - return VMCS_FIELD_WIDTH_U32; - return (field >> 13) & 0x3 ; -} - static inline int vmcs_field_readonly(unsigned long field) { - return (((field >> 10) & 0x3) == 1); + return VMCS_FIELD_TYPE(field) == VMCS_FIELD_TYPE_INFO; } static void init_vmcs_shadow_fields(void) -- 2.15.1.620.gb9897f4670-goog