VirtualBox

Changeset 33939 in vbox


Ignore:
Timestamp:
Nov 10, 2010 4:08:55 PM (14 years ago)
Author:
vboxsync
Message:

Support/linux: the user does not need to disable the Local APIC anymore (this is now done during a world switch)

Location:
trunk/src/VBox
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c

    r33540 r33939  
    2323 * You may elect to license modified versions of this file under the
    2424 * terms and conditions of either the GPL or the CDDL or both.
    25  * Some lines of code to disable the local APIC on x86_64 machines taken
    26  * from a Mandriva patch by Gwenole Beauchesne <[email protected]>.
    2725 */
    2826
     
    5957# include <linux/miscdevice.h>
    6058#endif
    61 #ifdef CONFIG_X86_LOCAL_APIC
    62 # include <asm/apic.h>
    63 # include <asm/nmi.h>
    64 #endif
    6559#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
    6660# include <linux/platform_device.h>
     
    9286# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
    9387#endif
    94 
    95 #ifdef CONFIG_X86_LOCAL_APIC
    96 
    97 /* If an NMI occurs while we are inside the world switcher the machine will
    98  * crash. The Linux NMI watchdog generates periodic NMIs increasing a counter
    99  * which is compared with another counter increased in the timer interrupt
    100  * handler. We disable the NMI watchdog.
    101  *
    102  * - Linux >= 2.6.21: The watchdog is disabled by default on i386 and x86_64.
    103  * - Linux <  2.6.21: The watchdog is normally enabled by default on x86_64
    104  *                    and disabled on i386.
    105  */
    106 # if defined(RT_ARCH_AMD64)
    107 #  if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) && !defined(VBOX_REDHAT_KABI)
    108 #   define DO_DISABLE_NMI 1
    109 #  endif
    110 # endif
    111 
    112 # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
    113 extern int nmi_active;
    114 #  define nmi_atomic_read(P)    *(P)
    115 #  define nmi_atomic_set(P, V)  *(P) = (V)
    116 #  define nmi_atomic_dec(P)     nmi_atomic_set(P, 0)
    117 # else
    118 #  define nmi_atomic_read(P)    atomic_read(P)
    119 #  define nmi_atomic_set(P, V)  atomic_set(P, V)
    120 #  define nmi_atomic_dec(P)     atomic_dec(P)
    121 # endif
    122 
    123 # ifndef X86_FEATURE_ARCH_PERFMON
    124 #  define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
    125 # endif
    126 # ifndef MSR_ARCH_PERFMON_EVENTSEL0
    127 #  define MSR_ARCH_PERFMON_EVENTSEL0 0x186
    128 # endif
    129 # ifndef ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT
    130 #  define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
    131 # endif
    132 
    133 #endif /* CONFIG_X86_LOCAL_APIC */
    13488
    13589
     
    264218
    265219
    266 
    267 
    268 
    269 #ifdef CONFIG_X86_LOCAL_APIC
    270 # ifdef DO_DISABLE_NMI
    271 /** Stop AMD NMI watchdog (x86_64 only). */
    272 static int vboxdrvStopK7Watchdog(void)
    273 {
    274     wrmsr(MSR_K7_EVNTSEL0, 0, 0);
    275     return 1;
    276 }
    277 
    278 /** Stop Intel P4 NMI watchdog (x86_64 only). */
    279 static int vboxdrvStopP4Watchdog(void)
    280 {
    281     wrmsr(MSR_P4_IQ_CCCR0,  0, 0);
    282     wrmsr(MSR_P4_IQ_CCCR1,  0, 0);
    283     wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
    284     return 1;
    285 }
    286 
    287 /** The new method of detecting the event counter */
    288 static int vboxdrvStopIntelArchWatchdog(void)
    289 {
    290     unsigned ebx;
    291 
    292     ebx = cpuid_ebx(10);
    293     if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
    294         wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
    295     return 1;
    296 }
    297 
    298 /** Stop NMI watchdog. */
    299 static void vboxdrvStopApicNmiWatchdog(void *unused)
    300 {
    301     int stopped = 0;
    302 
    303     /* only support LOCAL and IO APICs for now */
    304     if ((nmi_watchdog != NMI_LOCAL_APIC) &&
    305         (nmi_watchdog != NMI_IO_APIC))
    306         return;
    307 
    308     if (nmi_watchdog == NMI_LOCAL_APIC)
    309     {
    310         switch (boot_cpu_data.x86_vendor)
    311         {
    312         case X86_VENDOR_AMD:
    313             if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
    314                return;
    315             stopped = vboxdrvStopK7Watchdog();
    316             break;
    317         case X86_VENDOR_INTEL:
    318             if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
    319             {
    320                 stopped = vboxdrvStopIntelArchWatchdog();
    321                 break;
    322             }
    323             stopped = vboxdrvStopP4Watchdog();
    324             break;
    325         default:
    326             return;
    327         }
    328     }
    329 
    330     if (stopped)
    331         nmi_atomic_dec(&nmi_active);
    332 }
    333 
    334 /** Disable LAPIC NMI watchdog. */
    335 static void DisableLapicNmiWatchdog(void)
    336 {
    337     BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
    338 
    339     if (nmi_atomic_read(&nmi_active) <= 0)
    340         return;
    341 
    342     on_each_cpu(vboxdrvStopApicNmiWatchdog, NULL, 1, 1);
    343 
    344     BUG_ON(nmi_atomic_read(&nmi_active) != 0);
    345 
    346     /* tell do_nmi() and others that we're not active any more */
    347     nmi_watchdog = NMI_NONE;
    348 }
    349 
    350 /** Shutdown NMI. */
    351 static void vboxdrvNmiCpuShutdown(void * dummy)
    352 {
    353     unsigned int vERR, vPC;
    354 
    355     vPC = apic_read(APIC_LVTPC);
    356 
    357     if ((GET_APIC_DELIVERY_MODE(vPC) == APIC_MODE_NMI) && !(vPC & APIC_LVT_MASKED))
    358     {
    359         vERR = apic_read(APIC_LVTERR);
    360         apic_write(APIC_LVTERR, vERR | APIC_LVT_MASKED);
    361         apic_write(APIC_LVTPC,  vPC  | APIC_LVT_MASKED);
    362         apic_write(APIC_LVTERR, vERR);
    363     }
    364 }
    365 
    366 static void vboxdrvNmiShutdown(void)
    367 {
    368     on_each_cpu(vboxdrvNmiCpuShutdown, NULL, 0, 1);
    369 }
    370 # endif /* DO_DISABLE_NMI */
    371 #endif /* CONFIG_X86_LOCAL_APIC */
    372 
    373 
    374220DECLINLINE(RTUID) vboxdrvLinuxUid(void)
    375221{
     
    407253{
    408254    int       rc;
    409 
    410 #ifdef CONFIG_X86_LOCAL_APIC
    411     /*
    412      * If an NMI occurs while we are inside the world switcher the machine will crash.
    413      * The Linux NMI watchdog generates periodic NMIs increasing a counter which is
    414      * compared with another counter increased in the timer interrupt handler. Therefore
    415      * we don't allow to setup an NMI watchdog.
    416      */
    417 # if !defined(VBOX_REDHAT_KABI)
    418     /*
    419      * First test: NMI activated? Works only works with Linux 2.6 -- 2.4 does not export
    420      *             the nmi_watchdog variable.
    421      */
    422 #  if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || defined CONFIG_X86_64
    423 #   ifdef DO_DISABLE_NMI
    424     if (nmi_atomic_read(&nmi_active) > 0)
    425     {
    426         printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog...\n");
    427 
    428         switch (nmi_watchdog)
    429         {
    430             case NMI_LOCAL_APIC:
    431                 DisableLapicNmiWatchdog();
    432                 break;
    433             case NMI_NONE:
    434                 nmi_atomic_dec(&nmi_active);
    435                 break;
    436         }
    437 
    438         if (nmi_atomic_read(&nmi_active) == 0)
    439         {
    440             vboxdrvNmiShutdown();
    441             printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
    442         }
    443         else
    444             printk(KERN_DEBUG DEVICE_NAME ": Failed!\n");
    445     }
    446 #   endif /* DO_DISABLE_NMI */
    447 
    448     /*
    449      * Permanent IO_APIC mode active? No way to handle this!
    450      */
    451     if (nmi_watchdog == NMI_IO_APIC)
    452     {
    453         printk(KERN_ERR DEVICE_NAME
    454                ": NMI watchdog in IO_APIC mode active -- refused to load the kernel module!\n"
    455                         DEVICE_NAME
    456                ": Please disable the NMI watchdog by specifying 'nmi_watchdog=0' at kernel\n"
    457                         DEVICE_NAME
    458                ": command line.\n");
    459         return -EINVAL;
    460     }
    461 
    462     /*
    463      * See arch/i386/kernel/nmi.c on >= 2.6.19: -1 means it can never enabled again
    464      */
    465     nmi_atomic_set(&nmi_active, -1);
    466     printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog permanently...\n");
    467 
    468     /*
    469      * Now fall through and see if it actually was enabled before. If so, fail
    470      * as we cannot deactivate it cleanly from here.
    471      */
    472 #  else /* < 2.6.19 */
    473     /*
    474      * Older 2.6 kernels: nmi_watchdog is not initialized by default
    475      */
    476     if (nmi_watchdog != NMI_NONE)
    477         goto nmi_activated;
    478 #  endif
    479 # endif /* >= 2.6.0 && !defined(VBOX_REDHAT_KABI) */
    480 
    481     /*
    482      * Second test: Interrupt generated by performance counter not masked and can
    483      *              generate an NMI. Works also with Linux 2.4.
    484      */
    485     {
    486         unsigned int v, ver, maxlvt;
    487 
    488         v   = apic_read(APIC_LVR);
    489         ver = GET_APIC_VERSION(v);
    490         /* 82489DXs do not report # of LVT entries. */
    491         maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
    492         if (maxlvt >= 4)
    493         {
    494             /* Read status of performance counter IRQ vector */
    495             v = apic_read(APIC_LVTPC);
    496 
    497             /* performance counter generates NMI and is not masked? */
    498             if ((GET_APIC_DELIVERY_MODE(v) == APIC_MODE_NMI) && !(v & APIC_LVT_MASKED))
    499             {
    500 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) \
    501      && (defined(CONFIG_PERF_COUNTERS) || defined(CONFIG_PERF_EVENTS))
    502                 /* 2.6.31+: The performance counter framework will initialize the LVTPC
    503                  * vector as NMI. We can't disable the framework but the kernel loader
    504                  * script will do 'echo 2 > /proc/sys/kernel/perf_counter_paranoid'
    505                  * which hopefully prevents any usage of hardware performance counters
    506                  * and therefore triggering of NMIs.
    507                  * 2.6.32+: CONFIG_PERF_COUNTERS => CONFIG_PERF_EVENTS */
    508                 printk(KERN_ERR DEVICE_NAME
    509                        ": Warning: 2.6.31+ kernel detected. Most likely the hardware performance\n"
    510                                 DEVICE_NAME
    511                        ": counter framework which can generate NMIs is active. You have to prevent\n"
    512                                 DEVICE_NAME
    513                        ": the usage of hardware performance counters by\n"
    514                                 DEVICE_NAME
    515                        ":   echo 2 > /proc/sys/kernel/perf_counter_paranoid\n");
    516                 /* We can't do more here :-( */
    517                 goto no_error;
    518 # endif
    519 
    520 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || defined CONFIG_X86_64
    521                 printk(KERN_ERR DEVICE_NAME
    522                 ": NMI watchdog either active or at least initialized. Please disable the NMI\n"
    523                                 DEVICE_NAME
    524                 ": watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
    525                 return -EINVAL;
    526 # else /* < 2.6.19 */
    527 #  if !defined(VBOX_REDHAT_KABI)
    528 nmi_activated:
    529 #  endif
    530                 printk(KERN_ERR DEVICE_NAME
    531                 ": NMI watchdog active -- refused to load the kernel module! Please disable\n"
    532                                 DEVICE_NAME
    533                 ": the NMI watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
    534                 return -EINVAL;
    535 # endif /* >= 2.6.19 */
    536             }
    537         }
    538     }
    539 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
    540     printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
    541 #  if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) \
    542       && (defined(CONFIG_PERF_COUNTERS) || defined(CONFIG_PERF_EVENTS))
    543 no_error:
    544 #  endif
    545 # endif /* >= 2.6.19 */
    546 #endif /* CONFIG_X86_LOCAL_APIC */
    547255
    548256    /*
  • trunk/src/VBox/Installer/linux/vboxdrv.sh.in

    r32548 r33939  
    165165        if ! rm -f $DEVICE; then
    166166            failure "Cannot remove $DEVICE"
    167         fi
    168         # HACK: disable the hardware performance counter framework
    169         if [ -e /proc/sys/kernel/perf_counter_paranoid ]; then
    170           echo 2 > /proc/sys/kernel/perf_counter_paranoid
    171167        fi
    172168        if ! $MODPROBE vboxdrv > /dev/null 2>&1; then
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette