This patch is to implement the feature that at initialization of
kvm_intel module, fills VMCSINFO with a VMCS revision identifier,
and encoded offsets of VMCS fields. The reason why we put the
VMCSINFO processing at the initialization of kvm_intel module
is that it's dangerous to rob VMX resources while kvm module is
loaded.
Note, offsets of fields below will not be filled into VMCSINFO:
1. fields defined in Intel specification (Intel® 64 and
IA-32 Architectures Software Developer’s Manual, Volume
3C) but not defined in *vmcs_field*.
2. fields don't exist because their corresponding control bits
are not set.
Signed-off-by: zhangyanfei zhangyan...@cn.fujitsu.com
---
arch/x86/kvm/vmx.c | 350
1 files changed, 350 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ad85adf..e98fafa 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -41,6 +41,7 @@
#include asm/i387.h
#include asm/xcr.h
#include asm/perf_event.h
+#include asm/vmcsinfo.h
#include trace.h
@@ -2599,6 +2600,353 @@ static __init int alloc_kvm_area(void)
return 0;
}
+/*
+ * For caculating offsets of fields in VMCS data, we index every 16-bit
+ * field by this kind of format:
+ * | - 16 bits -- |
+ * +-+-++-+
+ * | high 7 bits |1| low 7 bits |0|
+ * +-+-++-+
+ * In high byte, the lowest bit must be 1; In low byte, the lowest bit
+ * must be 0. The two bits are set like this in case indexes in VMCS
+ * data are read as big endian mode.
+ * The remaining 14 bits of the index indicate the real offset of the
+ * field. Because the size of a VMCS region is at most 4 KBytes, so
+ * 14 bits are enough to index the whole VMCS region.
+ *
+ * ENCODING_OFFSET: encode the offset into the index of this kind.
+ */
+#define OFFSET_HIGH_SHIFT (7)
+#define OFFSET_LOW_MASK ((1 OFFSET_HIGH_SHIFT) - 1) /* 0x7f */
+#define OFFSET_HIGH_MASK (OFFSET_LOW_MASK OFFSET_HIGH_SHIFT) /* 0x3f80 */
+#define ENCODING_OFFSET(offset) \
+ offset) OFFSET_LOW_MASK) 1) + \
+ offset) OFFSET_HIGH_MASK) 2) | 0x100))
+
+/*
+ * We separate these five control fields from other fields
+ * because some fields only exist on processors that support
+ * the 1-setting of control bits in the five control fields.
+ */
+static inline void append_control_field(void)
+{
+#define CONTROL_FIELD_OFFSET(field) \
+ VMCSINFO_FIELD32(field, vmcs_read32(field))
+
+ CONTROL_FIELD_OFFSET(PIN_BASED_VM_EXEC_CONTROL);
+ CONTROL_FIELD_OFFSET(CPU_BASED_VM_EXEC_CONTROL);
+ if (cpu_has_secondary_exec_ctrls()) {
+ CONTROL_FIELD_OFFSET(SECONDARY_VM_EXEC_CONTROL);
+ }
+ CONTROL_FIELD_OFFSET(VM_EXIT_CONTROLS);
+ CONTROL_FIELD_OFFSET(VM_ENTRY_CONTROLS);
+}
+
+static inline void append_field16(void)
+{
+#define FIELD_OFFSET16(field) \
+ VMCSINFO_FIELD16(field, vmcs_read16(field));
+
+ FIELD_OFFSET16(GUEST_ES_SELECTOR);
+ FIELD_OFFSET16(GUEST_CS_SELECTOR);
+ FIELD_OFFSET16(GUEST_SS_SELECTOR);
+ FIELD_OFFSET16(GUEST_DS_SELECTOR);
+ FIELD_OFFSET16(GUEST_FS_SELECTOR);
+ FIELD_OFFSET16(GUEST_GS_SELECTOR);
+ FIELD_OFFSET16(GUEST_LDTR_SELECTOR);
+ FIELD_OFFSET16(GUEST_TR_SELECTOR);
+ FIELD_OFFSET16(HOST_ES_SELECTOR);
+ FIELD_OFFSET16(HOST_CS_SELECTOR);
+ FIELD_OFFSET16(HOST_SS_SELECTOR);
+ FIELD_OFFSET16(HOST_DS_SELECTOR);
+ FIELD_OFFSET16(HOST_FS_SELECTOR);
+ FIELD_OFFSET16(HOST_GS_SELECTOR);
+ FIELD_OFFSET16(HOST_TR_SELECTOR);
+}
+
+static inline void append_field64(void)
+{
+#define FIELD_OFFSET64(field) \
+ VMCSINFO_FIELD64(field, vmcs_read64(field));
+
+ FIELD_OFFSET64(IO_BITMAP_A);
+ FIELD_OFFSET64(IO_BITMAP_A_HIGH);
+ FIELD_OFFSET64(IO_BITMAP_B);
+ FIELD_OFFSET64(IO_BITMAP_B_HIGH);
+ FIELD_OFFSET64(VM_EXIT_MSR_STORE_ADDR);
+ FIELD_OFFSET64(VM_EXIT_MSR_STORE_ADDR_HIGH);
+ FIELD_OFFSET64(VM_EXIT_MSR_LOAD_ADDR);
+ FIELD_OFFSET64(VM_EXIT_MSR_LOAD_ADDR_HIGH);
+ FIELD_OFFSET64(VM_ENTRY_MSR_LOAD_ADDR);
+ FIELD_OFFSET64(VM_ENTRY_MSR_LOAD_ADDR_HIGH);
+ FIELD_OFFSET64(TSC_OFFSET);
+ FIELD_OFFSET64(TSC_OFFSET_HIGH);
+ FIELD_OFFSET64(VMCS_LINK_POINTER);
+ FIELD_OFFSET64(VMCS_LINK_POINTER_HIGH);
+ FIELD_OFFSET64(GUEST_IA32_DEBUGCTL);
+ FIELD_OFFSET64(GUEST_IA32_DEBUGCTL_HIGH);
+
+ if (cpu_has_vmx_msr_bitmap()) {
+ FIELD_OFFSET64(MSR_BITMAP);
+ FIELD_OFFSET64(MSR_BITMAP_HIGH);
+ }
+
+ if (cpu_has_vmx_tpr_shadow()) {
+ FIELD_OFFSET64(VIRTUAL_APIC_PAGE_ADDR);
+ FIELD_OFFSET64(VIRTUAL_APIC_PAGE_ADDR_HIGH);
+ }
+
+ if (cpu_has_secondary_exec_ctrls()) {
+ if (vmcs_config.cpu_based_2nd_exec_ctrl
+