VirtualBox

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

Last change on this file since 67954 was 67137, checked in by vboxsync, 7 years ago

HostDrivers/Support, VMM: bugref:8864: On Linux 4.12 the GDT is mapped read-only. The writable-mapped GDT is available and is used for clearing the TSS BUSY descriptor bit and for LTR.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.9 KB
Line 
1/* $Rev: 67137 $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 6291456 /* 6 MB */
148# else
149# define EXEC_MEMORY_SIZE 1572864 /* 1.5 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#ifdef HAVE_UNLOCKED_IOCTL
585 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
586 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
587 || uCmd == SUP_IOCTL_FAST_DO_NOP)
588 && pSession->fUnrestricted == true))
589 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
590 else
591 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
592#else /* !HAVE_UNLOCKED_IOCTL */
593 unlock_kernel();
594 if (RT_LIKELY( ( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
595 || uCmd == SUP_IOCTL_FAST_DO_HM_RUN
596 || uCmd == SUP_IOCTL_FAST_DO_NOP)
597 && pSession->fUnrestricted == true))
598 rc = supdrvIOCtlFast(uCmd, ulArg, &g_DevExt, pSession);
599 else
600 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
601 lock_kernel();
602#endif /* !HAVE_UNLOCKED_IOCTL */
603
604#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
605 /*
606 * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
607 * accidentially modified it or some other important flag.
608 */
609 if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF))
610 != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF)) | X86_EFL_AC) ))
611 {
612 char szTmp[48];
613 RTStrPrintf(szTmp, sizeof(szTmp), "uCmd=%#x: %#x->%#x!", _IOC_NR(uCmd), (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
614 supdrvBadContext(&g_DevExt, "SUPDrv-linux.c", __LINE__, szTmp);
615 }
616 ASMSetFlags(fSavedEfl);
617#else
618 clac();
619#endif
620 return rc;
621}
622
623
624/**
625 * Device I/O Control entry point.
626 *
627 * @param pFilp Associated file pointer.
628 * @param uCmd The function specified to ioctl().
629 * @param ulArg The argument specified to ioctl().
630 * @param pSession The session instance.
631 */
632static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession)
633{
634 int rc;
635 SUPREQHDR Hdr;
636 PSUPREQHDR pHdr;
637 uint32_t cbBuf;
638
639 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
640
641 /*
642 * Read the header.
643 */
644 if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
645 {
646 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
647 return -EFAULT;
648 }
649 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
650 {
651 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
652 return -EINVAL;
653 }
654
655 /*
656 * Buffer the request.
657 */
658 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
659 if (RT_UNLIKELY(cbBuf > _1M*16))
660 {
661 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
662 return -E2BIG;
663 }
664 if (RT_UNLIKELY(_IOC_SIZE(uCmd) ? cbBuf != _IOC_SIZE(uCmd) : Hdr.cbIn < sizeof(Hdr)))
665 {
666 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
667 return -EINVAL;
668 }
669 pHdr = RTMemAlloc(cbBuf);
670 if (RT_UNLIKELY(!pHdr))
671 {
672 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
673 return -ENOMEM;
674 }
675 if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
676 {
677 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
678 RTMemFree(pHdr);
679 return -EFAULT;
680 }
681 if (Hdr.cbIn < cbBuf)
682 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
683
684 /*
685 * Process the IOCtl.
686 */
687 rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
688
689 /*
690 * Copy ioctl data and output buffer back to user space.
691 */
692 if (RT_LIKELY(!rc))
693 {
694 uint32_t cbOut = pHdr->cbOut;
695 if (RT_UNLIKELY(cbOut > cbBuf))
696 {
697 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
698 cbOut = cbBuf;
699 }
700 if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
701 {
702 /* this is really bad! */
703 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
704 rc = -EFAULT;
705 }
706 }
707 else
708 {
709 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
710 rc = -EINVAL;
711 }
712 RTMemFree(pHdr);
713
714 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
715 return rc;
716}
717
718
719/**
720 * The SUPDRV IDC entry point.
721 *
722 * @returns VBox status code, see supdrvIDC.
723 * @param uReq The request code.
724 * @param pReq The request.
725 */
726int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
727{
728 PSUPDRVSESSION pSession;
729
730 /*
731 * Some quick validations.
732 */
733 if (RT_UNLIKELY(!VALID_PTR(pReq)))
734 return VERR_INVALID_POINTER;
735
736 pSession = pReq->pSession;
737 if (pSession)
738 {
739 if (RT_UNLIKELY(!VALID_PTR(pSession)))
740 return VERR_INVALID_PARAMETER;
741 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
742 return VERR_INVALID_PARAMETER;
743 }
744 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
745 return VERR_INVALID_PARAMETER;
746
747 /*
748 * Do the job.
749 */
750 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
751}
752
753EXPORT_SYMBOL(SUPDrvLinuxIDC);
754
755
756RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask)
757{
758#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 20, 0)
759 RTCCUINTREG uOld = this_cpu_read(cpu_tlbstate.cr4);
760 RTCCUINTREG uNew = (uOld & fAndMask) | fOrMask;
761 if (uNew != uOld)
762 {
763 this_cpu_write(cpu_tlbstate.cr4, uNew);
764 __write_cr4(uNew);
765 }
766#else
767 RTCCUINTREG uOld = ASMGetCR4();
768 RTCCUINTREG uNew = (uOld & fAndMask) | fOrMask;
769 if (uNew != uOld)
770 ASMSetCR4(uNew);
771#endif
772 return uOld;
773}
774
775
776void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
777{
778 NOREF(pDevExt);
779 NOREF(pSession);
780}
781
782
783void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
784{
785 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
786}
787
788
789void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
790{
791 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
792}
793
794
795/**
796 * Initializes any OS specific object creator fields.
797 */
798void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
799{
800 NOREF(pObj);
801 NOREF(pSession);
802}
803
804
805/**
806 * Checks if the session can access the object.
807 *
808 * @returns true if a decision has been made.
809 * @returns false if the default access policy should be applied.
810 *
811 * @param pObj The object in question.
812 * @param pSession The session wanting to access the object.
813 * @param pszObjName The object name, can be NULL.
814 * @param prc Where to store the result when returning true.
815 */
816bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
817{
818 NOREF(pObj);
819 NOREF(pSession);
820 NOREF(pszObjName);
821 NOREF(prc);
822 return false;
823}
824
825
826bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
827{
828 return force_async_tsc != 0;
829}
830
831
832bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
833{
834 return true;
835}
836
837
838bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
839{
840 return false;
841}
842
843
844int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
845{
846 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
847 return VERR_NOT_SUPPORTED;
848}
849
850
851int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
852{
853 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
854 return VERR_NOT_SUPPORTED;
855}
856
857
858int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
859{
860 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
861 return VERR_NOT_SUPPORTED;
862}
863
864
865void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
866{
867 NOREF(pDevExt); NOREF(pImage);
868}
869
870
871/** @def VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
872 * A very crude hack for debugging using perf and dtrace.
873 *
874 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
875 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
876 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
877 *
878 */
879#if 0 || defined(DOXYGEN_RUNNING)
880# define VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
881#endif
882
883#if defined(VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS) && defined(CONFIG_MODULES_TREE_LOOKUP)
884/** Whether g_pfnModTreeInsert and g_pfnModTreeRemove have been initialized.
885 * @remarks can still be NULL after init. */
886static volatile bool g_fLookedForModTreeFunctions = false;
887static void (*g_pfnModTreeInsert)(struct mod_tree_node *) = NULL; /**< __mod_tree_insert */
888static void (*g_pfnModTreeRemove)(struct mod_tree_node *) = NULL; /**< __mod_tree_remove */
889#endif
890
891
892void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
893{
894#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
895 /*
896 * This trick stops working with 4.2 when CONFIG_MODULES_TREE_LOOKUP is
897 * defined. The module lookups are done via a tree structure and we
898 * cannot get at the root of it. :-(
899 */
900# ifdef CONFIG_KALLSYMS
901 size_t const cchName = strlen(pImage->szName);
902# endif
903 struct module *pMyMod, *pSelfMod, *pTestMod, *pTestModByName;
904 IPRT_LINUX_SAVE_EFL_AC();
905
906 pImage->pLnxModHack = NULL;
907
908# ifdef CONFIG_MODULES_TREE_LOOKUP
909 /*
910 * This is pretty naive, but works for 4.2 on arch linux. I don't think we
911 * can count on finding __mod_tree_remove in all kernel builds as it's not
912 * marked noinline like __mod_tree_insert.
913 */
914 if (!g_fLookedForModTreeFunctions)
915 {
916 unsigned long ulInsert = kallsyms_lookup_name("__mod_tree_insert");
917 unsigned long ulRemove = kallsyms_lookup_name("__mod_tree_remove");
918 if (!ulInsert || !ulRemove)
919 {
920 g_fLookedForModTreeFunctions = true;
921 printk(KERN_ERR "vboxdrv: failed to locate __mod_tree_insert and __mod_tree_remove.\n");
922 IPRT_LINUX_RESTORE_EFL_AC();
923 return;
924 }
925 *(unsigned long *)&g_pfnModTreeInsert = ulInsert;
926 *(unsigned long *)&g_pfnModTreeRemove = ulRemove;
927 ASMCompilerBarrier();
928 g_fLookedForModTreeFunctions = true;
929 }
930 else if (!g_pfnModTreeInsert || !g_pfnModTreeRemove)
931 return;
932#endif
933
934 /*
935 * Make sure we've found our own module, otherwise we cannot access the linked list.
936 */
937 mutex_lock(&module_mutex);
938 pSelfMod = find_module("vboxdrv");
939 mutex_unlock(&module_mutex);
940 if (!pSelfMod)
941 {
942 IPRT_LINUX_RESTORE_EFL_AC();
943 return;
944 }
945
946 /*
947 * Cook up a module structure for the image.
948 * We allocate symbol and string tables in the allocation and the module to keep things simple.
949 */
950# ifdef CONFIG_KALLSYMS
951 pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod)
952 + sizeof(Elf_Sym) * 3
953 + 1 + cchName * 2 + sizeof("_start") + sizeof("_end") + 4 );
954# else
955 pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod));
956# endif
957 if (pMyMod)
958 {
959 int rc = VINF_SUCCESS;
960# ifdef CONFIG_KALLSYMS
961 Elf_Sym *paSymbols = (Elf_Sym *)(pMyMod + 1);
962 char *pchStrTab = (char *)(paSymbols + 3);
963# endif
964
965 pMyMod->state = MODULE_STATE_LIVE;
966 INIT_LIST_HEAD(&pMyMod->list); /* just in case */
967
968 /* Perf only matches up files with a .ko extension (maybe .ko.gz),
969 so in order for this crap to work smoothly, we append .ko to the
970 module name and require the user to create symbolic links in
971 /lib/modules/`uname -r`:
972 for i in VMMR0.r0 VBoxDDR0.r0 VBoxDD2R0.r0; do
973 sudo ln -s /mnt/scratch/vbox/svn/trunk/out/linux.amd64/debug/bin/$i /lib/modules/`uname -r`/$i.ko;
974 done */
975 RTStrPrintf(pMyMod->name, sizeof(pMyMod->name), "%s", pImage->szName);
976
977 /* sysfs bits. */
978 INIT_LIST_HEAD(&pMyMod->mkobj.kobj.entry); /* rest of kobj is already zeroed, hopefully never accessed... */
979 pMyMod->mkobj.mod = pMyMod;
980 pMyMod->mkobj.drivers_dir = NULL;
981 pMyMod->mkobj.mp = NULL;
982 pMyMod->mkobj.kobj_completion = NULL;
983
984 pMyMod->modinfo_attrs = NULL; /* hopefully not accessed after setup. */
985 pMyMod->holders_dir = NULL; /* hopefully not accessed. */
986 pMyMod->version = "N/A";
987 pMyMod->srcversion = "N/A";
988
989 /* We export no symbols. */
990 pMyMod->num_syms = 0;
991 pMyMod->syms = NULL;
992 pMyMod->crcs = NULL;
993
994 pMyMod->num_gpl_syms = 0;
995 pMyMod->gpl_syms = NULL;
996 pMyMod->gpl_crcs = NULL;
997
998 pMyMod->num_gpl_future_syms = 0;
999 pMyMod->gpl_future_syms = NULL;
1000 pMyMod->gpl_future_crcs = NULL;
1001
1002# if CONFIG_UNUSED_SYMBOLS
1003 pMyMod->num_unused_syms = 0;
1004 pMyMod->unused_syms = NULL;
1005 pMyMod->unused_crcs = NULL;
1006
1007 pMyMod->num_unused_gpl_syms = 0;
1008 pMyMod->unused_gpl_syms = NULL;
1009 pMyMod->unused_gpl_crcs = NULL;
1010# endif
1011 /* No kernel parameters either. */
1012 pMyMod->kp = NULL;
1013 pMyMod->num_kp = 0;
1014
1015# ifdef CONFIG_MODULE_SIG
1016 /* Pretend ok signature. */
1017 pMyMod->sig_ok = true;
1018# endif
1019 /* No exception table. */
1020 pMyMod->num_exentries = 0;
1021 pMyMod->extable = NULL;
1022
1023 /* No init function */
1024 pMyMod->init = NULL;
1025 pMyMod->module_init = NULL;
1026 pMyMod->init_size = 0;
1027 pMyMod->init_ro_size = 0;
1028 pMyMod->init_text_size = 0;
1029
1030 /* The module address and size. It's all text. */
1031 pMyMod->module_core = pImage->pvImage;
1032 pMyMod->core_size = pImage->cbImageBits;
1033 pMyMod->core_text_size = pImage->cbImageBits;
1034 pMyMod->core_ro_size = pImage->cbImageBits;
1035
1036#ifdef CONFIG_MODULES_TREE_LOOKUP
1037 /* Fill in the self pointers for the tree nodes. */
1038 pMyMod->mtn_core.mod = pMyMod;
1039 pMyMod->mtn_init.mod = pMyMod;
1040#endif
1041 /* They invented the tained bit for us, didn't they? */
1042 pMyMod->taints = 1;
1043
1044# ifdef CONFIG_GENERIC_BUGS
1045 /* No BUGs in our modules. */
1046 pMyMod->num_bugs = 0;
1047 INIT_LIST_HEAD(&pMyMod->bug_list);
1048 pMyMod->bug_table = NULL;
1049# endif
1050
1051# ifdef CONFIG_KALLSYMS
1052 /* The core stuff is documented as only used when loading. So just zero them. */
1053 pMyMod->core_num_syms = 0;
1054 pMyMod->core_symtab = NULL;
1055 pMyMod->core_strtab = NULL;
1056
1057 /* Construct a symbol table with start and end symbols.
1058 Note! We don't have our own symbol table at this point, image bit
1059 are not uploaded yet! */
1060 pMyMod->num_symtab = 3;
1061 pMyMod->symtab = paSymbols;
1062 pMyMod->strtab = pchStrTab;
1063 RT_ZERO(paSymbols[0]);
1064 pchStrTab[0] = '\0';
1065 paSymbols[1].st_name = 1;
1066 paSymbols[2].st_name = 2 + RTStrPrintf(&pchStrTab[paSymbols[1].st_name], cchName + sizeof("_start"),
1067 "%s_start", pImage->szName);
1068 RTStrPrintf(&pchStrTab[paSymbols[2].st_name], cchName + sizeof("_end"), "%s_end", pImage->szName);
1069 paSymbols[1].st_info = 't';
1070 paSymbols[2].st_info = 'b';
1071 paSymbols[1].st_other = 0;
1072 paSymbols[2].st_other = 0;
1073 paSymbols[1].st_shndx = 0;
1074 paSymbols[2].st_shndx = 0;
1075 paSymbols[1].st_value = (uintptr_t)pImage->pvImage;
1076 paSymbols[2].st_value = (uintptr_t)pImage->pvImage + pImage->cbImageBits - 1;
1077 paSymbols[1].st_size = pImage->cbImageBits - 1;
1078 paSymbols[2].st_size = 1;
1079# endif
1080 /* No arguments, but seems its always non-NULL so put empty string there. */
1081 pMyMod->args = "";
1082
1083# ifdef CONFIG_SMP
1084 /* No per CPU data. */
1085 pMyMod->percpu = NULL;
1086 pMyMod->percpu_size = 0;
1087# endif
1088# ifdef CONFIG_TRACEPOINTS
1089 /* No tracepoints we like to share. */
1090 pMyMod->num_tracepoints = 0;
1091 pMyMod->tracepoints_ptrs = NULL;
1092#endif
1093# ifdef HAVE_JUMP_LABEL
1094 /* No jump lable stuff either. */
1095 pMyMod->jump_entries = NULL;
1096 pMyMod->num_jump_entries = 0;
1097# endif
1098# ifdef CONFIG_TRACING
1099 pMyMod->num_trace_bprintk_fmt = 0;
1100 pMyMod->trace_bprintk_fmt_start = NULL;
1101# endif
1102# ifdef CONFIG_EVENT_TRACING
1103 pMyMod->trace_events = NULL;
1104 pMyMod->num_trace_events = 0;
1105# endif
1106# ifdef CONFIG_FTRACE_MCOUNT_RECORD
1107 pMyMod->num_ftrace_callsites = 0;
1108 pMyMod->ftrace_callsites = NULL;
1109# endif
1110# ifdef CONFIG_MODULE_UNLOAD
1111 /* Dependency lists, not worth sharing */
1112 INIT_LIST_HEAD(&pMyMod->source_list);
1113 INIT_LIST_HEAD(&pMyMod->target_list);
1114
1115 /* Nobody waiting and no exit function. */
1116# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
1117 pMyMod->waiter = NULL;
1118# endif
1119 pMyMod->exit = NULL;
1120
1121 /* References, very important as we must not allow the module
1122 to be unloaded using rmmod. */
1123# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
1124 atomic_set(&pMyMod->refcnt, 42);
1125# else
1126 pMyMod->refptr = alloc_percpu(struct module_ref);
1127 if (pMyMod->refptr)
1128 {
1129 int iCpu;
1130 for_each_possible_cpu(iCpu)
1131 {
1132 per_cpu_ptr(pMyMod->refptr, iCpu)->decs = 0;
1133 per_cpu_ptr(pMyMod->refptr, iCpu)->incs = 1;
1134 }
1135 }
1136 else
1137 rc = VERR_NO_MEMORY;
1138# endif
1139# endif
1140# ifdef CONFIG_CONSTRUCTORS
1141 /* No constructors. */
1142 pMyMod->ctors = NULL;
1143 pMyMod->num_ctors = 0;
1144# endif
1145 if (RT_SUCCESS(rc))
1146 {
1147 bool fIsModText;
1148
1149 /*
1150 * Add the module to the list.
1151 */
1152 mutex_lock(&module_mutex);
1153 list_add_rcu(&pMyMod->list, &pSelfMod->list);
1154 pImage->pLnxModHack = pMyMod;
1155# ifdef CONFIG_MODULES_TREE_LOOKUP
1156 g_pfnModTreeInsert(&pMyMod->mtn_core); /* __mod_tree_insert */
1157# endif
1158 mutex_unlock(&module_mutex);
1159
1160 /*
1161 * Test it.
1162 */
1163 mutex_lock(&module_mutex);
1164 pTestModByName = find_module(pMyMod->name);
1165 pTestMod = __module_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 4);
1166 fIsModText = __module_text_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 2);
1167 mutex_unlock(&module_mutex);
1168 if ( pTestMod == pMyMod
1169 && pTestModByName == pMyMod
1170 && fIsModText)
1171 printk(KERN_ERR "vboxdrv: fake module works for '%s' (%#lx to %#lx)\n",
1172 pMyMod->name, (unsigned long)paSymbols[1].st_value, (unsigned long)paSymbols[2].st_value);
1173 else
1174 printk(KERN_ERR "vboxdrv: failed to find fake module (pTestMod=%p, pTestModByName=%p, pMyMod=%p, fIsModText=%d)\n",
1175 pTestMod, pTestModByName, pMyMod, fIsModText);
1176 }
1177 else
1178 RTMemFree(pMyMod);
1179 }
1180
1181 IPRT_LINUX_RESTORE_EFL_AC();
1182#else
1183 pImage->pLnxModHack = NULL;
1184#endif
1185 NOREF(pDevExt); NOREF(pImage);
1186}
1187
1188
1189void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1190{
1191#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
1192 struct module *pMyMod = pImage->pLnxModHack;
1193 pImage->pLnxModHack = NULL;
1194 if (pMyMod)
1195 {
1196 /*
1197 * Remove the fake module list entry and free it.
1198 */
1199 IPRT_LINUX_SAVE_EFL_AC();
1200 mutex_lock(&module_mutex);
1201 list_del_rcu(&pMyMod->list);
1202# ifdef CONFIG_MODULES_TREE_LOOKUP
1203 g_pfnModTreeRemove(&pMyMod->mtn_core);
1204# endif
1205 synchronize_sched();
1206 mutex_unlock(&module_mutex);
1207
1208# if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
1209 free_percpu(pMyMod->refptr);
1210# endif
1211 RTMemFree(pMyMod);
1212 IPRT_LINUX_RESTORE_EFL_AC();
1213 }
1214
1215#else
1216 Assert(pImage->pLnxModHack == NULL);
1217#endif
1218 NOREF(pDevExt); NOREF(pImage);
1219}
1220
1221
1222#ifdef SUPDRV_WITH_MSR_PROBER
1223
1224int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
1225{
1226# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1227 uint32_t u32Low, u32High;
1228 int rc;
1229
1230 IPRT_LINUX_SAVE_EFL_AC();
1231 if (idCpu == NIL_RTCPUID)
1232 rc = rdmsr_safe(uMsr, &u32Low, &u32High);
1233 else if (RTMpIsCpuOnline(idCpu))
1234 rc = rdmsr_safe_on_cpu(idCpu, uMsr, &u32Low, &u32High);
1235 else
1236 return VERR_CPU_OFFLINE;
1237 IPRT_LINUX_RESTORE_EFL_AC();
1238 if (rc == 0)
1239 {
1240 *puValue = RT_MAKE_U64(u32Low, u32High);
1241 return VINF_SUCCESS;
1242 }
1243 return VERR_ACCESS_DENIED;
1244# else
1245 return VERR_NOT_SUPPORTED;
1246# endif
1247}
1248
1249
1250int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
1251{
1252# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1253 int rc;
1254
1255 IPRT_LINUX_SAVE_EFL_AC();
1256 if (idCpu == NIL_RTCPUID)
1257 rc = wrmsr_safe(uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
1258 else if (RTMpIsCpuOnline(idCpu))
1259 rc = wrmsr_safe_on_cpu(idCpu, uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
1260 else
1261 return VERR_CPU_OFFLINE;
1262 IPRT_LINUX_RESTORE_EFL_AC();
1263
1264 if (rc == 0)
1265 return VINF_SUCCESS;
1266 return VERR_ACCESS_DENIED;
1267# else
1268 return VERR_NOT_SUPPORTED;
1269# endif
1270}
1271
1272# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1273/**
1274 * Worker for supdrvOSMsrProberModify.
1275 */
1276static DECLCALLBACK(void) supdrvLnxMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1277{
1278 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
1279 register uint32_t uMsr = pReq->u.In.uMsr;
1280 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
1281 uint64_t uBefore;
1282 uint64_t uWritten;
1283 uint64_t uAfter;
1284 int rcBefore, rcWrite, rcAfter, rcRestore;
1285 RTCCUINTREG fOldFlags;
1286
1287 /* Initialize result variables. */
1288 uBefore = uWritten = uAfter = 0;
1289 rcWrite = rcAfter = rcRestore = -EIO;
1290
1291 /*
1292 * Do the job.
1293 */
1294 fOldFlags = ASMIntDisableFlags();
1295 ASMCompilerBarrier(); /* paranoia */
1296 if (!fFaster)
1297 ASMWriteBackAndInvalidateCaches();
1298
1299 rcBefore = rdmsrl_safe(uMsr, &uBefore);
1300 if (rcBefore >= 0)
1301 {
1302 register uint64_t uRestore = uBefore;
1303 uWritten = uRestore;
1304 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
1305 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
1306
1307 rcWrite = wrmsr_safe(uMsr, RT_LODWORD(uWritten), RT_HIDWORD(uWritten));
1308 rcAfter = rdmsrl_safe(uMsr, &uAfter);
1309 rcRestore = wrmsr_safe(uMsr, RT_LODWORD(uRestore), RT_HIDWORD(uRestore));
1310
1311 if (!fFaster)
1312 {
1313 ASMWriteBackAndInvalidateCaches();
1314 ASMReloadCR3();
1315 ASMNopPause();
1316 }
1317 }
1318
1319 ASMCompilerBarrier(); /* paranoia */
1320 ASMSetFlags(fOldFlags);
1321
1322 /*
1323 * Write out the results.
1324 */
1325 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1326 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1327 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1328 pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
1329 pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
1330 pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
1331 pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
1332 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1333}
1334# endif
1335
1336
1337int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1338{
1339# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1340 if (idCpu == NIL_RTCPUID)
1341 {
1342 supdrvLnxMsrProberModifyOnCpu(idCpu, pReq, NULL);
1343 return VINF_SUCCESS;
1344 }
1345 return RTMpOnSpecific(idCpu, supdrvLnxMsrProberModifyOnCpu, pReq, NULL);
1346# else
1347 return VERR_NOT_SUPPORTED;
1348# endif
1349}
1350
1351#endif /* SUPDRV_WITH_MSR_PROBER */
1352
1353
1354/**
1355 * Converts a supdrv error code to an linux error code.
1356 *
1357 * @returns corresponding linux error code.
1358 * @param rc IPRT status code.
1359 */
1360static int VBoxDrvLinuxErr2LinuxErr(int rc)
1361{
1362 switch (rc)
1363 {
1364 case VINF_SUCCESS: return 0;
1365 case VERR_GENERAL_FAILURE: return -EACCES;
1366 case VERR_INVALID_PARAMETER: return -EINVAL;
1367 case VERR_INVALID_MAGIC: return -EILSEQ;
1368 case VERR_INVALID_HANDLE: return -ENXIO;
1369 case VERR_INVALID_POINTER: return -EFAULT;
1370 case VERR_LOCK_FAILED: return -ENOLCK;
1371 case VERR_ALREADY_LOADED: return -EEXIST;
1372 case VERR_PERMISSION_DENIED: return -EPERM;
1373 case VERR_VERSION_MISMATCH: return -ENOSYS;
1374 case VERR_IDT_FAILED: return -1000;
1375 }
1376
1377 return -EPERM;
1378}
1379
1380
1381RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1382{
1383 va_list va;
1384 char szMsg[512];
1385 IPRT_LINUX_SAVE_EFL_AC();
1386
1387 va_start(va, pszFormat);
1388 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
1389 va_end(va);
1390 szMsg[sizeof(szMsg) - 1] = '\0';
1391
1392 printk("%s", szMsg);
1393
1394 IPRT_LINUX_RESTORE_EFL_AC();
1395 return 0;
1396}
1397
1398
1399SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
1400{
1401 uint32_t fFlags = 0;
1402#ifdef CONFIG_PAX_KERNEXEC
1403 fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY;
1404#endif
1405#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
1406 fFlags |= SUPKERNELFEATURES_GDT_NEED_WRITABLE;
1407#endif
1408#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
1409 fFlags |= SUPKERNELFEATURES_SMAP;
1410#elif defined(CONFIG_X86_SMAP)
1411 if (ASMGetCR4() & X86_CR4_SMAP)
1412 fFlags |= SUPKERNELFEATURES_SMAP;
1413#endif
1414 return fFlags;
1415}
1416
1417
1418int VBOXCALL supdrvOSGetCurrentGdtRw(RTHCUINTPTR *pGdtRw)
1419{
1420#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
1421 *pGdtRw = (RTHCUINTPTR)get_current_gdt_rw();
1422 return VINF_SUCCESS;
1423#else
1424 return VERR_NOT_IMPLEMENTED;
1425#endif
1426}
1427
1428
1429module_init(VBoxDrvLinuxInit);
1430module_exit(VBoxDrvLinuxUnload);
1431
1432MODULE_AUTHOR(VBOX_VENDOR);
1433MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
1434MODULE_LICENSE("GPL");
1435#ifdef MODULE_VERSION
1436MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV) " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
1437#endif
1438
1439module_param(force_async_tsc, int, 0444);
1440MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1441
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use