VirtualBox

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

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

Increased the IOC version to 7.4 with the exporting of SUPR0ComponentQueryFactory and friends. Added release logging to darwin, windows and freebsd.

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