VirtualBox

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

Last change on this file since 42739 was 41067, checked in by vboxsync, 13 years ago

supdrvOSLdrNotifyOpened so we can record the load address in NVRAM if we choose to.

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