]> xenbits.xensource.com Git - xen.git/commitdiff
x86 svm: Clean up and fix start_svm() to avoid memory leaks and
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 18 Jun 2009 08:47:49 +0000 (09:47 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 18 Jun 2009 08:47:49 +0000 (09:47 +0100)
resetting ASID generations.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/x86/cpu/amd.c
xen/arch/x86/hvm/svm/asid.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c

index 48b8cccd20ddf5f146bf79f101f09282509cade3..348a7cebde9559c2d584f6eb4b055fb69d63caaf 100644 (file)
@@ -12,7 +12,7 @@
 #include "cpu.h"
 #include "amd.h"
 
-int start_svm(struct cpuinfo_x86 *c);
+void start_svm(struct cpuinfo_x86 *c);
 
 /*
  * Pre-canned values for overriding the CPUID features 
index 57477aac8fa8f4a3b4022093c70100e270739ac3..bca0d2acf9e4f4df410e62b3e9dc51b804c8744e 100644 (file)
@@ -61,6 +61,7 @@ struct svm_asid_data {
    u32 next_asid;
    u32 max_asid;
    u32 erratum170:1;
+   u32 initialised:1;
 };
 
 static DEFINE_PER_CPU(struct svm_asid_data, svm_asid_data);
@@ -70,7 +71,7 @@ static DEFINE_PER_CPU(struct svm_asid_data, svm_asid_data);
  */
 static struct svm_asid_data *svm_asid_core_data(void)
 {
-    return &get_cpu_var(svm_asid_data);
+    return &this_cpu(svm_asid_data);
 }
 
 /*
@@ -81,6 +82,15 @@ void svm_asid_init(struct cpuinfo_x86 *c)
     int nasids;
     struct svm_asid_data *data = svm_asid_core_data();
 
+    /*
+     * If already initialised, we just bump the generation to force a TLB
+     * flush. Resetting the generation could be dangerous, if VCPUs still
+     * exist that reference earlier generations on this CPU.
+     */
+    if ( data->initialised )
+        return svm_asid_inc_generation();
+    data->initialised = 1;
+
     /* Find #ASID. */
     nasids = cpuid_ebx(0x8000000A);
     data->max_asid = nasids - 1;
index 13ef5d03254eaa838b77ea97e47a9e0e21a00e30..154bc270f8e9f8e5ef6a0c05ca0e59ea81090406 100644 (file)
@@ -839,45 +839,66 @@ static struct hvm_function_table svm_function_table = {
     .invlpg_intercept     = svm_invlpg_intercept
 };
 
-int start_svm(struct cpuinfo_x86 *c)
+static int svm_cpu_up(struct cpuinfo_x86 *c)
 {
-    u32 eax, ecx, edx;
-    u32 phys_hsa_lo, phys_hsa_hi;   
+    u32 eax, edx, phys_hsa_lo, phys_hsa_hi;   
     u64 phys_hsa;
     int cpu = smp_processor_id();
  
-    /* Xen does not fill x86_capability words except 0. */
-    ecx = cpuid_ecx(0x80000001);
-    boot_cpu_data.x86_capability[5] = ecx;
-    
-    if ( !(test_bit(X86_FEATURE_SVME, &boot_cpu_data.x86_capability)) )
-        return 0;
-
     /* Check whether SVM feature is disabled in BIOS */
     rdmsr(MSR_K8_VM_CR, eax, edx);
     if ( eax & K8_VMCR_SVME_DISABLE )
     {
-        printk("AMD SVM Extension is disabled in BIOS.\n");
+        printk("CPU%d: AMD SVM Extension is disabled in BIOS.\n", cpu);
         return 0;
     }
 
-    if ( ((hsa[cpu] = alloc_host_save_area()) == NULL) ||
-         ((root_vmcb[cpu] = alloc_vmcb()) == NULL) )
+    if ( ((hsa[cpu] == NULL) &&
+          ((hsa[cpu] = alloc_host_save_area()) == NULL)) ||
+         ((root_vmcb[cpu] == NULL) &&
+          ((root_vmcb[cpu] = alloc_vmcb()) == NULL)) )
         return 0;
 
     write_efer(read_efer() | EFER_SVME);
 
     /* Initialize the HSA for this core. */
-    phys_hsa = (u64) virt_to_maddr(hsa[cpu]);
-    phys_hsa_lo = (u32) phys_hsa;
-    phys_hsa_hi = (u32) (phys_hsa >> 32);    
+    phys_hsa = (u64)virt_to_maddr(hsa[cpu]);
+    phys_hsa_lo = (u32)phys_hsa;
+    phys_hsa_hi = (u32)(phys_hsa >> 32);    
     wrmsr(MSR_K8_VM_HSAVE_PA, phys_hsa_lo, phys_hsa_hi);
 
     /* Initialize core's ASID handling. */
     svm_asid_init(c);
 
-    if ( cpu != 0 )
-        return 1;
+    return 1;
+}
+
+void start_svm(struct cpuinfo_x86 *c)
+{
+    static bool_t bootstrapped;
+
+    if ( !test_and_set_bool(bootstrapped) )
+    {
+        if ( hvm_enabled && !svm_cpu_up(c) )
+        {
+            printk("SVM: FATAL: failed to initialise CPU%d!\n",
+                   smp_processor_id());
+            BUG();
+        }
+        return;
+    }
+
+    /* Xen does not fill x86_capability words except 0. */
+    boot_cpu_data.x86_capability[5] = cpuid_ecx(0x80000001);
+
+    if ( !test_bit(X86_FEATURE_SVME, &boot_cpu_data.x86_capability) )
+        return;
+
+    if ( !svm_cpu_up(c) )
+    {
+        printk("SVM: failed to initialise.\n");
+        return;
+    }
 
     setup_vmcb_dump();
 
@@ -887,8 +908,6 @@ int start_svm(struct cpuinfo_x86 *c)
     svm_function_table.hap_supported = cpu_has_svm_npt;
 
     hvm_enable(&svm_function_table);
-
-    return 1;
 }
 
 static void svm_do_nested_pgfault(paddr_t gpa, struct cpu_user_regs *regs)
index 13e2d7905189fe1a2204448e15ae108f21ee7854..322652cf2db7a0d13eb1793bed57fe67395fe55b 100644 (file)
@@ -1403,11 +1403,11 @@ static unsigned long *vpid_bitmap;
 
 void start_vmx(void)
 {
-    static int bootstrapped;
+    static bool_t bootstrapped;
 
     vmx_save_host_msrs();
 
-    if ( bootstrapped )
+    if ( !test_and_set_bool(bootstrapped) )
     {
         if ( hvm_enabled && !vmx_cpu_up() )
         {
@@ -1418,8 +1418,6 @@ void start_vmx(void)
         return;
     }
 
-    bootstrapped = 1;
-
     /* Xen does not fill x86_capability words except 0. */
     boot_cpu_data.x86_capability[4] = cpuid_ecx(1);