VirtualBox

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

Last change on this file since 44529 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/* $Rev: 44528 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_SUP_DRV
31#include "../SUPDrvInternal.h"
32#include "the-linux-kernel.h"
33#include "version-generated.h"
34#include "product-generated.h"
35
36#include <iprt/assert.h>
37#include <iprt/spinlock.h>
38#include <iprt/semaphore.h>
39#include <iprt/initterm.h>
40#include <iprt/process.h>
41#include <VBox/err.h>
42#include <iprt/mem.h>
43#include <VBox/log.h>
44#include <iprt/mp.h>
45
46/** @todo figure out the exact version number */
47#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
48# include <iprt/power.h>
49# define VBOX_WITH_SUSPEND_NOTIFICATION
50#endif
51
52#include <linux/sched.h>
53#ifdef CONFIG_DEVFS_FS
54# include <linux/devfs_fs_kernel.h>
55#endif
56#ifdef CONFIG_VBOXDRV_AS_MISC
57# include <linux/miscdevice.h>
58#endif
59#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
60# include <linux/platform_device.h>
61#endif
62
63
64/*******************************************************************************
65* Defined Constants And Macros *
66*******************************************************************************/
67/* check kernel version */
68# ifndef SUPDRV_AGNOSTIC
69# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
70# error Unsupported kernel version!
71# endif
72# endif
73
74/* devfs defines */
75#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
76# ifdef VBOX_WITH_HARDENING
77# define VBOX_DEV_FMASK (S_IWUSR | S_IRUSR)
78# else
79# define VBOX_DEV_FMASK (S_IRUGO | S_IWUGO)
80# endif
81#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
82
83#ifdef CONFIG_X86_HIGH_ENTRY
84# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
85#endif
86
87/* to include the version number of VirtualBox into kernel backtraces */
88#define VBoxDrvLinuxVersion RT_CONCAT3(RT_CONCAT(VBOX_VERSION_MAJOR, _), \
89 RT_CONCAT(VBOX_VERSION_MINOR, _), \
90 VBOX_VERSION_BUILD)
91#define VBoxDrvLinuxIOCtl RT_CONCAT(VBoxDrvLinuxIOCtl_,VBoxDrvLinuxVersion)
92
93/*******************************************************************************
94* Internal Functions *
95*******************************************************************************/
96static int VBoxDrvLinuxInit(void);
97static void VBoxDrvLinuxUnload(void);
98static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp);
99static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp);
100static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
101#ifdef HAVE_UNLOCKED_IOCTL
102static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
103#else
104static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
105#endif
106static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession);
107static int VBoxDrvLinuxErr2LinuxErr(int);
108#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
109static int VBoxDrvProbe(struct platform_device *pDev);
110# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
111static int VBoxDrvSuspend(struct device *pDev);
112static int VBoxDrvResume(struct device *pDev);
113# else
114static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
115static int VBoxDrvResume(struct platform_device *pDev);
116# endif
117static void VBoxDevRelease(struct device *pDev);
118#endif
119
120
121/*******************************************************************************
122* Global Variables *
123*******************************************************************************/
124/**
125 * Device extention & session data association structure.
126 */
127static SUPDRVDEVEXT g_DevExt;
128
129#ifndef CONFIG_VBOXDRV_AS_MISC
130/** Module major number for vboxdrv. */
131#define DEVICE_MAJOR_SYS 234
132/** Saved major device number for vboxdrv. */
133static int g_iModuleMajorSys;
134/** Module major number for vboxdrvu. */
135#define DEVICE_MAJOR_USR 235
136/** Saved major device number for vboxdrvu. */
137static int g_iModuleMajorUsr;
138#endif /* !CONFIG_VBOXDRV_AS_MISC */
139
140/** Module parameter.
141 * Not prefixed because the name is used by macros and the end of this file. */
142static int force_async_tsc = 0;
143
144/** The system device name. */
145#define DEVICE_NAME_SYS "vboxdrv"
146/** The user device name. */
147#define DEVICE_NAME_USR "vboxdrvu"
148
149#if defined(RT_ARCH_AMD64) && !defined(CONFIG_DEBUG_SET_MODULE_RONX)
150/**
151 * Memory for the executable memory heap (in IPRT).
152 */
153extern uint8_t g_abExecMemory[1572864]; /* 1.5 MB */
154__asm__(".section execmemory, \"awx\", @progbits\n\t"
155 ".align 32\n\t"
156 ".globl g_abExecMemory\n"
157 "g_abExecMemory:\n\t"
158 ".zero 1572864\n\t"
159 ".type g_abExecMemory, @object\n\t"
160 ".size g_abExecMemory, 1572864\n\t"
161 ".text\n\t");
162#endif
163
164/** The file_operations structure. */
165static struct file_operations gFileOpsVBoxDrvSys =
166{
167 owner: THIS_MODULE,
168 open: VBoxDrvLinuxCreateSys,
169 release: VBoxDrvLinuxClose,
170#ifdef HAVE_UNLOCKED_IOCTL
171 unlocked_ioctl: VBoxDrvLinuxIOCtl,
172#else
173 ioctl: VBoxDrvLinuxIOCtl,
174#endif
175};
176
177/** The file_operations structure. */
178static struct file_operations gFileOpsVBoxDrvUsr =
179{
180 owner: THIS_MODULE,
181 open: VBoxDrvLinuxCreateUsr,
182 release: VBoxDrvLinuxClose,
183#ifdef HAVE_UNLOCKED_IOCTL
184 unlocked_ioctl: VBoxDrvLinuxIOCtl,
185#else
186 ioctl: VBoxDrvLinuxIOCtl,
187#endif
188};
189
190#ifdef CONFIG_VBOXDRV_AS_MISC
191/** The miscdevice structure for vboxdrv. */
192static struct miscdevice gMiscDeviceSys =
193{
194 minor: MISC_DYNAMIC_MINOR,
195 name: DEVICE_NAME_SYS,
196 fops: &gFileOpsVBoxDrvSys,
197# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
198 devfs_name: DEVICE_NAME_SYS,
199# endif
200};
201/** The miscdevice structure for vboxdrvu. */
202static struct miscdevice gMiscDeviceUsr =
203{
204 minor: MISC_DYNAMIC_MINOR,
205 name: DEVICE_NAME_USR,
206 fops: &gFileOpsVBoxDrvUsr,
207# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
208 devfs_name: DEVICE_NAME_USR,
209# endif
210};
211#endif
212
213
214#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
215# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
216static struct dev_pm_ops gPlatformPMOps =
217{
218 .suspend = VBoxDrvSuspend, /* before entering deep sleep */
219 .resume = VBoxDrvResume, /* after wakeup from deep sleep */
220 .freeze = VBoxDrvSuspend, /* before creating hibernation image */
221 .restore = VBoxDrvResume, /* after waking up from hibernation */
222};
223# endif
224
225static struct platform_driver gPlatformDriver =
226{
227 .probe = VBoxDrvProbe,
228# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
229 .suspend = VBoxDrvSuspend,
230 .resume = VBoxDrvResume,
231# endif
232 /** @todo .shutdown? */
233 .driver =
234 {
235 .name = "vboxdrv",
236# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
237 .pm = &gPlatformPMOps,
238# endif
239 }
240};
241
242static struct platform_device gPlatformDevice =
243{
244 .name = "vboxdrv",
245 .dev =
246 {
247 .release = VBoxDevRelease
248 }
249};
250#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
251
252
253DECLINLINE(RTUID) vboxdrvLinuxUid(void)
254{
255#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
256 return current->cred->uid;
257#else
258 return current->uid;
259#endif
260}
261
262DECLINLINE(RTGID) vboxdrvLinuxGid(void)
263{
264#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
265 return current->cred->gid;
266#else
267 return current->gid;
268#endif
269}
270
271DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
272{
273#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
274 return current->cred->euid;
275#else
276 return current->euid;
277#endif
278}
279
280/**
281 * Initialize module.
282 *
283 * @returns appropriate status code.
284 */
285static int __init VBoxDrvLinuxInit(void)
286{
287 int rc;
288
289 /*
290 * Check for synchronous/asynchronous TSC mode.
291 */
292 printk(KERN_DEBUG "vboxdrv: Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount());
293#ifdef CONFIG_VBOXDRV_AS_MISC
294 rc = misc_register(&gMiscDeviceSys);
295 if (rc)
296 {
297 printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc);
298 return rc;
299 }
300 rc = misc_register(&gMiscDeviceUsr);
301 if (rc)
302 {
303 printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc);
304 misc_deregister(&gMiscDeviceSys);
305 return rc;
306 }
307#else /* !CONFIG_VBOXDRV_AS_MISC */
308 /*
309 * Register character devices and save the returned major numbers.
310 */
311 /* /dev/vboxdrv */
312 g_iModuleMajorSys = DEVICE_MAJOR_SYS;
313 rc = register_chrdev((dev_t)g_iModuleMajorSys, DEVICE_NAME_SYS, &gFileOpsVBoxDrvSys);
314 if (rc < 0)
315 {
316 Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc));
317 return rc;
318 }
319 if (DEVICE_MAJOR_SYS != 0)
320 g_iModuleMajorSys = DEVICE_MAJOR_SYS;
321 else
322 g_iModuleMajorSys = rc;
323
324 /* /dev/vboxdrvu */
325 /** @todo Use a minor number of this bugger (not sure if this code is used
326 * though, so not bothering right now.) */
327 g_iModuleMajorUsr = DEVICE_MAJOR_USR;
328 rc = register_chrdev((dev_t)g_iModuleMajorUsr, DEVICE_NAME_USR, &gFileOpsVBoxDrvUsr);
329 if (rc < 0)
330 {
331 Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc));
332 return rc;
333 }
334 if (DEVICE_MAJOR_USR != 0)
335 g_iModuleMajorUsr = DEVICE_MAJOR_USR;
336 else
337 g_iModuleMajorUsr = rc;
338 rc = 0;
339
340# ifdef CONFIG_DEVFS_FS
341 /*
342 * Register a device entry
343 */
344 if ( devfs_mk_cdev(MKDEV(DEVICE_MAJOR_SYS, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_SYS) != 0
345 || devfs_mk_cdev(MKDEV(DEVICE_MAJOR_USR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_USR) != 0)
346 {
347 Log(("devfs_register failed!\n"));
348 rc = -EINVAL;
349 }
350# endif
351#endif /* !CONFIG_VBOXDRV_AS_MISC */
352 if (!rc)
353 {
354 /*
355 * Initialize the runtime.
356 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
357 */
358 rc = RTR0Init(0);
359 if (RT_SUCCESS(rc))
360 {
361#if defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
362 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
363 printk(KERN_DEBUG "VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
364#endif
365 Log(("VBoxDrv::ModuleInit\n"));
366
367 /*
368 * Initialize the device extension.
369 */
370 if (RT_SUCCESS(rc))
371 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
372 if (RT_SUCCESS(rc))
373 {
374#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
375 rc = platform_driver_register(&gPlatformDriver);
376 if (rc == 0)
377 {
378 rc = platform_device_register(&gPlatformDevice);
379 if (rc == 0)
380#endif
381 {
382 printk(KERN_INFO "vboxdrv: TSC mode is %s, kernel timer mode is 'normal'.\n",
383 g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'");
384 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
385 printk(KERN_DEBUG "vboxdrv: Successfully loaded version "
386 VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ").\n");
387 return rc;
388 }
389#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
390 else
391 platform_driver_unregister(&gPlatformDriver);
392 }
393#endif
394 }
395
396 rc = -EINVAL;
397 RTR0TermForced();
398 }
399 else
400 rc = -EINVAL;
401
402 /*
403 * Failed, cleanup and return the error code.
404 */
405#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
406 devfs_remove(DEVICE_NAME_SYS);
407 devfs_remove(DEVICE_NAME_USR);
408#endif
409 }
410#ifdef CONFIG_VBOXDRV_AS_MISC
411 misc_deregister(&gMiscDeviceSys);
412 misc_deregister(&gMiscDeviceUsr);
413 Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor));
414#else
415 unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR);
416 unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS);
417 Log(("VBoxDrv::ModuleInit returning %#x (major:%d & %d)\n", rc, g_iModuleMajorSys, g_iModuleMajorUsr));
418#endif
419 return rc;
420}
421
422
423/**
424 * Unload the module.
425 */
426static void __exit VBoxDrvLinuxUnload(void)
427{
428 int rc;
429 Log(("VBoxDrvLinuxUnload\n"));
430 NOREF(rc);
431
432#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
433 platform_device_unregister(&gPlatformDevice);
434 platform_driver_unregister(&gPlatformDriver);
435#endif
436
437 /*
438 * I Don't think it's possible to unload a driver which processes have
439 * opened, at least we'll blindly assume that here.
440 */
441#ifdef CONFIG_VBOXDRV_AS_MISC
442 rc = misc_deregister(&gMiscDeviceUsr);
443 if (rc < 0)
444 {
445 Log(("misc_deregister failed with rc=%#x on vboxdrvu\n", rc));
446 }
447 rc = misc_deregister(&gMiscDeviceSys);
448 if (rc < 0)
449 {
450 Log(("misc_deregister failed with rc=%#x on vboxdrv\n", rc));
451 }
452#else /* !CONFIG_VBOXDRV_AS_MISC */
453# ifdef CONFIG_DEVFS_FS
454 /*
455 * Unregister a device entry
456 */
457 devfs_remove(DEVICE_NAME_USR);
458 devfs_remove(DEVICE_NAME_SYS);
459# endif /* devfs */
460 unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR);
461 unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS);
462#endif /* !CONFIG_VBOXDRV_AS_MISC */
463
464 /*
465 * Destroy GIP, delete the device extension and terminate IPRT.
466 */
467 supdrvDeleteDevExt(&g_DevExt);
468 RTR0TermForced();
469}
470
471
472/**
473 * Common open code.
474 *
475 * @param pInode Pointer to inode info structure.
476 * @param pFilp Associated file pointer.
477 * @param fUnrestricted Indicates which device node which was opened.
478 */
479static int vboxdrvLinuxCreateCommon(struct inode *pInode, struct file *pFilp, bool fUnrestricted)
480{
481 int rc;
482 PSUPDRVSESSION pSession;
483 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
484
485#ifdef VBOX_WITH_HARDENING
486 /*
487 * Only root is allowed to access the device, enforce it!
488 */
489 if (vboxdrvLinuxEuid() != 0 /* root */ )
490 {
491 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
492 return -EPERM;
493 }
494#endif /* VBOX_WITH_HARDENING */
495
496 /*
497 * Call common code for the rest.
498 */
499 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
500 if (!rc)
501 {
502 pSession->Uid = vboxdrvLinuxUid();
503 pSession->Gid = vboxdrvLinuxGid();
504 }
505
506 pFilp->private_data = pSession;
507
508 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
509 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
510 RTProcSelf(), current->pid, current->comm));
511 return VBoxDrvLinuxErr2LinuxErr(rc);
512}
513
514
515/** /dev/vboxdrv. */
516static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp)
517{
518 return vboxdrvLinuxCreateCommon(pInode, pFilp, true);
519}
520
521
522/** /dev/vboxdrvu. */
523static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp)
524{
525 return vboxdrvLinuxCreateCommon(pInode, pFilp, false);
526}
527
528
529/**
530 * Close device.
531 *
532 * @param pInode Pointer to inode info structure.
533 * @param pFilp Associated file pointer.
534 */
535static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
536{
537 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
538 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
539 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
540 pFilp->private_data = NULL;
541 return 0;
542}
543
544
545#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
546/**
547 * Dummy device release function. We have to provide this function,
548 * otherwise the kernel will complain.
549 *
550 * @param pDev Pointer to the platform device.
551 */
552static void VBoxDevRelease(struct device *pDev)
553{
554}
555
556/**
557 * Dummy probe function.
558 *
559 * @param pDev Pointer to the platform device.
560 */
561static int VBoxDrvProbe(struct platform_device *pDev)
562{
563 return 0;
564}
565
566/**
567 * Suspend callback.
568 * @param pDev Pointer to the platform device.
569 * @param State message type, see Documentation/power/devices.txt.
570 */
571# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
572static int VBoxDrvSuspend(struct device *pDev)
573# else
574static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
575# endif
576{
577 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
578 return 0;
579}
580
581/**
582 * Resume callback.
583 *
584 * @param pDev Pointer to the platform device.
585 */
586# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
587static int VBoxDrvResume(struct device *pDev)
588# else
589static int VBoxDrvResume(struct platform_device *pDev)
590# endif
591{
592 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
593 return 0;
594}
595#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
596
597
598/**
599 * Device I/O Control entry point.
600 *
601 * @param pFilp Associated file pointer.
602 * @param uCmd The function specified to ioctl().
603 * @param ulArg The argument specified to ioctl().
604 */
605#ifdef HAVE_UNLOCKED_IOCTL
606static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
607#else
608static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
609#endif
610{
611 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data;
612
613 /*
614 * Deal with the two high-speed IOCtl that takes it's arguments from
615 * the session and iCmd, and only returns a VBox status code.
616 */
617#ifdef HAVE_UNLOCKED_IOCTL
618 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
619 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
620 || uCmd == SUP_IOCTL_FAST_DO_NOP)
621 && pSession->fUnrestricted == true))
622 return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
623 return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
624
625#else /* !HAVE_UNLOCKED_IOCTL */
626
627 int rc;
628 unlock_kernel();
629 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
630 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
631 || uCmd == SUP_IOCTL_FAST_DO_NOP)
632 && pSession->fUnrestricted == true))
633 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
634 else
635 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
636 lock_kernel();
637 return rc;
638#endif /* !HAVE_UNLOCKED_IOCTL */
639}
640
641
642/**
643 * Device I/O Control entry point.
644 *
645 * @param pFilp Associated file pointer.
646 * @param uCmd The function specified to ioctl().
647 * @param ulArg The argument specified to ioctl().
648 * @param pSession The session instance.
649 */
650static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession)
651{
652 int rc;
653 SUPREQHDR Hdr;
654 PSUPREQHDR pHdr;
655 uint32_t cbBuf;
656
657 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
658
659 /*
660 * Read the header.
661 */
662 if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
663 {
664 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
665 return -EFAULT;
666 }
667 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
668 {
669 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
670 return -EINVAL;
671 }
672
673 /*
674 * Buffer the request.
675 */
676 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
677 if (RT_UNLIKELY(cbBuf > _1M*16))
678 {
679 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
680 return -E2BIG;
681 }
682 if (RT_UNLIKELY(cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd)))
683 {
684 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
685 return -EINVAL;
686 }
687 pHdr = RTMemAlloc(cbBuf);
688 if (RT_UNLIKELY(!pHdr))
689 {
690 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x.\n", cbBuf, uCmd));
691 return -ENOMEM;
692 }
693 if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
694 {
695 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
696 RTMemFree(pHdr);
697 return -EFAULT;
698 }
699
700 /*
701 * Process the IOCtl.
702 */
703 rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr);
704
705 /*
706 * Copy ioctl data and output buffer back to user space.
707 */
708 if (RT_LIKELY(!rc))
709 {
710 uint32_t cbOut = pHdr->cbOut;
711 if (RT_UNLIKELY(cbOut > cbBuf))
712 {
713 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
714 cbOut = cbBuf;
715 }
716 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
717 {
718 /* this is really bad! */
719 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
720 rc = -EFAULT;
721 }
722 }
723 else
724 {
725 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
726 rc = -EINVAL;
727 }
728 RTMemFree(pHdr);
729
730 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
731 return rc;
732}
733
734
735/**
736 * The SUPDRV IDC entry point.
737 *
738 * @returns VBox status code, see supdrvIDC.
739 * @param iReq The request code.
740 * @param pReq The request.
741 */
742int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
743{
744 PSUPDRVSESSION pSession;
745
746 /*
747 * Some quick validations.
748 */
749 if (RT_UNLIKELY(!VALID_PTR(pReq)))
750 return VERR_INVALID_POINTER;
751
752 pSession = pReq->pSession;
753 if (pSession)
754 {
755 if (RT_UNLIKELY(!VALID_PTR(pSession)))
756 return VERR_INVALID_PARAMETER;
757 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
758 return VERR_INVALID_PARAMETER;
759 }
760 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
761 return VERR_INVALID_PARAMETER;
762
763 /*
764 * Do the job.
765 */
766 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
767}
768
769EXPORT_SYMBOL(SUPDrvLinuxIDC);
770
771
772/**
773 * Initializes any OS specific object creator fields.
774 */
775void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
776{
777 NOREF(pObj);
778 NOREF(pSession);
779}
780
781
782/**
783 * Checks if the session can access the object.
784 *
785 * @returns true if a decision has been made.
786 * @returns false if the default access policy should be applied.
787 *
788 * @param pObj The object in question.
789 * @param pSession The session wanting to access the object.
790 * @param pszObjName The object name, can be NULL.
791 * @param prc Where to store the result when returning true.
792 */
793bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
794{
795 NOREF(pObj);
796 NOREF(pSession);
797 NOREF(pszObjName);
798 NOREF(prc);
799 return false;
800}
801
802
803bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
804{
805 return force_async_tsc != 0;
806}
807
808
809int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
810{
811 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
812 return VERR_NOT_SUPPORTED;
813}
814
815
816void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
817{
818 NOREF(pDevExt); NOREF(pImage);
819}
820
821
822int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
823{
824 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
825 return VERR_NOT_SUPPORTED;
826}
827
828
829int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
830{
831 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
832 return VERR_NOT_SUPPORTED;
833}
834
835
836void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
837{
838 NOREF(pDevExt); NOREF(pImage);
839}
840
841
842/**
843 * Converts a supdrv error code to an linux error code.
844 *
845 * @returns corresponding linux error code.
846 * @param rc IPRT status code.
847 */
848static int VBoxDrvLinuxErr2LinuxErr(int rc)
849{
850 switch (rc)
851 {
852 case VINF_SUCCESS: return 0;
853 case VERR_GENERAL_FAILURE: return -EACCES;
854 case VERR_INVALID_PARAMETER: return -EINVAL;
855 case VERR_INVALID_MAGIC: return -EILSEQ;
856 case VERR_INVALID_HANDLE: return -ENXIO;
857 case VERR_INVALID_POINTER: return -EFAULT;
858 case VERR_LOCK_FAILED: return -ENOLCK;
859 case VERR_ALREADY_LOADED: return -EEXIST;
860 case VERR_PERMISSION_DENIED: return -EPERM;
861 case VERR_VERSION_MISMATCH: return -ENOSYS;
862 case VERR_IDT_FAILED: return -1000;
863 }
864
865 return -EPERM;
866}
867
868
869RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
870{
871 va_list va;
872 char szMsg[512];
873
874 va_start(va, pszFormat);
875 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
876 va_end(va);
877 szMsg[sizeof(szMsg) - 1] = '\0';
878
879 printk("%s", szMsg);
880 return 0;
881}
882
883module_init(VBoxDrvLinuxInit);
884module_exit(VBoxDrvLinuxUnload);
885
886MODULE_AUTHOR(VBOX_VENDOR);
887MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
888MODULE_LICENSE("GPL");
889#ifdef MODULE_VERSION
890MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
891#endif
892
893module_param(force_async_tsc, int, 0444);
894MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
895
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