Changeset 33939 in vbox
- Timestamp:
- Nov 10, 2010 4:08:55 PM (14 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
r33540 r33939 23 23 * You may elect to license modified versions of this file under the 24 24 * 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 taken26 * from a Mandriva patch by Gwenole Beauchesne <[email protected]>.27 25 */ 28 26 … … 59 57 # include <linux/miscdevice.h> 60 58 #endif 61 #ifdef CONFIG_X86_LOCAL_APIC62 # include <asm/apic.h>63 # include <asm/nmi.h>64 #endif65 59 #ifdef VBOX_WITH_SUSPEND_NOTIFICATION 66 60 # include <linux/platform_device.h> … … 92 86 # error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time." 93 87 #endif 94 95 #ifdef CONFIG_X86_LOCAL_APIC96 97 /* If an NMI occurs while we are inside the world switcher the machine will98 * crash. The Linux NMI watchdog generates periodic NMIs increasing a counter99 * which is compared with another counter increased in the timer interrupt100 * 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_64104 * 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 1109 # endif110 # endif111 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 # else118 # 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 # endif122 123 # ifndef X86_FEATURE_ARCH_PERFMON124 # define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */125 # endif126 # ifndef MSR_ARCH_PERFMON_EVENTSEL0127 # define MSR_ARCH_PERFMON_EVENTSEL0 0x186128 # endif129 # ifndef ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT130 # define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)131 # endif132 133 #endif /* CONFIG_X86_LOCAL_APIC */134 88 135 89 … … 264 218 265 219 266 267 268 269 #ifdef CONFIG_X86_LOCAL_APIC270 # ifdef DO_DISABLE_NMI271 /** 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 374 220 DECLINLINE(RTUID) vboxdrvLinuxUid(void) 375 221 { … … 407 253 { 408 254 int rc; 409 410 #ifdef CONFIG_X86_LOCAL_APIC411 /*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 is414 * compared with another counter increased in the timer interrupt handler. Therefore415 * 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 export420 * the nmi_watchdog variable.421 */422 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || defined CONFIG_X86_64423 # ifdef DO_DISABLE_NMI424 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 else444 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_NAME454 ": NMI watchdog in IO_APIC mode active -- refused to load the kernel module!\n"455 DEVICE_NAME456 ": Please disable the NMI watchdog by specifying 'nmi_watchdog=0' at kernel\n"457 DEVICE_NAME458 ": 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 again464 */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, fail470 * 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 default475 */476 if (nmi_watchdog != NMI_NONE)477 goto nmi_activated;478 # endif479 # endif /* >= 2.6.0 && !defined(VBOX_REDHAT_KABI) */480 481 /*482 * Second test: Interrupt generated by performance counter not masked and can483 * 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 LVTPC503 * vector as NMI. We can't disable the framework but the kernel loader504 * script will do 'echo 2 > /proc/sys/kernel/perf_counter_paranoid'505 * which hopefully prevents any usage of hardware performance counters506 * and therefore triggering of NMIs.507 * 2.6.32+: CONFIG_PERF_COUNTERS => CONFIG_PERF_EVENTS */508 printk(KERN_ERR DEVICE_NAME509 ": Warning: 2.6.31+ kernel detected. Most likely the hardware performance\n"510 DEVICE_NAME511 ": counter framework which can generate NMIs is active. You have to prevent\n"512 DEVICE_NAME513 ": the usage of hardware performance counters by\n"514 DEVICE_NAME515 ": echo 2 > /proc/sys/kernel/perf_counter_paranoid\n");516 /* We can't do more here :-( */517 goto no_error;518 # endif519 520 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || defined CONFIG_X86_64521 printk(KERN_ERR DEVICE_NAME522 ": NMI watchdog either active or at least initialized. Please disable the NMI\n"523 DEVICE_NAME524 ": 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 # endif530 printk(KERN_ERR DEVICE_NAME531 ": NMI watchdog active -- refused to load the kernel module! Please disable\n"532 DEVICE_NAME533 ": 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 # endif545 # endif /* >= 2.6.19 */546 #endif /* CONFIG_X86_LOCAL_APIC */547 255 548 256 /* -
trunk/src/VBox/Installer/linux/vboxdrv.sh.in
r32548 r33939 165 165 if ! rm -f $DEVICE; then 166 166 failure "Cannot remove $DEVICE" 167 fi168 # HACK: disable the hardware performance counter framework169 if [ -e /proc/sys/kernel/perf_counter_paranoid ]; then170 echo 2 > /proc/sys/kernel/perf_counter_paranoid171 167 fi 172 168 if ! $MODPROBE vboxdrv > /dev/null 2>&1; then
Note:
See TracChangeset
for help on using the changeset viewer.