VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c@ 16793

Last change on this file since 16793 was 15999, checked in by vboxsync, 16 years ago

hrmpf

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.9 KB
Line 
1/* $Rev: 15999 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 * Some lines of code to disable the local APIC on x86_64 machines taken
30 * from a Mandriva patch by Gwenole Beauchesne <[email protected]>.
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#define LOG_GROUP LOG_GROUP_SUP_DRV
37#include "../SUPDrvInternal.h"
38#include "the-linux-kernel.h"
39#include "version-generated.h"
40
41#include <iprt/assert.h>
42#include <iprt/spinlock.h>
43#include <iprt/semaphore.h>
44#include <iprt/initterm.h>
45#include <iprt/process.h>
46#include <iprt/err.h>
47#include <iprt/mem.h>
48#include <VBox/log.h>
49#include <iprt/mp.h>
50
51/** @todo figure out the exact version number */
52#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
53# include <iprt/power.h>
54# define VBOX_WITH_SUSPEND_NOTIFICATION
55#endif
56
57#include <linux/sched.h>
58#ifdef CONFIG_DEVFS_FS
59# include <linux/devfs_fs_kernel.h>
60#endif
61#ifdef CONFIG_VBOXDRV_AS_MISC
62# include <linux/miscdevice.h>
63#endif
64#ifdef CONFIG_X86_LOCAL_APIC
65# include <asm/apic.h>
66# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
67# include <asm/nmi.h>
68# endif
69#endif
70#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
71# include <linux/platform_device.h>
72#endif
73
74#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
75# include <asm/pgtable.h>
76# define global_flush_tlb __flush_tlb_global
77#endif
78
79#include <iprt/mem.h>
80
81
82/* devfs defines */
83#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
84# ifdef VBOX_WITH_HARDENING
85# define VBOX_DEV_FMASK (S_IWUSR | S_IRUSR)
86# else
87# define VBOX_DEV_FMASK (S_IRUGO | S_IWUGO)
88# endif
89
90# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
91
92# define VBOX_REGISTER_DEVFS() \
93({ \
94 void *rc = NULL; \
95 if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), \
96 S_IFCHR | VBOX_DEV_FMASK, \
97 DEVICE_NAME) == 0) \
98 rc = (void *)' '; /* return not NULL */ \
99 rc; \
100 })
101
102# define VBOX_UNREGISTER_DEVFS(handle) \
103 devfs_remove(DEVICE_NAME);
104
105# else /* < 2.6.0 */
106
107# define VBOX_REGISTER_DEVFS() \
108 devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, \
109 DEVICE_MAJOR, 0, \
110 S_IFCHR | VBOX_DEV_FMASK, \
111 &gFileOpsVBoxDrv, NULL)
112
113# define VBOX_UNREGISTER_DEVFS(handle) \
114 if (handle != NULL) \
115 devfs_unregister(handle)
116
117# endif /* < 2.6.0 */
118#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
119
120#ifndef CONFIG_VBOXDRV_AS_MISC
121# if defined(CONFIG_DEVFS_FS) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 0)
122# define VBOX_REGISTER_DEVICE(a,b,c) devfs_register_chrdev(a,b,c)
123# define VBOX_UNREGISTER_DEVICE(a,b) devfs_unregister_chrdev(a,b)
124# else
125# define VBOX_REGISTER_DEVICE(a,b,c) register_chrdev(a,b,c)
126# define VBOX_UNREGISTER_DEVICE(a,b) unregister_chrdev(a,b)
127# endif
128#endif /* !CONFIG_VBOXDRV_AS_MISC */
129
130
131#ifdef CONFIG_X86_HIGH_ENTRY
132# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
133#endif
134
135#ifdef CONFIG_X86_LOCAL_APIC
136
137/* If an NMI occurs while we are inside the world switcher the machine will
138 * crash. The Linux NMI watchdog generates periodic NMIs increasing a counter
139 * which is compared with another counter increased in the timer interrupt
140 * handler. We disable the NMI watchdog.
141 *
142 * - Linux >= 2.6.21: The watchdog is disabled by default on i386 and x86_64.
143 * - Linux < 2.6.21: The watchdog is normally enabled by default on x86_64
144 * and disabled on i386.
145 */
146# if defined(RT_ARCH_AMD64)
147# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) && !defined(VBOX_REDHAT_KABI)
148# define DO_DISABLE_NMI 1
149# endif
150# endif
151
152# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
153extern int nmi_active;
154# define nmi_atomic_read(P) *(P)
155# define nmi_atomic_set(P, V) *(P) = (V)
156# define nmi_atomic_dec(P) nmi_atomic_set(P, 0)
157# else
158# define nmi_atomic_read(P) atomic_read(P)
159# define nmi_atomic_set(P, V) atomic_set(P, V)
160# define nmi_atomic_dec(P) atomic_dec(P)
161# endif
162
163# ifndef X86_FEATURE_ARCH_PERFMON
164# define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
165# endif
166# ifndef MSR_ARCH_PERFMON_EVENTSEL0
167# define MSR_ARCH_PERFMON_EVENTSEL0 0x186
168# endif
169# ifndef ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT
170# define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
171# endif
172
173#endif /* CONFIG_X86_LOCAL_APIC */
174
175#define xstr(s) str(s)
176#define str(s) #s
177
178
179/*******************************************************************************
180* Global Variables *
181*******************************************************************************/
182/**
183 * Device extention & session data association structure.
184 */
185static SUPDRVDEVEXT g_DevExt;
186
187/** Registered devfs device handle. */
188#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
189# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
190static void *g_hDevFsVBoxDrv = NULL;
191# else
192static devfs_handle_t g_hDevFsVBoxDrv = NULL;
193# endif
194#endif
195
196#ifndef CONFIG_VBOXDRV_AS_MISC
197/** Module major number */
198#define DEVICE_MAJOR 234
199/** Saved major device number */
200static int g_iModuleMajor;
201#endif /* !CONFIG_VBOXDRV_AS_MISC */
202
203/** Module parameter.
204 * Not prefixed because the name is used by macros and the end of this file. */
205static int force_async_tsc = 0;
206
207/** The module name. */
208#define DEVICE_NAME "vboxdrv"
209
210#ifdef RT_ARCH_AMD64
211/**
212 * Memory for the executable memory heap (in IPRT).
213 */
214extern uint8_t g_abExecMemory[1572864]; /* 1.5 MB */
215__asm__(".section execmemory, \"awx\", @progbits\n\t"
216 ".align 32\n\t"
217 ".globl g_abExecMemory\n"
218 "g_abExecMemory:\n\t"
219 ".zero 1572864\n\t"
220 ".type g_abExecMemory, @object\n\t"
221 ".size g_abExecMemory, 1572864\n\t"
222 ".text\n\t");
223#endif
224
225
226/*******************************************************************************
227* Internal Functions *
228*******************************************************************************/
229static int VBoxDrvLinuxInit(void);
230static void VBoxDrvLinuxUnload(void);
231static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp);
232static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
233#ifdef HAVE_UNLOCKED_IOCTL
234static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
235#else
236static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
237#endif
238static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
239static int VBoxDrvLinuxErr2LinuxErr(int);
240#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
241static int VBoxDrvProbe(struct platform_device *pDev);
242static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
243static int VBoxDrvResume(struct platform_device *pDev);
244static void VBoxDevRelease(struct device *pDev);
245#endif
246
247/** The file_operations structure. */
248static struct file_operations gFileOpsVBoxDrv =
249{
250 owner: THIS_MODULE,
251 open: VBoxDrvLinuxCreate,
252 release: VBoxDrvLinuxClose,
253#ifdef HAVE_UNLOCKED_IOCTL
254 unlocked_ioctl: VBoxDrvLinuxIOCtl,
255#else
256 ioctl: VBoxDrvLinuxIOCtl,
257#endif
258};
259
260#ifdef CONFIG_VBOXDRV_AS_MISC
261/** The miscdevice structure. */
262static struct miscdevice gMiscDevice =
263{
264 minor: MISC_DYNAMIC_MINOR,
265 name: DEVICE_NAME,
266 fops: &gFileOpsVBoxDrv,
267# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && \
268 LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
269 devfs_name: DEVICE_NAME,
270# endif
271};
272#endif
273
274
275#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
276static struct platform_driver gPlatformDriver =
277{
278 .probe = VBoxDrvProbe,
279 .suspend = VBoxDrvSuspend,
280 .resume = VBoxDrvResume,
281 /** @todo .shutdown? */
282 .driver =
283 {
284 .name = "vboxdrv"
285 }
286};
287
288static struct platform_device gPlatformDevice =
289{
290 .name = "vboxdrv",
291 .dev =
292 {
293 .release = VBoxDevRelease
294 }
295};
296#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
297
298
299#ifdef CONFIG_X86_LOCAL_APIC
300# ifdef DO_DISABLE_NMI
301/** Stop AMD NMI watchdog (x86_64 only). */
302static int vboxdrvStopK7Watchdog(void)
303{
304 wrmsr(MSR_K7_EVNTSEL0, 0, 0);
305 return 1;
306}
307
308/** Stop Intel P4 NMI watchdog (x86_64 only). */
309static int vboxdrvStopP4Watchdog(void)
310{
311 wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
312 wrmsr(MSR_P4_IQ_CCCR1, 0, 0);
313 wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
314 return 1;
315}
316
317/** The new method of detecting the event counter */
318static int vboxdrvStopIntelArchWatchdog(void)
319{
320 unsigned ebx;
321
322 ebx = cpuid_ebx(10);
323 if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
324 wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
325 return 1;
326}
327
328/** Stop NMI watchdog. */
329static void vboxdrvStopApicNmiWatchdog(void *unused)
330{
331 int stopped = 0;
332
333 /* only support LOCAL and IO APICs for now */
334 if ((nmi_watchdog != NMI_LOCAL_APIC) &&
335 (nmi_watchdog != NMI_IO_APIC))
336 return;
337
338 if (nmi_watchdog == NMI_LOCAL_APIC)
339 {
340 switch (boot_cpu_data.x86_vendor)
341 {
342 case X86_VENDOR_AMD:
343 if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
344 return;
345 stopped = vboxdrvStopK7Watchdog();
346 break;
347 case X86_VENDOR_INTEL:
348 if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
349 {
350 stopped = vboxdrvStopIntelArchWatchdog();
351 break;
352 }
353 stopped = vboxdrvStopP4Watchdog();
354 break;
355 default:
356 return;
357 }
358 }
359
360 if (stopped)
361 nmi_atomic_dec(&nmi_active);
362}
363
364/** Disable LAPIC NMI watchdog. */
365static void DisableLapicNmiWatchdog(void)
366{
367 BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
368
369 if (nmi_atomic_read(&nmi_active) <= 0)
370 return;
371
372 on_each_cpu(vboxdrvStopApicNmiWatchdog, NULL, 1, 1);
373
374 BUG_ON(nmi_atomic_read(&nmi_active) != 0);
375
376 /* tell do_nmi() and others that we're not active any more */
377 nmi_watchdog = NMI_NONE;
378}
379
380/** Shutdown NMI. */
381static void vboxdrvNmiCpuShutdown(void * dummy)
382{
383 unsigned int vERR, vPC;
384
385 vPC = apic_read(APIC_LVTPC);
386
387 if ((GET_APIC_DELIVERY_MODE(vPC) == APIC_MODE_NMI) && !(vPC & APIC_LVT_MASKED))
388 {
389 vERR = apic_read(APIC_LVTERR);
390 apic_write(APIC_LVTERR, vERR | APIC_LVT_MASKED);
391 apic_write(APIC_LVTPC, vPC | APIC_LVT_MASKED);
392 apic_write(APIC_LVTERR, vERR);
393 }
394}
395
396static void vboxdrvNmiShutdown(void)
397{
398 on_each_cpu(vboxdrvNmiCpuShutdown, NULL, 0, 1);
399}
400# endif /* DO_DISABLE_NMI */
401#endif /* CONFIG_X86_LOCAL_APIC */
402
403
404DECLINLINE(RTUID) vboxdrvLinuxUid(void)
405{
406#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
407 return current->cred->uid;
408#else
409 return current->uid;
410#endif
411}
412
413DECLINLINE(RTGID) vboxdrvLinuxGid(void)
414{
415#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
416 return current->cred->gid;
417#else
418 return current->gid;
419#endif
420}
421
422DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
423{
424#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
425 return current->cred->euid;
426#else
427 return current->euid;
428#endif
429}
430
431/**
432 * Initialize module.
433 *
434 * @returns appropriate status code.
435 */
436static int __init VBoxDrvLinuxInit(void)
437{
438 int rc;
439
440 dprintf(("VBoxDrv::ModuleInit\n"));
441
442#ifdef CONFIG_X86_LOCAL_APIC
443 /*
444 * If an NMI occurs while we are inside the world switcher the macine will crash.
445 * The Linux NMI watchdog generates periodic NMIs increasing a counter which is
446 * compared with another counter increased in the timer interrupt handler. Therefore
447 * we don't allow to setup an NMI watchdog.
448 */
449# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VBOX_REDHAT_KABI)
450 /*
451 * First test: NMI actiated? Works only works with Linux 2.6 -- 2.4 does not export
452 * the nmi_watchdog variable.
453 */
454# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
455 (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
456# ifdef DO_DISABLE_NMI
457 if (nmi_atomic_read(&nmi_active) > 0)
458 {
459 printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog...\n");
460
461 switch (nmi_watchdog)
462 {
463 case NMI_LOCAL_APIC:
464 DisableLapicNmiWatchdog();
465 break;
466 case NMI_NONE:
467 nmi_atomic_dec(&nmi_active);
468 break;
469 }
470
471 if (nmi_atomic_read(&nmi_active) == 0)
472 {
473 vboxdrvNmiShutdown();
474 printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
475 }
476 else
477 printk(KERN_DEBUG DEVICE_NAME ": Failed!\n");
478 }
479# endif /* DO_DISABLE_NMI */
480
481 /*
482 * Permanent IO_APIC mode active? No way to handle this!
483 */
484 if (nmi_watchdog == NMI_IO_APIC)
485 {
486 printk(KERN_ERR DEVICE_NAME
487 ": NMI watchdog in IO_APIC mode active -- refused to load the kernel module!\n"
488 DEVICE_NAME
489 ": Please disable the NMI watchdog by specifying 'nmi_watchdog=0' at kernel\n"
490 DEVICE_NAME
491 ": command line.\n");
492 return -EINVAL;
493 }
494
495 /*
496 * See arch/i386/kernel/nmi.c on >= 2.6.19: -1 means it can never enabled again
497 */
498 nmi_atomic_set(&nmi_active, -1);
499 printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog permanently...\n");
500
501 /*
502 * Now fall through and see if it actually was enabled before. If so, fail
503 * as we cannot deactivate it cleanly from here.
504 */
505# else /* < 2.6.19 */
506 /*
507 * Older 2.6 kernels: nmi_watchdog is not initalized by default
508 */
509 if (nmi_watchdog != NMI_NONE)
510 goto nmi_activated;
511# endif
512# endif /* >= 2.6.0 && !defined(VBOX_REDHAT_KABI) */
513
514 /*
515 * Second test: Interrupt generated by performance counter not masked and can
516 * generate an NMI. Works also with Linux 2.4.
517 */
518 {
519 unsigned int v, ver, maxlvt;
520
521 v = apic_read(APIC_LVR);
522 ver = GET_APIC_VERSION(v);
523 /* 82489DXs do not report # of LVT entries. */
524 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
525 if (maxlvt >= 4)
526 {
527 /* Read status of performance counter IRQ vector */
528 v = apic_read(APIC_LVTPC);
529
530 /* performance counter generates NMI and is not masked? */
531 if ((GET_APIC_DELIVERY_MODE(v) == APIC_MODE_NMI) && !(v & APIC_LVT_MASKED))
532 {
533# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
534 (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
535 printk(KERN_ERR DEVICE_NAME
536 ": NMI watchdog either active or at least initialized. Please disable the NMI\n"
537 DEVICE_NAME
538 ": watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
539 return -EINVAL;
540# else /* < 2.6.19 */
541# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VBOX_REDHAT_KABI)
542nmi_activated:
543# endif
544 printk(KERN_ERR DEVICE_NAME
545 ": NMI watchdog active -- refused to load the kernel module! Please disable\n"
546 DEVICE_NAME
547 ": the NMI watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
548 return -EINVAL;
549# endif /* >= 2.6.19 */
550 }
551 }
552 }
553# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
554 printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
555# endif /* >= 2.6.19 */
556#endif /* CONFIG_X86_LOCAL_APIC */
557
558 /*
559 * Check for synchronous/asynchronous TSC mode.
560 */
561 printk(KERN_DEBUG DEVICE_NAME ": Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount());
562#ifdef CONFIG_VBOXDRV_AS_MISC
563 rc = misc_register(&gMiscDevice);
564 if (rc)
565 {
566 printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc);
567 return rc;
568 }
569#else /* !CONFIG_VBOXDRV_AS_MISC */
570 /*
571 * Register character device.
572 */
573 g_iModuleMajor = DEVICE_MAJOR;
574 rc = VBOX_REGISTER_DEVICE((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv);
575 if (rc < 0)
576 {
577 dprintf(("VBOX_REGISTER_DEVICE failed with rc=%#x!\n", rc));
578 return rc;
579 }
580
581 /*
582 * Save returned module major number
583 */
584 if (DEVICE_MAJOR != 0)
585 g_iModuleMajor = DEVICE_MAJOR;
586 else
587 g_iModuleMajor = rc;
588 rc = 0;
589
590#ifdef CONFIG_DEVFS_FS
591 /*
592 * Register a device entry
593 */
594 g_hDevFsVBoxDrv = VBOX_REGISTER_DEVFS();
595 if (g_hDevFsVBoxDrv == NULL)
596 {
597 dprintf(("devfs_register failed!\n"));
598 rc = -EINVAL;
599 }
600#endif
601#endif /* !CONFIG_VBOXDRV_AS_MISC */
602 if (!rc)
603 {
604 /*
605 * Initialize the runtime.
606 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
607 */
608 rc = RTR0Init(0);
609 if (RT_SUCCESS(rc))
610 {
611#ifdef RT_ARCH_AMD64
612 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
613 printk("VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
614#endif
615 /*
616 * Initialize the device extension.
617 */
618 if (RT_SUCCESS(rc))
619 rc = supdrvInitDevExt(&g_DevExt);
620 if (RT_SUCCESS(rc))
621 {
622#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
623 rc = platform_driver_register(&gPlatformDriver);
624 if (rc == 0)
625 {
626 rc = platform_device_register(&gPlatformDevice);
627 if (rc == 0)
628#endif
629 {
630 printk(KERN_INFO DEVICE_NAME ": TSC mode is %s, kernel timer mode is "
631#ifdef VBOX_HRTIMER
632 "'high-res'"
633#else
634 "'normal'"
635#endif
636 ".\n",
637 g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'");
638 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
639 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
640 VBOX_VERSION_STRING " (interface " xstr(SUPDRV_IOC_VERSION) ").\n");
641 return rc;
642 }
643#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
644 else
645 platform_driver_unregister(&gPlatformDriver);
646 }
647#endif
648 }
649
650 rc = -EINVAL;
651 RTR0Term();
652 }
653 else
654 rc = -EINVAL;
655
656 /*
657 * Failed, cleanup and return the error code.
658 */
659#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
660 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
661#endif
662 }
663#ifdef CONFIG_VBOXDRV_AS_MISC
664 misc_deregister(&gMiscDevice);
665 dprintf(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
666#else
667 VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
668 dprintf(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
669#endif
670 return rc;
671}
672
673
674/**
675 * Unload the module.
676 */
677static void __exit VBoxDrvLinuxUnload(void)
678{
679 int rc;
680 dprintf(("VBoxDrvLinuxUnload\n"));
681 NOREF(rc);
682
683#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
684 platform_device_unregister(&gPlatformDevice);
685 platform_driver_unregister(&gPlatformDriver);
686#endif
687
688 /*
689 * I Don't think it's possible to unload a driver which processes have
690 * opened, at least we'll blindly assume that here.
691 */
692#ifdef CONFIG_VBOXDRV_AS_MISC
693 rc = misc_deregister(&gMiscDevice);
694 if (rc < 0)
695 {
696 dprintf(("misc_deregister failed with rc=%#x\n", rc));
697 }
698#else /* !CONFIG_VBOXDRV_AS_MISC */
699# ifdef CONFIG_DEVFS_FS
700 /*
701 * Unregister a device entry
702 */
703 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
704# endif /* devfs */
705 VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
706#endif /* !CONFIG_VBOXDRV_AS_MISC */
707
708 /*
709 * Destroy GIP, delete the device extension and terminate IPRT.
710 */
711 supdrvDeleteDevExt(&g_DevExt);
712 RTR0Term();
713}
714
715
716/**
717 * Device open. Called on open /dev/vboxdrv
718 *
719 * @param pInode Pointer to inode info structure.
720 * @param pFilp Associated file pointer.
721 */
722static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp)
723{
724 int rc;
725 PSUPDRVSESSION pSession;
726 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
727
728#ifdef VBOX_WITH_HARDENING
729 /*
730 * Only root is allowed to access the device, enforce it!
731 */
732 if (vboxdrvLinuxEuid() != 0 /* root */ )
733 {
734 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
735 return -EPERM;
736 }
737#endif /* VBOX_WITH_HARDENING */
738
739 /*
740 * Call common code for the rest.
741 */
742 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, (PSUPDRVSESSION *)&pSession);
743 if (!rc)
744 {
745 pSession->Uid = vboxdrvLinuxUid();
746 pSession->Gid = vboxdrvLinuxGid();
747 }
748
749 pFilp->private_data = pSession;
750
751 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
752 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
753 RTProcSelf(), current->pid, current->comm));
754 return VBoxDrvLinuxErr2LinuxErr(rc);
755}
756
757
758/**
759 * Close device.
760 *
761 * @param pInode Pointer to inode info structure.
762 * @param pFilp Associated file pointer.
763 */
764static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
765{
766 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
767 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
768 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
769 pFilp->private_data = NULL;
770 return 0;
771}
772
773
774#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
775/**
776 * Dummy device release function. We have to provide this function,
777 * otherwise the kernel will complain.
778 *
779 * @param pDev Pointer to the platform device.
780 */
781static void VBoxDevRelease(struct device *pDev)
782{
783}
784
785/**
786 * Dummy probe function.
787 *
788 * @param pDev Pointer to the platform device.
789 */
790static int VBoxDrvProbe(struct platform_device *pDev)
791{
792 return 0;
793}
794
795/**
796 * Suspend callback.
797 * @param pDev Pointer to the platform device.
798 * @param State message type, see Documentation/power/devices.txt.
799 */
800static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
801{
802 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
803 return 0;
804}
805
806/**
807 * Resume callback.
808 *
809 * @param pDev Pointer to the platform device.
810 */
811static int VBoxDrvResume(struct platform_device *pDev)
812{
813 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
814 return 0;
815}
816#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
817
818
819/**
820 * Device I/O Control entry point.
821 *
822 * @param pFilp Associated file pointer.
823 * @param uCmd The function specified to ioctl().
824 * @param ulArg The argument specified to ioctl().
825 */
826#ifdef HAVE_UNLOCKED_IOCTL
827static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
828#else
829static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
830#endif
831{
832 /*
833 * Deal with the two high-speed IOCtl that takes it's arguments from
834 * the session and iCmd, and only returns a VBox status code.
835 */
836#ifdef HAVE_UNLOCKED_IOCTL
837 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
838 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
839 || uCmd == SUP_IOCTL_FAST_DO_NOP))
840 return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
841 return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
842
843#else /* !HAVE_UNLOCKED_IOCTL */
844
845 int rc;
846 unlock_kernel();
847 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
848 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
849 || uCmd == SUP_IOCTL_FAST_DO_NOP))
850 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
851 else
852 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
853 lock_kernel();
854 return rc;
855#endif /* !HAVE_UNLOCKED_IOCTL */
856}
857
858
859/**
860 * Device I/O Control entry point.
861 *
862 * @param pFilp Associated file pointer.
863 * @param uCmd The function specified to ioctl().
864 * @param ulArg The argument specified to ioctl().
865 */
866static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
867{
868 int rc;
869 SUPREQHDR Hdr;
870 PSUPREQHDR pHdr;
871 uint32_t cbBuf;
872
873 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
874
875 /*
876 * Read the header.
877 */
878 if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
879 {
880 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
881 return -EFAULT;
882 }
883 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
884 {
885 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
886 return -EINVAL;
887 }
888
889 /*
890 * Buffer the request.
891 */
892 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
893 if (RT_UNLIKELY(cbBuf > _1M*16))
894 {
895 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
896 return -E2BIG;
897 }
898 if (RT_UNLIKELY(cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd)))
899 {
900 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
901 return -EINVAL;
902 }
903 pHdr = RTMemAlloc(cbBuf);
904 if (RT_UNLIKELY(!pHdr))
905 {
906 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x.\n", cbBuf, uCmd));
907 return -ENOMEM;
908 }
909 if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
910 {
911 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
912 RTMemFree(pHdr);
913 return -EFAULT;
914 }
915
916 /*
917 * Process the IOCtl.
918 */
919 rc = supdrvIOCtl(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data, pHdr);
920
921 /*
922 * Copy ioctl data and output buffer back to user space.
923 */
924 if (RT_LIKELY(!rc))
925 {
926 uint32_t cbOut = pHdr->cbOut;
927 if (RT_UNLIKELY(cbOut > cbBuf))
928 {
929 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
930 cbOut = cbBuf;
931 }
932 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
933 {
934 /* this is really bad! */
935 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
936 rc = -EFAULT;
937 }
938 }
939 else
940 {
941 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
942 rc = -EINVAL;
943 }
944 RTMemFree(pHdr);
945
946 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
947 return rc;
948}
949
950
951/**
952 * The SUPDRV IDC entry point.
953 *
954 * @returns VBox status code, see supdrvIDC.
955 * @param iReq The request code.
956 * @param pReq The request.
957 */
958int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
959{
960 PSUPDRVSESSION pSession;
961
962 /*
963 * Some quick validations.
964 */
965 if (RT_UNLIKELY(!VALID_PTR(pReq)))
966 return VERR_INVALID_POINTER;
967
968 pSession = pReq->pSession;
969 if (pSession)
970 {
971 if (RT_UNLIKELY(!VALID_PTR(pSession)))
972 return VERR_INVALID_PARAMETER;
973 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
974 return VERR_INVALID_PARAMETER;
975 }
976 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
977 return VERR_INVALID_PARAMETER;
978
979 /*
980 * Do the job.
981 */
982 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
983}
984
985EXPORT_SYMBOL(SUPDrvLinuxIDC);
986
987
988/**
989 * Initializes any OS specific object creator fields.
990 */
991void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
992{
993 NOREF(pObj);
994 NOREF(pSession);
995}
996
997
998/**
999 * Checks if the session can access the object.
1000 *
1001 * @returns true if a decision has been made.
1002 * @returns false if the default access policy should be applied.
1003 *
1004 * @param pObj The object in question.
1005 * @param pSession The session wanting to access the object.
1006 * @param pszObjName The object name, can be NULL.
1007 * @param prc Where to store the result when returning true.
1008 */
1009bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1010{
1011 NOREF(pObj);
1012 NOREF(pSession);
1013 NOREF(pszObjName);
1014 NOREF(prc);
1015 return false;
1016}
1017
1018
1019bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1020{
1021 return force_async_tsc != 0;
1022}
1023
1024
1025/**
1026 * Converts a supdrv error code to an linux error code.
1027 *
1028 * @returns corresponding linux error code.
1029 * @param rc supdrv error code (SUPDRV_ERR_* defines).
1030 */
1031static int VBoxDrvLinuxErr2LinuxErr(int rc)
1032{
1033 switch (rc)
1034 {
1035 case 0: return 0;
1036 case SUPDRV_ERR_GENERAL_FAILURE: return -EACCES;
1037 case SUPDRV_ERR_INVALID_PARAM: return -EINVAL;
1038 case SUPDRV_ERR_INVALID_MAGIC: return -EILSEQ;
1039 case SUPDRV_ERR_INVALID_HANDLE: return -ENXIO;
1040 case SUPDRV_ERR_INVALID_POINTER: return -EFAULT;
1041 case SUPDRV_ERR_LOCK_FAILED: return -ENOLCK;
1042 case SUPDRV_ERR_ALREADY_LOADED: return -EEXIST;
1043 case SUPDRV_ERR_PERMISSION_DENIED: return -EPERM;
1044 case SUPDRV_ERR_VERSION_MISMATCH: return -ENOSYS;
1045 case SUPDRV_ERR_IDT_FAILED: return -1000;
1046 }
1047
1048 return -EPERM;
1049}
1050
1051
1052RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1053{
1054#if 1
1055 va_list args;
1056 char szMsg[512];
1057
1058 va_start(args, pszFormat);
1059 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
1060 szMsg[sizeof(szMsg) - 1] = '\0';
1061 printk("%s", szMsg);
1062 va_end(args);
1063#else
1064 /* forward to printf - needs some more GCC hacking to fix ebp... */
1065 __asm__ __volatile__ ("mov %0, %esp\n\t"
1066 "jmp %1\n\t",
1067 :: "r" ((uintptr_t)&pszFormat - 4),
1068 "m" (printk));
1069#endif
1070 return 0;
1071}
1072
1073module_init(VBoxDrvLinuxInit);
1074module_exit(VBoxDrvLinuxUnload);
1075
1076MODULE_AUTHOR("Sun Microsystems, Inc.");
1077MODULE_DESCRIPTION("VirtualBox Support Driver");
1078MODULE_LICENSE("GPL");
1079#ifdef MODULE_VERSION
1080MODULE_VERSION(VBOX_VERSION_STRING " (" xstr(SUPDRV_IOC_VERSION) ")");
1081#endif
1082
1083#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1084module_param(force_async_tsc, int, 0444);
1085#else
1086MODULE_PARM(force_async_tsc, "i");
1087#endif
1088MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1089
Note: See TracBrowser for help on using the repository browser.

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