kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Reduce the size of the vmcs_field_to_offset_table
@ 2017-12-21 20:46 Jim Mattson
  2017-12-21 20:46 ` [PATCH 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX Jim Mattson
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Jim Mattson @ 2017-12-21 20:46 UTC (permalink / raw)
  To: kvm; +Cc: Jim Mattson


The vmcs_field_to_offset_table is quite sparse, with its size determined
by the highest VMCS field encoding (0x6c16 for HOST_RIP). To support multiple
VMCS12 formats, we will need multiple vmcs_field_to_offset_tables, and
it would be a shame to replicate this sparse table.

Jim Mattson (3):
  kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX
  kvm: vmx: Change vmcs_field_type to vmcs_field_width
  kvm: vmx: Reduce size of vmcs_field_to_offset_table

 arch/x86/kvm/vmx.c | 197 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 117 insertions(+), 80 deletions(-)

-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX
  2017-12-21 20:46 [PATCH 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
@ 2017-12-21 20:46 ` Jim Mattson
  2017-12-22 20:11   ` [PATCH v2 " Jim Mattson
  2017-12-21 20:46 ` [PATCH 2/3] kvm: vmx: Change vmcs_field_type to vmcs_field_width Jim Mattson
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 12+ messages in thread
From: Jim Mattson @ 2017-12-21 20:46 UTC (permalink / raw)
  To: kvm; +Cc: Jim Mattson

This is the highest index value used in any supported VMCS12 field
encoding. It is used to populate the IA32_VMX_VMCS_ENUM MSR.

Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 669f5f74857d..dfce28498636 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -418,6 +418,12 @@ struct __packed vmcs12 {
  */
 #define VMCS12_SIZE 0x1000
 
+/*
+ * VMCS12_MAX_FIELD_INDEX is the highest index value used in any
+ * supported VMCS12 field encoding.
+ */
+#define VMCS12_MAX_FIELD_INDEX 0x17
+
 /*
  * The nested_vmx structure is part of vcpu_vmx, and holds information we need
  * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -3005,7 +3011,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
 	rdmsrl(MSR_IA32_VMX_CR4_FIXED1, vmx->nested.nested_vmx_cr4_fixed1);
 
 	/* highest index: VMX_PREEMPTION_TIMER_VALUE */
-	vmx->nested.nested_vmx_vmcs_enum = 0x2e;
+	vmx->nested.nested_vmx_vmcs_enum = VMCS12_MAX_FIELD_INDEX << 1;
 }
 
 /*
-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/3] kvm: vmx: Change vmcs_field_type to vmcs_field_width
  2017-12-21 20:46 [PATCH 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
  2017-12-21 20:46 ` [PATCH 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX Jim Mattson
@ 2017-12-21 20:46 ` Jim Mattson
  2017-12-22 20:12   ` [PATCH v2 " Jim Mattson
  2017-12-21 20:46 ` [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table Jim Mattson
  2017-12-22 20:09 ` [PATCH v2 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
  3 siblings, 1 reply; 12+ messages in thread
From: Jim Mattson @ 2017-12-21 20:46 UTC (permalink / raw)
  To: kvm; +Cc: Jim Mattson

Per the SDM, "[VMCS] Fields are grouped by width (16-bit, 32-bit,
etc.) and type (guest-state, host-state, etc.)." Previously, the width
was indicated by vmcs_field_type. To avoid confusion when we start
dealing with both field width and field type, change vmcs_field_type
to vmcs_field_width.

Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 58 +++++++++++++++++++++++++++---------------------------
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index dfce28498636..1847000fbb0c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4050,17 +4050,17 @@ static void free_kvm_area(void)
 	}
 }
 
-enum vmcs_field_type {
-	VMCS_FIELD_TYPE_U16 = 0,
-	VMCS_FIELD_TYPE_U64 = 1,
-	VMCS_FIELD_TYPE_U32 = 2,
-	VMCS_FIELD_TYPE_NATURAL_WIDTH = 3
+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_type(unsigned long field)
+static inline int vmcs_field_width(unsigned long field)
 {
 	if (0x1 & field)	/* the *_HIGH fields are all 32 bit */
-		return VMCS_FIELD_TYPE_U32;
+		return VMCS_FIELD_WIDTH_U32;
 	return (field >> 13) & 0x3 ;
 }
 
@@ -4098,7 +4098,7 @@ static void init_vmcs_shadow_fields(void)
 
 		clear_bit(field, vmx_vmwrite_bitmap);
 		clear_bit(field, vmx_vmread_bitmap);
-		if (vmcs_field_type(field) == VMCS_FIELD_TYPE_U64) {
+		if (vmcs_field_width(field) == VMCS_FIELD_WIDTH_U64) {
 			clear_bit(field + 1, vmx_vmwrite_bitmap);
 			clear_bit(field + 1, vmx_vmread_bitmap);
 		}
@@ -4107,7 +4107,7 @@ static void init_vmcs_shadow_fields(void)
 		unsigned long field = shadow_read_only_fields[i];
 
 		clear_bit(field, vmx_vmread_bitmap);
-		if (vmcs_field_type(field) == VMCS_FIELD_TYPE_U64)
+		if (vmcs_field_width(field) == VMCS_FIELD_WIDTH_U64)
 			clear_bit(field + 1, vmx_vmread_bitmap);
 	}
 }
@@ -7751,17 +7751,17 @@ static inline int vmcs12_read_any(struct kvm_vcpu *vcpu,
 
 	p = ((char *)(get_vmcs12(vcpu))) + offset;
 
-	switch (vmcs_field_type(field)) {
-	case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+	switch (vmcs_field_width(field)) {
+	case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 		*ret = *((natural_width *)p);
 		return 0;
-	case VMCS_FIELD_TYPE_U16:
+	case VMCS_FIELD_WIDTH_U16:
 		*ret = *((u16 *)p);
 		return 0;
-	case VMCS_FIELD_TYPE_U32:
+	case VMCS_FIELD_WIDTH_U32:
 		*ret = *((u32 *)p);
 		return 0;
-	case VMCS_FIELD_TYPE_U64:
+	case VMCS_FIELD_WIDTH_U64:
 		*ret = *((u64 *)p);
 		return 0;
 	default:
@@ -7778,17 +7778,17 @@ static inline int vmcs12_write_any(struct kvm_vcpu *vcpu,
 	if (offset < 0)
 		return offset;
 
-	switch (vmcs_field_type(field)) {
-	case VMCS_FIELD_TYPE_U16:
+	switch (vmcs_field_width(field)) {
+	case VMCS_FIELD_WIDTH_U16:
 		*(u16 *)p = field_value;
 		return 0;
-	case VMCS_FIELD_TYPE_U32:
+	case VMCS_FIELD_WIDTH_U32:
 		*(u32 *)p = field_value;
 		return 0;
-	case VMCS_FIELD_TYPE_U64:
+	case VMCS_FIELD_WIDTH_U64:
 		*(u64 *)p = field_value;
 		return 0;
-	case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+	case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 		*(natural_width *)p = field_value;
 		return 0;
 	default:
@@ -7813,17 +7813,17 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
 
 	for (i = 0; i < num_fields; i++) {
 		field = fields[i];
-		switch (vmcs_field_type(field)) {
-		case VMCS_FIELD_TYPE_U16:
+		switch (vmcs_field_width(field)) {
+		case VMCS_FIELD_WIDTH_U16:
 			field_value = vmcs_read16(field);
 			break;
-		case VMCS_FIELD_TYPE_U32:
+		case VMCS_FIELD_WIDTH_U32:
 			field_value = vmcs_read32(field);
 			break;
-		case VMCS_FIELD_TYPE_U64:
+		case VMCS_FIELD_WIDTH_U64:
 			field_value = vmcs_read64(field);
 			break;
-		case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+		case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 			field_value = vmcs_readl(field);
 			break;
 		default:
@@ -7861,17 +7861,17 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
 			field = fields[q][i];
 			vmcs12_read_any(&vmx->vcpu, field, &field_value);
 
-			switch (vmcs_field_type(field)) {
-			case VMCS_FIELD_TYPE_U16:
+			switch (vmcs_field_width(field)) {
+			case VMCS_FIELD_WIDTH_U16:
 				vmcs_write16(field, (u16)field_value);
 				break;
-			case VMCS_FIELD_TYPE_U32:
+			case VMCS_FIELD_WIDTH_U32:
 				vmcs_write32(field, (u32)field_value);
 				break;
-			case VMCS_FIELD_TYPE_U64:
+			case VMCS_FIELD_WIDTH_U64:
 				vmcs_write64(field, (u64)field_value);
 				break;
-			case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+			case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 				vmcs_writel(field, (long)field_value);
 				break;
 			default:
-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table
  2017-12-21 20:46 [PATCH 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
  2017-12-21 20:46 ` [PATCH 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX Jim Mattson
  2017-12-21 20:46 ` [PATCH 2/3] kvm: vmx: Change vmcs_field_type to vmcs_field_width Jim Mattson
@ 2017-12-21 20:46 ` Jim Mattson
  2017-12-22 16:26   ` Paolo Bonzini
  2017-12-22 20:09 ` [PATCH v2 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
  3 siblings, 1 reply; 12+ messages in thread
From: Jim Mattson @ 2017-12-21 20:46 UTC (permalink / raw)
  To: kvm; +Cc: Jim Mattson

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@google.com>
---
 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

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table
  2017-12-21 20:46 ` [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table Jim Mattson
@ 2017-12-22 16:26   ` Paolo Bonzini
  2017-12-22 18:28     ` Jim Mattson
  0 siblings, 1 reply; 12+ messages in thread
From: Paolo Bonzini @ 2017-12-22 16:26 UTC (permalink / raw)
  To: Jim Mattson, kvm

On 21/12/2017 21:46, Jim Mattson wrote:
> 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.

Would it be faster if, instead of the three-dimensional table, we
indexed the array by

   ((field >> 10) | ((field << 5) & 0x3ff))

which would waste one bit, but still reduce the table a lot.

Alternatively, it could use rotate-right-16(field, 10):

   (u16)((field >> 10) | ((field << 6))

That would waste two bits, but it would faster still to build the index.

Paolo

> Signed-off-by: Jim Mattson <jmattson@google.com>
> ---
>  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)
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table
  2017-12-22 16:26   ` Paolo Bonzini
@ 2017-12-22 18:28     ` Jim Mattson
  2017-12-22 20:13       ` [PATCH v2 " Jim Mattson
  0 siblings, 1 reply; 12+ messages in thread
From: Jim Mattson @ 2017-12-22 18:28 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm list

On Fri, Dec 22, 2017 at 8:26 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 21/12/2017 21:46, Jim Mattson wrote:
>> 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.
>
> Would it be faster if, instead of the three-dimensional table, we
> indexed the array by
>
>    ((field >> 10) | ((field << 5) & 0x3ff))

That doesn't look quite right to me. Do you mean:
        ((field >> 10) & 0x1f) | ((field & 0x3ff) << 5)

> which would waste one bit, but still reduce the table a lot.
>
> Alternatively, it could use rotate-right-16(field, 10):
>
>    (u16)((field >> 10) | ((field << 6))
>
> That would waste two bits, but it would faster still to build the index.

Amusingly, gcc prefers a rol to a ror.

On my E5-1650 v4 workstation, I get:

3D: 16 cycles @ 768 bytes
Alternative 1: 8 cycles @ 2982 bytes
Alternative 2: 4 cycles @ 5926 bytes

Let me send out v2 using the rol.

> Paolo
>
>> Signed-off-by: Jim Mattson <jmattson@google.com>
>> ---
>>  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)
>>
>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 0/3] Reduce the size of the vmcs_field_to_offset_table
  2017-12-21 20:46 [PATCH 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
                   ` (2 preceding siblings ...)
  2017-12-21 20:46 ` [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table Jim Mattson
@ 2017-12-22 20:09 ` Jim Mattson
  2018-01-01 22:55   ` Paolo Bonzini
  3 siblings, 1 reply; 12+ messages in thread
From: Jim Mattson @ 2017-12-22 20:09 UTC (permalink / raw)
  To: kvm, Paolo Bonzini; +Cc: Jim Mattson

The vmcs_field_to_offset_table is quite sparse, with its size determined
by the highest VMCS field encoding (0x6c16 for HOST_RIP). To support multiple
VMCS12 formats, we will need multiple vmcs_field_to_offset_tables, and
it would be a shame to replicate this sparse table.

Patches 1 and 2 are no longer necessary for v2, but I'm going to leave them
in the patch set, because I still think they are worthwhile.

Jim Mattson (3):
  kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX
  kvm: vmx: Change vmcs_field_type to vmcs_field_width
  kvm: vmx: Reduce size of vmcs_field_to_offset_table

 arch/x86/kvm/vmx.c | 86 +++++++++++++++++++++++++++++++-----------------------
 1 file changed, 49 insertions(+), 37 deletions(-)

-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX
  2017-12-21 20:46 ` [PATCH 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX Jim Mattson
@ 2017-12-22 20:11   ` Jim Mattson
  2018-01-18 16:46     ` David Hildenbrand
  0 siblings, 1 reply; 12+ messages in thread
From: Jim Mattson @ 2017-12-22 20:11 UTC (permalink / raw)
  To: kvm, Paolo Bonzini; +Cc: Jim Mattson

This is the highest index value used in any supported VMCS12 field
encoding. It is used to populate the IA32_VMX_VMCS_ENUM MSR.

Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 669f5f74857d..dfce28498636 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -418,6 +418,12 @@ struct __packed vmcs12 {
  */
 #define VMCS12_SIZE 0x1000
 
+/*
+ * VMCS12_MAX_FIELD_INDEX is the highest index value used in any
+ * supported VMCS12 field encoding.
+ */
+#define VMCS12_MAX_FIELD_INDEX 0x17
+
 /*
  * The nested_vmx structure is part of vcpu_vmx, and holds information we need
  * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -3005,7 +3011,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
 	rdmsrl(MSR_IA32_VMX_CR4_FIXED1, vmx->nested.nested_vmx_cr4_fixed1);
 
 	/* highest index: VMX_PREEMPTION_TIMER_VALUE */
-	vmx->nested.nested_vmx_vmcs_enum = 0x2e;
+	vmx->nested.nested_vmx_vmcs_enum = VMCS12_MAX_FIELD_INDEX << 1;
 }
 
 /*
-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 2/3] kvm: vmx: Change vmcs_field_type to vmcs_field_width
  2017-12-21 20:46 ` [PATCH 2/3] kvm: vmx: Change vmcs_field_type to vmcs_field_width Jim Mattson
@ 2017-12-22 20:12   ` Jim Mattson
  0 siblings, 0 replies; 12+ messages in thread
From: Jim Mattson @ 2017-12-22 20:12 UTC (permalink / raw)
  To: kvm, Paolo Bonzini; +Cc: Jim Mattson

Per the SDM, "[VMCS] Fields are grouped by width (16-bit, 32-bit,
etc.) and type (guest-state, host-state, etc.)." Previously, the width
was indicated by vmcs_field_type. To avoid confusion when we start
dealing with both field width and field type, change vmcs_field_type
to vmcs_field_width.

Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 58 +++++++++++++++++++++++++++---------------------------
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index dfce28498636..1847000fbb0c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4050,17 +4050,17 @@ static void free_kvm_area(void)
 	}
 }
 
-enum vmcs_field_type {
-	VMCS_FIELD_TYPE_U16 = 0,
-	VMCS_FIELD_TYPE_U64 = 1,
-	VMCS_FIELD_TYPE_U32 = 2,
-	VMCS_FIELD_TYPE_NATURAL_WIDTH = 3
+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_type(unsigned long field)
+static inline int vmcs_field_width(unsigned long field)
 {
 	if (0x1 & field)	/* the *_HIGH fields are all 32 bit */
-		return VMCS_FIELD_TYPE_U32;
+		return VMCS_FIELD_WIDTH_U32;
 	return (field >> 13) & 0x3 ;
 }
 
@@ -4098,7 +4098,7 @@ static void init_vmcs_shadow_fields(void)
 
 		clear_bit(field, vmx_vmwrite_bitmap);
 		clear_bit(field, vmx_vmread_bitmap);
-		if (vmcs_field_type(field) == VMCS_FIELD_TYPE_U64) {
+		if (vmcs_field_width(field) == VMCS_FIELD_WIDTH_U64) {
 			clear_bit(field + 1, vmx_vmwrite_bitmap);
 			clear_bit(field + 1, vmx_vmread_bitmap);
 		}
@@ -4107,7 +4107,7 @@ static void init_vmcs_shadow_fields(void)
 		unsigned long field = shadow_read_only_fields[i];
 
 		clear_bit(field, vmx_vmread_bitmap);
-		if (vmcs_field_type(field) == VMCS_FIELD_TYPE_U64)
+		if (vmcs_field_width(field) == VMCS_FIELD_WIDTH_U64)
 			clear_bit(field + 1, vmx_vmread_bitmap);
 	}
 }
@@ -7751,17 +7751,17 @@ static inline int vmcs12_read_any(struct kvm_vcpu *vcpu,
 
 	p = ((char *)(get_vmcs12(vcpu))) + offset;
 
-	switch (vmcs_field_type(field)) {
-	case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+	switch (vmcs_field_width(field)) {
+	case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 		*ret = *((natural_width *)p);
 		return 0;
-	case VMCS_FIELD_TYPE_U16:
+	case VMCS_FIELD_WIDTH_U16:
 		*ret = *((u16 *)p);
 		return 0;
-	case VMCS_FIELD_TYPE_U32:
+	case VMCS_FIELD_WIDTH_U32:
 		*ret = *((u32 *)p);
 		return 0;
-	case VMCS_FIELD_TYPE_U64:
+	case VMCS_FIELD_WIDTH_U64:
 		*ret = *((u64 *)p);
 		return 0;
 	default:
@@ -7778,17 +7778,17 @@ static inline int vmcs12_write_any(struct kvm_vcpu *vcpu,
 	if (offset < 0)
 		return offset;
 
-	switch (vmcs_field_type(field)) {
-	case VMCS_FIELD_TYPE_U16:
+	switch (vmcs_field_width(field)) {
+	case VMCS_FIELD_WIDTH_U16:
 		*(u16 *)p = field_value;
 		return 0;
-	case VMCS_FIELD_TYPE_U32:
+	case VMCS_FIELD_WIDTH_U32:
 		*(u32 *)p = field_value;
 		return 0;
-	case VMCS_FIELD_TYPE_U64:
+	case VMCS_FIELD_WIDTH_U64:
 		*(u64 *)p = field_value;
 		return 0;
-	case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+	case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 		*(natural_width *)p = field_value;
 		return 0;
 	default:
@@ -7813,17 +7813,17 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
 
 	for (i = 0; i < num_fields; i++) {
 		field = fields[i];
-		switch (vmcs_field_type(field)) {
-		case VMCS_FIELD_TYPE_U16:
+		switch (vmcs_field_width(field)) {
+		case VMCS_FIELD_WIDTH_U16:
 			field_value = vmcs_read16(field);
 			break;
-		case VMCS_FIELD_TYPE_U32:
+		case VMCS_FIELD_WIDTH_U32:
 			field_value = vmcs_read32(field);
 			break;
-		case VMCS_FIELD_TYPE_U64:
+		case VMCS_FIELD_WIDTH_U64:
 			field_value = vmcs_read64(field);
 			break;
-		case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+		case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 			field_value = vmcs_readl(field);
 			break;
 		default:
@@ -7861,17 +7861,17 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
 			field = fields[q][i];
 			vmcs12_read_any(&vmx->vcpu, field, &field_value);
 
-			switch (vmcs_field_type(field)) {
-			case VMCS_FIELD_TYPE_U16:
+			switch (vmcs_field_width(field)) {
+			case VMCS_FIELD_WIDTH_U16:
 				vmcs_write16(field, (u16)field_value);
 				break;
-			case VMCS_FIELD_TYPE_U32:
+			case VMCS_FIELD_WIDTH_U32:
 				vmcs_write32(field, (u32)field_value);
 				break;
-			case VMCS_FIELD_TYPE_U64:
+			case VMCS_FIELD_WIDTH_U64:
 				vmcs_write64(field, (u64)field_value);
 				break;
-			case VMCS_FIELD_TYPE_NATURAL_WIDTH:
+			case VMCS_FIELD_WIDTH_NATURAL_WIDTH:
 				vmcs_writel(field, (long)field_value);
 				break;
 			default:
-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table
  2017-12-22 18:28     ` Jim Mattson
@ 2017-12-22 20:13       ` Jim Mattson
  0 siblings, 0 replies; 12+ messages in thread
From: Jim Mattson @ 2017-12-22 20:13 UTC (permalink / raw)
  To: kvm, Paolo Bonzini; +Cc: Jim Mattson

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. Rotating the
field encoding (as a 16-bit integer) left by 6 reduces that table to
5926 bytes.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 1847000fbb0c..fec38a1614b5 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -714,10 +714,12 @@ static struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu)
 	return &(to_vmx(vcpu)->pi_desc);
 }
 
+#define ROL16(val, n) ((u16)(((u16)(val) << (n)) | ((u16)(val) >> (16 - (n)))))
 #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 FIELD(number, name)	[ROL16(number, 6)] = VMCS12_OFFSET(name)
+#define FIELD64(number, name)						\
+	FIELD(number, name),						\
+	[ROL16(number##_HIGH, 6)] = VMCS12_OFFSET(name) + sizeof(u32)
 
 
 static unsigned long shadow_read_only_fields[] = {
@@ -925,13 +927,17 @@ static const unsigned short vmcs_field_to_offset_table[] = {
 
 static inline short vmcs_field_to_offset(unsigned long field)
 {
-	BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
+	unsigned index;
+
+	if (field >> 15)
+		return -ENOENT;
 
-	if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) ||
-	    vmcs_field_to_offset_table[field] == 0)
+	index = ROL16(field, 6);
+	if (index >= ARRAY_SIZE(vmcs_field_to_offset_table) ||
+	    vmcs_field_to_offset_table[index] == 0)
 		return -ENOENT;
 
-	return vmcs_field_to_offset_table[field];
+	return vmcs_field_to_offset_table[index];
 }
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
-- 
2.15.1.620.gb9897f4670-goog

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] Reduce the size of the vmcs_field_to_offset_table
  2017-12-22 20:09 ` [PATCH v2 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
@ 2018-01-01 22:55   ` Paolo Bonzini
  0 siblings, 0 replies; 12+ messages in thread
From: Paolo Bonzini @ 2018-01-01 22:55 UTC (permalink / raw)
  To: Jim Mattson, kvm

On 22/12/2017 21:09, Jim Mattson wrote:
> The vmcs_field_to_offset_table is quite sparse, with its size determined
> by the highest VMCS field encoding (0x6c16 for HOST_RIP). To support multiple
> VMCS12 formats, we will need multiple vmcs_field_to_offset_tables, and
> it would be a shame to replicate this sparse table.
> 
> Patches 1 and 2 are no longer necessary for v2, but I'm going to leave them
> in the patch set, because I still think they are worthwhile.
> 
> Jim Mattson (3):
>   kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX
>   kvm: vmx: Change vmcs_field_type to vmcs_field_width
>   kvm: vmx: Reduce size of vmcs_field_to_offset_table
> 
>  arch/x86/kvm/vmx.c | 86 +++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 49 insertions(+), 37 deletions(-)
> 

Looks good, I'll queue it shortly (after I look a bit more into
Wanpeng's report).

Paolo

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX
  2017-12-22 20:11   ` [PATCH v2 " Jim Mattson
@ 2018-01-18 16:46     ` David Hildenbrand
  0 siblings, 0 replies; 12+ messages in thread
From: David Hildenbrand @ 2018-01-18 16:46 UTC (permalink / raw)
  To: Jim Mattson, kvm, Paolo Bonzini

On 22.12.2017 21:11, Jim Mattson wrote:
> This is the highest index value used in any supported VMCS12 field
> encoding. It is used to populate the IA32_VMX_VMCS_ENUM MSR.
> 
> Signed-off-by: Jim Mattson <jmattson@google.com>
> ---
>  arch/x86/kvm/vmx.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 669f5f74857d..dfce28498636 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -418,6 +418,12 @@ struct __packed vmcs12 {
>   */
>  #define VMCS12_SIZE 0x1000
>  
> +/*
> + * VMCS12_MAX_FIELD_INDEX is the highest index value used in any
> + * supported VMCS12 field encoding.
> + */
> +#define VMCS12_MAX_FIELD_INDEX 0x17
> +
>  /*
>   * The nested_vmx structure is part of vcpu_vmx, and holds information we need
>   * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
> @@ -3005,7 +3011,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
>  	rdmsrl(MSR_IA32_VMX_CR4_FIXED1, vmx->nested.nested_vmx_cr4_fixed1);
>  
>  	/* highest index: VMX_PREEMPTION_TIMER_VALUE */
> -	vmx->nested.nested_vmx_vmcs_enum = 0x2e;
> +	vmx->nested.nested_vmx_vmcs_enum = VMCS12_MAX_FIELD_INDEX << 1;
>  }
>  
>  /*
> 

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 

Thanks,

David / dhildenb

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-01-18 16:46 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-12-21 20:46 [PATCH 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
2017-12-21 20:46 ` [PATCH 1/3] kvm: vmx: Introduce VMCS12_MAX_FIELD_INDEX Jim Mattson
2017-12-22 20:11   ` [PATCH v2 " Jim Mattson
2018-01-18 16:46     ` David Hildenbrand
2017-12-21 20:46 ` [PATCH 2/3] kvm: vmx: Change vmcs_field_type to vmcs_field_width Jim Mattson
2017-12-22 20:12   ` [PATCH v2 " Jim Mattson
2017-12-21 20:46 ` [PATCH 3/3] kvm: vmx: Reduce size of vmcs_field_to_offset_table Jim Mattson
2017-12-22 16:26   ` Paolo Bonzini
2017-12-22 18:28     ` Jim Mattson
2017-12-22 20:13       ` [PATCH v2 " Jim Mattson
2017-12-22 20:09 ` [PATCH v2 0/3] Reduce the size of the vmcs_field_to_offset_table Jim Mattson
2018-01-01 22:55   ` Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).