VirtualBox

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

Last change on this file since 33940 was 33940, checked in by vboxsync, 14 years ago

Support/linux: cosmetics

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