VirtualBox

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

Last change on this file since 38636 was 37972, checked in by vboxsync, 13 years ago

SUPDrv/Linux: Fix endless recursion

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