VirtualBox

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

Last change on this file since 58872 was 58872, checked in by vboxsync, 9 years ago

SUPDrv: linux debugging aid.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.1 KB
Line 
1/* $Rev: 58872 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#include "../SUPDrvInternal.h"
33#include "the-linux-kernel.h"
34#include "version-generated.h"
35#include "product-generated.h"
36
37#include <iprt/assert.h>
38#include <iprt/spinlock.h>
39#include <iprt/semaphore.h>
40#include <iprt/initterm.h>
41#include <iprt/process.h>
42#include <VBox/err.h>
43#include <iprt/mem.h>
44#include <VBox/log.h>
45#include <iprt/mp.h>
46
47/** @todo figure out the exact version number */
48#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16)
49# include <iprt/power.h>
50# define VBOX_WITH_SUSPEND_NOTIFICATION
51#endif
52
53#include <linux/sched.h>
54#ifdef CONFIG_DEVFS_FS
55# include <linux/devfs_fs_kernel.h>
56#endif
57#ifdef CONFIG_VBOXDRV_AS_MISC
58# include <linux/miscdevice.h>
59#endif
60#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
61# include <linux/platform_device.h>
62#endif
63#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)) && defined(SUPDRV_WITH_MSR_PROBER)
64# define SUPDRV_LINUX_HAS_SAFE_MSR_API
65# include <asm/msr.h>
66#endif
67#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) && defined(CONFIG_DYNAMIC_FTRACE)
68# include <linux/ftrace.h>
69#endif
70
71#include <iprt/asm-amd64-x86.h>
72
73
74/*********************************************************************************************************************************
75* Defined Constants And Macros *
76*********************************************************************************************************************************/
77/* check kernel version */
78# ifndef SUPDRV_AGNOSTIC
79# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
80# error Unsupported kernel version!
81# endif
82# endif
83
84/* devfs defines */
85#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
86# ifdef VBOX_WITH_HARDENING
87# define VBOX_DEV_FMASK (S_IWUSR | S_IRUSR)
88# else
89# define VBOX_DEV_FMASK (S_IRUGO | S_IWUGO)
90# endif
91#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
92
93#ifdef CONFIG_X86_HIGH_ENTRY
94# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
95#endif
96
97/* We cannot include x86.h, so we copy the defines we need here: */
98#define X86_EFL_IF RT_BIT(9)
99#define X86_EFL_AC RT_BIT(18)
100#define X86_EFL_DF RT_BIT(10)
101#define X86_EFL_IOPL (RT_BIT(12) | RT_BIT(13))
102
103/* To include the version number of VirtualBox into kernel backtraces: */
104#define VBoxDrvLinuxVersion RT_CONCAT3(RT_CONCAT(VBOX_VERSION_MAJOR, _), \
105 RT_CONCAT(VBOX_VERSION_MINOR, _), \
106 VBOX_VERSION_BUILD)
107#define VBoxDrvLinuxIOCtl RT_CONCAT(VBoxDrvLinuxIOCtl_,VBoxDrvLinuxVersion)
108
109
110
111/*********************************************************************************************************************************
112* Internal Functions *
113*********************************************************************************************************************************/
114static int VBoxDrvLinuxInit(void);
115static void VBoxDrvLinuxUnload(void);
116static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp);
117static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp);
118static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
119#ifdef HAVE_UNLOCKED_IOCTL
120static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
121#else
122static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
123#endif
124static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession);
125static int VBoxDrvLinuxErr2LinuxErr(int);
126#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
127static int VBoxDrvProbe(struct platform_device *pDev);
128# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
129static int VBoxDrvSuspend(struct device *pDev);
130static int VBoxDrvResume(struct device *pDev);
131# else
132static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
133static int VBoxDrvResume(struct platform_device *pDev);
134# endif
135static void VBoxDevRelease(struct device *pDev);
136#endif
137
138
139/*********************************************************************************************************************************
140* Global Variables *
141*********************************************************************************************************************************/
142/**
143 * Device extention & session data association structure.
144 */
145static SUPDRVDEVEXT g_DevExt;
146
147#ifndef CONFIG_VBOXDRV_AS_MISC
148/** Module major number for vboxdrv. */
149#define DEVICE_MAJOR_SYS 234
150/** Saved major device number for vboxdrv. */
151static int g_iModuleMajorSys;
152/** Module major number for vboxdrvu. */
153#define DEVICE_MAJOR_USR 235
154/** Saved major device number for vboxdrvu. */
155static int g_iModuleMajorUsr;
156#endif /* !CONFIG_VBOXDRV_AS_MISC */
157
158/** Module parameter.
159 * Not prefixed because the name is used by macros and the end of this file. */
160static int force_async_tsc = 0;
161
162/** The system device name. */
163#define DEVICE_NAME_SYS "vboxdrv"
164/** The user device name. */
165#define DEVICE_NAME_USR "vboxdrvu"
166
167#if (defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)) || defined(VBOX_WITH_TEXT_MODMEM_HACK)
168/**
169 * Memory for the executable memory heap (in IPRT).
170 */
171# ifdef DEBUG
172# define EXEC_MEMORY_SIZE 6291456 /* 6 MB */
173# else
174# define EXEC_MEMORY_SIZE 1572864 /* 1.5 MB */
175# endif
176extern uint8_t g_abExecMemory[EXEC_MEMORY_SIZE];
177# ifndef VBOX_WITH_TEXT_MODMEM_HACK
178__asm__(".section execmemory, \"awx\", @progbits\n\t"
179 ".align 32\n\t"
180 ".globl g_abExecMemory\n"
181 "g_abExecMemory:\n\t"
182 ".zero " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
183 ".type g_abExecMemory, @object\n\t"
184 ".size g_abExecMemory, " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
185 ".text\n\t");
186# else
187__asm__(".text\n\t"
188 ".align 4096\n\t"
189 ".globl g_abExecMemory\n"
190 "g_abExecMemory:\n\t"
191 ".zero " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
192 ".type g_abExecMemory, @object\n\t"
193 ".size g_abExecMemory, " RT_XSTR(EXEC_MEMORY_SIZE) "\n\t"
194 ".text\n\t");
195# endif
196#endif
197
198/** The file_operations structure. */
199static struct file_operations gFileOpsVBoxDrvSys =
200{
201 owner: THIS_MODULE,
202 open: VBoxDrvLinuxCreateSys,
203 release: VBoxDrvLinuxClose,
204#ifdef HAVE_UNLOCKED_IOCTL
205 unlocked_ioctl: VBoxDrvLinuxIOCtl,
206#else
207 ioctl: VBoxDrvLinuxIOCtl,
208#endif
209};
210
211/** The file_operations structure. */
212static struct file_operations gFileOpsVBoxDrvUsr =
213{
214 owner: THIS_MODULE,
215 open: VBoxDrvLinuxCreateUsr,
216 release: VBoxDrvLinuxClose,
217#ifdef HAVE_UNLOCKED_IOCTL
218 unlocked_ioctl: VBoxDrvLinuxIOCtl,
219#else
220 ioctl: VBoxDrvLinuxIOCtl,
221#endif
222};
223
224#ifdef CONFIG_VBOXDRV_AS_MISC
225/** The miscdevice structure for vboxdrv. */
226static struct miscdevice gMiscDeviceSys =
227{
228 minor: MISC_DYNAMIC_MINOR,
229 name: DEVICE_NAME_SYS,
230 fops: &gFileOpsVBoxDrvSys,
231# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
232 devfs_name: DEVICE_NAME_SYS,
233# endif
234};
235/** The miscdevice structure for vboxdrvu. */
236static struct miscdevice gMiscDeviceUsr =
237{
238 minor: MISC_DYNAMIC_MINOR,
239 name: DEVICE_NAME_USR,
240 fops: &gFileOpsVBoxDrvUsr,
241# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
242 devfs_name: DEVICE_NAME_USR,
243# endif
244};
245#endif
246
247
248#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
249# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
250static struct dev_pm_ops gPlatformPMOps =
251{
252 .suspend = VBoxDrvSuspend, /* before entering deep sleep */
253 .resume = VBoxDrvResume, /* after wakeup from deep sleep */
254 .freeze = VBoxDrvSuspend, /* before creating hibernation image */
255 .restore = VBoxDrvResume, /* after waking up from hibernation */
256};
257# endif
258
259static struct platform_driver gPlatformDriver =
260{
261 .probe = VBoxDrvProbe,
262# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
263 .suspend = VBoxDrvSuspend,
264 .resume = VBoxDrvResume,
265# endif
266 /** @todo .shutdown? */
267 .driver =
268 {
269 .name = "vboxdrv",
270# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
271 .pm = &gPlatformPMOps,
272# endif
273 }
274};
275
276static struct platform_device gPlatformDevice =
277{
278 .name = "vboxdrv",
279 .dev =
280 {
281 .release = VBoxDevRelease
282 }
283};
284#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
285
286
287DECLINLINE(RTUID) vboxdrvLinuxUid(void)
288{
289#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
290# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
291 return from_kuid(current_user_ns(), current->cred->uid);
292# else
293 return current->cred->uid;
294# endif
295#else
296 return current->uid;
297#endif
298}
299
300DECLINLINE(RTGID) vboxdrvLinuxGid(void)
301{
302#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
303# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
304 return from_kgid(current_user_ns(), current->cred->gid);
305# else
306 return current->cred->gid;
307# endif
308#else
309 return current->gid;
310#endif
311}
312
313DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
314{
315#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
316# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
317 return from_kuid(current_user_ns(), current->cred->euid);
318# else
319 return current->cred->euid;
320# endif
321#else
322 return current->euid;
323#endif
324}
325
326/**
327 * Initialize module.
328 *
329 * @returns appropriate status code.
330 */
331static int __init VBoxDrvLinuxInit(void)
332{
333 int rc;
334
335 /*
336 * Check for synchronous/asynchronous TSC mode.
337 */
338 printk(KERN_DEBUG "vboxdrv: Found %u processor cores\n", (unsigned)RTMpGetOnlineCount());
339#ifdef CONFIG_VBOXDRV_AS_MISC
340 rc = misc_register(&gMiscDeviceSys);
341 if (rc)
342 {
343 printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc);
344 return rc;
345 }
346 rc = misc_register(&gMiscDeviceUsr);
347 if (rc)
348 {
349 printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc);
350 misc_deregister(&gMiscDeviceSys);
351 return rc;
352 }
353#else /* !CONFIG_VBOXDRV_AS_MISC */
354 /*
355 * Register character devices and save the returned major numbers.
356 */
357 /* /dev/vboxdrv */
358 g_iModuleMajorSys = DEVICE_MAJOR_SYS;
359 rc = register_chrdev((dev_t)g_iModuleMajorSys, DEVICE_NAME_SYS, &gFileOpsVBoxDrvSys);
360 if (rc < 0)
361 {
362 Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc));
363 return rc;
364 }
365 if (DEVICE_MAJOR_SYS != 0)
366 g_iModuleMajorSys = DEVICE_MAJOR_SYS;
367 else
368 g_iModuleMajorSys = rc;
369
370 /* /dev/vboxdrvu */
371 /** @todo Use a minor number of this bugger (not sure if this code is used
372 * though, so not bothering right now.) */
373 g_iModuleMajorUsr = DEVICE_MAJOR_USR;
374 rc = register_chrdev((dev_t)g_iModuleMajorUsr, DEVICE_NAME_USR, &gFileOpsVBoxDrvUsr);
375 if (rc < 0)
376 {
377 Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc));
378 return rc;
379 }
380 if (DEVICE_MAJOR_USR != 0)
381 g_iModuleMajorUsr = DEVICE_MAJOR_USR;
382 else
383 g_iModuleMajorUsr = rc;
384 rc = 0;
385
386# ifdef CONFIG_DEVFS_FS
387 /*
388 * Register a device entry
389 */
390 if ( devfs_mk_cdev(MKDEV(DEVICE_MAJOR_SYS, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_SYS) != 0
391 || devfs_mk_cdev(MKDEV(DEVICE_MAJOR_USR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_USR) != 0)
392 {
393 Log(("devfs_register failed!\n"));
394 rc = -EINVAL;
395 }
396# endif
397#endif /* !CONFIG_VBOXDRV_AS_MISC */
398 if (!rc)
399 {
400 /*
401 * Initialize the runtime.
402 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
403 */
404 rc = RTR0Init(0);
405 if (RT_SUCCESS(rc))
406 {
407#if (defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)) || defined(VBOX_WITH_TEXT_MODMEM_HACK)
408# ifdef VBOX_WITH_TEXT_MODMEM_HACK
409 set_memory_x(&g_abExecMemory[0], sizeof(g_abExecMemory) / PAGE_SIZE);
410 set_memory_rw(&g_abExecMemory[0], sizeof(g_abExecMemory) / PAGE_SIZE);
411# endif
412 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
413 printk(KERN_DEBUG "VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]);
414#endif
415 Log(("VBoxDrv::ModuleInit\n"));
416
417 /*
418 * Initialize the device extension.
419 */
420 if (RT_SUCCESS(rc))
421 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
422 if (RT_SUCCESS(rc))
423 {
424#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
425 rc = platform_driver_register(&gPlatformDriver);
426 if (rc == 0)
427 {
428 rc = platform_device_register(&gPlatformDevice);
429 if (rc == 0)
430#endif
431 {
432 printk(KERN_INFO "vboxdrv: TSC mode is %s, tentative frequency %llu Hz\n",
433 SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz);
434 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
435 printk(KERN_DEBUG "vboxdrv: Successfully loaded version "
436 VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ")\n");
437 return rc;
438 }
439#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
440 else
441 platform_driver_unregister(&gPlatformDriver);
442 }
443#endif
444 }
445
446 rc = -EINVAL;
447 RTR0TermForced();
448 }
449 else
450 rc = -EINVAL;
451
452 /*
453 * Failed, cleanup and return the error code.
454 */
455#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
456 devfs_remove(DEVICE_NAME_SYS);
457 devfs_remove(DEVICE_NAME_USR);
458#endif
459 }
460#ifdef CONFIG_VBOXDRV_AS_MISC
461 misc_deregister(&gMiscDeviceSys);
462 misc_deregister(&gMiscDeviceUsr);
463 Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor));
464#else
465 unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR);
466 unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS);
467 Log(("VBoxDrv::ModuleInit returning %#x (major:%d & %d)\n", rc, g_iModuleMajorSys, g_iModuleMajorUsr));
468#endif
469 return rc;
470}
471
472
473/**
474 * Unload the module.
475 */
476static void __exit VBoxDrvLinuxUnload(void)
477{
478 Log(("VBoxDrvLinuxUnload\n"));
479
480#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
481 platform_device_unregister(&gPlatformDevice);
482 platform_driver_unregister(&gPlatformDriver);
483#endif
484
485 /*
486 * I Don't think it's possible to unload a driver which processes have
487 * opened, at least we'll blindly assume that here.
488 */
489#ifdef CONFIG_VBOXDRV_AS_MISC
490 misc_deregister(&gMiscDeviceUsr);
491 misc_deregister(&gMiscDeviceSys);
492#else /* !CONFIG_VBOXDRV_AS_MISC */
493# ifdef CONFIG_DEVFS_FS
494 /*
495 * Unregister a device entry
496 */
497 devfs_remove(DEVICE_NAME_USR);
498 devfs_remove(DEVICE_NAME_SYS);
499# endif /* devfs */
500 unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR);
501 unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS);
502#endif /* !CONFIG_VBOXDRV_AS_MISC */
503
504 /*
505 * Destroy GIP, delete the device extension and terminate IPRT.
506 */
507 supdrvDeleteDevExt(&g_DevExt);
508 RTR0TermForced();
509}
510
511
512/**
513 * Common open code.
514 *
515 * @param pInode Pointer to inode info structure.
516 * @param pFilp Associated file pointer.
517 * @param fUnrestricted Indicates which device node which was opened.
518 */
519static int vboxdrvLinuxCreateCommon(struct inode *pInode, struct file *pFilp, bool fUnrestricted)
520{
521 int rc;
522 PSUPDRVSESSION pSession;
523 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
524
525#ifdef VBOX_WITH_HARDENING
526 /*
527 * Only root is allowed to access the unrestricted device, enforce it!
528 */
529 if ( fUnrestricted
530 && vboxdrvLinuxEuid() != 0 /* root */ )
531 {
532 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
533 return -EPERM;
534 }
535#endif /* VBOX_WITH_HARDENING */
536
537 /*
538 * Call common code for the rest.
539 */
540 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
541 if (!rc)
542 {
543 pSession->Uid = vboxdrvLinuxUid();
544 pSession->Gid = vboxdrvLinuxGid();
545 }
546
547 pFilp->private_data = pSession;
548
549 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
550 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
551 RTProcSelf(), current->pid, current->comm));
552 return VBoxDrvLinuxErr2LinuxErr(rc);
553}
554
555
556/** /dev/vboxdrv. */
557static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp)
558{
559 return vboxdrvLinuxCreateCommon(pInode, pFilp, true);
560}
561
562
563/** /dev/vboxdrvu. */
564static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp)
565{
566 return vboxdrvLinuxCreateCommon(pInode, pFilp, false);
567}
568
569
570/**
571 * Close device.
572 *
573 * @param pInode Pointer to inode info structure.
574 * @param pFilp Associated file pointer.
575 */
576static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
577{
578 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
579 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
580 supdrvSessionRelease((PSUPDRVSESSION)pFilp->private_data);
581 pFilp->private_data = NULL;
582 return 0;
583}
584
585
586#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
587/**
588 * Dummy device release function. We have to provide this function,
589 * otherwise the kernel will complain.
590 *
591 * @param pDev Pointer to the platform device.
592 */
593static void VBoxDevRelease(struct device *pDev)
594{
595}
596
597/**
598 * Dummy probe function.
599 *
600 * @param pDev Pointer to the platform device.
601 */
602static int VBoxDrvProbe(struct platform_device *pDev)
603{
604 return 0;
605}
606
607/**
608 * Suspend callback.
609 * @param pDev Pointer to the platform device.
610 * @param State Message type, see Documentation/power/devices.txt.
611 * Ignored.
612 */
613# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && !defined(DOXYGEN_RUNNING)
614static int VBoxDrvSuspend(struct device *pDev)
615# else
616static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
617# endif
618{
619 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
620 return 0;
621}
622
623/**
624 * Resume callback.
625 *
626 * @param pDev Pointer to the platform device.
627 */
628# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
629static int VBoxDrvResume(struct device *pDev)
630# else
631static int VBoxDrvResume(struct platform_device *pDev)
632# endif
633{
634 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
635 return 0;
636}
637#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
638
639
640/**
641 * Device I/O Control entry point.
642 *
643 * @param pFilp Associated file pointer.
644 * @param uCmd The function specified to ioctl().
645 * @param ulArg The argument specified to ioctl().
646 */
647#if defined(HAVE_UNLOCKED_IOCTL) || defined(DOXYGEN_RUNNING)
648static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
649#else
650static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
651#endif
652{
653 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data;
654 int rc;
655#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
656 RTCCUINTREG fSavedEfl;
657
658 /*
659 * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
660 *
661 * This isn't a problem, as there is absolutely nothing in the kernel context that
662 * depend on user context triggering cleanups. That would be pretty wild, right?
663 */
664 if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
665 {
666 SUPR0Printf("VBoxDrvLinuxIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
667 return ESPIPE;
668 }
669
670 fSavedEfl = ASMAddFlags(X86_EFL_AC);
671# else
672 stac();
673# endif
674
675 /*
676 * Deal with the two high-speed IOCtl that takes it's arguments from
677 * the session and iCmd, and only returns a VBox status code.
678 */
679#ifdef HAVE_UNLOCKED_IOCTL
680 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
681 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
682 || uCmd == SUP_IOCTL_FAST_DO_NOP)
683 && pSession->fUnrestricted == true))
684 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
685 else
686 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
687#else /* !HAVE_UNLOCKED_IOCTL */
688 unlock_kernel();
689 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
690 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
691 || uCmd == SUP_IOCTL_FAST_DO_NOP)
692 && pSession->fUnrestricted == true))
693 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
694 else
695 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
696 lock_kernel();
697#endif /* !HAVE_UNLOCKED_IOCTL */
698
699#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
700 /*
701 * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
702 * accidentially modified it or some other important flag.
703 */
704 if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL))
705 != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL)) | X86_EFL_AC) ))
706 {
707 char szTmp[48];
708 RTStrPrintf(szTmp, sizeof(szTmp), "uCmd=%#x: %#x->%#x!", _IOC_NR(uCmd), (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
709 supdrvBadContext(&g_DevExt, "SUPDrv-linux.c", __LINE__, szTmp);
710 }
711 ASMSetFlags(fSavedEfl);
712#else
713 clac();
714#endif
715 return rc;
716}
717
718
719/**
720 * Device I/O Control entry point.
721 *
722 * @param pFilp Associated file pointer.
723 * @param uCmd The function specified to ioctl().
724 * @param ulArg The argument specified to ioctl().
725 * @param pSession The session instance.
726 */
727static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession)
728{
729 int rc;
730 SUPREQHDR Hdr;
731 PSUPREQHDR pHdr;
732 uint32_t cbBuf;
733
734 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
735
736 /*
737 * Read the header.
738 */
739 if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
740 {
741 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
742 return -EFAULT;
743 }
744 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
745 {
746 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
747 return -EINVAL;
748 }
749
750 /*
751 * Buffer the request.
752 */
753 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
754 if (RT_UNLIKELY(cbBuf > _1M*16))
755 {
756 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
757 return -E2BIG;
758 }
759 if (RT_UNLIKELY(_IOC_SIZE(uCmd) ? cbBuf != _IOC_SIZE(uCmd) : Hdr.cbIn < sizeof(Hdr)))
760 {
761 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
762 return -EINVAL;
763 }
764 pHdr = RTMemAlloc(cbBuf);
765 if (RT_UNLIKELY(!pHdr))
766 {
767 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
768 return -ENOMEM;
769 }
770 if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
771 {
772 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
773 RTMemFree(pHdr);
774 return -EFAULT;
775 }
776 if (Hdr.cbIn < cbBuf)
777 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
778
779 /*
780 * Process the IOCtl.
781 */
782 rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
783
784 /*
785 * Copy ioctl data and output buffer back to user space.
786 */
787 if (RT_LIKELY(!rc))
788 {
789 uint32_t cbOut = pHdr->cbOut;
790 if (RT_UNLIKELY(cbOut > cbBuf))
791 {
792 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
793 cbOut = cbBuf;
794 }
795 if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
796 {
797 /* this is really bad! */
798 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
799 rc = -EFAULT;
800 }
801 }
802 else
803 {
804 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
805 rc = -EINVAL;
806 }
807 RTMemFree(pHdr);
808
809 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
810 return rc;
811}
812
813
814/**
815 * The SUPDRV IDC entry point.
816 *
817 * @returns VBox status code, see supdrvIDC.
818 * @param uReq The request code.
819 * @param pReq The request.
820 */
821int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
822{
823 PSUPDRVSESSION pSession;
824
825 /*
826 * Some quick validations.
827 */
828 if (RT_UNLIKELY(!VALID_PTR(pReq)))
829 return VERR_INVALID_POINTER;
830
831 pSession = pReq->pSession;
832 if (pSession)
833 {
834 if (RT_UNLIKELY(!VALID_PTR(pSession)))
835 return VERR_INVALID_PARAMETER;
836 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
837 return VERR_INVALID_PARAMETER;
838 }
839 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
840 return VERR_INVALID_PARAMETER;
841
842 /*
843 * Do the job.
844 */
845 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
846}
847
848EXPORT_SYMBOL(SUPDrvLinuxIDC);
849
850
851RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask)
852{
853#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 20, 0)
854 RTCCUINTREG uOld = this_cpu_read(cpu_tlbstate.cr4);
855 RTCCUINTREG uNew = (uOld & fAndMask) | fOrMask;
856 if (uNew != uOld)
857 {
858 this_cpu_write(cpu_tlbstate.cr4, uNew);
859 __write_cr4(uNew);
860 }
861#else
862 RTCCUINTREG uOld = ASMGetCR4();
863 RTCCUINTREG uNew = (uOld & fAndMask) | fOrMask;
864 if (uNew != uOld)
865 ASMSetCR4(uNew);
866#endif
867 return uOld;
868}
869
870
871void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
872{
873 NOREF(pDevExt);
874 NOREF(pSession);
875}
876
877
878void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
879{
880 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
881}
882
883
884void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
885{
886 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
887}
888
889
890/**
891 * Initializes any OS specific object creator fields.
892 */
893void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
894{
895 NOREF(pObj);
896 NOREF(pSession);
897}
898
899
900/**
901 * Checks if the session can access the object.
902 *
903 * @returns true if a decision has been made.
904 * @returns false if the default access policy should be applied.
905 *
906 * @param pObj The object in question.
907 * @param pSession The session wanting to access the object.
908 * @param pszObjName The object name, can be NULL.
909 * @param prc Where to store the result when returning true.
910 */
911bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
912{
913 NOREF(pObj);
914 NOREF(pSession);
915 NOREF(pszObjName);
916 NOREF(prc);
917 return false;
918}
919
920
921bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
922{
923 return force_async_tsc != 0;
924}
925
926
927bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
928{
929 return true;
930}
931
932
933bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
934{
935 return false;
936}
937
938
939int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
940{
941 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
942 return VERR_NOT_SUPPORTED;
943}
944
945
946int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
947{
948 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
949 return VERR_NOT_SUPPORTED;
950}
951
952
953int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
954{
955 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
956 return VERR_NOT_SUPPORTED;
957}
958
959
960void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
961{
962 NOREF(pDevExt); NOREF(pImage);
963}
964
965
966/** @def VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
967 * A very crude hack for debugging using perf and dtrace.
968 *
969 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
970 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
971 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
972 *
973 */
974#if 0 || defined(DOXYGEN_RUNNING)
975# define VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
976#endif
977
978#if defined(VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS) && defined(CONFIG_MODULES_TREE_LOOKUP)
979/** Whether g_pfnModTreeInsert and g_pfnModTreeRemove have been initialized.
980 * @remarks can still be NULL after init. */
981static volatile bool g_fLookedForModTreeFunctions = false;
982static void (*g_pfnModTreeInsert)(struct mod_tree_node *) = NULL; /**< __mod_tree_insert */
983static void (*g_pfnModTreeRemove)(struct mod_tree_node *) = NULL; /**< __mod_tree_remove */
984#endif
985
986#if 0 /* instant host lockup, can't be bothered debugging it */
987#if defined(VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS) \
988 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) \
989 && defined(CONFIG_MODULES_TREE_LOOKUP) \
990 && defined(CONFIG_DYNAMIC_FTRACE)
991
992/**
993 * Using a static array here because that's what is suggested in the docs to
994 * avoid/reduce potential race conditions.
995 */
996static struct supdrv_ftrace_ops
997{
998 struct ftrace_ops Core;
999 bool volatile fUsed;
1000} g_aFTraceOps[16] __read_mostly;
1001
1002/** Stub function for the ugly debug hack below. */
1003static void notrace __attribute__((optimize("-fomit-frame-pointer")))
1004supdrvLnxFTraceStub(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
1005{
1006 return;
1007}
1008
1009#endif
1010#endif
1011
1012
1013void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1014{
1015#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
1016 /*
1017 * This trick stops working with 4.2 when CONFIG_MODULES_TREE_LOOKUP is
1018 * defined. The module lookups are done via a tree structure and we
1019 * cannot get at the root of it. :-(
1020 */
1021# ifdef CONFIG_KALLSYMS
1022 size_t const cchName = strlen(pImage->szName);
1023# endif
1024 struct module *pMyMod, *pSelfMod, *pTestMod, *pTestModByName;
1025 IPRT_LINUX_SAVE_EFL_AC();
1026
1027 pImage->pLnxModHack = NULL;
1028 pImage->pLnxFTraceHack = NULL;
1029
1030# ifdef CONFIG_MODULES_TREE_LOOKUP
1031 /*
1032 * This is pretty naive, but works for 4.2 on arch linux. I don't think we
1033 * can count on finding __mod_tree_remove in all kernel builds as it's not
1034 * marked noinline like __mod_tree_insert.
1035 */
1036 if (!g_fLookedForModTreeFunctions)
1037 {
1038 unsigned long ulInsert = kallsyms_lookup_name("__mod_tree_insert");
1039 unsigned long ulRemove = kallsyms_lookup_name("__mod_tree_remove");
1040 if (!ulInsert || !ulRemove)
1041 {
1042 g_fLookedForModTreeFunctions = true;
1043 printk(KERN_ERR "vboxdrv: failed to locate __mod_tree_insert and __mod_tree_remove.\n");
1044 IPRT_LINUX_RESTORE_EFL_AC();
1045 return;
1046 }
1047 *(unsigned long *)&g_pfnModTreeInsert = ulInsert;
1048 *(unsigned long *)&g_pfnModTreeRemove = ulRemove;
1049 ASMCompilerBarrier();
1050 g_fLookedForModTreeFunctions = true;
1051 }
1052 else if (!g_pfnModTreeInsert || !g_pfnModTreeRemove)
1053 return;
1054#endif
1055
1056 /*
1057 * Make sure we've found our own module, otherwise we cannot access the linked list.
1058 */
1059 mutex_lock(&module_mutex);
1060 pSelfMod = find_module("vboxdrv");
1061 mutex_unlock(&module_mutex);
1062 if (!pSelfMod)
1063 {
1064 IPRT_LINUX_RESTORE_EFL_AC();
1065 return;
1066 }
1067
1068 /*
1069 * Cook up a module structure for the image.
1070 * We allocate symbol and string tables in the allocation and the module to keep things simple.
1071 */
1072# ifdef CONFIG_KALLSYMS
1073 pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod)
1074 + sizeof(Elf_Sym) * 3
1075 + 1 + cchName * 2 + sizeof("_start") + sizeof("_end") + 4 );
1076# else
1077 pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod));
1078# endif
1079 if (pMyMod)
1080 {
1081 int rc = VINF_SUCCESS;
1082 //size_t cch;
1083# ifdef CONFIG_KALLSYMS
1084 Elf_Sym *paSymbols = (Elf_Sym *)(pMyMod + 1);
1085 char *pchStrTab = (char *)(paSymbols + 3);
1086# endif
1087
1088 pMyMod->state = MODULE_STATE_LIVE;
1089 INIT_LIST_HEAD(&pMyMod->list); /* just in case */
1090
1091 /* Come up with a good name that perf can translate with minimum help... */
1092# if 0
1093 cch = strlen(pszFilename);
1094 if (cch < sizeof(pMyMod->name))
1095 memcpy(pMyMod->name, pszFilename, cch + 1);
1096 else
1097 {
1098 const char *pszTmp = pszFilename;
1099 for (;;)
1100 {
1101 /* skip one path component. */
1102 while (*pszTmp == '/')
1103 pszTmp++, cch--;
1104 while (*pszTmp != '/' && *pszTmp != '\0')
1105 pszTmp++, cch--;
1106
1107 /* If we've skipped past the final component, hack something up based on the module name. */
1108 if (*pszTmp != '/')
1109 {
1110 RTStrPrintf(pMyMod->name, sizeof(pMyMod->name), "/opt/VirtualBox/%s", pImage->szName);
1111 break;
1112 }
1113 /* When we've got space for two dots and the remaining path, we're done. */
1114 if (cch + 2 < sizeof(pMyMod->name))
1115 {
1116 pMyMod->name[0] = '.';
1117 pMyMod->name[1] = '.';
1118 memcpy(&pMyMod->name[2], pszTmp, cch + 1);
1119 break;
1120 }
1121 }
1122 }
1123# else
1124 /* Perf only matches up files with a .ko extension (maybe .ko.gz),
1125 so in order for this crap to work smoothly, we append .ko to the
1126 module name and require the user to create symbolic links in
1127 /lib/modules/`uname -r`:
1128 for i in VMMR0.r0 VBoxDDR0.r0 VBoxDD2R0.r0; do
1129 sudo ln -s /mnt/scratch/vbox/svn/trunk/out/linux.amd64/debug/bin/$i /lib/modules/`uname -r`/$i.ko;
1130 done */
1131 RTStrPrintf(pMyMod->name, sizeof(pMyMod->name), "%s", pImage->szName);
1132# endif
1133
1134 /* sysfs bits. */
1135 INIT_LIST_HEAD(&pMyMod->mkobj.kobj.entry); /* rest of kobj is already zeroed, hopefully never accessed... */
1136 pMyMod->mkobj.mod = pMyMod;
1137 pMyMod->mkobj.drivers_dir = NULL;
1138 pMyMod->mkobj.mp = NULL;
1139 pMyMod->mkobj.kobj_completion = NULL;
1140
1141 pMyMod->modinfo_attrs = NULL; /* hopefully not accessed after setup. */
1142 pMyMod->holders_dir = NULL; /* hopefully not accessed. */
1143 pMyMod->version = "N/A";
1144 pMyMod->srcversion = "N/A";
1145
1146 /* We export no symbols. */
1147 pMyMod->num_syms = 0;
1148 pMyMod->syms = NULL;
1149 pMyMod->crcs = NULL;
1150
1151 pMyMod->num_gpl_syms = 0;
1152 pMyMod->gpl_syms = NULL;
1153 pMyMod->gpl_crcs = NULL;
1154
1155 pMyMod->num_gpl_future_syms = 0;
1156 pMyMod->gpl_future_syms = NULL;
1157 pMyMod->gpl_future_crcs = NULL;
1158
1159# if CONFIG_UNUSED_SYMBOLS
1160 pMyMod->num_unused_syms = 0;
1161 pMyMod->unused_syms = NULL;
1162 pMyMod->unused_crcs = NULL;
1163
1164 pMyMod->num_unused_gpl_syms = 0;
1165 pMyMod->unused_gpl_syms = NULL;
1166 pMyMod->unused_gpl_crcs = NULL;
1167# endif
1168 /* No kernel parameters either. */
1169 pMyMod->kp = NULL;
1170 pMyMod->num_kp = 0;
1171
1172# ifdef CONFIG_MODULE_SIG
1173 /* Pretend ok signature. */
1174 pMyMod->sig_ok = true;
1175# endif
1176 /* No exception table. */
1177 pMyMod->num_exentries = 0;
1178 pMyMod->extable = NULL;
1179
1180 /* No init function */
1181 pMyMod->init = NULL;
1182 pMyMod->module_init = NULL;
1183 pMyMod->init_size = 0;
1184 pMyMod->init_ro_size = 0;
1185 pMyMod->init_text_size = 0;
1186
1187 /* The module address and size. It's all text. */
1188 pMyMod->module_core = pImage->pvImage;
1189 pMyMod->core_size = pImage->cbImageBits;
1190 pMyMod->core_text_size = pImage->cbImageBits;
1191 pMyMod->core_ro_size = pImage->cbImageBits;
1192
1193#ifdef CONFIG_MODULES_TREE_LOOKUP
1194 /* Fill in the self pointers for the tree nodes. */
1195 pMyMod->mtn_core.mod = pMyMod;
1196 pMyMod->mtn_init.mod = pMyMod;
1197#endif
1198 /* They invented the tained bit for us, didn't they? */
1199 pMyMod->taints = 1;
1200
1201# ifdef CONFIG_GENERIC_BUGS
1202 /* No BUGs in our modules. */
1203 pMyMod->num_bugs = 0;
1204 INIT_LIST_HEAD(&pMyMod->bug_list);
1205 pMyMod->bug_table = NULL;
1206# endif
1207
1208# ifdef CONFIG_KALLSYMS
1209 /* The core stuff is documented as only used when loading. So just zero them. */
1210 pMyMod->core_num_syms = 0;
1211 pMyMod->core_symtab = NULL;
1212 pMyMod->core_strtab = NULL;
1213
1214 /* Construct a symbol table with start and end symbols.
1215 Note! We don't have our own symbol table at this point, image bit
1216 are not uploaded yet! */
1217 pMyMod->num_symtab = 3;
1218 pMyMod->symtab = paSymbols;
1219 pMyMod->strtab = pchStrTab;
1220 RT_ZERO(paSymbols[0]);
1221 pchStrTab[0] = '\0';
1222 paSymbols[1].st_name = 1;
1223 paSymbols[2].st_name = 2 + RTStrPrintf(&pchStrTab[paSymbols[1].st_name], cchName + sizeof("_start"),
1224 "%s_start", pImage->szName);
1225 RTStrPrintf(&pchStrTab[paSymbols[2].st_name], cchName + sizeof("_end"), "%s_end", pImage->szName);
1226 paSymbols[1].st_info = 't';
1227 paSymbols[2].st_info = 'b';
1228 paSymbols[1].st_other = 0;
1229 paSymbols[2].st_other = 0;
1230 paSymbols[1].st_shndx = 0;
1231 paSymbols[2].st_shndx = 0;
1232 paSymbols[1].st_value = (uintptr_t)pImage->pvImage;
1233 paSymbols[2].st_value = (uintptr_t)pImage->pvImage + pImage->cbImageBits - 1;
1234 paSymbols[1].st_size = pImage->cbImageBits - 1;
1235 paSymbols[2].st_size = 1;
1236# endif
1237 /* No arguments, but seems its always non-NULL so put empty string there. */
1238 pMyMod->args = "";
1239
1240# ifdef CONFIG_SMP
1241 /* No per CPU data. */
1242 pMyMod->percpu = NULL;
1243 pMyMod->percpu_size = 0;
1244# endif
1245# ifdef CONFIG_TRACEPOINTS
1246 /* No tracepoints we like to share. */
1247 pMyMod->num_tracepoints = 0;
1248 pMyMod->tracepoints_ptrs = NULL;
1249#endif
1250# ifdef HAVE_JUMP_LABEL
1251 /* No jump lable stuff either. */
1252 pMyMod->jump_entries = NULL;
1253 pMyMod->num_jump_entries = 0;
1254# endif
1255# ifdef CONFIG_TRACING
1256 pMyMod->num_trace_bprintk_fmt = 0;
1257 pMyMod->trace_bprintk_fmt_start = NULL;
1258# endif
1259# ifdef CONFIG_EVENT_TRACING
1260 pMyMod->trace_events = NULL;
1261 pMyMod->num_trace_events = 0;
1262# endif
1263# ifdef CONFIG_FTRACE_MCOUNT_RECORD
1264 pMyMod->num_ftrace_callsites = 0;
1265 pMyMod->ftrace_callsites = NULL;
1266# endif
1267# ifdef CONFIG_MODULE_UNLOAD
1268 /* Dependency lists, not worth sharing */
1269 INIT_LIST_HEAD(&pMyMod->source_list);
1270 INIT_LIST_HEAD(&pMyMod->target_list);
1271
1272 /* Nobody waiting and no exit function. */
1273# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
1274 pMyMod->waiter = NULL;
1275# endif
1276 pMyMod->exit = NULL;
1277
1278 /* References, very important as we must not allow the module
1279 to be unloaded using rmmod. */
1280# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
1281 atomic_set(&pMyMod->refcnt, 42);
1282# else
1283 pMyMod->refptr = alloc_percpu(struct module_ref);
1284 if (pMyMod->refptr)
1285 {
1286 int iCpu;
1287 for_each_possible_cpu(iCpu)
1288 {
1289 per_cpu_ptr(pMyMod->refptr, iCpu)->decs = 0;
1290 per_cpu_ptr(pMyMod->refptr, iCpu)->incs = 1;
1291 }
1292 }
1293 else
1294 rc = VERR_NO_MEMORY;
1295# endif
1296# endif
1297# ifdef CONFIG_CONSTRUCTORS
1298 /* No constructors. */
1299 pMyMod->ctors = NULL;
1300 pMyMod->num_ctors = 0;
1301# endif
1302 if (RT_SUCCESS(rc))
1303 {
1304 bool fIsModText;
1305
1306 /*
1307 * Add the module to the list.
1308 */
1309 mutex_lock(&module_mutex);
1310 list_add_rcu(&pMyMod->list, &pSelfMod->list);
1311 pImage->pLnxModHack = pMyMod;
1312# ifdef CONFIG_MODULES_TREE_LOOKUP
1313 g_pfnModTreeInsert(&pMyMod->mtn_core); /* __mod_tree_insert */
1314# endif
1315 mutex_unlock(&module_mutex);
1316
1317#if 0 /* Horrible, non-working hack. Debug when __mod_tree_remove can't be found on a box we care about. */
1318# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) && defined(CONFIG_MODULES_TREE_LOOKUP)
1319# if defined(CONFIG_DYNAMIC_FTRACE)
1320 /*
1321 * Starting with 4.2 there's the module tree lookup which thwarts
1322 * the above module hack. So, we must install an additional hack
1323 * to get the job done. This relies on dynmaic ftrace trampolines
1324 * and is just as ugly as the above. Only for debugging!!
1325 */
1326 uint32_t i = 0;
1327 while (i < RT_ELEMENTS(g_aFTraceOps)
1328 && ASMAtomicXchgBool(&g_aFTraceOps[i].fUsed, true) == true)
1329 i++;
1330 if (i < RT_ELEMENTS(g_aFTraceOps))
1331 {
1332 struct supdrv_ftrace_ops *pOps = &g_aFTraceOps[i];
1333 pOps->Core.func = supdrvLnxFTraceStub;
1334 pOps->Core.flags = /*FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB |*/ FTRACE_OPS_FL_DYNAMIC;
1335 pOps->Core.trampoline = (uintptr_t)pImage->pvImage;
1336 pOps->Core.trampoline_size = (uintptr_t)pImage->cbImageBits;
1337
1338 rc = register_ftrace_function(&pOps->Core);
1339 if (rc == 0)
1340 pImage->pLnxFTraceHack = pOps;
1341 else
1342 printk(KERN_ERR "vboxdrv: register_ftrace_function failed: %d\n", rc);
1343 }
1344# else
1345# error "Sorry, without CONFIG_DYNAMIC_FTRACE currently not possible to get proper stack traces"
1346# endif
1347# endif
1348#endif
1349 /*
1350 * Test it.
1351 */
1352 mutex_lock(&module_mutex);
1353 pTestModByName = find_module(pMyMod->name);
1354 pTestMod = __module_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 4);
1355 fIsModText = __module_text_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 2);
1356 mutex_unlock(&module_mutex);
1357 if ( pTestMod == pMyMod
1358 && pTestModByName == pMyMod
1359 && fIsModText)
1360 printk(KERN_ERR "vboxdrv: fake module works for '%s' (%#lx to %#lx)\n",
1361 pMyMod->name, (unsigned long)paSymbols[1].st_value, (unsigned long)paSymbols[2].st_value);
1362 else
1363 printk(KERN_ERR "vboxdrv: failed to find fake module (pTestMod=%p, pTestModByName=%p, pMyMod=%p, fIsModText=%d)\n",
1364 pTestMod, pTestModByName, pMyMod, fIsModText);
1365 }
1366 else
1367 RTMemFree(pMyMod);
1368 }
1369
1370 IPRT_LINUX_RESTORE_EFL_AC();
1371#else
1372 pImage->pLnxModHack = NULL;
1373 pImage->pLnxFTraceHack = NULL;
1374#endif
1375 NOREF(pDevExt); NOREF(pImage);
1376}
1377
1378
1379void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1380{
1381#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
1382 struct module *pMyMod = pImage->pLnxModHack;
1383 pImage->pLnxModHack = NULL;
1384 if (pMyMod)
1385 {
1386 /*
1387 * Remove the fake module list entry and free it.
1388 */
1389 IPRT_LINUX_SAVE_EFL_AC();
1390 mutex_lock(&module_mutex);
1391 list_del_rcu(&pMyMod->list);
1392# ifdef CONFIG_MODULES_TREE_LOOKUP
1393 g_pfnModTreeRemove(&pMyMod->mtn_core);
1394# endif
1395 synchronize_sched();
1396 mutex_unlock(&module_mutex);
1397
1398# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
1399 free_percpu(pMyMod->refptr);
1400# endif
1401 RTMemFree(pMyMod);
1402 IPRT_LINUX_RESTORE_EFL_AC();
1403 }
1404
1405#if 0 /* Butt-ugly and ain't working yet. */
1406# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) && defined(CONFIG_MODULES_TREE_LOOKUP)
1407# if defined(CONFIG_DYNAMIC_FTRACE)
1408 {
1409 /*
1410 * Undo the ftrace hack.
1411 */
1412 struct supdrv_ftrace_ops *pOps = pImage->pLnxFTraceHack;
1413 pImage->pLnxFTraceHack = NULL;
1414 if (pOps)
1415 {
1416 IPRT_LINUX_SAVE_EFL_AC();
1417 int rc = unregister_ftrace_function(&pOps->Core);
1418 if (rc == 0)
1419 ASMAtomicWriteBool(&pOps->fUsed, false);
1420 else
1421 printk(KERN_ERR "vboxdrv: unregister_ftrace_function failed: %d\n", rc);
1422 IPRT_LINUX_RESTORE_EFL_AC();
1423 }
1424 }
1425# else
1426# error "Sorry, without CONFIG_DYNAMIC_FTRACE currently not possible to get proper stack traces"
1427# endif
1428# endif
1429#endif
1430
1431#else
1432 Assert(pImage->pLnxModHack == NULL);
1433#endif
1434 NOREF(pDevExt); NOREF(pImage);
1435}
1436
1437
1438#ifdef SUPDRV_WITH_MSR_PROBER
1439
1440int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
1441{
1442# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1443 uint32_t u32Low, u32High;
1444 int rc;
1445
1446 IPRT_LINUX_SAVE_EFL_AC();
1447 if (idCpu == NIL_RTCPUID)
1448 rc = rdmsr_safe(uMsr, &u32Low, &u32High);
1449 else if (RTMpIsCpuOnline(idCpu))
1450 rc = rdmsr_safe_on_cpu(idCpu, uMsr, &u32Low, &u32High);
1451 else
1452 return VERR_CPU_OFFLINE;
1453 IPRT_LINUX_RESTORE_EFL_AC();
1454 if (rc == 0)
1455 {
1456 *puValue = RT_MAKE_U64(u32Low, u32High);
1457 return VINF_SUCCESS;
1458 }
1459 return VERR_ACCESS_DENIED;
1460# else
1461 return VERR_NOT_SUPPORTED;
1462# endif
1463}
1464
1465
1466int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
1467{
1468# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1469 int rc;
1470
1471 IPRT_LINUX_SAVE_EFL_AC();
1472 if (idCpu == NIL_RTCPUID)
1473 rc = wrmsr_safe(uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
1474 else if (RTMpIsCpuOnline(idCpu))
1475 rc = wrmsr_safe_on_cpu(idCpu, uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
1476 else
1477 return VERR_CPU_OFFLINE;
1478 IPRT_LINUX_RESTORE_EFL_AC();
1479
1480 if (rc == 0)
1481 return VINF_SUCCESS;
1482 return VERR_ACCESS_DENIED;
1483# else
1484 return VERR_NOT_SUPPORTED;
1485# endif
1486}
1487
1488# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1489/**
1490 * Worker for supdrvOSMsrProberModify.
1491 */
1492static DECLCALLBACK(void) supdrvLnxMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1493{
1494 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
1495 register uint32_t uMsr = pReq->u.In.uMsr;
1496 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
1497 uint64_t uBefore;
1498 uint64_t uWritten;
1499 uint64_t uAfter;
1500 int rcBefore, rcWrite, rcAfter, rcRestore;
1501 RTCCUINTREG fOldFlags;
1502
1503 /* Initialize result variables. */
1504 uBefore = uWritten = uAfter = 0;
1505 rcWrite = rcAfter = rcRestore = -EIO;
1506
1507 /*
1508 * Do the job.
1509 */
1510 fOldFlags = ASMIntDisableFlags();
1511 ASMCompilerBarrier(); /* paranoia */
1512 if (!fFaster)
1513 ASMWriteBackAndInvalidateCaches();
1514
1515 rcBefore = rdmsrl_safe(uMsr, &uBefore);
1516 if (rcBefore >= 0)
1517 {
1518 register uint64_t uRestore = uBefore;
1519 uWritten = uRestore;
1520 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
1521 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
1522
1523 rcWrite = wrmsr_safe(uMsr, RT_LODWORD(uWritten), RT_HIDWORD(uWritten));
1524 rcAfter = rdmsrl_safe(uMsr, &uAfter);
1525 rcRestore = wrmsr_safe(uMsr, RT_LODWORD(uRestore), RT_HIDWORD(uRestore));
1526
1527 if (!fFaster)
1528 {
1529 ASMWriteBackAndInvalidateCaches();
1530 ASMReloadCR3();
1531 ASMNopPause();
1532 }
1533 }
1534
1535 ASMCompilerBarrier(); /* paranoia */
1536 ASMSetFlags(fOldFlags);
1537
1538 /*
1539 * Write out the results.
1540 */
1541 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1542 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1543 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1544 pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
1545 pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
1546 pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
1547 pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
1548 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1549}
1550# endif
1551
1552
1553int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1554{
1555# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1556 if (idCpu == NIL_RTCPUID)
1557 {
1558 supdrvLnxMsrProberModifyOnCpu(idCpu, pReq, NULL);
1559 return VINF_SUCCESS;
1560 }
1561 return RTMpOnSpecific(idCpu, supdrvLnxMsrProberModifyOnCpu, pReq, NULL);
1562# else
1563 return VERR_NOT_SUPPORTED;
1564# endif
1565}
1566
1567#endif /* SUPDRV_WITH_MSR_PROBER */
1568
1569
1570/**
1571 * Converts a supdrv error code to an linux error code.
1572 *
1573 * @returns corresponding linux error code.
1574 * @param rc IPRT status code.
1575 */
1576static int VBoxDrvLinuxErr2LinuxErr(int rc)
1577{
1578 switch (rc)
1579 {
1580 case VINF_SUCCESS: return 0;
1581 case VERR_GENERAL_FAILURE: return -EACCES;
1582 case VERR_INVALID_PARAMETER: return -EINVAL;
1583 case VERR_INVALID_MAGIC: return -EILSEQ;
1584 case VERR_INVALID_HANDLE: return -ENXIO;
1585 case VERR_INVALID_POINTER: return -EFAULT;
1586 case VERR_LOCK_FAILED: return -ENOLCK;
1587 case VERR_ALREADY_LOADED: return -EEXIST;
1588 case VERR_PERMISSION_DENIED: return -EPERM;
1589 case VERR_VERSION_MISMATCH: return -ENOSYS;
1590 case VERR_IDT_FAILED: return -1000;
1591 }
1592
1593 return -EPERM;
1594}
1595
1596
1597RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1598{
1599 va_list va;
1600 char szMsg[512];
1601 IPRT_LINUX_SAVE_EFL_AC();
1602
1603 va_start(va, pszFormat);
1604 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
1605 va_end(va);
1606 szMsg[sizeof(szMsg) - 1] = '\0';
1607
1608 printk("%s", szMsg);
1609
1610 IPRT_LINUX_RESTORE_EFL_AC();
1611 return 0;
1612}
1613
1614
1615SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
1616{
1617 uint32_t fFlags = 0;
1618#ifdef CONFIG_PAX_KERNEXEC
1619 fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY;
1620#endif
1621#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
1622 fFlags |= SUPKERNELFEATURES_SMAP;
1623#elif defined(CONFIG_X86_SMAP)
1624 if (ASMGetCR4() & X86_CR4_SMAP)
1625 fFlags |= SUPKERNELFEATURES_SMAP;
1626#endif
1627 return fFlags;
1628}
1629
1630
1631module_init(VBoxDrvLinuxInit);
1632module_exit(VBoxDrvLinuxUnload);
1633
1634MODULE_AUTHOR(VBOX_VENDOR);
1635MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
1636MODULE_LICENSE("GPL");
1637#ifdef MODULE_VERSION
1638MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
1639#endif
1640
1641module_param(force_async_tsc, int, 0444);
1642MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1643
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