Hello, Thank you for pointing out the flaws in V1 of this patch. I now make sure to save, load, and restore the proper VMCS pointer for each read and write. The benefit of this interface over implementing custom IOCtls is that it exposes a single consistent API for experimenting with virtual machines. Implementing another IOCtl each time you need to twiddle some new field sounds like a fair bit of work to me, but if this is the way you currently develop KVM I trust that it works well enough for you. In particular, my professor wanted to use this feature to single step VMs. He wanted to adjust the GUEST_RIP, VMX_PREMPTION_TIMER_VALUE, and probably several other fields to keep multiple VMs in sync cycle by cycle and inspect their state. This is the first step in a grander scheme involving formal verification, and we thought these changes to KVM would benefit the wider Linux community. If you would like I can look into making certain other fields such as the GUEST_CR3 read only or somehow additionally configurable. I am open to suggestions. Thank you, Ian Kronquist On 5/9/17, Ian Kronquist <iankronquist@xxxxxxxxx> wrote: > Users doing research or development on KVM and the Intel VMX virtualization > extensions may desire fine grained control of Virtual Machine host and > guest state by reading or writing fields in the Virtual Machine Control > Structure (VMCS). > > In order to allow users to manipulate VMCSs, we expose individual VMCSs via > SYSFS. VMCS fields are under the directory `/sys/kernel/vmcsctl/vmcsN` > where N is the PID of the process which controls the VMCS. Each attribute > under such a directory is named after the corresponding symbol in `vmx.h`, > which closely follow the field names in the Intel manual. > > By default, this feature is disabled. It can be enabled via the KVM_VMCSCTL > Kconfig option. > > New in version 2: > * Load and restore the VMCS pointer when reading and writing. > * Use kstrtouint instead of kstrtoint. > > Signed-off-by: Ian Kronquist <iankronquist@xxxxxxxxx> > --- > arch/x86/include/asm/vmx.h | 149 +++++++++++ > arch/x86/kvm/Kconfig | 9 + > arch/x86/kvm/Makefile | 1 + > arch/x86/kvm/vmcsctl.c | 649 > +++++++++++++++++++++++++++++++++++++++++++++ > arch/x86/kvm/vmcsctl.h | 27 ++ > arch/x86/kvm/vmx.c | 167 +++--------- > 6 files changed, 871 insertions(+), 131 deletions(-) > create mode 100644 arch/x86/kvm/vmcsctl.c > create mode 100644 arch/x86/kvm/vmcsctl.h > > diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h > index cc54b7026567..fe8708d61d74 100644 > --- a/arch/x86/include/asm/vmx.h > +++ b/arch/x86/include/asm/vmx.h > @@ -25,10 +25,15 @@ > #define VMX_H > > > +#include <linux/kvm_host.h> > #include <linux/bitops.h> > #include <linux/types.h> > #include <uapi/asm/vmx.h> > > +#define __ex(x) __kvm_handle_fault_on_reboot(x) > +#define __ex_clear(x, reg) \ > + ____kvm_handle_fault_on_reboot(x, "xor " reg " , " reg) > + > /* > * Definitions of Primary Processor-Based VM-Execution Controls. > */ > @@ -112,6 +117,8 @@ > #define VMX_MISC_SAVE_EFER_LMA 0x00000020 > #define VMX_MISC_ACTIVITY_HLT 0x00000040 > > +noinline void vmwrite_error(unsigned long field, unsigned long value); > + > static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic) > { > return vmx_basic & GENMASK_ULL(30, 0); > @@ -485,6 +492,7 @@ enum vmcs_field { > #define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2" > #define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3" > #define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30" > +#define ASM_VMX_VMPTRST_RAX ".byte 0x0f, 0xc7, 0x38" > #define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0" > #define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0" > #define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" > @@ -499,6 +507,12 @@ struct vmx_msr_entry { > u64 value; > } __aligned(16); > > +struct vmcs { > + u32 revision_id; > + u32 abort; > + char data[0]; > +}; > + > /* > * Exit Qualifications for entry failure during or after loading guest > state > */ > @@ -554,4 +568,139 @@ enum vm_instruction_error_number { > VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28, > }; > > +static __always_inline void vmcs_check16(unsigned long field) > +{ > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6001) == 0x2000, > + "16-bit accessor invalid for 64-bit field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6001) == 0x2001, > + "16-bit accessor invalid for 64-bit high field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0x4000, > + "16-bit accessor invalid for 32-bit high field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0x6000, > + "16-bit accessor invalid for natural width field"); > +} > + > +static __always_inline void vmcs_check32(unsigned long field) > +{ > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0, > + "32-bit accessor invalid for 16-bit field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0x6000, > + "32-bit accessor invalid for natural width field"); > +} > + > +static __always_inline void vmcs_check64(unsigned long field) > +{ > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0, > + "64-bit accessor invalid for 16-bit field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6001) == 0x2001, > + "64-bit accessor invalid for 64-bit high field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0x4000, > + "64-bit accessor invalid for 32-bit field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0x6000, > + "64-bit accessor invalid for natural width field"); > +} > + > +static __always_inline void vmcs_checkl(unsigned long field) > +{ > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0, > + "Natural width accessor invalid for 16-bit field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6001) == 0x2000, > + "Natural width accessor invalid for 64-bit field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6001) == 0x2001, > + "Natural width accessor invalid for 64-bit high field"); > + BUILD_BUG_ON_MSG(__builtin_constant_p(field) && > + ((field) & 0x6000) == 0x4000, > + "Natural width accessor invalid for 32-bit field"); > +} > + > +static __always_inline unsigned long __vmcs_readl(unsigned long field) > +{ > + unsigned long value; > + > + asm volatile (__ex_clear(ASM_VMX_VMREAD_RDX_RAX, "%0") > + : "=a"(value) : "d"(field) : "cc"); > + return value; > +} > + > +static __always_inline u16 vmcs_read16(unsigned long field) > +{ > + vmcs_check16(field); > + return __vmcs_readl(field); > +} > + > +static __always_inline u32 vmcs_read32(unsigned long field) > +{ > + vmcs_check32(field); > + return __vmcs_readl(field); > +} > + > +static __always_inline u64 vmcs_read64(unsigned long field) > +{ > + vmcs_check64(field); > +#ifdef CONFIG_X86_64 > + return __vmcs_readl(field); > +#else > + return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32); > +#endif > +} > + > +static __always_inline unsigned long vmcs_readl(unsigned long field) > +{ > + vmcs_checkl(field); > + return __vmcs_readl(field); > +} > + > +static __always_inline void __vmcs_writel(unsigned long field, > + unsigned long value) > +{ > + u8 error; > + > + asm volatile (__ex(ASM_VMX_VMWRITE_RAX_RDX) "; setna %0" > + : "=q"(error) : "a"(value), "d"(field) : "cc"); > + if (unlikely(error)) > + vmwrite_error(field, value); > +} > + > +static __always_inline void vmcs_writel(unsigned long field, > + unsigned long value) > +{ > + vmcs_checkl(field); > + __vmcs_writel(field, value); > +} > + > +static __always_inline void vmcs_write16(unsigned long field, u16 value) > +{ > + vmcs_check16(field); > + __vmcs_writel(field, value); > +} > + > +static __always_inline void vmcs_write32(unsigned long field, u32 value) > +{ > + vmcs_check32(field); > + __vmcs_writel(field, value); > +} > + > +static __always_inline void vmcs_write64(unsigned long field, u64 value) > +{ > + vmcs_check64(field); > + __vmcs_writel(field, value); > +#ifndef CONFIG_X86_64 > + asm volatile (""); > + __vmcs_writel(field+1, value >> 32); > +#endif > +} > + > +struct vmcs *vmcs_store(void); > +void vmcs_load(struct vmcs *vmcs); > #endif > diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig > index ab8e32f7b9a8..30137fe8ae13 100644 > --- a/arch/x86/kvm/Kconfig > +++ b/arch/x86/kvm/Kconfig > @@ -69,6 +69,15 @@ config KVM_INTEL > To compile this as a module, choose M here: the module > will be called kvm-intel. > > +config KVM_VMCSCTL > + bool "Expose the VMCS to sysfs" > + depends on KVM > + depends on KVM_INTEL > + default n > + ---help--- > + Adds entries to sysfs which allow fine grained virtual machine state to > + be manipulated from userland. > + > config KVM_AMD > tristate "KVM for AMD processors support" > depends on KVM > diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile > index 3bff20710471..4d1c5a321a8e 100644 > --- a/arch/x86/kvm/Makefile > +++ b/arch/x86/kvm/Makefile > @@ -22,4 +22,5 @@ kvm-amd-y += svm.o pmu_amd.o > > obj-$(CONFIG_KVM) += kvm.o > obj-$(CONFIG_KVM_INTEL) += kvm-intel.o > +obj-$(CONFIG_KVM_VMCSCTL) += vmcsctl.o > obj-$(CONFIG_KVM_AMD) += kvm-amd.o > diff --git a/arch/x86/kvm/vmcsctl.c b/arch/x86/kvm/vmcsctl.c > new file mode 100644 > index 000000000000..6d5db494003b > --- /dev/null > +++ b/arch/x86/kvm/vmcsctl.c > @@ -0,0 +1,649 @@ > +#include "vmcsctl.h" > + > +static struct kset *vmcsctl_set; > +static bool vmxon; > + > +static inline struct vmcsctl *vmcsctl_container_of(struct kobject *kobj) > +{ > + return container_of(kobj, struct vmcsctl, kobj); > +} > + > +static void vmcsctl_release(struct kobject *kobj) > +{ > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + > + kfree(vmcsctl); > +} > + > +static struct kobj_type vmcsctl_kobj_ktype = { > + .release = vmcsctl_release, > + .sysfs_ops = &kobj_sysfs_ops, > +}; > + > +static ssize_t revision_id_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf) > +{ > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + return sprintf(buf, "%d\n", vmcsctl->vmcs->revision_id); > +} > + > +static ssize_t abort_show(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf) > +{ > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + return sprintf(buf, "%d\n", vmcsctl->vmcs->abort); > +} > + > +static ssize_t vmcs_field_show_u16(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf, enum vmcs_field field) > +{ > + u16 value; > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + struct vmcs *original_vmcs = vmcs_store(); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + vmcs_load(vmcsctl->vmcs); > + > + value = vmcs_read16(field); > + vmcs_load(original_vmcs); > + return sprintf(buf, "%hu\n", value); > +} > + > +static ssize_t vmcs_field_store_u16(struct kobject *kobj, > + struct kobj_attribute *attr, const char *buf, size_t count, > + enum vmcs_field field) > +{ > + int ret; > + u16 value; > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + struct vmcs *original_vmcs = vmcs_store(); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + vmcs_load(vmcsctl->vmcs); > + > + ret = kstrtou16(buf, 10, &value); > + if (ret < 0) > + return ret; > + > + vmcs_write16(field, value); > + vmcs_load(original_vmcs); > + return count; > +} > + > +static ssize_t vmcs_field_show_u32(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf, enum vmcs_field field) > +{ > + u32 value; > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + struct vmcs *original_vmcs = vmcs_store(); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + vmcs_load(vmcsctl->vmcs); > + value = vmcs_read32(field); > + vmcs_load(original_vmcs); > + return sprintf(buf, "%u\n", value); > +} > + > +static ssize_t vmcs_field_store_u32(struct kobject *kobj, > + struct kobj_attribute *attr, const char *buf, size_t count, > + enum vmcs_field field) > +{ > + int ret; > + u32 value; > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + struct vmcs *original_vmcs = vmcs_store(); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + vmcs_load(vmcsctl->vmcs); > + ret = kstrtouint(buf, 10, &value); > + if (ret < 0) > + return ret; > + > + vmcs_write32(field, value); > + vmcs_load(original_vmcs); > + return count; > +} > + > +static ssize_t vmcs_field_show_u64(struct kobject *kobj, > + struct kobj_attribute *attr, char *buf, enum vmcs_field field) > +{ > + u64 value; > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + struct vmcs *original_vmcs = vmcs_store(); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + vmcs_load(vmcsctl->vmcs); > + value = vmcs_read64(field); > + > + vmcs_load(original_vmcs); > + return sprintf(buf, "%llu\n", value); > +} > + > +static ssize_t vmcs_field_store_u64(struct kobject *kobj, > + struct kobj_attribute *attr, const char *buf, size_t count, > + enum vmcs_field field) > +{ > + int ret; > + u64 value; > + struct vmcsctl *vmcsctl = vmcsctl_container_of(kobj); > + struct vmcs *original_vmcs = vmcs_store(); > + > + vmcs_load(vmcsctl->vmcs); > + > + WARN_ON(vmcsctl->vmcs == NULL); > + ret = kstrtoull(buf, 10, &value); > + if (ret < 0) > + return ret; > + > + vmcs_write64(field, value); > + > + vmcs_load(original_vmcs); > + return count; > +} > + > + > +#ifdef x86_64 > +#define natural_width u64 > +#else > +#define natural_width u32 > +#endif > + > +#define VMCS_ATTR_SHOW(attr_field, type) \ > +static ssize_t vmcs_##attr_field##_show(struct kobject *kobj, \ > + struct kobj_attribute *attr, char *buf) \ > +{ \ > + if (vmxon) { \ > + return vmcs_field_show_##type(kobj, attr, buf, attr_field); \ > + } else { \ > + return -1; \ > + } \ > +} > + > +#define VMCS_ATTR_STORE(attr_field, type) \ > +static ssize_t vmcs_##attr_field##_store(struct kobject *kobj, \ > + struct kobj_attribute *attr, const char *buf, size_t count) \ > +{ \ > + if (vmxon) { \ > + return vmcs_field_store_##type(kobj, attr, buf, count, \ > + attr_field); \ > + } else { \ > + return -1; \ > + } \ > +} > + > +#define VMCS_ATTR(attr_field, type) \ > + VMCS_ATTR_SHOW(attr_field, type) \ > + VMCS_ATTR_STORE(attr_field, type) \ > + static struct kobj_attribute vmcs_field_##attr_field = \ > + __ATTR(attr_field, 0644, vmcs_##attr_field##_show, \ > + vmcs_##attr_field##_store) > + > +#define VMCS_ATTR_RO(attr_field, type) \ > + VMCS_ATTR_SHOW(attr_field, type) \ > + static struct kobj_attribute vmcs_field_##attr_field = \ > + __ATTR(attr_field, 0444, vmcs_##attr_field##_show, \ > + NULL) > + > +VMCS_ATTR(VIRTUAL_PROCESSOR_ID, u16); > +VMCS_ATTR(POSTED_INTR_NV, u16); > +VMCS_ATTR(GUEST_ES_SELECTOR, u16); > +VMCS_ATTR(GUEST_CS_SELECTOR, u16); > +VMCS_ATTR(GUEST_SS_SELECTOR, u16); > +VMCS_ATTR(GUEST_DS_SELECTOR, u16); > +VMCS_ATTR(GUEST_FS_SELECTOR, u16); > +VMCS_ATTR(GUEST_GS_SELECTOR, u16); > +VMCS_ATTR(GUEST_LDTR_SELECTOR, u16); > +VMCS_ATTR(GUEST_TR_SELECTOR, u16); > +VMCS_ATTR(GUEST_INTR_STATUS, u16); > +VMCS_ATTR(GUEST_PML_INDEX, u16); > +VMCS_ATTR(HOST_ES_SELECTOR, u16); > +VMCS_ATTR(HOST_CS_SELECTOR, u16); > +VMCS_ATTR(HOST_SS_SELECTOR, u16); > +VMCS_ATTR(HOST_DS_SELECTOR, u16); > +VMCS_ATTR(HOST_FS_SELECTOR, u16); > +VMCS_ATTR(HOST_GS_SELECTOR, u16); > +VMCS_ATTR(HOST_TR_SELECTOR, u16); > +VMCS_ATTR(IO_BITMAP_A, u64); > +VMCS_ATTR(IO_BITMAP_A_HIGH, u64); > +VMCS_ATTR(IO_BITMAP_B, u64); > +VMCS_ATTR(IO_BITMAP_B_HIGH, u64); > +VMCS_ATTR(MSR_BITMAP, u64); > +VMCS_ATTR(MSR_BITMAP_HIGH, u64); > +VMCS_ATTR(VM_EXIT_MSR_STORE_ADDR, u64); > +VMCS_ATTR(VM_EXIT_MSR_STORE_ADDR_HIGH, u64); > +VMCS_ATTR(VM_EXIT_MSR_LOAD_ADDR, u64); > +VMCS_ATTR(VM_EXIT_MSR_LOAD_ADDR_HIGH, u64); > +VMCS_ATTR(VM_ENTRY_MSR_LOAD_ADDR, u64); > +VMCS_ATTR(VM_ENTRY_MSR_LOAD_ADDR_HIGH, u64); > +VMCS_ATTR(PML_ADDRESS, u64); > +VMCS_ATTR(PML_ADDRESS_HIGH, u64); > +VMCS_ATTR(TSC_OFFSET, u64); > +VMCS_ATTR(TSC_OFFSET_HIGH, u64); > +VMCS_ATTR(VIRTUAL_APIC_PAGE_ADDR, u64); > +VMCS_ATTR(VIRTUAL_APIC_PAGE_ADDR_HIGH, u64); > +VMCS_ATTR(APIC_ACCESS_ADDR, u64); > +VMCS_ATTR(APIC_ACCESS_ADDR_HIGH, u64); > +VMCS_ATTR(POSTED_INTR_DESC_ADDR, u64); > +VMCS_ATTR(POSTED_INTR_DESC_ADDR_HIGH, u64); > +VMCS_ATTR(EPT_POINTER, u64); > +VMCS_ATTR(EPT_POINTER_HIGH, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP0, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP0_HIGH, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP1, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP1_HIGH, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP2, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP2_HIGH, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP3, u64); > +VMCS_ATTR(EOI_EXIT_BITMAP3_HIGH, u64); > +VMCS_ATTR(VMREAD_BITMAP, u64); > +VMCS_ATTR(VMWRITE_BITMAP, u64); > +VMCS_ATTR(XSS_EXIT_BITMAP, u64); > +VMCS_ATTR(XSS_EXIT_BITMAP_HIGH, u64); > +VMCS_ATTR(TSC_MULTIPLIER, u64); > +VMCS_ATTR(TSC_MULTIPLIER_HIGH, u64); > +VMCS_ATTR_RO(GUEST_PHYSICAL_ADDRESS, u64); > +VMCS_ATTR_RO(GUEST_PHYSICAL_ADDRESS_HIGH, u64); > +VMCS_ATTR(VMCS_LINK_POINTER, u64); > +VMCS_ATTR(VMCS_LINK_POINTER_HIGH, u64); > +VMCS_ATTR(GUEST_IA32_DEBUGCTL, u64); > +VMCS_ATTR(GUEST_IA32_DEBUGCTL_HIGH, u64); > +VMCS_ATTR(GUEST_IA32_PAT, u64); > +VMCS_ATTR(GUEST_IA32_PAT_HIGH, u64); > +VMCS_ATTR(GUEST_IA32_EFER, u64); > +VMCS_ATTR(GUEST_IA32_EFER_HIGH, u64); > +VMCS_ATTR(GUEST_IA32_PERF_GLOBAL_CTRL, u64); > +VMCS_ATTR(GUEST_IA32_PERF_GLOBAL_CTRL_HIGH, u64); > +VMCS_ATTR(GUEST_PDPTR0, u64); > +VMCS_ATTR(GUEST_PDPTR0_HIGH, u64); > +VMCS_ATTR(GUEST_PDPTR1, u64); > +VMCS_ATTR(GUEST_PDPTR1_HIGH, u64); > +VMCS_ATTR(GUEST_PDPTR2, u64); > +VMCS_ATTR(GUEST_PDPTR2_HIGH, u64); > +VMCS_ATTR(GUEST_PDPTR3, u64); > +VMCS_ATTR(GUEST_PDPTR3_HIGH, u64); > +VMCS_ATTR(GUEST_BNDCFGS, u64); > +VMCS_ATTR(GUEST_BNDCFGS_HIGH, u64); > +VMCS_ATTR(HOST_IA32_PAT, u64); > +VMCS_ATTR(HOST_IA32_PAT_HIGH, u64); > +VMCS_ATTR(HOST_IA32_EFER, u64); > +VMCS_ATTR(HOST_IA32_EFER_HIGH, u64); > +VMCS_ATTR(HOST_IA32_PERF_GLOBAL_CTRL, u64); > +VMCS_ATTR(HOST_IA32_PERF_GLOBAL_CTRL_HIGH, u64); > +VMCS_ATTR(PIN_BASED_VM_EXEC_CONTROL, u32); > +VMCS_ATTR(CPU_BASED_VM_EXEC_CONTROL, u32); > +VMCS_ATTR(EXCEPTION_BITMAP, u32); > +VMCS_ATTR(PAGE_FAULT_ERROR_CODE_MASK, u32); > +VMCS_ATTR(PAGE_FAULT_ERROR_CODE_MATCH, u32); > +VMCS_ATTR(CR3_TARGET_COUNT, u32); > +VMCS_ATTR(VM_EXIT_CONTROLS, u32); > +VMCS_ATTR(VM_EXIT_MSR_STORE_COUNT, u32); > +VMCS_ATTR(VM_EXIT_MSR_LOAD_COUNT, u32); > +VMCS_ATTR(VM_ENTRY_CONTROLS, u32); > +VMCS_ATTR(VM_ENTRY_MSR_LOAD_COUNT, u32); > +VMCS_ATTR(VM_ENTRY_INTR_INFO_FIELD, u32); > +VMCS_ATTR(VM_ENTRY_EXCEPTION_ERROR_CODE, u32); > +VMCS_ATTR(VM_ENTRY_INSTRUCTION_LEN, u32); > +VMCS_ATTR(TPR_THRESHOLD, u32); > +VMCS_ATTR(SECONDARY_VM_EXEC_CONTROL, u32); > +VMCS_ATTR(PLE_GAP, u32); > +VMCS_ATTR(PLE_WINDOW, u32); > +VMCS_ATTR_RO(VM_INSTRUCTION_ERROR, u32); > +VMCS_ATTR_RO(VM_EXIT_REASON, u32); > +VMCS_ATTR_RO(VM_EXIT_INTR_INFO, u32); > +VMCS_ATTR_RO(VM_EXIT_INTR_ERROR_CODE, u32); > +VMCS_ATTR_RO(IDT_VECTORING_INFO_FIELD, u32); > +VMCS_ATTR_RO(IDT_VECTORING_ERROR_CODE, u32); > +VMCS_ATTR_RO(VM_EXIT_INSTRUCTION_LEN, u32); > +VMCS_ATTR_RO(VMX_INSTRUCTION_INFO, u32); > +VMCS_ATTR(GUEST_ES_LIMIT, u32); > +VMCS_ATTR(GUEST_CS_LIMIT, u32); > +VMCS_ATTR(GUEST_SS_LIMIT, u32); > +VMCS_ATTR(GUEST_DS_LIMIT, u32); > +VMCS_ATTR(GUEST_FS_LIMIT, u32); > +VMCS_ATTR(GUEST_GS_LIMIT, u32); > +VMCS_ATTR(GUEST_LDTR_LIMIT, u32); > +VMCS_ATTR(GUEST_TR_LIMIT, u32); > +VMCS_ATTR(GUEST_GDTR_LIMIT, u32); > +VMCS_ATTR(GUEST_IDTR_LIMIT, u32); > +VMCS_ATTR(GUEST_ES_AR_BYTES, u32); > +VMCS_ATTR(GUEST_CS_AR_BYTES, u32); > +VMCS_ATTR(GUEST_SS_AR_BYTES, u32); > +VMCS_ATTR(GUEST_DS_AR_BYTES, u32); > +VMCS_ATTR(GUEST_FS_AR_BYTES, u32); > +VMCS_ATTR(GUEST_GS_AR_BYTES, u32); > +VMCS_ATTR(GUEST_LDTR_AR_BYTES, u32); > +VMCS_ATTR(GUEST_TR_AR_BYTES, u32); > +VMCS_ATTR(GUEST_INTERRUPTIBILITY_INFO, u32); > +VMCS_ATTR(GUEST_ACTIVITY_STATE, u32); > +VMCS_ATTR(GUEST_SYSENTER_CS, u32); > +VMCS_ATTR(VMX_PREEMPTION_TIMER_VALUE, u32); > +VMCS_ATTR(HOST_IA32_SYSENTER_CS, u32); > +VMCS_ATTR(CR0_GUEST_HOST_MASK, natural_width); > +VMCS_ATTR(CR4_GUEST_HOST_MASK, natural_width); > +VMCS_ATTR(CR0_READ_SHADOW, natural_width); > +VMCS_ATTR(CR4_READ_SHADOW, natural_width); > +VMCS_ATTR(CR3_TARGET_VALUE0, natural_width); > +VMCS_ATTR(CR3_TARGET_VALUE1, natural_width); > +VMCS_ATTR(CR3_TARGET_VALUE2, natural_width); > +VMCS_ATTR(CR3_TARGET_VALUE3, natural_width); > +VMCS_ATTR_RO(EXIT_QUALIFICATION, natural_width); > +VMCS_ATTR_RO(GUEST_LINEAR_ADDRESS, natural_width); > +VMCS_ATTR(GUEST_CR0, natural_width); > +VMCS_ATTR(GUEST_CR3, natural_width); > +VMCS_ATTR(GUEST_CR4, natural_width); > +VMCS_ATTR(GUEST_ES_BASE, natural_width); > +VMCS_ATTR(GUEST_CS_BASE, natural_width); > +VMCS_ATTR(GUEST_SS_BASE, natural_width); > +VMCS_ATTR(GUEST_DS_BASE, natural_width); > +VMCS_ATTR(GUEST_FS_BASE, natural_width); > +VMCS_ATTR(GUEST_GS_BASE, natural_width); > +VMCS_ATTR(GUEST_LDTR_BASE, natural_width); > +VMCS_ATTR(GUEST_TR_BASE, natural_width); > +VMCS_ATTR(GUEST_GDTR_BASE, natural_width); > +VMCS_ATTR(GUEST_IDTR_BASE, natural_width); > +VMCS_ATTR(GUEST_DR7, natural_width); > +VMCS_ATTR(GUEST_RSP, natural_width); > +VMCS_ATTR(GUEST_RIP, natural_width); > +VMCS_ATTR(GUEST_RFLAGS, natural_width); > +VMCS_ATTR(GUEST_PENDING_DBG_EXCEPTIONS, natural_width); > +VMCS_ATTR(GUEST_SYSENTER_ESP, natural_width); > +VMCS_ATTR(GUEST_SYSENTER_EIP, natural_width); > +VMCS_ATTR(HOST_CR0, natural_width); > +VMCS_ATTR(HOST_CR3, natural_width); > +VMCS_ATTR(HOST_CR4, natural_width); > +VMCS_ATTR(HOST_FS_BASE, natural_width); > +VMCS_ATTR(HOST_GS_BASE, natural_width); > +VMCS_ATTR(HOST_TR_BASE, natural_width); > +VMCS_ATTR(HOST_GDTR_BASE, natural_width); > +VMCS_ATTR(HOST_IDTR_BASE, natural_width); > +VMCS_ATTR(HOST_IA32_SYSENTER_ESP, natural_width); > +VMCS_ATTR(HOST_IA32_SYSENTER_EIP, natural_width); > +VMCS_ATTR(HOST_RSP, natural_width); > +VMCS_ATTR(HOST_RIP, natural_width); > + > +static struct kobj_attribute revision_id_attribute = > + __ATTR(revision_id, 0444, revision_id_show, NULL); > + > +static struct kobj_attribute abort_attribute = > + __ATTR(abort, 0444, abort_show, NULL); > + > +static struct attribute *vmcsctl_attrs[] = { > + &revision_id_attribute.attr, > + &abort_attribute.attr, > + &vmcs_field_VIRTUAL_PROCESSOR_ID.attr, > + &vmcs_field_POSTED_INTR_NV.attr, > + &vmcs_field_GUEST_ES_SELECTOR.attr, > + &vmcs_field_GUEST_CS_SELECTOR.attr, > + &vmcs_field_GUEST_SS_SELECTOR.attr, > + &vmcs_field_GUEST_DS_SELECTOR.attr, > + &vmcs_field_GUEST_FS_SELECTOR.attr, > + &vmcs_field_GUEST_GS_SELECTOR.attr, > + &vmcs_field_GUEST_LDTR_SELECTOR.attr, > + &vmcs_field_GUEST_TR_SELECTOR.attr, > + &vmcs_field_GUEST_INTR_STATUS.attr, > + &vmcs_field_GUEST_PML_INDEX.attr, > + &vmcs_field_HOST_ES_SELECTOR.attr, > + &vmcs_field_HOST_CS_SELECTOR.attr, > + &vmcs_field_HOST_SS_SELECTOR.attr, > + &vmcs_field_HOST_DS_SELECTOR.attr, > + &vmcs_field_HOST_FS_SELECTOR.attr, > + &vmcs_field_HOST_GS_SELECTOR.attr, > + &vmcs_field_HOST_TR_SELECTOR.attr, > + &vmcs_field_IO_BITMAP_A.attr, > + &vmcs_field_IO_BITMAP_A_HIGH.attr, > + &vmcs_field_IO_BITMAP_B.attr, > + &vmcs_field_IO_BITMAP_B_HIGH.attr, > + &vmcs_field_MSR_BITMAP.attr, > + &vmcs_field_MSR_BITMAP_HIGH.attr, > + &vmcs_field_VM_EXIT_MSR_STORE_ADDR.attr, > + &vmcs_field_VM_EXIT_MSR_STORE_ADDR_HIGH.attr, > + &vmcs_field_VM_EXIT_MSR_LOAD_ADDR.attr, > + &vmcs_field_VM_EXIT_MSR_LOAD_ADDR_HIGH.attr, > + &vmcs_field_VM_ENTRY_MSR_LOAD_ADDR.attr, > + &vmcs_field_VM_ENTRY_MSR_LOAD_ADDR_HIGH.attr, > + &vmcs_field_PML_ADDRESS.attr, > + &vmcs_field_PML_ADDRESS_HIGH.attr, > + &vmcs_field_TSC_OFFSET.attr, > + &vmcs_field_TSC_OFFSET_HIGH.attr, > + &vmcs_field_VIRTUAL_APIC_PAGE_ADDR.attr, > + &vmcs_field_VIRTUAL_APIC_PAGE_ADDR_HIGH.attr, > + &vmcs_field_APIC_ACCESS_ADDR.attr, > + &vmcs_field_APIC_ACCESS_ADDR_HIGH.attr, > + &vmcs_field_POSTED_INTR_DESC_ADDR.attr, > + &vmcs_field_POSTED_INTR_DESC_ADDR_HIGH.attr, > + &vmcs_field_EPT_POINTER.attr, > + &vmcs_field_EPT_POINTER_HIGH.attr, > + &vmcs_field_EOI_EXIT_BITMAP0.attr, > + &vmcs_field_EOI_EXIT_BITMAP0_HIGH.attr, > + &vmcs_field_EOI_EXIT_BITMAP1.attr, > + &vmcs_field_EOI_EXIT_BITMAP1_HIGH.attr, > + &vmcs_field_EOI_EXIT_BITMAP2.attr, > + &vmcs_field_EOI_EXIT_BITMAP2_HIGH.attr, > + &vmcs_field_EOI_EXIT_BITMAP3.attr, > + &vmcs_field_EOI_EXIT_BITMAP3_HIGH.attr, > + &vmcs_field_VMREAD_BITMAP.attr, > + &vmcs_field_VMWRITE_BITMAP.attr, > + &vmcs_field_XSS_EXIT_BITMAP.attr, > + &vmcs_field_XSS_EXIT_BITMAP_HIGH.attr, > + &vmcs_field_TSC_MULTIPLIER.attr, > + &vmcs_field_TSC_MULTIPLIER_HIGH.attr, > + &vmcs_field_GUEST_PHYSICAL_ADDRESS.attr, > + &vmcs_field_GUEST_PHYSICAL_ADDRESS_HIGH.attr, > + &vmcs_field_VMCS_LINK_POINTER.attr, > + &vmcs_field_VMCS_LINK_POINTER_HIGH.attr, > + &vmcs_field_GUEST_IA32_DEBUGCTL.attr, > + &vmcs_field_GUEST_IA32_DEBUGCTL_HIGH.attr, > + &vmcs_field_GUEST_IA32_PAT.attr, > + &vmcs_field_GUEST_IA32_PAT_HIGH.attr, > + &vmcs_field_GUEST_IA32_EFER.attr, > + &vmcs_field_GUEST_IA32_EFER_HIGH.attr, > + &vmcs_field_GUEST_IA32_PERF_GLOBAL_CTRL.attr, > + &vmcs_field_GUEST_IA32_PERF_GLOBAL_CTRL_HIGH.attr, > + &vmcs_field_GUEST_PDPTR0.attr, > + &vmcs_field_GUEST_PDPTR0_HIGH.attr, > + &vmcs_field_GUEST_PDPTR1.attr, > + &vmcs_field_GUEST_PDPTR1_HIGH.attr, > + &vmcs_field_GUEST_PDPTR2.attr, > + &vmcs_field_GUEST_PDPTR2_HIGH.attr, > + &vmcs_field_GUEST_PDPTR3.attr, > + &vmcs_field_GUEST_PDPTR3_HIGH.attr, > + &vmcs_field_GUEST_BNDCFGS.attr, > + &vmcs_field_GUEST_BNDCFGS_HIGH.attr, > + &vmcs_field_HOST_IA32_PAT.attr, > + &vmcs_field_HOST_IA32_PAT_HIGH.attr, > + &vmcs_field_HOST_IA32_EFER.attr, > + &vmcs_field_HOST_IA32_EFER_HIGH.attr, > + &vmcs_field_HOST_IA32_PERF_GLOBAL_CTRL.attr, > + &vmcs_field_HOST_IA32_PERF_GLOBAL_CTRL_HIGH.attr, > + &vmcs_field_PIN_BASED_VM_EXEC_CONTROL.attr, > + &vmcs_field_CPU_BASED_VM_EXEC_CONTROL.attr, > + &vmcs_field_EXCEPTION_BITMAP.attr, > + &vmcs_field_PAGE_FAULT_ERROR_CODE_MASK.attr, > + &vmcs_field_PAGE_FAULT_ERROR_CODE_MATCH.attr, > + &vmcs_field_CR3_TARGET_COUNT.attr, > + &vmcs_field_VM_EXIT_CONTROLS.attr, > + &vmcs_field_VM_EXIT_MSR_STORE_COUNT.attr, > + &vmcs_field_VM_EXIT_MSR_LOAD_COUNT.attr, > + &vmcs_field_VM_ENTRY_CONTROLS.attr, > + &vmcs_field_VM_ENTRY_MSR_LOAD_COUNT.attr, > + &vmcs_field_VM_ENTRY_INTR_INFO_FIELD.attr, > + &vmcs_field_VM_ENTRY_EXCEPTION_ERROR_CODE.attr, > + &vmcs_field_VM_ENTRY_INSTRUCTION_LEN.attr, > + &vmcs_field_TPR_THRESHOLD.attr, > + &vmcs_field_SECONDARY_VM_EXEC_CONTROL.attr, > + &vmcs_field_PLE_GAP.attr, > + &vmcs_field_PLE_WINDOW.attr, > + &vmcs_field_VM_INSTRUCTION_ERROR.attr, > + &vmcs_field_VM_EXIT_REASON.attr, > + &vmcs_field_VM_EXIT_INTR_INFO.attr, > + &vmcs_field_VM_EXIT_INTR_ERROR_CODE.attr, > + &vmcs_field_IDT_VECTORING_INFO_FIELD.attr, > + &vmcs_field_IDT_VECTORING_ERROR_CODE.attr, > + &vmcs_field_VM_EXIT_INSTRUCTION_LEN.attr, > + &vmcs_field_VMX_INSTRUCTION_INFO.attr, > + &vmcs_field_GUEST_ES_LIMIT.attr, > + &vmcs_field_GUEST_CS_LIMIT.attr, > + &vmcs_field_GUEST_SS_LIMIT.attr, > + &vmcs_field_GUEST_DS_LIMIT.attr, > + &vmcs_field_GUEST_FS_LIMIT.attr, > + &vmcs_field_GUEST_GS_LIMIT.attr, > + &vmcs_field_GUEST_LDTR_LIMIT.attr, > + &vmcs_field_GUEST_TR_LIMIT.attr, > + &vmcs_field_GUEST_GDTR_LIMIT.attr, > + &vmcs_field_GUEST_IDTR_LIMIT.attr, > + &vmcs_field_GUEST_ES_AR_BYTES.attr, > + &vmcs_field_GUEST_CS_AR_BYTES.attr, > + &vmcs_field_GUEST_SS_AR_BYTES.attr, > + &vmcs_field_GUEST_DS_AR_BYTES.attr, > + &vmcs_field_GUEST_FS_AR_BYTES.attr, > + &vmcs_field_GUEST_GS_AR_BYTES.attr, > + &vmcs_field_GUEST_LDTR_AR_BYTES.attr, > + &vmcs_field_GUEST_TR_AR_BYTES.attr, > + &vmcs_field_GUEST_INTERRUPTIBILITY_INFO.attr, > + &vmcs_field_GUEST_ACTIVITY_STATE.attr, > + &vmcs_field_GUEST_SYSENTER_CS.attr, > + &vmcs_field_VMX_PREEMPTION_TIMER_VALUE.attr, > + &vmcs_field_HOST_IA32_SYSENTER_CS.attr, > + &vmcs_field_CR0_GUEST_HOST_MASK.attr, > + &vmcs_field_CR4_GUEST_HOST_MASK.attr, > + &vmcs_field_CR0_READ_SHADOW.attr, > + &vmcs_field_CR4_READ_SHADOW.attr, > + &vmcs_field_CR3_TARGET_VALUE0.attr, > + &vmcs_field_CR3_TARGET_VALUE1.attr, > + &vmcs_field_CR3_TARGET_VALUE2.attr, > + &vmcs_field_CR3_TARGET_VALUE3.attr, > + &vmcs_field_EXIT_QUALIFICATION.attr, > + &vmcs_field_GUEST_LINEAR_ADDRESS.attr, > + &vmcs_field_GUEST_CR0.attr, > + &vmcs_field_GUEST_CR3.attr, > + &vmcs_field_GUEST_CR4.attr, > + &vmcs_field_GUEST_ES_BASE.attr, > + &vmcs_field_GUEST_CS_BASE.attr, > + &vmcs_field_GUEST_SS_BASE.attr, > + &vmcs_field_GUEST_DS_BASE.attr, > + &vmcs_field_GUEST_FS_BASE.attr, > + &vmcs_field_GUEST_GS_BASE.attr, > + &vmcs_field_GUEST_LDTR_BASE.attr, > + &vmcs_field_GUEST_TR_BASE.attr, > + &vmcs_field_GUEST_GDTR_BASE.attr, > + &vmcs_field_GUEST_IDTR_BASE.attr, > + &vmcs_field_GUEST_DR7.attr, > + &vmcs_field_GUEST_RSP.attr, > + &vmcs_field_GUEST_RIP.attr, > + &vmcs_field_GUEST_RFLAGS.attr, > + &vmcs_field_GUEST_PENDING_DBG_EXCEPTIONS.attr, > + &vmcs_field_GUEST_SYSENTER_ESP.attr, > + &vmcs_field_GUEST_SYSENTER_EIP.attr, > + &vmcs_field_HOST_CR0.attr, > + &vmcs_field_HOST_CR3.attr, > + &vmcs_field_HOST_CR4.attr, > + &vmcs_field_HOST_FS_BASE.attr, > + &vmcs_field_HOST_GS_BASE.attr, > + &vmcs_field_HOST_TR_BASE.attr, > + &vmcs_field_HOST_GDTR_BASE.attr, > + &vmcs_field_HOST_IDTR_BASE.attr, > + &vmcs_field_HOST_IA32_SYSENTER_ESP.attr, > + &vmcs_field_HOST_IA32_SYSENTER_EIP.attr, > + &vmcs_field_HOST_RSP.attr, > + &vmcs_field_HOST_RIP.attr, > + NULL, /* need to NULL terminate the list of attributes */ > +}; > + > +static struct attribute_group attr_group = { > + .attrs = vmcsctl_attrs, > +}; > + > +static struct vmcsctl *vmcsctl_create(struct vmcs *vmcs) > +{ > + struct vmcsctl *new; > + > + new = kzalloc(sizeof(*new), GFP_KERNEL); > + if (new == NULL) > + return NULL; > + kobject_init(&new->kobj, &vmcsctl_kobj_ktype); > + new->vmcs = vmcs; > + new->pid = task_pid_nr(current); > + return new; > +} > + > +static void vmcsctl_del(struct vmcsctl *vmcsctl) > +{ > + kobject_del(&vmcsctl->kobj); > + kfree(vmcsctl); > +} > + > +int vmcsctl_register(struct vmcs *vmcs) > +{ > + int err; > + struct vmcsctl *vmcsctl; > + > + WARN_ON(vmcs == NULL); > + vmcsctl = vmcsctl_create(vmcs); > + if (vmcsctl == NULL) > + return -1; > + vmcsctl->kobj.kset = vmcsctl_set; > + err = kobject_add(&vmcsctl->kobj, NULL, "vmcs%d", > + vmcsctl->pid); > + if (err != 0) > + goto out; > + err = sysfs_create_group(&vmcsctl->kobj, &attr_group); > + if (err != 0) > + goto out; > + return 0; > +out: > + vmcsctl_del(vmcsctl); > + return err; > +} > + > +void vmcsctl_unregister(struct vmcs *vmcs) > +{ > + struct kobject *kobj; > + struct vmcsctl *vmcsctl; > + > + list_for_each_entry(kobj, &vmcsctl_set->list, entry) { > + vmcsctl = vmcsctl_container_of(kobj); > + if (vmcsctl->vmcs == vmcs) { > + vmcsctl_del(vmcsctl); > + return; > + } > + } > +} > + > +void vmcsctl_vmxon(void) > +{ > + vmxon = true; > +} > + > +void vmcsctl_vmxoff(void) > +{ > + vmxon = false; > +} > + > +static int __init vmcsctl_init(void) > +{ > + int err; > + > + vmcsctl_set = kset_create_and_add("vmcsctl", NULL, kernel_kobj); > + if (vmcsctl_set == NULL) > + return -ENOMEM; > + err = kset_register(vmcsctl_set); > + if (err != 0) > + return err; > + return 0; > +} > + > +static void __exit vmcsctl_exit(void) > +{ > + kset_unregister(vmcsctl_set); > + kset_put(vmcsctl_set); > +} > + > +module_init(vmcsctl_init); > +module_exit(vmcsctl_exit); > + > +MODULE_AUTHOR("Ian Kronquist <iankronquist@xxxxxxxxx>"); > +MODULE_LICENSE("Dual MIT/GPL"); > diff --git a/arch/x86/kvm/vmcsctl.h b/arch/x86/kvm/vmcsctl.h > new file mode 100644 > index 000000000000..022d4878f2b8 > --- /dev/null > +++ b/arch/x86/kvm/vmcsctl.h > @@ -0,0 +1,27 @@ > +#ifndef __VMCSCTL_H > +#define __VMCSCTL_H > + > +#include <linux/kobject.h> > +#include <linux/module.h> > +#include <linux/sched.h> > +#include <linux/slab.h> > +#include <linux/sysfs.h> > + > +#include <asm/vmx.h> > + > +struct vmcs; > + > +struct vmcsctl { > + int pid; > + struct kobject kobj; > + struct vmcs *vmcs; > +}; > + > +int vmcsctl_register(struct vmcs *vmcs); > + > +void vmcsctl_unregister(struct vmcs *vmcs); > + > +void vmcsctl_vmxon(void); > + > +void vmcsctl_vmxoff(void); > +#endif > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c > index 259e9b28ccf8..262f09007ca3 100644 > --- a/arch/x86/kvm/vmx.c > +++ b/arch/x86/kvm/vmx.c > @@ -36,6 +36,10 @@ > #include "kvm_cache_regs.h" > #include "x86.h" > > +#ifdef CONFIG_KVM_VMCSCTL > +#include "vmcsctl.h" > +#endif > + > #include <asm/cpu.h> > #include <asm/io.h> > #include <asm/desc.h> > @@ -52,10 +56,6 @@ > #include "trace.h" > #include "pmu.h" > > -#define __ex(x) __kvm_handle_fault_on_reboot(x) > -#define __ex_clear(x, reg) \ > - ____kvm_handle_fault_on_reboot(x, "xor " reg " , " reg) > - > MODULE_AUTHOR("Qumranet"); > MODULE_LICENSE("GPL"); > > @@ -184,12 +184,6 @@ extern const ulong vmx_return; > #define NR_AUTOLOAD_MSRS 8 > #define VMCS02_POOL_SIZE 1 > > -struct vmcs { > - u32 revision_id; > - u32 abort; > - char data[0]; > -}; > - > /* > * Track a VMCS that may be loaded on a certain CPU. If it is (cpu!=-1), > also > * remember whether it was VMLAUNCHed, and maintain a linked list of all > VMCSs > @@ -1469,7 +1463,7 @@ static inline void loaded_vmcs_init(struct > loaded_vmcs *loaded_vmcs) > loaded_vmcs->launched = 0; > } > > -static void vmcs_load(struct vmcs *vmcs) > +void vmcs_load(struct vmcs *vmcs) > { > u64 phys_addr = __pa(vmcs); > u8 error; > @@ -1482,6 +1476,19 @@ static void vmcs_load(struct vmcs *vmcs) > vmcs, phys_addr); > } > > +struct vmcs *vmcs_store(void) > +{ > + struct vmcs *vmcs; > + u64 phys_addr; > + > + asm volatile (__ex(ASM_VMX_VMPTRST_RAX) > + : : "a"(&phys_addr) > + : "memory"); > + > + vmcs = __va(phys_addr); > + return vmcs; > +} > + > #ifdef CONFIG_KEXEC_CORE > /* > * This bitmap is used to indicate whether the vmclear > @@ -1594,132 +1601,13 @@ static inline void ept_sync_context(u64 eptp) > } > } > > -static __always_inline void vmcs_check16(unsigned long field) > -{ > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6001) == 0x2000, > - "16-bit accessor invalid for 64-bit field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6001) == 0x2001, > - "16-bit accessor invalid for 64-bit high field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x4000, > - "16-bit accessor invalid for 32-bit high field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x6000, > - "16-bit accessor invalid for natural width field"); > -} > - > -static __always_inline void vmcs_check32(unsigned long field) > -{ > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0, > - "32-bit accessor invalid for 16-bit field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x6000, > - "32-bit accessor invalid for natural width field"); > -} > - > -static __always_inline void vmcs_check64(unsigned long field) > -{ > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0, > - "64-bit accessor invalid for 16-bit field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6001) == 0x2001, > - "64-bit accessor invalid for 64-bit high field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x4000, > - "64-bit accessor invalid for 32-bit field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x6000, > - "64-bit accessor invalid for natural width field"); > -} > - > -static __always_inline void vmcs_checkl(unsigned long field) > -{ > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0, > - "Natural width accessor invalid for 16-bit field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6001) == 0x2000, > - "Natural width accessor invalid for 64-bit field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6001) == 0x2001, > - "Natural width accessor invalid for 64-bit high field"); > - BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x4000, > - "Natural width accessor invalid for 32-bit field"); > -} > - > -static __always_inline unsigned long __vmcs_readl(unsigned long field) > -{ > - unsigned long value; > - > - asm volatile (__ex_clear(ASM_VMX_VMREAD_RDX_RAX, "%0") > - : "=a"(value) : "d"(field) : "cc"); > - return value; > -} > - > -static __always_inline u16 vmcs_read16(unsigned long field) > -{ > - vmcs_check16(field); > - return __vmcs_readl(field); > -} > - > -static __always_inline u32 vmcs_read32(unsigned long field) > -{ > - vmcs_check32(field); > - return __vmcs_readl(field); > -} > - > -static __always_inline u64 vmcs_read64(unsigned long field) > -{ > - vmcs_check64(field); > -#ifdef CONFIG_X86_64 > - return __vmcs_readl(field); > -#else > - return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32); > -#endif > -} > - > -static __always_inline unsigned long vmcs_readl(unsigned long field) > -{ > - vmcs_checkl(field); > - return __vmcs_readl(field); > -} > - > -static noinline void vmwrite_error(unsigned long field, unsigned long > value) > +noinline void vmwrite_error(unsigned long field, unsigned long value) > { > printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", > field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); > dump_stack(); > } > > -static __always_inline void __vmcs_writel(unsigned long field, > unsigned long value) > -{ > - u8 error; > - > - asm volatile (__ex(ASM_VMX_VMWRITE_RAX_RDX) "; setna %0" > - : "=q"(error) : "a"(value), "d"(field) : "cc"); > - if (unlikely(error)) > - vmwrite_error(field, value); > -} > - > -static __always_inline void vmcs_write16(unsigned long field, u16 value) > -{ > - vmcs_check16(field); > - __vmcs_writel(field, value); > -} > - > -static __always_inline void vmcs_write32(unsigned long field, u32 value) > -{ > - vmcs_check32(field); > - __vmcs_writel(field, value); > -} > - > -static __always_inline void vmcs_write64(unsigned long field, u64 value) > -{ > - vmcs_check64(field); > - __vmcs_writel(field, value); > -#ifndef CONFIG_X86_64 > - asm volatile (""); > - __vmcs_writel(field+1, value >> 32); > -#endif > -} > - > -static __always_inline void vmcs_writel(unsigned long field, unsigned > long value) > -{ > - vmcs_checkl(field); > - __vmcs_writel(field, value); > -} > - > static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask) > { > BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & > 0x6000) == 0x2000, > @@ -3427,6 +3315,10 @@ static void kvm_cpu_vmxon(u64 addr) > asm volatile (ASM_VMX_VMXON_RAX > : : "a"(&addr), "m"(addr) > : "memory", "cc"); > + > +#ifdef CONFIG_KVM_VMCSCTL > + vmcsctl_vmxon(); > +#endif > } > > static int hardware_enable(void) > @@ -3495,6 +3387,10 @@ static void kvm_cpu_vmxoff(void) > asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc"); > > intel_pt_handle_vmx(0); > + > +#ifdef CONFIG_KVM_VMCSCTL > + vmcsctl_vmxoff(); > +#endif > } > > static void hardware_disable(void) > @@ -3729,6 +3625,11 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) > vmcs = page_address(pages); > memset(vmcs, 0, vmcs_config.size); > vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ > + > +#ifdef CONFIG_KVM_VMCSCTL > + vmcsctl_register(vmcs); > +#endif > + > return vmcs; > } > > @@ -3739,6 +3640,9 @@ static struct vmcs *alloc_vmcs(void) > > static void free_vmcs(struct vmcs *vmcs) > { > +#ifdef CONFIG_KVM_VMCSCTL > + vmcsctl_unregister(vmcs); > +#endif > free_pages((unsigned long)vmcs, vmcs_config.order); > } > > @@ -3800,6 +3704,7 @@ static void init_vmcs_shadow_fields(void) > vmx_vmread_bitmap); > } > > + > static __init int alloc_kvm_area(void) > { > int cpu; > -- > 2.12.2 >