ioapic: By default, disable I/O APIC if we are booting on a virtual machine
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 14 Mar 2012 03:18:44 +0000 (11:18 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 14 Mar 2012 03:18:44 +0000 (11:18 +0800)
I/O APIC causes too much trouble on virtual machines; simply disable
I/O APIC for virtual machines by default.

You could always explicitly enable I/O APIC on virtual machines by
setting tunable hw.ioapic_enable to 1

Thank swildner@ for hint on virtual machine detection method.

Reported-by: many
sys/platform/pc32/apic/ioapic.c
sys/platform/pc32/i386/machdep.c
sys/platform/pc64/apic/ioapic.c
sys/platform/pc64/x86_64/machdep.c

index 55db0e1..18d06f1 100644 (file)
@@ -80,7 +80,7 @@ static struct ioapic_conf     ioapic_conf;
 static TAILQ_HEAD(, ioapic_enumerator) ioapic_enumerators =
        TAILQ_HEAD_INITIALIZER(ioapic_enumerators);
 
-int            ioapic_enable = 1; /* I/O APIC is enabled by default */
+int            ioapic_enable = -1; /* I/O APIC auto-enable mode */
 
 static int
 ioapic_config(void)
index 85c18db..6864c51 100644 (file)
@@ -1953,6 +1953,19 @@ init386(int first)
        TUNABLE_INT_FETCH("hw.lapic_enable", &lapic_enable);
 
        /*
+        * Some of the virtaul machines do not work w/ I/O APIC
+        * enabled.  If the user does not explicitly enable or
+        * disable the I/O APIC (ioapic_enable < 0), then we
+        * disable I/O APIC on all virtual machines.
+        */
+       if (ioapic_enable < 0) {
+               if (cpu_feature2 & CPUID2_VMM)
+                       ioapic_enable = 0;
+               else
+                       ioapic_enable = 1;
+       }
+
+       /*
         * start with one cpu.  Note: with one cpu, ncpus2_shift, ncpus2_mask,
         * and ncpus_fit_mask remain 0.
         */
index a1e6709..6065205 100644 (file)
@@ -80,7 +80,7 @@ static struct ioapic_conf     ioapic_conf;
 static TAILQ_HEAD(, ioapic_enumerator) ioapic_enumerators =
        TAILQ_HEAD_INITIALIZER(ioapic_enumerators);
 
-int            ioapic_enable = 1; /* I/O APIC is enabled by default */
+int            ioapic_enable = -1; /* I/O APIC auto-enable mode */
 
 static int
 ioapic_config(void)
index ac879b7..4260785 100644 (file)
@@ -1795,10 +1795,6 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
         */
        MachIntrABI = MachIntrABI_ICU;
 
-       TUNABLE_INT_FETCH("hw.apic_io_enable", &ioapic_enable); /* for compat */
-       TUNABLE_INT_FETCH("hw.ioapic_enable", &ioapic_enable);
-       TUNABLE_INT_FETCH("hw.lapic_enable", &lapic_enable);
-
        /*
         * start with one cpu.  Note: with one cpu, ncpus2_shift, ncpus2_mask,
         * and ncpus_fit_mask remain 0.
@@ -1910,6 +1906,27 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
        identify_cpu();         /* Final stage of CPU initialization */
        initializecpu();        /* Initialize CPU registers */
 
+       TUNABLE_INT_FETCH("hw.apic_io_enable", &ioapic_enable); /* for compat */
+       TUNABLE_INT_FETCH("hw.ioapic_enable", &ioapic_enable);
+       TUNABLE_INT_FETCH("hw.lapic_enable", &lapic_enable);
+
+       /*
+        * Some of the virtaul machines do not work w/ I/O APIC
+        * enabled.  If the user does not explicitly enable or
+        * disable the I/O APIC (ioapic_enable < 0), then we
+        * disable I/O APIC on all virtual machines.
+        *
+        * NOTE:
+        * This must be done after identify_cpu(), which sets
+        * 'cpu_feature2'
+        */
+       if (ioapic_enable < 0) {
+               if (cpu_feature2 & CPUID2_VMM)
+                       ioapic_enable = 0;
+               else
+                       ioapic_enable = 1;
+       }
+
        /* make an initial tss so cpu can get interrupt stack on syscall! */
        gd->gd_common_tss.tss_rsp0 =
                (register_t)(thread0.td_kstack +