VirtualBox

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

Last change on this file since 28545 was 28283, checked in by vboxsync, 15 years ago

Linux HostDrivers/Additions: fixed missing symbol RTMemAllocZVar(); rebranding

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