VirtualBox

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

Last change on this file since 54578 was 54144, checked in by vboxsync, 10 years ago

HostDrivers/Support/linux: don't prevent VBox R0 code from touching R3 code as a workaround for SMAP in Broadwell+ CPUs (thanks to Mathias Krause!)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.4 KB
Line 
1/* $Rev: 54144 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
52# include <asm/smap.h>
53#else
54static inline void clac(void) { }
55static inline void stac(void) { }
56#endif
57
58#include <linux/sched.h>
59#ifdef CONFIG_DEVFS_FS
60# include <linux/devfs_fs_kernel.h>
61#endif
62#ifdef CONFIG_VBOXDRV_AS_MISC
63# include <linux/miscdevice.h>
64#endif
65#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
66# include <linux/platform_device.h>
67#endif
68#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) && defined(SUPDRV_WITH_MSR_PROBER)
69# define SUPDRV_LINUX_HAS_SAFE_MSR_API
70# include <asm/msr.h>
71# include <iprt/asm-amd64-x86.h>
72#endif
73
74
75
76/*******************************************************************************
77* Defined Constants And Macros *
78*******************************************************************************/
79/* check kernel version */
80# ifndef SUPDRV_AGNOSTIC
81# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
82# error Unsupported kernel version!
83# endif
84# endif
85
86/* devfs defines */
87#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
88# ifdef VBOX_WITH_HARDENING
89# define VBOX_DEV_FMASK (S_IWUSR | S_IRUSR)
90# else
91# define VBOX_DEV_FMASK (S_IRUGO | S_IWUGO)
92# endif
93#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
94
95#ifdef CONFIG_X86_HIGH_ENTRY
96# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
97#endif
98
99/* to include the version number of VirtualBox into kernel backtraces */
100#define VBoxDrvLinuxVersion RT_CONCAT3(RT_CONCAT(VBOX_VERSION_MAJOR, _), \
101 RT_CONCAT(VBOX_VERSION_MINOR, _), \
102 VBOX_VERSION_BUILD)
103#define VBoxDrvLinuxIOCtl RT_CONCAT(VBoxDrvLinuxIOCtl_,VBoxDrvLinuxVersion)
104
105/*******************************************************************************
106* Internal Functions *
107*******************************************************************************/
108static int VBoxDrvLinuxInit(void);
109static void VBoxDrvLinuxUnload(void);
110static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp);
111static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp);
112static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
113#ifdef HAVE_UNLOCKED_IOCTL
114static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
115#else
116static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
117#endif
118static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession);
119static int VBoxDrvLinuxErr2LinuxErr(int);
120#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
121static int VBoxDrvProbe(struct platform_device *pDev);
122# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
123static int VBoxDrvSuspend(struct device *pDev);
124static int VBoxDrvResume(struct device *pDev);
125# else
126static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
127static int VBoxDrvResume(struct platform_device *pDev);
128# endif
129static void VBoxDevRelease(struct device *pDev);
130#endif
131
132
133/*******************************************************************************
134* Global Variables *
135*******************************************************************************/
136/**
137 * Device extention & session data association structure.
138 */
139static SUPDRVDEVEXT g_DevExt;
140
141#ifndef CONFIG_VBOXDRV_AS_MISC
142/** Module major number for vboxdrv. */
143#define DEVICE_MAJOR_SYS 234
144/** Saved major device number for vboxdrv. */
145static int g_iModuleMajorSys;
146/** Module major number for vboxdrvu. */
147#define DEVICE_MAJOR_USR 235
148/** Saved major device number for vboxdrvu. */
149static int g_iModuleMajorUsr;
150#endif /* !CONFIG_VBOXDRV_AS_MISC */
151
152/** Module parameter.
153 * Not prefixed because the name is used by macros and the end of this file. */
154static int force_async_tsc = 0;
155
156/** The system device name. */
157#define DEVICE_NAME_SYS "vboxdrv"
158/** The user device name. */
159#define DEVICE_NAME_USR "vboxdrvu"
160
161#if (defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)) || defined(VBOX_WITH_TEXT_MODMEM_HACK)
162/**
163 * Memory for the executable memory heap (in IPRT).
164 */
165# ifdef DEBUG
166# define EXEC_MEMORY_SIZE 6291456 /* 6 MB */
167# else
168# define EXEC_MEMORY_SIZE 1572864 /* 1.5 MB */
169# endif
170extern uint8_t g_abExecMemory[EXEC_MEMORY_SIZE];
171# ifndef VBOX_WITH_TEXT_MODMEM_HACK
172__asm__(".section execmemory, \"awx\", @progbits\n\t"
173 ".align 32\n\t"
174 ".globl g_abExecMemory\n"
175 "g_abExecMemory:\n\t"
176 ".zero " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
177 ".type g_abExecMemory, @object\n\t"
178 ".size g_abExecMemory, " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
179 ".text\n\t");
180# else
181__asm__(".text\n\t"
182 ".align 4096\n\t"
183 ".globl g_abExecMemory\n"
184 "g_abExecMemory:\n\t"
185 ".zero " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
186 ".type g_abExecMemory, @object\n\t"
187 ".size g_abExecMemory, " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
188 ".text\n\t");
189# endif
190#endif
191
192/** The file_operations structure. */
193static struct file_operations gFileOpsVBoxDrvSys =
194{
195 owner: THIS_MODULE,
196 open: VBoxDrvLinuxCreateSys,
197 release: VBoxDrvLinuxClose,
198#ifdef HAVE_UNLOCKED_IOCTL
199 unlocked_ioctl: VBoxDrvLinuxIOCtl,
200#else
201 ioctl: VBoxDrvLinuxIOCtl,
202#endif
203};
204
205/** The file_operations structure. */
206static struct file_operations gFileOpsVBoxDrvUsr =
207{
208 owner: THIS_MODULE,
209 open: VBoxDrvLinuxCreateUsr,
210 release: VBoxDrvLinuxClose,
211#ifdef HAVE_UNLOCKED_IOCTL
212 unlocked_ioctl: VBoxDrvLinuxIOCtl,
213#else
214 ioctl: VBoxDrvLinuxIOCtl,
215#endif
216};
217
218#ifdef CONFIG_VBOXDRV_AS_MISC
219/** The miscdevice structure for vboxdrv. */
220static struct miscdevice gMiscDeviceSys =
221{
222 minor: MISC_DYNAMIC_MINOR,
223 name: DEVICE_NAME_SYS,
224 fops: &gFileOpsVBoxDrvSys,
225# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
226 devfs_name: DEVICE_NAME_SYS,
227# endif
228};
229/** The miscdevice structure for vboxdrvu. */
230static struct miscdevice gMiscDeviceUsr =
231{
232 minor: MISC_DYNAMIC_MINOR,
233 name: DEVICE_NAME_USR,
234 fops: &gFileOpsVBoxDrvUsr,
235# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
236 devfs_name: DEVICE_NAME_USR,
237# endif
238};
239#endif
240
241
242#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
243# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
244static struct dev_pm_ops gPlatformPMOps =
245{
246 .suspend = VBoxDrvSuspend, /* before entering deep sleep */
247 .resume = VBoxDrvResume, /* after wakeup from deep sleep */
248 .freeze = VBoxDrvSuspend, /* before creating hibernation image */
249 .restore = VBoxDrvResume, /* after waking up from hibernation */
250};
251# endif
252
253static struct platform_driver gPlatformDriver =
254{
255 .probe = VBoxDrvProbe,
256# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
257 .suspend = VBoxDrvSuspend,
258 .resume = VBoxDrvResume,
259# endif
260 /** @todo .shutdown? */
261 .driver =
262 {
263 .name = "vboxdrv",
264# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
265 .pm = &gPlatformPMOps,
266# endif
267 }
268};
269
270static struct platform_device gPlatformDevice =
271{
272 .name = "vboxdrv",
273 .dev =
274 {
275 .release = VBoxDevRelease
276 }
277};
278#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
279
280
281DECLINLINE(RTUID) vboxdrvLinuxUid(void)
282{
283#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
284# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
285 return from_kuid(current_user_ns(), current->cred->uid);
286# else
287 return current->cred->uid;
288# endif
289#else
290 return current->uid;
291#endif
292}
293
294DECLINLINE(RTGID) vboxdrvLinuxGid(void)
295{
296#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
297# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
298 return from_kgid(current_user_ns(), current->cred->gid);
299# else
300 return current->cred->gid;
301# endif
302#else
303 return current->gid;
304#endif
305}
306
307DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
308{
309#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
310# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
311 return from_kuid(current_user_ns(), current->cred->euid);
312# else
313 return current->cred->euid;
314# endif
315#else
316 return current->euid;
317#endif
318}
319
320/**
321 * Initialize module.
322 *
323 * @returns appropriate status code.
324 */
325static int __init VBoxDrvLinuxInit(void)
326{
327 int rc;
328
329 /*
330 * Check for synchronous/asynchronous TSC mode.
331 */
332 printk(KERN_DEBUG "vboxdrv: Found %u processor cores\n", (unsigned)RTMpGetOnlineCount());
333#ifdef CONFIG_VBOXDRV_AS_MISC
334 rc = misc_register(&gMiscDeviceSys);
335 if (rc)
336 {
337 printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc);
338 return rc;
339 }
340 rc = misc_register(&gMiscDeviceUsr);
341 if (rc)
342 {
343 printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc);
344 misc_deregister(&gMiscDeviceSys);
345 return rc;
346 }
347#else /* !CONFIG_VBOXDRV_AS_MISC */
348 /*
349 * Register character devices and save the returned major numbers.
350 */
351 /* /dev/vboxdrv */
352 g_iModuleMajorSys = DEVICE_MAJOR_SYS;
353 rc = register_chrdev((dev_t)g_iModuleMajorSys, DEVICE_NAME_SYS, &gFileOpsVBoxDrvSys);
354 if (rc < 0)
355 {
356 Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc));
357 return rc;
358 }
359 if (DEVICE_MAJOR_SYS != 0)
360 g_iModuleMajorSys = DEVICE_MAJOR_SYS;
361 else
362 g_iModuleMajorSys = rc;
363
364 /* /dev/vboxdrvu */
365 /** @todo Use a minor number of this bugger (not sure if this code is used
366 * though, so not bothering right now.) */
367 g_iModuleMajorUsr = DEVICE_MAJOR_USR;
368 rc = register_chrdev((dev_t)g_iModuleMajorUsr, DEVICE_NAME_USR, &gFileOpsVBoxDrvUsr);
369 if (rc < 0)
370 {
371 Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc));
372 return rc;
373 }
374 if (DEVICE_MAJOR_USR != 0)
375 g_iModuleMajorUsr = DEVICE_MAJOR_USR;
376 else
377 g_iModuleMajorUsr = rc;
378 rc = 0;
379
380# ifdef CONFIG_DEVFS_FS
381 /*
382 * Register a device entry
383 */
384 if ( devfs_mk_cdev(MKDEV(DEVICE_MAJOR_SYS, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_SYS) != 0
385 || devfs_mk_cdev(MKDEV(DEVICE_MAJOR_USR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_USR) != 0)
386 {
387 Log(("devfs_register failed!\n"));
388 rc = -EINVAL;
389 }
390# endif
391#endif /* !CONFIG_VBOXDRV_AS_MISC */
392 if (!rc)
393 {
394 /*
395 * Initialize the runtime.
396 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
397 */
398 rc = RTR0Init(0);
399 if (RT_SUCCESS(rc))
400 {
401#if (defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)) || defined(VBOX_WITH_TEXT_MODMEM_HACK)
402# ifdef VBOX_WITH_TEXT_MODMEM_HACK
403 set_memory_x(&g_abExecMemory[0], sizeof(g_abExecMemory) / PAGE_SIZE);
404 set_memory_rw(&g_abExecMemory[0], sizeof(g_abExecMemory) / PAGE_SIZE);
405# endif
406 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
407 printk(KERN_DEBUG "VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
408#endif
409 Log(("VBoxDrv::ModuleInit\n"));
410
411 /*
412 * Initialize the device extension.
413 */
414 if (RT_SUCCESS(rc))
415 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
416 if (RT_SUCCESS(rc))
417 {
418#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
419 rc = platform_driver_register(&gPlatformDriver);
420 if (rc == 0)
421 {
422 rc = platform_device_register(&gPlatformDevice);
423 if (rc == 0)
424#endif
425 {
426 printk(KERN_INFO "vboxdrv: TSC mode is %s, tentative frequency %llu Hz\n",
427 SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz);
428 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
429 printk(KERN_DEBUG "vboxdrv: Successfully loaded version "
430 VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ")\n");
431 return rc;
432 }
433#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
434 else
435 platform_driver_unregister(&gPlatformDriver);
436 }
437#endif
438 }
439
440 rc = -EINVAL;
441 RTR0TermForced();
442 }
443 else
444 rc = -EINVAL;
445
446 /*
447 * Failed, cleanup and return the error code.
448 */
449#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
450 devfs_remove(DEVICE_NAME_SYS);
451 devfs_remove(DEVICE_NAME_USR);
452#endif
453 }
454#ifdef CONFIG_VBOXDRV_AS_MISC
455 misc_deregister(&gMiscDeviceSys);
456 misc_deregister(&gMiscDeviceUsr);
457 Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor));
458#else
459 unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR);
460 unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS);
461 Log(("VBoxDrv::ModuleInit returning %#x (major:%d & %d)\n", rc, g_iModuleMajorSys, g_iModuleMajorUsr));
462#endif
463 return rc;
464}
465
466
467/**
468 * Unload the module.
469 */
470static void __exit VBoxDrvLinuxUnload(void)
471{
472 int rc;
473 Log(("VBoxDrvLinuxUnload\n"));
474 NOREF(rc);
475
476#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
477 platform_device_unregister(&gPlatformDevice);
478 platform_driver_unregister(&gPlatformDriver);
479#endif
480
481 /*
482 * I Don't think it's possible to unload a driver which processes have
483 * opened, at least we'll blindly assume that here.
484 */
485#ifdef CONFIG_VBOXDRV_AS_MISC
486 rc = misc_deregister(&gMiscDeviceUsr);
487 if (rc < 0)
488 {
489 Log(("misc_deregister failed with rc=%#x on vboxdrvu\n", rc));
490 }
491 rc = misc_deregister(&gMiscDeviceSys);
492 if (rc < 0)
493 {
494 Log(("misc_deregister failed with rc=%#x on vboxdrv\n", rc));
495 }
496#else /* !CONFIG_VBOXDRV_AS_MISC */
497# ifdef CONFIG_DEVFS_FS
498 /*
499 * Unregister a device entry
500 */
501 devfs_remove(DEVICE_NAME_USR);
502 devfs_remove(DEVICE_NAME_SYS);
503# endif /* devfs */
504 unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR);
505 unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS);
506#endif /* !CONFIG_VBOXDRV_AS_MISC */
507
508 /*
509 * Destroy GIP, delete the device extension and terminate IPRT.
510 */
511 supdrvDeleteDevExt(&g_DevExt);
512 RTR0TermForced();
513}
514
515
516/**
517 * Common open code.
518 *
519 * @param pInode Pointer to inode info structure.
520 * @param pFilp Associated file pointer.
521 * @param fUnrestricted Indicates which device node which was opened.
522 */
523static int vboxdrvLinuxCreateCommon(struct inode *pInode, struct file *pFilp, bool fUnrestricted)
524{
525 int rc;
526 PSUPDRVSESSION pSession;
527 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
528
529#ifdef VBOX_WITH_HARDENING
530 /*
531 * Only root is allowed to access the unrestricted device, enforce it!
532 */
533 if ( fUnrestricted
534 && vboxdrvLinuxEuid() != 0 /* root */ )
535 {
536 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
537 return -EPERM;
538 }
539#endif /* VBOX_WITH_HARDENING */
540
541 /*
542 * Call common code for the rest.
543 */
544 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
545 if (!rc)
546 {
547 pSession->Uid = vboxdrvLinuxUid();
548 pSession->Gid = vboxdrvLinuxGid();
549 }
550
551 pFilp->private_data = pSession;
552
553 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
554 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
555 RTProcSelf(), current->pid, current->comm));
556 return VBoxDrvLinuxErr2LinuxErr(rc);
557}
558
559
560/** /dev/vboxdrv. */
561static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp)
562{
563 return vboxdrvLinuxCreateCommon(pInode, pFilp, true);
564}
565
566
567/** /dev/vboxdrvu. */
568static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp)
569{
570 return vboxdrvLinuxCreateCommon(pInode, pFilp, false);
571}
572
573
574/**
575 * Close device.
576 *
577 * @param pInode Pointer to inode info structure.
578 * @param pFilp Associated file pointer.
579 */
580static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
581{
582 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
583 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
584 supdrvSessionRelease((PSUPDRVSESSION)pFilp->private_data);
585 pFilp->private_data = NULL;
586 return 0;
587}
588
589
590#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
591/**
592 * Dummy device release function. We have to provide this function,
593 * otherwise the kernel will complain.
594 *
595 * @param pDev Pointer to the platform device.
596 */
597static void VBoxDevRelease(struct device *pDev)
598{
599}
600
601/**
602 * Dummy probe function.
603 *
604 * @param pDev Pointer to the platform device.
605 */
606static int VBoxDrvProbe(struct platform_device *pDev)
607{
608 return 0;
609}
610
611/**
612 * Suspend callback.
613 * @param pDev Pointer to the platform device.
614 * @param State message type, see Documentation/power/devices.txt.
615 */
616# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
617static int VBoxDrvSuspend(struct device *pDev)
618# else
619static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
620# endif
621{
622 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
623 return 0;
624}
625
626/**
627 * Resume callback.
628 *
629 * @param pDev Pointer to the platform device.
630 */
631# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
632static int VBoxDrvResume(struct device *pDev)
633# else
634static int VBoxDrvResume(struct platform_device *pDev)
635# endif
636{
637 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
638 return 0;
639}
640#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
641
642
643/**
644 * Device I/O Control entry point.
645 *
646 * @param pFilp Associated file pointer.
647 * @param uCmd The function specified to ioctl().
648 * @param ulArg The argument specified to ioctl().
649 */
650#ifdef HAVE_UNLOCKED_IOCTL
651static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
652#else
653static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
654#endif
655{
656 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data;
657 int rc;
658
659 /*
660 * Deal with the two high-speed IOCtl that takes it's arguments from
661 * the session and iCmd, and only returns a VBox status code.
662 */
663#ifdef HAVE_UNLOCKED_IOCTL
664 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
665 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
666 || uCmd == SUP_IOCTL_FAST_DO_NOP)
667 && pSession->fUnrestricted == true))
668 {
669 stac();
670 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
671 clac();
672 return rc;
673 }
674 return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
675
676#else /* !HAVE_UNLOCKED_IOCTL */
677 unlock_kernel();
678 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
679 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
680 || uCmd == SUP_IOCTL_FAST_DO_NOP)
681 && pSession->fUnrestricted == true))
682 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
683 else
684 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
685 lock_kernel();
686 return rc;
687#endif /* !HAVE_UNLOCKED_IOCTL */
688}
689
690
691/**
692 * Device I/O Control entry point.
693 *
694 * @param pFilp Associated file pointer.
695 * @param uCmd The function specified to ioctl().
696 * @param ulArg The argument specified to ioctl().
697 * @param pSession The session instance.
698 */
699static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession)
700{
701 int rc;
702 SUPREQHDR Hdr;
703 PSUPREQHDR pHdr;
704 uint32_t cbBuf;
705
706 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
707
708 /*
709 * Read the header.
710 */
711 if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
712 {
713 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
714 return -EFAULT;
715 }
716 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
717 {
718 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
719 return -EINVAL;
720 }
721
722 /*
723 * Buffer the request.
724 */
725 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
726 if (RT_UNLIKELY(cbBuf > _1M*16))
727 {
728 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
729 return -E2BIG;
730 }
731 if (RT_UNLIKELY(_IOC_SIZE(uCmd) ? cbBuf != _IOC_SIZE(uCmd) : Hdr.cbIn < sizeof(Hdr)))
732 {
733 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
734 return -EINVAL;
735 }
736 pHdr = RTMemAlloc(cbBuf);
737 if (RT_UNLIKELY(!pHdr))
738 {
739 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
740 return -ENOMEM;
741 }
742 if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
743 {
744 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
745 RTMemFree(pHdr);
746 return -EFAULT;
747 }
748 if (Hdr.cbIn < cbBuf)
749 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
750
751 /*
752 * Process the IOCtl.
753 */
754 stac();
755 rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
756 clac();
757
758 /*
759 * Copy ioctl data and output buffer back to user space.
760 */
761 if (RT_LIKELY(!rc))
762 {
763 uint32_t cbOut = pHdr->cbOut;
764 if (RT_UNLIKELY(cbOut > cbBuf))
765 {
766 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
767 cbOut = cbBuf;
768 }
769 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
770 {
771 /* this is really bad! */
772 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
773 rc = -EFAULT;
774 }
775 }
776 else
777 {
778 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
779 rc = -EINVAL;
780 }
781 RTMemFree(pHdr);
782
783 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
784 return rc;
785}
786
787
788/**
789 * The SUPDRV IDC entry point.
790 *
791 * @returns VBox status code, see supdrvIDC.
792 * @param iReq The request code.
793 * @param pReq The request.
794 */
795int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
796{
797 PSUPDRVSESSION pSession;
798
799 /*
800 * Some quick validations.
801 */
802 if (RT_UNLIKELY(!VALID_PTR(pReq)))
803 return VERR_INVALID_POINTER;
804
805 pSession = pReq->pSession;
806 if (pSession)
807 {
808 if (RT_UNLIKELY(!VALID_PTR(pSession)))
809 return VERR_INVALID_PARAMETER;
810 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
811 return VERR_INVALID_PARAMETER;
812 }
813 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
814 return VERR_INVALID_PARAMETER;
815
816 /*
817 * Do the job.
818 */
819 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
820}
821
822EXPORT_SYMBOL(SUPDrvLinuxIDC);
823
824
825void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
826{
827 NOREF(pDevExt);
828 NOREF(pSession);
829}
830
831
832void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
833{
834 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
835}
836
837
838void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
839{
840 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
841}
842
843
844/**
845 * Initializes any OS specific object creator fields.
846 */
847void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
848{
849 NOREF(pObj);
850 NOREF(pSession);
851}
852
853
854/**
855 * Checks if the session can access the object.
856 *
857 * @returns true if a decision has been made.
858 * @returns false if the default access policy should be applied.
859 *
860 * @param pObj The object in question.
861 * @param pSession The session wanting to access the object.
862 * @param pszObjName The object name, can be NULL.
863 * @param prc Where to store the result when returning true.
864 */
865bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
866{
867 NOREF(pObj);
868 NOREF(pSession);
869 NOREF(pszObjName);
870 NOREF(prc);
871 return false;
872}
873
874
875bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
876{
877 return force_async_tsc != 0;
878}
879
880
881bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
882{
883 return false;
884}
885
886
887int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
888{
889 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
890 return VERR_NOT_SUPPORTED;
891}
892
893
894void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
895{
896 NOREF(pDevExt); NOREF(pImage);
897}
898
899
900int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
901{
902 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
903 return VERR_NOT_SUPPORTED;
904}
905
906
907int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
908{
909 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
910 return VERR_NOT_SUPPORTED;
911}
912
913
914void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
915{
916 NOREF(pDevExt); NOREF(pImage);
917}
918
919
920#ifdef SUPDRV_WITH_MSR_PROBER
921
922int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
923{
924# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
925 uint32_t u32Low, u32High;
926 int rc;
927
928 if (idCpu == NIL_RTCPUID)
929 rc = rdmsr_safe(uMsr, &u32Low, &u32High);
930 else if (RTMpIsCpuOnline(idCpu))
931 rc = rdmsr_safe_on_cpu(idCpu, uMsr, &u32Low, &u32High);
932 else
933 return VERR_CPU_OFFLINE;
934 if (rc == 0)
935 {
936 *puValue = RT_MAKE_U64(u32Low, u32High);
937 return VINF_SUCCESS;
938 }
939 return VERR_ACCESS_DENIED;
940# else
941 return VERR_NOT_SUPPORTED;
942# endif
943}
944
945
946int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
947{
948# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
949 int rc;
950
951 if (idCpu == NIL_RTCPUID)
952 rc = wrmsr_safe(uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
953 else if (RTMpIsCpuOnline(idCpu))
954 rc = wrmsr_safe_on_cpu(idCpu, uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
955 else
956 return VERR_CPU_OFFLINE;
957 if (rc == 0)
958 return VINF_SUCCESS;
959 return VERR_ACCESS_DENIED;
960# else
961 return VERR_NOT_SUPPORTED;
962# endif
963}
964
965# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
966/**
967 * Worker for supdrvOSMsrProberModify.
968 */
969static DECLCALLBACK(void) supdrvLnxMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
970{
971 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
972 register uint32_t uMsr = pReq->u.In.uMsr;
973 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
974 uint64_t uBefore;
975 uint64_t uWritten;
976 uint64_t uAfter;
977 int rcBefore, rcWrite, rcAfter, rcRestore;
978 RTCCUINTREG fOldFlags;
979
980 /* Initialize result variables. */
981 uBefore = uWritten = uAfter = 0;
982 rcWrite = rcAfter = rcRestore = -EIO;
983
984 /*
985 * Do the job.
986 */
987 fOldFlags = ASMIntDisableFlags();
988 ASMCompilerBarrier(); /* paranoia */
989 if (!fFaster)
990 ASMWriteBackAndInvalidateCaches();
991
992 rcBefore = rdmsrl_safe(uMsr, &uBefore);
993 if (rcBefore >= 0)
994 {
995 register uint64_t uRestore = uBefore;
996 uWritten = uRestore;
997 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
998 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
999
1000 rcWrite = wrmsr_safe(uMsr, RT_LODWORD(uWritten), RT_HIDWORD(uWritten));
1001 rcAfter = rdmsrl_safe(uMsr, &uAfter);
1002 rcRestore = wrmsr_safe(uMsr, RT_LODWORD(uRestore), RT_HIDWORD(uRestore));
1003
1004 if (!fFaster)
1005 {
1006 ASMWriteBackAndInvalidateCaches();
1007 ASMReloadCR3();
1008 ASMNopPause();
1009 }
1010 }
1011
1012 ASMCompilerBarrier(); /* paranoia */
1013 ASMSetFlags(fOldFlags);
1014
1015 /*
1016 * Write out the results.
1017 */
1018 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1019 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1020 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1021 pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
1022 pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
1023 pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
1024 pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
1025 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1026}
1027# endif
1028
1029
1030int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1031{
1032# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1033 if (idCpu == NIL_RTCPUID)
1034 {
1035 supdrvLnxMsrProberModifyOnCpu(idCpu, pReq, NULL);
1036 return VINF_SUCCESS;
1037 }
1038 return RTMpOnSpecific(idCpu, supdrvLnxMsrProberModifyOnCpu, pReq, NULL);
1039# else
1040 return VERR_NOT_SUPPORTED;
1041# endif
1042}
1043
1044#endif /* SUPDRV_WITH_MSR_PROBER */
1045
1046
1047/**
1048 * Converts a supdrv error code to an linux error code.
1049 *
1050 * @returns corresponding linux error code.
1051 * @param rc IPRT status code.
1052 */
1053static int VBoxDrvLinuxErr2LinuxErr(int rc)
1054{
1055 switch (rc)
1056 {
1057 case VINF_SUCCESS: return 0;
1058 case VERR_GENERAL_FAILURE: return -EACCES;
1059 case VERR_INVALID_PARAMETER: return -EINVAL;
1060 case VERR_INVALID_MAGIC: return -EILSEQ;
1061 case VERR_INVALID_HANDLE: return -ENXIO;
1062 case VERR_INVALID_POINTER: return -EFAULT;
1063 case VERR_LOCK_FAILED: return -ENOLCK;
1064 case VERR_ALREADY_LOADED: return -EEXIST;
1065 case VERR_PERMISSION_DENIED: return -EPERM;
1066 case VERR_VERSION_MISMATCH: return -ENOSYS;
1067 case VERR_IDT_FAILED: return -1000;
1068 }
1069
1070 return -EPERM;
1071}
1072
1073
1074RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1075{
1076 va_list va;
1077 char szMsg[512];
1078
1079 va_start(va, pszFormat);
1080 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
1081 va_end(va);
1082 szMsg[sizeof(szMsg) - 1] = '\0';
1083
1084 printk("%s", szMsg);
1085 return 0;
1086}
1087
1088
1089/**
1090 * Returns configuration flags of the host kernel.
1091 */
1092SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
1093{
1094 uint32_t fFlags = 0;
1095#ifdef CONFIG_PAX_KERNEXEC
1096 fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY;
1097#endif
1098 return fFlags;
1099}
1100
1101
1102module_init(VBoxDrvLinuxInit);
1103module_exit(VBoxDrvLinuxUnload);
1104
1105MODULE_AUTHOR(VBOX_VENDOR);
1106MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
1107MODULE_LICENSE("GPL");
1108#ifdef MODULE_VERSION
1109MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
1110#endif
1111
1112module_param(force_async_tsc, int, 0444);
1113MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1114
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