VirtualBox

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

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

The gip timer is not high-res on linux.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Rev: 34856 $ */
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 'normal'.\n",
330 g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'");
331 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
332 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
333 VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ").\n");
334 return rc;
335 }
336#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
337 else
338 platform_driver_unregister(&gPlatformDriver);
339 }
340#endif
341 }
342
343 rc = -EINVAL;
344 RTR0TermForced();
345 }
346 else
347 rc = -EINVAL;
348
349 /*
350 * Failed, cleanup and return the error code.
351 */
352#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
353 devfs_remove(DEVICE_NAME);
354#endif
355 }
356#ifdef CONFIG_VBOXDRV_AS_MISC
357 misc_deregister(&gMiscDevice);
358 Log(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
359#else
360 unregister_chrdev(g_iModuleMajor, DEVICE_NAME);
361 Log(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
362#endif
363 return rc;
364}
365
366
367/**
368 * Unload the module.
369 */
370static void __exit VBoxDrvLinuxUnload(void)
371{
372 int rc;
373 Log(("VBoxDrvLinuxUnload\n"));
374 NOREF(rc);
375
376#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
377 platform_device_unregister(&gPlatformDevice);
378 platform_driver_unregister(&gPlatformDriver);
379#endif
380
381 /*
382 * I Don't think it's possible to unload a driver which processes have
383 * opened, at least we'll blindly assume that here.
384 */
385#ifdef CONFIG_VBOXDRV_AS_MISC
386 rc = misc_deregister(&gMiscDevice);
387 if (rc < 0)
388 {
389 Log(("misc_deregister failed with rc=%#x\n", rc));
390 }
391#else /* !CONFIG_VBOXDRV_AS_MISC */
392# ifdef CONFIG_DEVFS_FS
393 /*
394 * Unregister a device entry
395 */
396 devfs_remove(DEVICE_NAME);
397# endif /* devfs */
398 unregister_chrdev(g_iModuleMajor, DEVICE_NAME);
399#endif /* !CONFIG_VBOXDRV_AS_MISC */
400
401 /*
402 * Destroy GIP, delete the device extension and terminate IPRT.
403 */
404 supdrvDeleteDevExt(&g_DevExt);
405 RTR0TermForced();
406}
407
408
409/**
410 * Device open. Called on open /dev/vboxdrv
411 *
412 * @param pInode Pointer to inode info structure.
413 * @param pFilp Associated file pointer.
414 */
415static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp)
416{
417 int rc;
418 PSUPDRVSESSION pSession;
419 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
420
421#ifdef VBOX_WITH_HARDENING
422 /*
423 * Only root is allowed to access the device, enforce it!
424 */
425 if (vboxdrvLinuxEuid() != 0 /* root */ )
426 {
427 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
428 return -EPERM;
429 }
430#endif /* VBOX_WITH_HARDENING */
431
432 /*
433 * Call common code for the rest.
434 */
435 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
436 if (!rc)
437 {
438 pSession->Uid = vboxdrvLinuxUid();
439 pSession->Gid = vboxdrvLinuxGid();
440 }
441
442 pFilp->private_data = pSession;
443
444 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
445 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
446 RTProcSelf(), current->pid, current->comm));
447 return VBoxDrvLinuxErr2LinuxErr(rc);
448}
449
450
451/**
452 * Close device.
453 *
454 * @param pInode Pointer to inode info structure.
455 * @param pFilp Associated file pointer.
456 */
457static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
458{
459 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
460 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
461 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
462 pFilp->private_data = NULL;
463 return 0;
464}
465
466
467#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
468/**
469 * Dummy device release function. We have to provide this function,
470 * otherwise the kernel will complain.
471 *
472 * @param pDev Pointer to the platform device.
473 */
474static void VBoxDevRelease(struct device *pDev)
475{
476}
477
478/**
479 * Dummy probe function.
480 *
481 * @param pDev Pointer to the platform device.
482 */
483static int VBoxDrvProbe(struct platform_device *pDev)
484{
485 return 0;
486}
487
488/**
489 * Suspend callback.
490 * @param pDev Pointer to the platform device.
491 * @param State message type, see Documentation/power/devices.txt.
492 */
493# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
494static int VBoxDrvSuspend(struct device *pDev)
495# else
496static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
497# endif
498{
499 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
500 return 0;
501}
502
503/**
504 * Resume callback.
505 *
506 * @param pDev Pointer to the platform device.
507 */
508# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
509static int VBoxDrvResume(struct device *pDev)
510# else
511static int VBoxDrvResume(struct platform_device *pDev)
512# endif
513{
514 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
515 return 0;
516}
517#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
518
519
520/**
521 * Device I/O Control entry point.
522 *
523 * @param pFilp Associated file pointer.
524 * @param uCmd The function specified to ioctl().
525 * @param ulArg The argument specified to ioctl().
526 */
527#ifdef HAVE_UNLOCKED_IOCTL
528static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
529#else
530static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
531#endif
532{
533 /*
534 * Deal with the two high-speed IOCtl that takes it's arguments from
535 * the session and iCmd, and only returns a VBox status code.
536 */
537#ifdef HAVE_UNLOCKED_IOCTL
538 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
539 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
540 || uCmd == SUP_IOCTL_FAST_DO_NOP))
541 return supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
542 return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
543
544#else /* !HAVE_UNLOCKED_IOCTL */
545
546 int rc;
547 unlock_kernel();
548 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
549 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
550 || uCmd == SUP_IOCTL_FAST_DO_NOP))
551 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
552 else
553 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
554 lock_kernel();
555 return rc;
556#endif /* !HAVE_UNLOCKED_IOCTL */
557}
558
559
560/**
561 * Device I/O Control entry point.
562 *
563 * @param pFilp Associated file pointer.
564 * @param uCmd The function specified to ioctl().
565 * @param ulArg The argument specified to ioctl().
566 */
567static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
568{
569 int rc;
570 SUPREQHDR Hdr;
571 PSUPREQHDR pHdr;
572 uint32_t cbBuf;
573
574 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
575
576 /*
577 * Read the header.
578 */
579 if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
580 {
581 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
582 return -EFAULT;
583 }
584 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
585 {
586 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
587 return -EINVAL;
588 }
589
590 /*
591 * Buffer the request.
592 */
593 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
594 if (RT_UNLIKELY(cbBuf > _1M*16))
595 {
596 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
597 return -E2BIG;
598 }
599 if (RT_UNLIKELY(cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd)))
600 {
601 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
602 return -EINVAL;
603 }
604 pHdr = RTMemAlloc(cbBuf);
605 if (RT_UNLIKELY(!pHdr))
606 {
607 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x.\n", cbBuf, uCmd));
608 return -ENOMEM;
609 }
610 if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
611 {
612 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
613 RTMemFree(pHdr);
614 return -EFAULT;
615 }
616
617 /*
618 * Process the IOCtl.
619 */
620 rc = supdrvIOCtl(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data, pHdr);
621
622 /*
623 * Copy ioctl data and output buffer back to user space.
624 */
625 if (RT_LIKELY(!rc))
626 {
627 uint32_t cbOut = pHdr->cbOut;
628 if (RT_UNLIKELY(cbOut > cbBuf))
629 {
630 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
631 cbOut = cbBuf;
632 }
633 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
634 {
635 /* this is really bad! */
636 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
637 rc = -EFAULT;
638 }
639 }
640 else
641 {
642 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
643 rc = -EINVAL;
644 }
645 RTMemFree(pHdr);
646
647 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
648 return rc;
649}
650
651
652/**
653 * The SUPDRV IDC entry point.
654 *
655 * @returns VBox status code, see supdrvIDC.
656 * @param iReq The request code.
657 * @param pReq The request.
658 */
659int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
660{
661 PSUPDRVSESSION pSession;
662
663 /*
664 * Some quick validations.
665 */
666 if (RT_UNLIKELY(!VALID_PTR(pReq)))
667 return VERR_INVALID_POINTER;
668
669 pSession = pReq->pSession;
670 if (pSession)
671 {
672 if (RT_UNLIKELY(!VALID_PTR(pSession)))
673 return VERR_INVALID_PARAMETER;
674 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
675 return VERR_INVALID_PARAMETER;
676 }
677 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
678 return VERR_INVALID_PARAMETER;
679
680 /*
681 * Do the job.
682 */
683 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
684}
685
686EXPORT_SYMBOL(SUPDrvLinuxIDC);
687
688
689/**
690 * Initializes any OS specific object creator fields.
691 */
692void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
693{
694 NOREF(pObj);
695 NOREF(pSession);
696}
697
698
699/**
700 * Checks if the session can access the object.
701 *
702 * @returns true if a decision has been made.
703 * @returns false if the default access policy should be applied.
704 *
705 * @param pObj The object in question.
706 * @param pSession The session wanting to access the object.
707 * @param pszObjName The object name, can be NULL.
708 * @param prc Where to store the result when returning true.
709 */
710bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
711{
712 NOREF(pObj);
713 NOREF(pSession);
714 NOREF(pszObjName);
715 NOREF(prc);
716 return false;
717}
718
719
720bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
721{
722 return force_async_tsc != 0;
723}
724
725
726int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
727{
728 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
729 return VERR_NOT_SUPPORTED;
730}
731
732
733int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
734{
735 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
736 return VERR_NOT_SUPPORTED;
737}
738
739
740int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits)
741{
742 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits);
743 return VERR_NOT_SUPPORTED;
744}
745
746
747void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
748{
749 NOREF(pDevExt); NOREF(pImage);
750}
751
752
753/**
754 * Converts a supdrv error code to an linux error code.
755 *
756 * @returns corresponding linux error code.
757 * @param rc IPRT status code.
758 */
759static int VBoxDrvLinuxErr2LinuxErr(int rc)
760{
761 switch (rc)
762 {
763 case VINF_SUCCESS: return 0;
764 case VERR_GENERAL_FAILURE: return -EACCES;
765 case VERR_INVALID_PARAMETER: return -EINVAL;
766 case VERR_INVALID_MAGIC: return -EILSEQ;
767 case VERR_INVALID_HANDLE: return -ENXIO;
768 case VERR_INVALID_POINTER: return -EFAULT;
769 case VERR_LOCK_FAILED: return -ENOLCK;
770 case VERR_ALREADY_LOADED: return -EEXIST;
771 case VERR_PERMISSION_DENIED: return -EPERM;
772 case VERR_VERSION_MISMATCH: return -ENOSYS;
773 case VERR_IDT_FAILED: return -1000;
774 }
775
776 return -EPERM;
777}
778
779
780RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
781{
782#if 1
783 va_list args;
784 char szMsg[512];
785
786 va_start(args, pszFormat);
787 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
788 szMsg[sizeof(szMsg) - 1] = '\0';
789 printk("%s", szMsg);
790 va_end(args);
791#else
792 /* forward to printf - needs some more GCC hacking to fix ebp... */
793 __asm__ __volatile__ ("mov %0, %esp\n\t"
794 "jmp %1\n\t",
795 :: "r" ((uintptr_t)&pszFormat - 4),
796 "m" (printk));
797#endif
798 return 0;
799}
800
801module_init(VBoxDrvLinuxInit);
802module_exit(VBoxDrvLinuxUnload);
803
804MODULE_AUTHOR(VBOX_VENDOR);
805MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
806MODULE_LICENSE("GPL");
807#ifdef MODULE_VERSION
808MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
809#endif
810
811module_param(force_async_tsc, int, 0444);
812MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
813
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