VirtualBox

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

Last change on this file since 76410 was 75282, checked in by vboxsync, 6 years ago

SUPDrv: Adding supdrvOSLdrQuerySymbol so we don't have to save a copy of the symbol table for native modules. bugref:9232

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