Re: [PATCH 4/7] Nested VMX patch 4 implements vmread and vmwrite

2009-12-16 Thread Avi Kivity

On 12/10/2009 08:38 PM, or...@il.ibm.com wrote:

From: Orit Wassermanor...@il.ibm.com

---
  arch/x86/kvm/vmx.c |  670 +++-
  1 files changed, 660 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 46a4f3a..8745d44 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -239,6 +239,7 @@ struct __attribute__ ((__packed__)) level_state {
  struct __attribute__ ((__packed__)) nested_vmcs_page {
u32 revision_id;
u32 abort;
+   struct shadow_vmcs shadow_vmcs;
struct level_state l2_state;
  };

@@ -263,6 +264,55 @@ struct nested_vmx {
struct nested_vmcs_page *current_l2_page;
  };

+enum vmcs_field_type {
+   VMCS_FIELD_TYPE_U16 = 0,
+   VMCS_FIELD_TYPE_U64 = 1,
+   VMCS_FIELD_TYPE_U32 = 2,
+   VMCS_FIELD_TYPE_ULONG = 3
+};
+
+#define VMCS_FIELD_LENGTH_OFFSET 13
+#define VMCS_FIELD_LENGTH_MASK 0x6000
+
+/*
+  Returns VMCS Field type
+*/
+static inline int vmcs_field_type(unsigned long field)
+{
+   /* For 32 bit L1 when it using the HIGH field */
+   if (0x1  field)
+   return VMCS_FIELD_TYPE_U32;
+
+   return (VMCS_FIELD_LENGTH_MASK  field)  13;
+}
+
+/*
+  Returncs VMCS field size in bits
+*/
+static inline int vmcs_field_size(int field_type, struct kvm_vcpu *vcpu)
+{
+   switch (field_type) {
+   case VMCS_FIELD_TYPE_U16:
+   return 2;
+   case VMCS_FIELD_TYPE_U32:
+   return 4;
+   case VMCS_FIELD_TYPE_U64:
+   return 8;
+   case VMCS_FIELD_TYPE_ULONG:
+#ifdef CONFIG_X86_64
+   if (is_long_mode(vcpu))
+   return 8;
+   else
   


Can replace with #endif


+   return 4;
+#else
+   return 4;
+#endif
   


... and drop the previous three lines.


+   }
+
+   printk(KERN_INFO WARNING: invalid field type %d \n, field_type);
+   return 0;
   


Can this happen?  The field is only two bits wide.



+static inline struct shadow_vmcs *get_shadow_vmcs(struct kvm_vcpu *vcpu)
+{
+   WARN_ON(!to_vmx(vcpu)-nested.current_l2_page);
+   return(to_vmx(vcpu)-nested.current_l2_page-shadow_vmcs);
+}
+
+#define SHADOW_VMCS_OFFSET(x) offsetof(struct shadow_vmcs, x)
+
+static unsigned short vmcs_field_to_offset_table[HOST_RIP+1] = {
+
+   [VIRTUAL_PROCESSOR_ID] =
+   SHADOW_VMCS_OFFSET(virtual_processor_id),
   


Keep on one line, you can use a shorter macro name if it helps.  This 
table is just noise.



+
+static inline unsigned short vmcs_field_to_offset(unsigned long field)
+{
+
+   if (field  HOST_RIP || vmcs_field_to_offset_table[field] == 0) {
+   printk(KERN_ERR invalid vmcs encoding 0x%lx\n, field);
+   return -1;
   


This will be converted to 0x.


+   }
+
+   return vmcs_field_to_offset_table[field];
+}
+
+static inline unsigned long nested_vmcs_readl(struct kvm_vcpu *vcpu,
+ unsigned long field)
+{
+   struct vcpu_vmx *vmx = to_vmx(vcpu);
+   unsigned long *entry;
+
+   if (!vmx-nested.current_l2_page) {
+   printk(KERN_ERR %s invalid nested vmcs\n, __func__);
+   return -1;
+   }
+
+   entry = (unsigned long *)((char *)(get_shadow_vmcs(vcpu)) +
+vmcs_field_to_offset(field));
   


Error check?


+static inline u64 nested_vmcs_read64(struct kvm_vcpu *vcpu, unsigned long 
field)
+{
+   struct vcpu_vmx *vmx = to_vmx(vcpu);
+   u64 *entry;
+   if (!vmx-nested.current_l2_page) {
+   printk(KERN_ERR %s invalid nested vmcs\n, __func__);
+   return -1;
+   }
+
+   entry = (u64 *)((char *)(get_shadow_vmcs(vcpu)) +
+vmcs_field_to_offset(field));
   


Need to support the 'high' part of 64-bit fields.


+   return *entry;
+}

+
+static inline void nested_vmcs_write64(struct kvm_vcpu *vcpu,
+  unsigned long field, u64 value)
+{
+#ifdef CONFIG_X86_64
+   nested_vmcs_writel(vcpu, field, value);
+#else /* nested: 32 bit not actually tested */
+   nested_vmcs_writel(vcpu, field, value);
+   nested_vmcs_writel(vcpu, field+1, value  32);
+#endif
   


High field support needed.


  static struct page *nested_get_page(struct kvm_vcpu *vcpu,
u64 vmcs_addr)
  {
@@ -354,11 +809,6 @@ static int nested_map_current(struct kvm_vcpu *vcpu)

mapped_page = kmap_atomic(vmcs_page, KM_USER0);

-   if (!mapped_page) {
-   printk(KERN_INFO %s: error in kmap_atomic\n, __func__);
-   return 0;
-   }
-
   


Fold.


vmx-nested.current_l2_page = mapped_page;

return 1;
@@ -1390,7 +1840,7 @@ static int read_guest_vmcs_gpa(struct kvm_vcpu *vcpu, 
gva_t gva, u64 *gentry)
size, vcpu);
if (r) {

[PATCH 4/7] Nested VMX patch 4 implements vmread and vmwrite

2009-12-10 Thread oritw
From: Orit Wasserman or...@il.ibm.com

---
 arch/x86/kvm/vmx.c |  670 +++-
 1 files changed, 660 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 46a4f3a..8745d44 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -239,6 +239,7 @@ struct __attribute__ ((__packed__)) level_state {
 struct __attribute__ ((__packed__)) nested_vmcs_page {
u32 revision_id;
u32 abort;
+   struct shadow_vmcs shadow_vmcs;
struct level_state l2_state;
 };
 
@@ -263,6 +264,55 @@ struct nested_vmx {
struct nested_vmcs_page *current_l2_page;
 };
 
+enum vmcs_field_type {
+   VMCS_FIELD_TYPE_U16 = 0,
+   VMCS_FIELD_TYPE_U64 = 1,
+   VMCS_FIELD_TYPE_U32 = 2,
+   VMCS_FIELD_TYPE_ULONG = 3
+};
+
+#define VMCS_FIELD_LENGTH_OFFSET 13
+#define VMCS_FIELD_LENGTH_MASK 0x6000
+
+/*
+  Returns VMCS Field type
+*/
+static inline int vmcs_field_type(unsigned long field)
+{
+   /* For 32 bit L1 when it using the HIGH field */
+   if (0x1  field)
+   return VMCS_FIELD_TYPE_U32;
+
+   return (VMCS_FIELD_LENGTH_MASK  field)  13;
+}
+
+/*
+  Returncs VMCS field size in bits
+*/
+static inline int vmcs_field_size(int field_type, struct kvm_vcpu *vcpu)
+{
+   switch (field_type) {
+   case VMCS_FIELD_TYPE_U16:
+   return 2;
+   case VMCS_FIELD_TYPE_U32:
+   return 4;
+   case VMCS_FIELD_TYPE_U64:
+   return 8;
+   case VMCS_FIELD_TYPE_ULONG:
+#ifdef CONFIG_X86_64
+   if (is_long_mode(vcpu))
+   return 8;
+   else
+   return 4;
+#else
+   return 4;
+#endif
+   }
+
+   printk(KERN_INFO WARNING: invalid field type %d \n, field_type);
+   return 0;
+}
+
 struct vcpu_vmx {
struct kvm_vcpu   vcpu;
struct list_head  local_vcpus_link;
@@ -317,6 +367,411 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu 
*vcpu)
return container_of(vcpu, struct vcpu_vmx, vcpu);
 }
 
+static inline struct shadow_vmcs *get_shadow_vmcs(struct kvm_vcpu *vcpu)
+{
+   WARN_ON(!to_vmx(vcpu)-nested.current_l2_page);
+   return (to_vmx(vcpu)-nested.current_l2_page-shadow_vmcs);
+}
+
+#define SHADOW_VMCS_OFFSET(x) offsetof(struct shadow_vmcs, x)
+
+static unsigned short vmcs_field_to_offset_table[HOST_RIP+1] = {
+
+   [VIRTUAL_PROCESSOR_ID] =
+   SHADOW_VMCS_OFFSET(virtual_processor_id),
+   [GUEST_ES_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_es_selector),
+   [GUEST_CS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_cs_selector),
+   [GUEST_SS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_ss_selector),
+   [GUEST_DS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_ds_selector),
+   [GUEST_FS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_fs_selector),
+   [GUEST_GS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_gs_selector),
+   [GUEST_LDTR_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_ldtr_selector),
+   [GUEST_TR_SELECTOR] =
+   SHADOW_VMCS_OFFSET(guest_tr_selector),
+   [HOST_ES_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_es_selector),
+   [HOST_CS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_cs_selector),
+   [HOST_SS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_ss_selector),
+   [HOST_DS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_ds_selector),
+   [HOST_FS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_fs_selector),
+   [HOST_GS_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_gs_selector),
+   [HOST_TR_SELECTOR] =
+   SHADOW_VMCS_OFFSET(host_tr_selector),
+   [IO_BITMAP_A] =
+   SHADOW_VMCS_OFFSET(io_bitmap_a),
+   [IO_BITMAP_A_HIGH] =
+   SHADOW_VMCS_OFFSET(io_bitmap_a)+4,
+   [IO_BITMAP_B] =
+   SHADOW_VMCS_OFFSET(io_bitmap_b),
+   [IO_BITMAP_B_HIGH] =
+   SHADOW_VMCS_OFFSET(io_bitmap_b)+4,
+   [MSR_BITMAP] =
+   SHADOW_VMCS_OFFSET(msr_bitmap),
+   [MSR_BITMAP_HIGH] =
+   SHADOW_VMCS_OFFSET(msr_bitmap)+4,
+   [VM_EXIT_MSR_STORE_ADDR] =
+   SHADOW_VMCS_OFFSET(vm_exit_msr_store_addr),
+   [VM_EXIT_MSR_STORE_ADDR_HIGH] =
+   SHADOW_VMCS_OFFSET(vm_exit_msr_store_addr)+4,
+   [VM_EXIT_MSR_LOAD_ADDR] =
+   SHADOW_VMCS_OFFSET(vm_exit_msr_load_addr),
+   [VM_EXIT_MSR_LOAD_ADDR_HIGH] =
+   SHADOW_VMCS_OFFSET(vm_exit_msr_load_addr)+4,
+   [VM_ENTRY_MSR_LOAD_ADDR] =
+   SHADOW_VMCS_OFFSET(vm_entry_msr_load_addr),
+   [VM_ENTRY_MSR_LOAD_ADDR_HIGH] =
+   SHADOW_VMCS_OFFSET(vm_entry_msr_load_addr)+4,
+   [TSC_OFFSET] =
+   SHADOW_VMCS_OFFSET(tsc_offset),
+   [TSC_OFFSET_HIGH] =
+   SHADOW_VMCS_OFFSET(tsc_offset)+4,
+