VirtualBox

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

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

Compile fixes

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