VirtualBox

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

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

Linux hosts: quick fix for CONFIG_DEBUG_SET_MODULE_RONX

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette