VirtualBox

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

Last change on this file since 32767 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.7 KB
Line 
1/* $Rev: 28800 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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 * Some lines of code to disable the local APIC on x86_64 machines taken
26 * from a Mandriva patch by Gwenole Beauchesne <[email protected]>.
27 */
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#define LOG_GROUP LOG_GROUP_SUP_DRV
33#include "../SUPDrvInternal.h"
34#include "the-linux-kernel.h"
35#include "version-generated.h"
36#include "product-generated.h"
37
38#include <iprt/assert.h>
39#include <iprt/spinlock.h>
40#include <iprt/semaphore.h>
41#include <iprt/initterm.h>
42#include <iprt/process.h>
43#include <VBox/err.h>
44#include <iprt/mem.h>
45#include <VBox/log.h>
46#include <iprt/mp.h>
47
48/** @todo figure out the exact version number */
49#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
50# include <iprt/power.h>
51# define VBOX_WITH_SUSPEND_NOTIFICATION
52#endif
53
54#include <linux/sched.h>
55#ifdef CONFIG_DEVFS_FS
56# include <linux/devfs_fs_kernel.h>
57#endif
58#ifdef CONFIG_VBOXDRV_AS_MISC
59# include <linux/miscdevice.h>
60#endif
61#ifdef CONFIG_X86_LOCAL_APIC
62# include <asm/apic.h>
63# include <asm/nmi.h>
64#endif
65#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
66# include <linux/platform_device.h>
67#endif
68
69#include <iprt/mem.h>
70
71
72/*******************************************************************************
73* Defined Constants And Macros *
74*******************************************************************************/
75/* check kernel version */
76# ifndef SUPDRV_AGNOSTIC
77# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
78# error Unsupported kernel version!
79# endif
80# endif
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#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
90
91#ifdef CONFIG_X86_HIGH_ENTRY
92# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
93#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)
113extern 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 */
134
135
136/*******************************************************************************
137* Internal Functions *
138*******************************************************************************/
139static int VBoxDrvLinuxInit(void);
140static void VBoxDrvLinuxUnload(void);
141static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp);
142static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
143#ifdef HAVE_UNLOCKED_IOCTL
144static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
145#else
146static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
147#endif
148static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
149static int VBoxDrvLinuxErr2LinuxErr(int);
150#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
151static int VBoxDrvProbe(struct platform_device *pDev);
152# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
153static int VBoxDrvSuspend(struct device *pDev);
154static int VBoxDrvResume(struct device *pDev);
155# else
156static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
157static int VBoxDrvResume(struct platform_device *pDev);
158# endif
159static void VBoxDevRelease(struct device *pDev);
160#endif
161
162
163/*******************************************************************************
164* Global Variables *
165*******************************************************************************/
166/**
167 * Device extention & session data association structure.
168 */
169static SUPDRVDEVEXT g_DevExt;
170
171#ifndef CONFIG_VBOXDRV_AS_MISC
172/** Module major number */
173#define DEVICE_MAJOR 234
174/** Saved major device number */
175static int g_iModuleMajor;
176#endif /* !CONFIG_VBOXDRV_AS_MISC */
177
178/** Module parameter.
179 * Not prefixed because the name is used by macros and the end of this file. */
180static int force_async_tsc = 0;
181
182/** The module name. */
183#define DEVICE_NAME "vboxdrv"
184
185#ifdef RT_ARCH_AMD64
186/**
187 * Memory for the executable memory heap (in IPRT).
188 */
189extern uint8_t g_abExecMemory[1572864]; /* 1.5 MB */
190__asm__(".section execmemory, \"awx\", @progbits\n\t"
191 ".align 32\n\t"
192 ".globl g_abExecMemory\n"
193 "g_abExecMemory:\n\t"
194 ".zero 1572864\n\t"
195 ".type g_abExecMemory, @object\n\t"
196 ".size g_abExecMemory, 1572864\n\t"
197 ".text\n\t");
198#endif
199
200/** The file_operations structure. */
201static struct file_operations gFileOpsVBoxDrv =
202{
203 owner: THIS_MODULE,
204 open: VBoxDrvLinuxCreate,
205 release: VBoxDrvLinuxClose,
206#ifdef HAVE_UNLOCKED_IOCTL
207 unlocked_ioctl: VBoxDrvLinuxIOCtl,
208#else
209 ioctl: VBoxDrvLinuxIOCtl,
210#endif
211};
212
213#ifdef CONFIG_VBOXDRV_AS_MISC
214/** The miscdevice structure. */
215static struct miscdevice gMiscDevice =
216{
217 minor: MISC_DYNAMIC_MINOR,
218 name: DEVICE_NAME,
219 fops: &gFileOpsVBoxDrv,
220# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
221 devfs_name: DEVICE_NAME,
222# endif
223};
224#endif
225
226
227#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
228# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
229static struct dev_pm_ops gPlatformPMOps =
230{
231 .suspend = VBoxDrvSuspend, /* before entering deep sleep */
232 .resume = VBoxDrvResume, /* after wakeup from deep sleep */
233 .freeze = VBoxDrvSuspend, /* before creating hibernation image */
234 .restore = VBoxDrvResume, /* after wakeing up from hibernation */
235};
236# endif
237
238static struct platform_driver gPlatformDriver =
239{
240 .probe = VBoxDrvProbe,
241# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
242 .suspend = VBoxDrvSuspend,
243 .resume = VBoxDrvResume,
244# endif
245 /** @todo .shutdown? */
246 .driver =
247 {
248 .name = "vboxdrv",
249# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
250 .pm = &gPlatformPMOps,
251# endif
252 }
253};
254
255static struct platform_device gPlatformDevice =
256{
257 .name = "vboxdrv",
258 .dev =
259 {
260 .release = VBoxDevRelease
261 }
262};
263#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
264
265
266
267
268
269#ifdef CONFIG_X86_LOCAL_APIC
270# ifdef DO_DISABLE_NMI
271/** Stop AMD NMI watchdog (x86_64 only). */
272static 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). */
279static 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 */
288static 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. */
299static 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. */
335static 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. */
351static 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
366static 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
374DECLINLINE(RTUID) vboxdrvLinuxUid(void)
375{
376#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
377 return current->cred->uid;
378#else
379 return current->uid;
380#endif
381}
382
383DECLINLINE(RTGID) vboxdrvLinuxGid(void)
384{
385#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
386 return current->cred->gid;
387#else
388 return current->gid;
389#endif
390}
391
392DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
393{
394#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
395 return current->cred->euid;
396#else
397 return current->euid;
398#endif
399}
400
401/**
402 * Initialize module.
403 *
404 * @returns appropriate status code.
405 */
406static int __init VBoxDrvLinuxInit(void)
407{
408 int rc;
409
410#ifdef CONFIG_X86_LOCAL_APIC
411 /*
412 * If an NMI occurs while we are inside the world switcher the macine 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 actiated? 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 initalized 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 hopefilly 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)
528nmi_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))
543no_error:
544# endif
545# endif /* >= 2.6.19 */
546#endif /* CONFIG_X86_LOCAL_APIC */
547
548 /*
549 * Check for synchronous/asynchronous TSC mode.
550 */
551 printk(KERN_DEBUG DEVICE_NAME ": Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount());
552#ifdef CONFIG_VBOXDRV_AS_MISC
553 rc = misc_register(&gMiscDevice);
554 if (rc)
555 {
556 printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc);
557 return rc;
558 }
559#else /* !CONFIG_VBOXDRV_AS_MISC */
560 /*
561 * Register character device.
562 */
563 g_iModuleMajor = DEVICE_MAJOR;
564 rc = register_chrdev((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv);
565 if (rc < 0)
566 {
567 Log(("register_chrdev() failed with rc=%#x!\n", rc));
568 return rc;
569 }
570
571 /*
572 * Save returned module major number
573 */
574 if (DEVICE_MAJOR != 0)
575 g_iModuleMajor = DEVICE_MAJOR;
576 else
577 g_iModuleMajor = rc;
578 rc = 0;
579
580# ifdef CONFIG_DEVFS_FS
581 /*
582 * Register a device entry
583 */
584 if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME) != 0)
585 {
586 Log(("devfs_register failed!\n"));
587 rc = -EINVAL;
588 }
589# endif
590#endif /* !CONFIG_VBOXDRV_AS_MISC */
591 if (!rc)
592 {
593 /*
594 * Initialize the runtime.
595 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
596 */
597 rc = RTR0Init(0);
598 if (RT_SUCCESS(rc))
599 {
600#ifdef RT_ARCH_AMD64
601 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
602 printk("VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
603#endif
604 Log(("VBoxDrv::ModuleInit\n"));
605
606 /*
607 * Initialize the device extension.
608 */
609 if (RT_SUCCESS(rc))
610 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
611 if (RT_SUCCESS(rc))
612 {
613#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
614 rc = platform_driver_register(&gPlatformDriver);
615 if (rc == 0)
616 {
617 rc = platform_device_register(&gPlatformDevice);
618 if (rc == 0)
619#endif
620 {
621 printk(KERN_INFO DEVICE_NAME ": TSC mode is %s, kernel timer mode is "
622#ifdef VBOX_HRTIMER
623 "'high-res'"
624#else
625 "'normal'"
626#endif
627 ".\n",
628 g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'");
629 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
630 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
631 VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ").\n");
632 return rc;
633 }
634#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
635 else
636 platform_driver_unregister(&gPlatformDriver);
637 }
638#endif
639 }
640
641 rc = -EINVAL;
642 RTR0TermForced();
643 }
644 else
645 rc = -EINVAL;
646
647 /*
648 * Failed, cleanup and return the error code.
649 */
650#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
651 devfs_remove(DEVICE_NAME);
652#endif
653 }
654#ifdef CONFIG_VBOXDRV_AS_MISC
655 misc_deregister(&gMiscDevice);
656 Log(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
657#else
658 unregister_chrdev(g_iModuleMajor, DEVICE_NAME);
659 Log(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
660#endif
661 return rc;
662}
663
664
665/**
666 * Unload the module.
667 */
668static void __exit VBoxDrvLinuxUnload(void)
669{
670 int rc;
671 Log(("VBoxDrvLinuxUnload\n"));
672 NOREF(rc);
673
674#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
675 platform_device_unregister(&gPlatformDevice);
676 platform_driver_unregister(&gPlatformDriver);
677#endif
678
679 /*
680 * I Don't think it's possible to unload a driver which processes have
681 * opened, at least we'll blindly assume that here.
682 */
683#ifdef CONFIG_VBOXDRV_AS_MISC
684 rc = misc_deregister(&gMiscDevice);
685 if (rc < 0)
686 {
687 Log(("misc_deregister failed with rc=%#x\n", rc));
688 }
689#else /* !CONFIG_VBOXDRV_AS_MISC */
690# ifdef CONFIG_DEVFS_FS
691 /*
692 * Unregister a device entry
693 */
694 devfs_remove(DEVICE_NAME);
695# endif /* devfs */
696 unregister_chrdev(g_iModuleMajor, DEVICE_NAME);
697#endif /* !CONFIG_VBOXDRV_AS_MISC */
698
699 /*
700 * Destroy GIP, delete the device extension and terminate IPRT.
701 */
702 supdrvDeleteDevExt(&g_DevExt);
703 RTR0TermForced();
704}
705
706
707/**
708 * Device open. Called on open /dev/vboxdrv
709 *
710 * @param pInode Pointer to inode info structure.
711 * @param pFilp Associated file pointer.
712 */
713static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp)
714{
715 int rc;
716 PSUPDRVSESSION pSession;
717 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
718
719#ifdef VBOX_WITH_HARDENING
720 /*
721 * Only root is allowed to access the device, enforce it!
722 */
723 if (vboxdrvLinuxEuid() != 0 /* root */ )
724 {
725 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
726 return -EPERM;
727 }
728#endif /* VBOX_WITH_HARDENING */
729
730 /*
731 * Call common code for the rest.
732 */
733 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
734 if (!rc)
735 {
736 pSession->Uid = vboxdrvLinuxUid();
737 pSession->Gid = vboxdrvLinuxGid();
738 }
739
740 pFilp->private_data = pSession;
741
742 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
743 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
744 RTProcSelf(), current->pid, current->comm));
745 return VBoxDrvLinuxErr2LinuxErr(rc);
746}
747
748
749/**
750 * Close device.
751 *
752 * @param pInode Pointer to inode info structure.
753 * @param pFilp Associated file pointer.
754 */
755static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
756{
757 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
758 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
759 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
760 pFilp->private_data = NULL;
761 return 0;
762}
763
764
765#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
766/**
767 * Dummy device release function. We have to provide this function,
768 * otherwise the kernel will complain.
769 *
770 * @param pDev Pointer to the platform device.
771 */
772static void VBoxDevRelease(struct device *pDev)
773{
774}
775
776/**
777 * Dummy probe function.
778 *
779 * @param pDev Pointer to the platform device.
780 */
781static int VBoxDrvProbe(struct platform_device *pDev)
782{
783 return 0;
784}
785
786/**
787 * Suspend callback.
788 * @param pDev Pointer to the platform device.
789 * @param State message type, see Documentation/power/devices.txt.
790 */
791# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
792static int VBoxDrvSuspend(struct device *pDev)
793# else
794static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
795# endif
796{
797 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
798 return 0;
799}
800
801/**
802 * Resume callback.
803 *
804 * @param pDev Pointer to the platform device.
805 */
806# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
807static int VBoxDrvResume(struct device *pDev)
808# else
809static int VBoxDrvResume(struct platform_device *pDev)
810# endif
811{
812 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
813 return 0;
814}
815#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
816
817
818/**
819 * Device I/O Control entry point.
820 *
821 * @param pFilp Associated file pointer.
822 * @param uCmd The function specified to ioctl().
823 * @param ulArg The argument specified to ioctl().
824 */
825#ifdef HAVE_UNLOCKED_IOCTL
826static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
827#else
828static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
829#endif
830{
831 /*
832 * Deal with the two high-speed IOCtl that takes it's arguments from
833 * the session and iCmd, and only returns a VBox status code.
834 */
835#ifdef HAVE_UNLOCKED_IOCTL
836 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
837 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
838 || uCmd == SUP_IOCTL_FAST_DO_NOP))
839 return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
840 return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
841
842#else /* !HAVE_UNLOCKED_IOCTL */
843
844 int rc;
845 unlock_kernel();
846 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
847 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
848 || uCmd == SUP_IOCTL_FAST_DO_NOP))
849 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
850 else
851 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
852 lock_kernel();
853 return rc;
854#endif /* !HAVE_UNLOCKED_IOCTL */
855}
856
857
858/**
859 * Device I/O Control entry point.
860 *
861 * @param pFilp Associated file pointer.
862 * @param uCmd The function specified to ioctl().
863 * @param ulArg The argument specified to ioctl().
864 */
865static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
866{
867 int rc;
868 SUPREQHDR Hdr;
869 PSUPREQHDR pHdr;
870 uint32_t cbBuf;
871
872 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
873
874 /*
875 * Read the header.
876 */
877 if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
878 {
879 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
880 return -EFAULT;
881 }
882 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
883 {
884 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
885 return -EINVAL;
886 }
887
888 /*
889 * Buffer the request.
890 */
891 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
892 if (RT_UNLIKELY(cbBuf > _1M*16))
893 {
894 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
895 return -E2BIG;
896 }
897 if (RT_UNLIKELY(cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd)))
898 {
899 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
900 return -EINVAL;
901 }
902 pHdr = RTMemAlloc(cbBuf);
903 if (RT_UNLIKELY(!pHdr))
904 {
905 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x.\n", cbBuf, uCmd));
906 return -ENOMEM;
907 }
908 if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
909 {
910 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
911 RTMemFree(pHdr);
912 return -EFAULT;
913 }
914
915 /*
916 * Process the IOCtl.
917 */
918 rc = supdrvIOCtl(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data, pHdr);
919
920 /*
921 * Copy ioctl data and output buffer back to user space.
922 */
923 if (RT_LIKELY(!rc))
924 {
925 uint32_t cbOut = pHdr->cbOut;
926 if (RT_UNLIKELY(cbOut > cbBuf))
927 {
928 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
929 cbOut = cbBuf;
930 }
931 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
932 {
933 /* this is really bad! */
934 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
935 rc = -EFAULT;
936 }
937 }
938 else
939 {
940 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
941 rc = -EINVAL;
942 }
943 RTMemFree(pHdr);
944
945 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
946 return rc;
947}
948
949
950/**
951 * The SUPDRV IDC entry point.
952 *
953 * @returns VBox status code, see supdrvIDC.
954 * @param iReq The request code.
955 * @param pReq The request.
956 */
957int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
958{
959 PSUPDRVSESSION pSession;
960
961 /*
962 * Some quick validations.
963 */
964 if (RT_UNLIKELY(!VALID_PTR(pReq)))
965 return VERR_INVALID_POINTER;
966
967 pSession = pReq->pSession;
968 if (pSession)
969 {
970 if (RT_UNLIKELY(!VALID_PTR(pSession)))
971 return VERR_INVALID_PARAMETER;
972 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
973 return VERR_INVALID_PARAMETER;
974 }
975 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
976 return VERR_INVALID_PARAMETER;
977
978 /*
979 * Do the job.
980 */
981 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
982}
983
984EXPORT_SYMBOL(SUPDrvLinuxIDC);
985
986
987/**
988 * Initializes any OS specific object creator fields.
989 */
990void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
991{
992 NOREF(pObj);
993 NOREF(pSession);
994}
995
996
997/**
998 * Checks if the session can access the object.
999 *
1000 * @returns true if a decision has been made.
1001 * @returns false if the default access policy should be applied.
1002 *
1003 * @param pObj The object in question.
1004 * @param pSession The session wanting to access the object.
1005 * @param pszObjName The object name, can be NULL.
1006 * @param prc Where to store the result when returning true.
1007 */
1008bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1009{
1010 NOREF(pObj);
1011 NOREF(pSession);
1012 NOREF(pszObjName);
1013 NOREF(prc);
1014 return false;
1015}
1016
1017
1018bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1019{
1020 return force_async_tsc != 0;
1021}
1022
1023
1024int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1025{
1026 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1027 return VERR_NOT_SUPPORTED;
1028}
1029
1030
1031int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
1032{
1033 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
1034 return VERR_NOT_SUPPORTED;
1035}
1036
1037
1038int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits)
1039{
1040 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits);
1041 return VERR_NOT_SUPPORTED;
1042}
1043
1044
1045void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1046{
1047 NOREF(pDevExt); NOREF(pImage);
1048}
1049
1050
1051/**
1052 * Converts a supdrv error code to an linux error code.
1053 *
1054 * @returns corresponding linux error code.
1055 * @param rc IPRT status code.
1056 */
1057static int VBoxDrvLinuxErr2LinuxErr(int rc)
1058{
1059 switch (rc)
1060 {
1061 case VINF_SUCCESS: return 0;
1062 case VERR_GENERAL_FAILURE: return -EACCES;
1063 case VERR_INVALID_PARAMETER: return -EINVAL;
1064 case VERR_INVALID_MAGIC: return -EILSEQ;
1065 case VERR_INVALID_HANDLE: return -ENXIO;
1066 case VERR_INVALID_POINTER: return -EFAULT;
1067 case VERR_LOCK_FAILED: return -ENOLCK;
1068 case VERR_ALREADY_LOADED: return -EEXIST;
1069 case VERR_PERMISSION_DENIED: return -EPERM;
1070 case VERR_VERSION_MISMATCH: return -ENOSYS;
1071 case VERR_IDT_FAILED: return -1000;
1072 }
1073
1074 return -EPERM;
1075}
1076
1077
1078RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1079{
1080#if 1
1081 va_list args;
1082 char szMsg[512];
1083
1084 va_start(args, pszFormat);
1085 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
1086 szMsg[sizeof(szMsg) - 1] = '\0';
1087 printk("%s", szMsg);
1088 va_end(args);
1089#else
1090 /* forward to printf - needs some more GCC hacking to fix ebp... */
1091 __asm__ __volatile__ ("mov %0, %esp\n\t"
1092 "jmp %1\n\t",
1093 :: "r" ((uintptr_t)&pszFormat - 4),
1094 "m" (printk));
1095#endif
1096 return 0;
1097}
1098
1099module_init(VBoxDrvLinuxInit);
1100module_exit(VBoxDrvLinuxUnload);
1101
1102MODULE_AUTHOR(VBOX_VENDOR);
1103MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
1104MODULE_LICENSE("GPL");
1105#ifdef MODULE_VERSION
1106MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
1107#endif
1108
1109module_param(force_async_tsc, int, 0444);
1110MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1111
Note: See TracBrowser for help on using the repository browser.

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