Re: [PATCH v2] KVM: Expose Virtual Machine Control Structure to SYSFS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
>



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux