References: FATE#313605

# HG changeset patch
# User Jiongxi Li <jiongxi.li@intel.com>
# Date 1361176458 -3600
# Node ID 45d59b822ed187c535b127679e32853b148ed411
# Parent  4c3355d776e115f979fd2abc135bb77ba710f0d4
x86/VMX: fix VMCS setting for x2APIC mode guest while enabling APICV

The "APIC-register virtualization" and "virtual-interrupt deliver"
VM-execution control has no effect on the behavior of RDMSR/WRMSR if
the "virtualize x2APIC mode" VM-execution control is 0.
When guest uses x2APIC mode, we should enable "virtualize x2APIC mode"
for APICV first.

Signed-off-by: Jiongxi Li <jiongxi.li@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
Acked-by: Jun Nakajima <jun.nakajima@intel.com>
Committed-by: Jan Beulich <jbeulich@suse.com>

Index: xen-4.2.5-testing/xen/arch/x86/hvm/vmx/vmcs.c
===================================================================
--- xen-4.2.5-testing.orig/xen/arch/x86/hvm/vmx/vmcs.c
+++ xen-4.2.5-testing/xen/arch/x86/hvm/vmx/vmcs.c
@@ -194,7 +194,8 @@ static int vmx_init_vmcs_config(void)
          */
         if ( _vmx_cpu_based_exec_control & CPU_BASED_TPR_SHADOW )
             opt |= SECONDARY_EXEC_APIC_REGISTER_VIRT |
-                   SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
+                   SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
+                   SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
 
 
         _vmx_secondary_exec_control = adjust_vmx_controls(
@@ -682,22 +683,27 @@ void vmx_disable_intercept_for_msr(struc
      */
     if ( msr <= 0x1fff )
     {
-        if (type & MSR_TYPE_R)
-            __clear_bit(msr, msr_bitmap + 0x000/BYTES_PER_LONG); /* read-low */
-        if (type & MSR_TYPE_W)
-            __clear_bit(msr, msr_bitmap + 0x800/BYTES_PER_LONG); /* write-low */
+        if ( type & MSR_TYPE_R )
+            clear_bit(msr, msr_bitmap + 0x000/BYTES_PER_LONG); /* read-low */
+        if ( type & MSR_TYPE_W )
+            clear_bit(msr, msr_bitmap + 0x800/BYTES_PER_LONG); /* write-low */
     }
     else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
     {
         msr &= 0x1fff;
-        if (type & MSR_TYPE_R)
-            __clear_bit(msr, msr_bitmap + 0x400/BYTES_PER_LONG); /* read-high */
-        if (type & MSR_TYPE_W)
-            __clear_bit(msr, msr_bitmap + 0xc00/BYTES_PER_LONG); /* write-high */
+        if ( type & MSR_TYPE_R )
+            clear_bit(msr, msr_bitmap + 0x400/BYTES_PER_LONG); /* read-high */
+        if ( type & MSR_TYPE_W )
+            clear_bit(msr, msr_bitmap + 0xc00/BYTES_PER_LONG); /* write-high */
     }
+    else
+        HVM_DBG_LOG(DBG_LEVEL_0,
+                   "msr %x is out of the control range"
+                   "0x00000000-0x00001fff and 0xc0000000-0xc0001fff"
+                   "RDMSR or WRMSR will cause a VM exit", msr);
 }
 
-void vmx_enable_intercept_for_msr(struct vcpu *v, u32 msr)
+void vmx_enable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
 {
     unsigned long *msr_bitmap = v->arch.hvm_vmx.msr_bitmap;
 
@@ -712,15 +718,24 @@ void vmx_enable_intercept_for_msr(struct
      */
     if ( msr <= 0x1fff )
     {
-        set_bit(msr, msr_bitmap + 0x000/BYTES_PER_LONG); /* read-low */
-        set_bit(msr, msr_bitmap + 0x800/BYTES_PER_LONG); /* write-low */
+        if ( type & MSR_TYPE_R )
+            set_bit(msr, msr_bitmap + 0x000/BYTES_PER_LONG); /* read-low */
+        if ( type & MSR_TYPE_W )
+            set_bit(msr, msr_bitmap + 0x800/BYTES_PER_LONG); /* write-low */
     }
     else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
     {
         msr &= 0x1fff;
-        set_bit(msr, msr_bitmap + 0x400/BYTES_PER_LONG); /* read-high */
-        set_bit(msr, msr_bitmap + 0xc00/BYTES_PER_LONG); /* write-high */
+        if ( type & MSR_TYPE_R )
+            set_bit(msr, msr_bitmap + 0x400/BYTES_PER_LONG); /* read-high */
+        if ( type & MSR_TYPE_W )
+            set_bit(msr, msr_bitmap + 0xc00/BYTES_PER_LONG); /* write-high */
     }
+    else
+        HVM_DBG_LOG(DBG_LEVEL_0,
+                   "msr %x is out of the control range"
+                   "0x00000000-0x00001fff and 0xc0000000-0xc0001fff"
+                   "RDMSR or WRMSR will cause a VM exit", msr);
 }
 
 /*
@@ -786,6 +801,10 @@ static int construct_vmcs(struct vcpu *v
         vmentry_ctl &= ~VM_ENTRY_LOAD_GUEST_PAT;
     }
 
+    /* Disable Virtualize x2APIC mode by default. */
+    v->arch.hvm_vmx.secondary_exec_control &=
+        ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
+
     /* Do not enable Monitor Trap Flag unless start single step debug */
     v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
 
@@ -823,18 +842,6 @@ static int construct_vmcs(struct vcpu *v
         vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_EIP, MSR_TYPE_R | MSR_TYPE_W);
         if ( paging_mode_hap(d) && (!iommu_enabled || iommu_snoop) )
             vmx_disable_intercept_for_msr(v, MSR_IA32_CR_PAT, MSR_TYPE_R | MSR_TYPE_W);
-        if ( cpu_has_vmx_apic_reg_virt )
-        {
-            int msr;
-            for (msr = MSR_IA32_APICBASE_MSR; msr <= MSR_IA32_APICBASE_MSR + 0xff; msr++)
-                vmx_disable_intercept_for_msr(v, msr, MSR_TYPE_R);
-        }
-        if ( cpu_has_vmx_virtual_intr_delivery )
-        {
-            vmx_disable_intercept_for_msr(v, MSR_IA32_APICTPR_MSR, MSR_TYPE_W);
-            vmx_disable_intercept_for_msr(v, MSR_IA32_APICEOI_MSR, MSR_TYPE_W);
-            vmx_disable_intercept_for_msr(v, MSR_IA32_APICSELF_MSR, MSR_TYPE_W);
-        }
     }
 
     /* I/O access bitmap. */
Index: xen-4.2.5-testing/xen/arch/x86/hvm/vmx/vmx.c
===================================================================
--- xen-4.2.5-testing.orig/xen/arch/x86/hvm/vmx/vmx.c
+++ xen-4.2.5-testing/xen/arch/x86/hvm/vmx/vmx.c
@@ -2092,18 +2092,63 @@ static void vmx_install_vlapic_mapping(s
 
 void vmx_vlapic_msr_changed(struct vcpu *v)
 {
+    int virtualize_x2apic_mode;
     struct vlapic *vlapic = vcpu_vlapic(v);
 
-    if ( !cpu_has_vmx_virtualize_apic_accesses )
+    virtualize_x2apic_mode = ( (cpu_has_vmx_apic_reg_virt ||
+                                cpu_has_vmx_virtual_intr_delivery) &&
+                               cpu_has_vmx_virtualize_x2apic_mode );
+
+    if ( !cpu_has_vmx_virtualize_apic_accesses &&
+         !virtualize_x2apic_mode )
         return;
 
     vmx_vmcs_enter(v);
     v->arch.hvm_vmx.secondary_exec_control &=
-        ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+        ~(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
+          SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE);
     if ( !vlapic_hw_disabled(vlapic) &&
          (vlapic_base_address(vlapic) == APIC_DEFAULT_PHYS_BASE) )
-        v->arch.hvm_vmx.secondary_exec_control |=
-            SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+    {
+        unsigned int msr;
+
+        if ( virtualize_x2apic_mode && vlapic_x2apic_mode(vlapic) )
+        {
+            v->arch.hvm_vmx.secondary_exec_control |=
+                SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
+            if ( cpu_has_vmx_apic_reg_virt )
+            {
+                for ( msr = MSR_IA32_APICBASE_MSR;
+                      msr <= MSR_IA32_APICBASE_MSR + 0xff; msr++ )
+                    vmx_disable_intercept_for_msr(v, msr, MSR_TYPE_R);
+
+                vmx_enable_intercept_for_msr(v, MSR_IA32_APICPPR_MSR,
+                                             MSR_TYPE_R);
+                vmx_enable_intercept_for_msr(v, MSR_IA32_APICTMICT_MSR,
+                                             MSR_TYPE_R);
+                vmx_enable_intercept_for_msr(v, MSR_IA32_APICTMCCT_MSR,
+                                             MSR_TYPE_R);
+            }
+            if ( cpu_has_vmx_virtual_intr_delivery )
+            {
+                vmx_disable_intercept_for_msr(v, MSR_IA32_APICTPR_MSR,
+                                              MSR_TYPE_W);
+                vmx_disable_intercept_for_msr(v, MSR_IA32_APICEOI_MSR,
+                                              MSR_TYPE_W);
+                vmx_disable_intercept_for_msr(v, MSR_IA32_APICSELF_MSR,
+                                              MSR_TYPE_W);
+            }
+        }
+        else
+        {
+            v->arch.hvm_vmx.secondary_exec_control |=
+                SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+            for ( msr = MSR_IA32_APICBASE_MSR;
+                  msr <= MSR_IA32_APICBASE_MSR + 0xff; msr++ )
+                vmx_enable_intercept_for_msr(v, msr,
+                                             MSR_TYPE_R | MSR_TYPE_W);
+        }
+    }
     vmx_update_secondary_exec_control(v);
     vmx_vmcs_exit(v);
 }
Index: xen-4.2.5-testing/xen/include/asm-x86/hvm/vmx/vmcs.h
===================================================================
--- xen-4.2.5-testing.orig/xen/include/asm-x86/hvm/vmx/vmcs.h
+++ xen-4.2.5-testing/xen/include/asm-x86/hvm/vmx/vmcs.h
@@ -183,6 +183,7 @@ extern u32 vmx_vmentry_control;
 #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
 #define SECONDARY_EXEC_ENABLE_EPT               0x00000002
 #define SECONDARY_EXEC_ENABLE_RDTSCP            0x00000008
+#define SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE   0x00000010
 #define SECONDARY_EXEC_ENABLE_VPID              0x00000020
 #define SECONDARY_EXEC_WBINVD_EXITING           0x00000040
 #define SECONDARY_EXEC_UNRESTRICTED_GUEST       0x00000080
@@ -240,6 +241,8 @@ extern bool_t cpu_has_vmx_ins_outs_instr
     (vmx_secondary_exec_control & SECONDARY_EXEC_APIC_REGISTER_VIRT)
 #define cpu_has_vmx_virtual_intr_delivery \
     (vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)
+#define cpu_has_vmx_virtualize_x2apic_mode \
+    (vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)
 
 /* GUEST_INTERRUPTIBILITY_INFO flags. */
 #define VMX_INTR_SHADOW_STI             0x00000001
@@ -415,7 +418,7 @@ enum vmcs_field {
 #define MSR_TYPE_R 1
 #define MSR_TYPE_W 2
 void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type);
-void vmx_enable_intercept_for_msr(struct vcpu *v, u32 msr);
+void vmx_enable_intercept_for_msr(struct vcpu *v, u32 msr, int type);
 int vmx_read_guest_msr(u32 msr, u64 *val);
 int vmx_write_guest_msr(u32 msr, u64 val);
 int vmx_add_guest_msr(u32 msr);
Index: xen-4.2.5-testing/xen/include/asm-x86/msr-index.h
===================================================================
--- xen-4.2.5-testing.orig/xen/include/asm-x86/msr-index.h
+++ xen-4.2.5-testing/xen/include/asm-x86/msr-index.h
@@ -296,7 +296,10 @@
 #define MSR_IA32_APICBASE_BASE		(0xfffff<<12)
 #define MSR_IA32_APICBASE_MSR           0x800
 #define MSR_IA32_APICTPR_MSR            0x808
+#define MSR_IA32_APICPPR_MSR            0x80a
 #define MSR_IA32_APICEOI_MSR            0x80b
+#define MSR_IA32_APICTMICT_MSR          0x838
+#define MSR_IA32_APICTMCCT_MSR          0x839
 #define MSR_IA32_APICSELF_MSR           0x83f
 
 #define MSR_IA32_UCODE_WRITE		0x00000079
