VirtualBox

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

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

SUPDrv-linux: Re-enabled root check (#3076).

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