VirtualBox

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

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

Linux hostdrivers: removed Linux 2.4.x compatibility

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