VirtualBox

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

Last change on this file was 104243, checked in by vboxsync, 10 days ago

HostDrivers/Support/SUPDrv-linux.c: Return the real effective user ID and not what it is mapped to in the current namespace, bugref:10642

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.1 KB
Line 
1/* $Id: SUPDrv-linux.c 104243 2024-04-09 07:16:25Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP LOG_GROUP_SUP_DRV
42#include "../SUPDrvInternal.h"
43#include "the-linux-kernel.h"
44#include "version-generated.h"
45#include "product-generated.h"
46#include "revision-generated.h"
47
48#include <iprt/assert.h>
49#include <iprt/spinlock.h>
50#include <iprt/semaphore.h>
51#include <iprt/initterm.h>
52#include <iprt/process.h>
53#include <iprt/thread.h>
54#include <VBox/err.h>
55#include <iprt/mem.h>
56#include <VBox/log.h>
57#include <VBox/VBoxLnxModInline.h>
58#include <iprt/mp.h>
59
60/** @todo figure out the exact version number */
61#if RTLNX_VER_MIN(2,6,16)
62# include <iprt/power.h>
63# define VBOX_WITH_SUSPEND_NOTIFICATION
64#endif
65
66#include <linux/sched.h>
67#include <linux/miscdevice.h>
68#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
69# include <linux/platform_device.h>
70#endif
71#if (RTLNX_VER_MIN(2,6,28)) && defined(SUPDRV_WITH_MSR_PROBER)
72# define SUPDRV_LINUX_HAS_SAFE_MSR_API
73# include <asm/msr.h>
74#endif
75
76#include <asm/desc.h>
77
78#include <iprt/asm-amd64-x86.h>
79
80
81/*********************************************************************************************************************************
82* Defined Constants And Macros *
83*********************************************************************************************************************************/
84/* check kernel version */
85# ifndef SUPDRV_AGNOSTIC
86# if RTLNX_VER_MAX(2,6,0)
87# error Unsupported kernel version!
88# endif
89# endif
90
91#ifdef CONFIG_X86_HIGH_ENTRY
92# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
93#endif
94
95/* We cannot include x86.h, so we copy the defines we need here: */
96#define X86_EFL_IF RT_BIT(9)
97#define X86_EFL_AC RT_BIT(18)
98#define X86_EFL_DF RT_BIT(10)
99#define X86_EFL_IOPL (RT_BIT(12) | RT_BIT(13))
100
101/* To include the version number of VirtualBox into kernel backtraces: */
102#define VBoxDrvLinuxVersion RT_CONCAT3(RT_CONCAT(VBOX_VERSION_MAJOR, _), \
103 RT_CONCAT(VBOX_VERSION_MINOR, _), \
104 VBOX_VERSION_BUILD)
105#define VBoxDrvLinuxIOCtl RT_CONCAT(VBoxDrvLinuxIOCtl_,VBoxDrvLinuxVersion)
106
107/* Once externally provided, this string will be printed into kernel log on
108 * module start together with the rest of versioning information. */
109#ifndef VBOX_EXTRA_VERSION_STRING
110# define VBOX_EXTRA_VERSION_STRING ""
111#endif
112
113
114/*********************************************************************************************************************************
115* Structures and Typedefs *
116*********************************************************************************************************************************/
117#if RTLNX_VER_MIN(5,0,0)
118/** Wrapper module list entry. */
119typedef struct SUPDRVLNXMODULE
120{
121 RTLISTNODE ListEntry;
122 struct module *pModule;
123} SUPDRVLNXMODULE;
124/** Pointer to a wrapper module list entry. */
125typedef SUPDRVLNXMODULE *PSUPDRVLNXMODULE;
126#endif
127
128
129/*********************************************************************************************************************************
130* Internal Functions *
131*********************************************************************************************************************************/
132static int __init VBoxDrvLinuxInit(void);
133static void __exit VBoxDrvLinuxUnload(void);
134static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp);
135static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp);
136static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
137#ifdef HAVE_UNLOCKED_IOCTL
138static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
139#else
140static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
141#endif
142static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession);
143static int VBoxDrvLinuxErr2LinuxErr(int);
144#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
145static int VBoxDrvProbe(struct platform_device *pDev);
146# if RTLNX_VER_MIN(2,6,30)
147static int VBoxDrvSuspend(struct device *pDev);
148static int VBoxDrvResume(struct device *pDev);
149# else
150static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
151static int VBoxDrvResume(struct platform_device *pDev);
152# endif
153static void VBoxDevRelease(struct device *pDev);
154#endif
155#if RTLNX_VER_MIN(5,0,0)
156static int supdrvLinuxLdrModuleNotifyCallback(struct notifier_block *pBlock,
157 unsigned long uModuleState, void *pvModule);
158#endif
159
160
161/*********************************************************************************************************************************
162* Global Variables *
163*********************************************************************************************************************************/
164/**
165 * Device extention & session data association structure.
166 */
167static SUPDRVDEVEXT g_DevExt;
168
169/** Module parameter.
170 * Not prefixed because the name is used by macros and the end of this file. */
171static int force_async_tsc = 0;
172
173/** The system device name. */
174#define DEVICE_NAME_SYS "vboxdrv"
175/** The user device name. */
176#define DEVICE_NAME_USR "vboxdrvu"
177
178/** The file_operations structure. */
179static struct file_operations gFileOpsVBoxDrvSys =
180{
181 owner: THIS_MODULE,
182 open: VBoxDrvLinuxCreateSys,
183 release: VBoxDrvLinuxClose,
184#ifdef HAVE_UNLOCKED_IOCTL
185 unlocked_ioctl: VBoxDrvLinuxIOCtl,
186#else
187 ioctl: VBoxDrvLinuxIOCtl,
188#endif
189};
190
191/** The file_operations structure. */
192static struct file_operations gFileOpsVBoxDrvUsr =
193{
194 owner: THIS_MODULE,
195 open: VBoxDrvLinuxCreateUsr,
196 release: VBoxDrvLinuxClose,
197#ifdef HAVE_UNLOCKED_IOCTL
198 unlocked_ioctl: VBoxDrvLinuxIOCtl,
199#else
200 ioctl: VBoxDrvLinuxIOCtl,
201#endif
202};
203
204/** The miscdevice structure for vboxdrv. */
205static struct miscdevice gMiscDeviceSys =
206{
207 minor: MISC_DYNAMIC_MINOR,
208 name: DEVICE_NAME_SYS,
209 fops: &gFileOpsVBoxDrvSys,
210# if RTLNX_VER_MAX(2,6,18)
211 devfs_name: DEVICE_NAME_SYS,
212# endif
213};
214/** The miscdevice structure for vboxdrvu. */
215static struct miscdevice gMiscDeviceUsr =
216{
217 minor: MISC_DYNAMIC_MINOR,
218 name: DEVICE_NAME_USR,
219 fops: &gFileOpsVBoxDrvUsr,
220# if RTLNX_VER_MAX(2,6,18)
221 devfs_name: DEVICE_NAME_USR,
222# endif
223};
224
225
226#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
227
228# if RTLNX_VER_MIN(2,6,30)
229static struct dev_pm_ops gPlatformPMOps =
230{
231 .suspend = VBoxDrvSuspend, /* before entering deep sleep */
232 .resume = VBoxDrvResume, /* after wakeup from deep sleep */
233 .freeze = VBoxDrvSuspend, /* before creating hibernation image */
234 .restore = VBoxDrvResume, /* after waking up from hibernation */
235};
236# endif
237
238static struct platform_driver gPlatformDriver =
239{
240 .probe = VBoxDrvProbe,
241# if RTLNX_VER_MAX(2,6,30)
242 .suspend = VBoxDrvSuspend,
243 .resume = VBoxDrvResume,
244# endif
245 /** @todo .shutdown? */
246 .driver =
247 {
248 .name = "vboxdrv",
249# if RTLNX_VER_MIN(2,6,30)
250 .pm = &gPlatformPMOps,
251# endif
252 }
253};
254
255static struct platform_device gPlatformDevice =
256{
257 .name = "vboxdrv",
258 .dev =
259 {
260 .release = VBoxDevRelease
261 }
262};
263
264#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
265
266#if RTLNX_VER_MIN(5,0,0)
267/** Module load/unload notification registration record. */
268static struct notifier_block g_supdrvLinuxModuleNotifierBlock =
269{
270 .notifier_call = supdrvLinuxLdrModuleNotifyCallback,
271 .priority = 0
272};
273/** Spinlock protecting g_supdrvLinuxWrapperModuleList. */
274static spinlock_t g_supdrvLinuxWrapperModuleSpinlock;
275/** List of potential wrapper modules (PSUPDRVLNXMODULE). */
276static RTLISTANCHOR g_supdrvLinuxWrapperModuleList;
277#endif
278
279
280/** Get the kernel UID for the current process. */
281DECLINLINE(RTUID) vboxdrvLinuxKernUid(void)
282{
283#if RTLNX_VER_MIN(2,6,29)
284# if RTLNX_VER_MIN(3,5,0)
285 return __kuid_val(current->cred->uid);
286# else
287 return current->cred->uid;
288# endif
289#else
290 return current->uid;
291#endif
292}
293
294
295/** Get the kernel GID for the current process. */
296DECLINLINE(RTGID) vboxdrvLinuxKernGid(void)
297{
298#if RTLNX_VER_MIN(2,6,29)
299# if RTLNX_VER_MIN(3,5,0)
300 return __kgid_val(current->cred->gid);
301# else
302 return current->cred->gid;
303# endif
304#else
305 return current->gid;
306#endif
307}
308
309
310#ifdef VBOX_WITH_HARDENING
311/** Get the effective UID of the current process. */
312DECLINLINE(RTUID) vboxdrvLinuxEuid(void)
313{
314# if RTLNX_VER_MIN(2,6,29)
315# if RTLNX_VER_MIN(3,5,0)
316 return __kuid_val(current->cred->euid);
317# else
318 return current->cred->euid;
319# endif
320# else
321 return current->euid;
322# endif
323}
324#endif
325
326
327/**
328 * Initialize module.
329 *
330 * @returns appropriate status code.
331 */
332static int __init VBoxDrvLinuxInit(void)
333{
334 int rc;
335
336 /* Check if modue loading was disabled. */
337 if (!vbox_mod_should_load())
338 return -EINVAL;
339
340#if RTLNX_VER_MIN(5,0,0)
341 spin_lock_init(&g_supdrvLinuxWrapperModuleSpinlock);
342 RTListInit(&g_supdrvLinuxWrapperModuleList);
343#endif
344
345 /*
346 * Check for synchronous/asynchronous TSC mode.
347 */
348 printk(KERN_DEBUG "vboxdrv: Found %u processor cores/threads\n", (unsigned)RTMpGetOnlineCount());
349 rc = misc_register(&gMiscDeviceSys);
350 if (rc)
351 {
352 printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc);
353 return rc;
354 }
355 rc = misc_register(&gMiscDeviceUsr);
356 if (rc)
357 {
358 printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc);
359 misc_deregister(&gMiscDeviceSys);
360 return rc;
361 }
362 if (!rc)
363 {
364 /*
365 * Initialize the runtime.
366 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
367 */
368 rc = RTR0Init(0);
369 if (RT_SUCCESS(rc))
370 {
371 Log(("VBoxDrv::ModuleInit\n"));
372
373 /*
374 * Initialize the device extension.
375 */
376 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
377 if (RT_SUCCESS(rc))
378 {
379#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
380 rc = platform_driver_register(&gPlatformDriver);
381 if (rc == 0)
382 {
383 rc = platform_device_register(&gPlatformDevice);
384 if (rc == 0)
385#endif
386 {
387#if RTLNX_VER_MIN(5,0,0)
388 /*
389 * Register the module notifier.
390 */
391 int rc2 = register_module_notifier(&g_supdrvLinuxModuleNotifierBlock);
392 if (rc2)
393 printk(KERN_WARNING "vboxdrv: failed to register module notifier! rc2=%d\n", rc2);
394#endif
395
396
397 printk(KERN_INFO "vboxdrv: TSC mode is %s, tentative frequency %llu Hz\n",
398 SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz);
399 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
400 printk(KERN_DEBUG "vboxdrv: Successfully loaded version "
401 VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV)
402 VBOX_EXTRA_VERSION_STRING
403 " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ")\n");
404 return rc;
405 }
406#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
407 else
408 platform_driver_unregister(&gPlatformDriver);
409 }
410#endif
411 }
412
413 rc = -EINVAL;
414 RTR0TermForced();
415 }
416 else
417 rc = -EINVAL;
418
419 /*
420 * Failed, cleanup and return the error code.
421 */
422 }
423 misc_deregister(&gMiscDeviceSys);
424 misc_deregister(&gMiscDeviceUsr);
425 Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor));
426 return rc;
427}
428
429
430/**
431 * Unload the module.
432 */
433static void __exit VBoxDrvLinuxUnload(void)
434{
435 Log(("VBoxDrvLinuxUnload\n"));
436
437#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
438 platform_device_unregister(&gPlatformDevice);
439 platform_driver_unregister(&gPlatformDriver);
440#endif
441
442#if RTLNX_VER_MIN(5,0,0)
443 /*
444 * Kick the list of potential wrapper modules.
445 */
446 unregister_module_notifier(&g_supdrvLinuxModuleNotifierBlock);
447
448 spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
449 while (!RTListIsEmpty(&g_supdrvLinuxWrapperModuleList))
450 {
451 PSUPDRVLNXMODULE pCur = RTListRemoveFirst(&g_supdrvLinuxWrapperModuleList, SUPDRVLNXMODULE, ListEntry);
452 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
453
454 pCur->pModule = NULL;
455 RTMemFree(pCur);
456
457 spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
458 }
459 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
460#endif
461
462 /*
463 * I Don't think it's possible to unload a driver which processes have
464 * opened, at least we'll blindly assume that here.
465 */
466 misc_deregister(&gMiscDeviceUsr);
467 misc_deregister(&gMiscDeviceSys);
468
469 /*
470 * Destroy GIP, delete the device extension and terminate IPRT.
471 */
472 supdrvDeleteDevExt(&g_DevExt);
473 RTR0TermForced();
474}
475
476
477/**
478 * Common open code.
479 *
480 * @param pInode Pointer to inode info structure.
481 * @param pFilp Associated file pointer.
482 * @param fUnrestricted Indicates which device node which was opened.
483 */
484static int vboxdrvLinuxCreateCommon(struct inode *pInode, struct file *pFilp, bool fUnrestricted)
485{
486 int rc;
487 PSUPDRVSESSION pSession;
488 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
489
490#ifdef VBOX_WITH_HARDENING
491 /*
492 * Only root is allowed to access the unrestricted device, enforce it!
493 */
494 if ( fUnrestricted
495 && vboxdrvLinuxEuid() != 0 /* root */ )
496 {
497 Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuid()));
498 return -EPERM;
499 }
500#endif /* VBOX_WITH_HARDENING */
501
502 /*
503 * Call common code for the rest.
504 */
505 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
506 if (!rc)
507 {
508 pSession->Uid = vboxdrvLinuxKernUid();
509 pSession->Gid = vboxdrvLinuxKernGid();
510 }
511
512 pFilp->private_data = pSession;
513
514 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
515 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
516 RTProcSelf(), current->pid, current->comm));
517 return VBoxDrvLinuxErr2LinuxErr(rc);
518}
519
520
521/** /dev/vboxdrv. */
522static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp)
523{
524 return vboxdrvLinuxCreateCommon(pInode, pFilp, true);
525}
526
527
528/** /dev/vboxdrvu. */
529static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp)
530{
531 return vboxdrvLinuxCreateCommon(pInode, pFilp, false);
532}
533
534
535/**
536 * Close device.
537 *
538 * @param pInode Pointer to inode info structure.
539 * @param pFilp Associated file pointer.
540 */
541static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
542{
543 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
544 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
545 supdrvSessionRelease((PSUPDRVSESSION)pFilp->private_data);
546 pFilp->private_data = NULL;
547 return 0;
548}
549
550
551#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
552/**
553 * Dummy device release function. We have to provide this function,
554 * otherwise the kernel will complain.
555 *
556 * @param pDev Pointer to the platform device.
557 */
558static void VBoxDevRelease(struct device *pDev)
559{
560}
561
562/**
563 * Dummy probe function.
564 *
565 * @param pDev Pointer to the platform device.
566 */
567static int VBoxDrvProbe(struct platform_device *pDev)
568{
569 return 0;
570}
571
572/**
573 * Suspend callback.
574 * @param pDev Pointer to the platform device.
575 * @param State Message type, see Documentation/power/devices.txt.
576 * Ignored.
577 */
578# if RTLNX_VER_MIN(2,6,30) && !defined(DOXYGEN_RUNNING)
579static int VBoxDrvSuspend(struct device *pDev)
580# else
581static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
582# endif
583{
584 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
585 return 0;
586}
587
588/**
589 * Resume callback.
590 *
591 * @param pDev Pointer to the platform device.
592 */
593# if RTLNX_VER_MIN(2,6,30)
594static int VBoxDrvResume(struct device *pDev)
595# else
596static int VBoxDrvResume(struct platform_device *pDev)
597# endif
598{
599 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
600 return 0;
601}
602#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
603
604
605/**
606 * Device I/O Control entry point.
607 *
608 * @param pFilp Associated file pointer.
609 * @param uCmd The function specified to ioctl().
610 * @param ulArg The argument specified to ioctl().
611 */
612#if defined(HAVE_UNLOCKED_IOCTL) || defined(DOXYGEN_RUNNING)
613static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
614#else
615static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
616#endif
617{
618 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data;
619 int rc;
620#ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
621# if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
622 RTCCUINTREG fSavedEfl;
623
624 /*
625 * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
626 *
627 * This isn't a problem, as there is absolutely nothing in the kernel context that
628 * depend on user context triggering cleanups. That would be pretty wild, right?
629 */
630 if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
631 {
632 SUPR0Printf("VBoxDrvLinuxIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
633 return ESPIPE;
634 }
635
636 fSavedEfl = ASMAddFlags(X86_EFL_AC);
637# else
638 stac();
639# endif
640#endif
641
642 /*
643 * Deal with the two high-speed IOCtl that takes it's arguments from
644 * the session and iCmd, and only returns a VBox status code.
645 */
646 AssertCompile(_IOC_NRSHIFT == 0 && _IOC_NRBITS == 8);
647#ifdef HAVE_UNLOCKED_IOCTL
648 if (RT_LIKELY( (unsigned int)(uCmd - SUP_IOCTL_FAST_DO_FIRST) < (unsigned int)32
649 && pSession->fUnrestricted))
650 rc = supdrvIOCtlFast(uCmd - SUP_IOCTL_FAST_DO_FIRST, ulArg, &g_DevExt, pSession);
651 else
652 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
653#else /* !HAVE_UNLOCKED_IOCTL */
654 unlock_kernel();
655 if (RT_LIKELY( (unsigned int)(uCmd - SUP_IOCTL_FAST_DO_FIRST) < (unsigned int)32
656 && pSession->fUnrestricted))
657 rc = supdrvIOCtlFast(uCmd - SUP_IOCTL_FAST_DO_FIRST, ulArg, &g_DevExt, pSession);
658 else
659 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
660 lock_kernel();
661#endif /* !HAVE_UNLOCKED_IOCTL */
662
663#ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
664# if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
665 /*
666 * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
667 * accidentially modified it or some other important flag.
668 */
669 if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF))
670 != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF)) | X86_EFL_AC) ))
671 {
672 char szTmp[48];
673 RTStrPrintf(szTmp, sizeof(szTmp), "uCmd=%#x: %#x->%#x!", _IOC_NR(uCmd), (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
674 supdrvBadContext(&g_DevExt, "SUPDrv-linux.c", __LINE__, szTmp);
675 }
676 ASMSetFlags(fSavedEfl);
677# else
678 clac();
679# endif
680#endif
681 return rc;
682}
683
684
685/**
686 * Device I/O Control entry point.
687 *
688 * @param pFilp Associated file pointer.
689 * @param uCmd The function specified to ioctl().
690 * @param ulArg The argument specified to ioctl().
691 * @param pSession The session instance.
692 */
693static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession)
694{
695 int rc;
696 SUPREQHDR Hdr;
697 PSUPREQHDR pHdr;
698 uint32_t cbBuf;
699
700 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
701
702 /*
703 * Read the header.
704 */
705 if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
706 {
707 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
708 return -EFAULT;
709 }
710 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
711 {
712 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
713 return -EINVAL;
714 }
715
716 /*
717 * Buffer the request.
718 */
719 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
720 if (RT_UNLIKELY(cbBuf > _1M*16))
721 {
722 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
723 return -E2BIG;
724 }
725 if (RT_UNLIKELY(_IOC_SIZE(uCmd) ? cbBuf != _IOC_SIZE(uCmd) : Hdr.cbIn < sizeof(Hdr)))
726 {
727 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
728 return -EINVAL;
729 }
730 pHdr = RTMemAlloc(cbBuf);
731 if (RT_UNLIKELY(!pHdr))
732 {
733 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
734 return -ENOMEM;
735 }
736 if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
737 {
738 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
739 RTMemFree(pHdr);
740 return -EFAULT;
741 }
742 if (Hdr.cbIn < cbBuf)
743 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
744
745 /*
746 * Process the IOCtl.
747 */
748 rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
749
750 /*
751 * Copy ioctl data and output buffer back to user space.
752 */
753 if (RT_LIKELY(!rc))
754 {
755 uint32_t cbOut = pHdr->cbOut;
756 if (RT_UNLIKELY(cbOut > cbBuf))
757 {
758 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
759 cbOut = cbBuf;
760 }
761 if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
762 {
763 /* this is really bad! */
764 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
765 rc = -EFAULT;
766 }
767 }
768 else
769 {
770 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
771 rc = -EINVAL;
772 }
773 RTMemFree(pHdr);
774
775 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
776 return rc;
777}
778
779
780/**
781 * The SUPDRV IDC entry point.
782 *
783 * @returns VBox status code, see supdrvIDC.
784 * @param uReq The request code.
785 * @param pReq The request.
786 */
787int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
788{
789 PSUPDRVSESSION pSession;
790
791 /*
792 * Some quick validations.
793 */
794 if (RT_UNLIKELY(!RT_VALID_PTR(pReq)))
795 return VERR_INVALID_POINTER;
796
797 pSession = pReq->pSession;
798 if (pSession)
799 {
800 if (RT_UNLIKELY(!RT_VALID_PTR(pSession)))
801 return VERR_INVALID_PARAMETER;
802 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
803 return VERR_INVALID_PARAMETER;
804 }
805 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
806 return VERR_INVALID_PARAMETER;
807
808 /*
809 * Do the job.
810 */
811 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
812}
813EXPORT_SYMBOL(SUPDrvLinuxIDC);
814
815
816#if RTLNX_VER_MIN(5,0,0)
817
818/**
819 * Checks if the given module is one of our potential wrapper modules or not.
820 */
821static bool supdrvLinuxLdrIsPotentialWrapperModule(struct module const *pModule)
822{
823 if ( pModule
824 && strncmp(pModule->name, RT_STR_TUPLE("vbox_")) == 0)
825 return true;
826 return false;
827}
828
829/**
830 * Called when a kernel module changes state.
831 *
832 * We use this to listen for wrapper modules being loaded, since some evil
833 * bugger removed the find_module() export in 5.13.
834 */
835static int supdrvLinuxLdrModuleNotifyCallback(struct notifier_block *pBlock, unsigned long uModuleState, void *pvModule)
836{
837 struct module *pModule = (struct module *)pvModule;
838 switch (uModuleState)
839 {
840 case MODULE_STATE_UNFORMED: /* Setting up the module... */
841 break;
842
843 /*
844 * The module is about to have its ctors & init functions called.
845 *
846 * Add anything that looks like a wrapper module to our tracker list.
847 */
848 case MODULE_STATE_COMING:
849 if (supdrvLinuxLdrIsPotentialWrapperModule(pModule))
850 {
851 PSUPDRVLNXMODULE pTracker = (PSUPDRVLNXMODULE)RTMemAlloc(sizeof(*pTracker));
852 if (pTracker)
853 {
854 pTracker->pModule = pModule;
855 spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
856 RTListPrepend(&g_supdrvLinuxWrapperModuleList, &pTracker->ListEntry);
857 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
858 }
859 }
860 break;
861
862 case MODULE_STATE_LIVE:
863 break;
864
865 /*
866 * The module has been uninited and is going away.
867 *
868 * Remove the tracker entry for the module, if we have one.
869 */
870 case MODULE_STATE_GOING:
871 {
872 PSUPDRVLNXMODULE pCur;
873 spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
874 RTListForEach(&g_supdrvLinuxWrapperModuleList, pCur, SUPDRVLNXMODULE, ListEntry)
875 {
876 if (pCur->pModule == pModule)
877 {
878 RTListNodeRemove(&pCur->ListEntry);
879 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
880
881 pCur->pModule = NULL;
882 RTMemFree(pCur);
883
884 spin_lock(&g_supdrvLinuxWrapperModuleSpinlock); /* silly */
885 break;
886 }
887 }
888 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
889 break;
890 }
891 }
892 RT_NOREF(pBlock);
893 return NOTIFY_OK;
894}
895
896/**
897 * Replacement for find_module() that's no longer exported with 5.13.
898 */
899static struct module *supdrvLinuxLdrFindModule(const char *pszLnxModName)
900{
901 PSUPDRVLNXMODULE pCur;
902
903 spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
904 RTListForEach(&g_supdrvLinuxWrapperModuleList, pCur, SUPDRVLNXMODULE, ListEntry)
905 {
906 struct module * const pModule = pCur->pModule;
907 if ( pModule
908 && strcmp(pszLnxModName, pModule->name) == 0)
909 {
910 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
911 return pModule;
912 }
913 }
914 spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
915 return NULL;
916}
917
918#endif /* >= 5.0.0 */
919
920
921/**
922 * Used by native wrapper modules, forwarding to supdrvLdrRegisterWrappedModule
923 * with device extension prepended to the argument list.
924 */
925SUPR0DECL(int) SUPDrvLinuxLdrRegisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo,
926 const char *pszLnxModName, void **phMod)
927{
928 AssertPtrReturn(pszLnxModName, VERR_INVALID_POINTER);
929 AssertReturn(*pszLnxModName, VERR_INVALID_NAME);
930
931 /* Locate the module structure for the caller so can later reference
932 and dereference it to prevent unloading while it is being used.
933
934 Before Linux v5.9 this could be done by address (__module_address()
935 or __module_text_address()), but someone (guess who) apparently on
936 a mission to make life miserable for out-of-tree modules or something,
937 decided it was only used by build-in code and unexported both of them.
938
939 I could find no init callouts getting a struct module pointer either,
940 nor any module name hint anywhere I could see. So, we're left with
941 hardcoding the module name via the compiler and pass it along to
942 SUPDrv so we can call find_module() here.
943
944 Sigh^2.
945
946 Update 5.13:
947 The find_module() and module_mutex symbols are no longer exported,
948 probably the doing of the same evil bugger mentioned above. So, we now
949 register a module notification callback and track the modules we're
950 interested in that way. */
951
952#if RTLNX_VER_MIN(5,0,0)
953 struct module *pLnxModule = supdrvLinuxLdrFindModule(pszLnxModName);
954 if (pLnxModule)
955 return supdrvLdrRegisterWrappedModule(&g_DevExt, pWrappedModInfo, pLnxModule, phMod);
956 printk("vboxdrv: supdrvLinuxLdrFindModule(%s) failed in SUPDrvLinuxLdrRegisterWrappedModule!\n", pszLnxModName);
957 return VERR_MODULE_NOT_FOUND;
958
959#elif RTLNX_VER_MIN(2,6,30)
960 if (mutex_lock_interruptible(&module_mutex) == 0)
961 {
962 struct module *pLnxModule = find_module(pszLnxModName);
963 mutex_unlock(&module_mutex);
964 if (pLnxModule)
965 return supdrvLdrRegisterWrappedModule(&g_DevExt, pWrappedModInfo, pLnxModule, phMod);
966 printk("vboxdrv: find_module(%s) failed in SUPDrvLinuxLdrRegisterWrappedModule!\n", pszLnxModName);
967 return VERR_MODULE_NOT_FOUND;
968 }
969 return VERR_INTERRUPTED;
970
971#else
972 printk("vboxdrv: wrapper modules are not supported on 2.6.29 and earlier. sorry.\n");
973 return VERR_NOT_SUPPORTED;
974#endif
975}
976EXPORT_SYMBOL(SUPDrvLinuxLdrRegisterWrappedModule);
977
978
979/**
980 * Used by native wrapper modules, forwarding to supdrvLdrDeregisterWrappedModule
981 * with device extension prepended to the argument list.
982 */
983SUPR0DECL(int) SUPDrvLinuxLdrDeregisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo, void **phMod)
984{
985 return supdrvLdrDeregisterWrappedModule(&g_DevExt, pWrappedModInfo, phMod);
986}
987EXPORT_SYMBOL(SUPDrvLinuxLdrDeregisterWrappedModule);
988
989
990RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask)
991{
992#if RTLNX_VER_MIN(5,8,0)
993 unsigned long fSavedFlags;
994 local_irq_save(fSavedFlags);
995 RTCCUINTREG const uOld = cr4_read_shadow();
996 cr4_update_irqsoff(fOrMask, ~fAndMask); /* Same as this function, only it is not returning the old value. */
997 AssertMsg(cr4_read_shadow() == ((uOld & fAndMask) | fOrMask),
998 ("fOrMask=%#RTreg fAndMask=%#RTreg uOld=%#RTreg; new cr4=%#llx\n", fOrMask, fAndMask, uOld, cr4_read_shadow()));
999 local_irq_restore(fSavedFlags);
1000#else
1001# if RTLNX_VER_MIN(3,20,0)
1002 RTCCUINTREG const uOld = this_cpu_read(cpu_tlbstate.cr4);
1003# else
1004 RTCCUINTREG const uOld = ASMGetCR4();
1005# endif
1006 RTCCUINTREG const uNew = (uOld & fAndMask) | fOrMask;
1007 if (uNew != uOld)
1008 {
1009# if RTLNX_VER_MIN(3,20,0)
1010 this_cpu_write(cpu_tlbstate.cr4, uNew);
1011 __write_cr4(uNew);
1012# else
1013 ASMSetCR4(uNew);
1014# endif
1015 }
1016#endif
1017 return uOld;
1018}
1019
1020
1021void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1022{
1023 NOREF(pDevExt);
1024 NOREF(pSession);
1025}
1026
1027
1028void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1029{
1030 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1031}
1032
1033
1034void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
1035{
1036 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
1037}
1038
1039
1040/**
1041 * Initializes any OS specific object creator fields.
1042 */
1043void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
1044{
1045 NOREF(pObj);
1046 NOREF(pSession);
1047}
1048
1049
1050/**
1051 * Checks if the session can access the object.
1052 *
1053 * @returns true if a decision has been made.
1054 * @returns false if the default access policy should be applied.
1055 *
1056 * @param pObj The object in question.
1057 * @param pSession The session wanting to access the object.
1058 * @param pszObjName The object name, can be NULL.
1059 * @param prc Where to store the result when returning true.
1060 */
1061bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1062{
1063 NOREF(pObj);
1064 NOREF(pSession);
1065 NOREF(pszObjName);
1066 NOREF(prc);
1067 return false;
1068}
1069
1070
1071bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1072{
1073 return force_async_tsc != 0;
1074}
1075
1076
1077bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
1078{
1079 return true;
1080}
1081
1082
1083bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
1084{
1085 return false;
1086}
1087
1088
1089int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1090{
1091 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1092 return VERR_NOT_SUPPORTED;
1093}
1094
1095
1096int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
1097 const uint8_t *pbImageBits, const char *pszSymbol)
1098{
1099 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits); NOREF(pszSymbol);
1100 return VERR_NOT_SUPPORTED;
1101}
1102
1103
1104int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1105{
1106 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
1107 return VERR_NOT_SUPPORTED;
1108}
1109
1110
1111void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1112{
1113 NOREF(pDevExt); NOREF(pImage);
1114}
1115
1116
1117/** @def VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
1118 * A very crude hack for debugging using perf and dtrace.
1119 *
1120 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
1121 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
1122 * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
1123 *
1124 */
1125#if 0 || defined(DOXYGEN_RUNNING)
1126# define VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
1127#endif
1128
1129#if defined(VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS) && defined(CONFIG_MODULES_TREE_LOOKUP)
1130/** Whether g_pfnModTreeInsert and g_pfnModTreeRemove have been initialized.
1131 * @remarks can still be NULL after init. */
1132static volatile bool g_fLookedForModTreeFunctions = false;
1133static void (*g_pfnModTreeInsert)(struct mod_tree_node *) = NULL; /**< __mod_tree_insert */
1134static void (*g_pfnModTreeRemove)(struct mod_tree_node *) = NULL; /**< __mod_tree_remove */
1135#endif
1136
1137
1138void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1139{
1140#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
1141 /*
1142 * This trick stops working with 4.2 when CONFIG_MODULES_TREE_LOOKUP is
1143 * defined. The module lookups are done via a tree structure and we
1144 * cannot get at the root of it. :-(
1145 */
1146# ifdef CONFIG_KALLSYMS
1147 size_t const cchName = strlen(pImage->szName);
1148# endif
1149 struct module *pMyMod, *pSelfMod, *pTestMod, *pTestModByName;
1150 IPRT_LINUX_SAVE_EFL_AC();
1151
1152 pImage->pLnxModHack = NULL;
1153
1154# ifdef CONFIG_MODULES_TREE_LOOKUP
1155 /*
1156 * This is pretty naive, but works for 4.2 on arch linux. I don't think we
1157 * can count on finding __mod_tree_remove in all kernel builds as it's not
1158 * marked noinline like __mod_tree_insert.
1159 */
1160 if (!g_fLookedForModTreeFunctions)
1161 {
1162 unsigned long ulInsert = kallsyms_lookup_name("__mod_tree_insert");
1163 unsigned long ulRemove = kallsyms_lookup_name("__mod_tree_remove");
1164 if (!ulInsert || !ulRemove)
1165 {
1166 g_fLookedForModTreeFunctions = true;
1167 printk(KERN_ERR "vboxdrv: failed to locate __mod_tree_insert and __mod_tree_remove.\n");
1168 IPRT_LINUX_RESTORE_EFL_AC();
1169 return;
1170 }
1171 *(unsigned long *)&g_pfnModTreeInsert = ulInsert;
1172 *(unsigned long *)&g_pfnModTreeRemove = ulRemove;
1173 ASMCompilerBarrier();
1174 g_fLookedForModTreeFunctions = true;
1175 }
1176 else if (!g_pfnModTreeInsert || !g_pfnModTreeRemove)
1177 return;
1178#endif
1179
1180 /*
1181 * Make sure we've found our own module, otherwise we cannot access the linked list.
1182 */
1183 mutex_lock(&module_mutex);
1184 pSelfMod = find_module("vboxdrv");
1185 mutex_unlock(&module_mutex);
1186 if (!pSelfMod)
1187 {
1188 IPRT_LINUX_RESTORE_EFL_AC();
1189 return;
1190 }
1191
1192 /*
1193 * Cook up a module structure for the image.
1194 * We allocate symbol and string tables in the allocation and the module to keep things simple.
1195 */
1196# ifdef CONFIG_KALLSYMS
1197 pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod)
1198 + sizeof(Elf_Sym) * 3
1199 + 1 + cchName * 2 + sizeof("_start") + sizeof("_end") + 4 );
1200# else
1201 pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod));
1202# endif
1203 if (pMyMod)
1204 {
1205 int rc = VINF_SUCCESS;
1206# ifdef CONFIG_KALLSYMS
1207 Elf_Sym *paSymbols = (Elf_Sym *)(pMyMod + 1);
1208 char *pchStrTab = (char *)(paSymbols + 3);
1209# endif
1210
1211 pMyMod->state = MODULE_STATE_LIVE;
1212 INIT_LIST_HEAD(&pMyMod->list); /* just in case */
1213
1214 /* Perf only matches up files with a .ko extension (maybe .ko.gz),
1215 so in order for this crap to work smoothly, we append .ko to the
1216 module name and require the user to create symbolic links in
1217 /lib/modules/`uname -r`:
1218 for i in VMMR0.r0 VBoxDDR0.r0 VBoxDD2R0.r0; do
1219 sudo ln -s /mnt/scratch/vbox/svn/trunk/out/linux.amd64/debug/bin/$i /lib/modules/`uname -r`/$i.ko;
1220 done */
1221 RTStrPrintf(pMyMod->name, sizeof(pMyMod->name), "%s", pImage->szName);
1222
1223 /* sysfs bits. */
1224 INIT_LIST_HEAD(&pMyMod->mkobj.kobj.entry); /* rest of kobj is already zeroed, hopefully never accessed... */
1225 pMyMod->mkobj.mod = pMyMod;
1226 pMyMod->mkobj.drivers_dir = NULL;
1227 pMyMod->mkobj.mp = NULL;
1228 pMyMod->mkobj.kobj_completion = NULL;
1229
1230 pMyMod->modinfo_attrs = NULL; /* hopefully not accessed after setup. */
1231 pMyMod->holders_dir = NULL; /* hopefully not accessed. */
1232 pMyMod->version = "N/A";
1233 pMyMod->srcversion = "N/A";
1234
1235 /* We export no symbols. */
1236 pMyMod->num_syms = 0;
1237 pMyMod->syms = NULL;
1238 pMyMod->crcs = NULL;
1239
1240 pMyMod->num_gpl_syms = 0;
1241 pMyMod->gpl_syms = NULL;
1242 pMyMod->gpl_crcs = NULL;
1243
1244 pMyMod->num_gpl_future_syms = 0;
1245 pMyMod->gpl_future_syms = NULL;
1246 pMyMod->gpl_future_crcs = NULL;
1247
1248# if CONFIG_UNUSED_SYMBOLS
1249 pMyMod->num_unused_syms = 0;
1250 pMyMod->unused_syms = NULL;
1251 pMyMod->unused_crcs = NULL;
1252
1253 pMyMod->num_unused_gpl_syms = 0;
1254 pMyMod->unused_gpl_syms = NULL;
1255 pMyMod->unused_gpl_crcs = NULL;
1256# endif
1257 /* No kernel parameters either. */
1258 pMyMod->kp = NULL;
1259 pMyMod->num_kp = 0;
1260
1261# ifdef CONFIG_MODULE_SIG
1262 /* Pretend ok signature. */
1263 pMyMod->sig_ok = true;
1264# endif
1265 /* No exception table. */
1266 pMyMod->num_exentries = 0;
1267 pMyMod->extable = NULL;
1268
1269 /* No init function */
1270 pMyMod->init = NULL;
1271 pMyMod->module_init = NULL;
1272 pMyMod->init_size = 0;
1273 pMyMod->init_ro_size = 0;
1274 pMyMod->init_text_size = 0;
1275
1276 /* The module address and size. It's all text. */
1277 pMyMod->module_core = pImage->pvImage;
1278 pMyMod->core_size = pImage->cbImageBits;
1279 pMyMod->core_text_size = pImage->cbImageBits;
1280 pMyMod->core_ro_size = pImage->cbImageBits;
1281
1282#ifdef CONFIG_MODULES_TREE_LOOKUP
1283 /* Fill in the self pointers for the tree nodes. */
1284 pMyMod->mtn_core.mod = pMyMod;
1285 pMyMod->mtn_init.mod = pMyMod;
1286#endif
1287 /* They invented the tained bit for us, didn't they? */
1288 pMyMod->taints = 1;
1289
1290# ifdef CONFIG_GENERIC_BUGS
1291 /* No BUGs in our modules. */
1292 pMyMod->num_bugs = 0;
1293 INIT_LIST_HEAD(&pMyMod->bug_list);
1294 pMyMod->bug_table = NULL;
1295# endif
1296
1297# ifdef CONFIG_KALLSYMS
1298 /* The core stuff is documented as only used when loading. So just zero them. */
1299 pMyMod->core_num_syms = 0;
1300 pMyMod->core_symtab = NULL;
1301 pMyMod->core_strtab = NULL;
1302
1303 /* Construct a symbol table with start and end symbols.
1304 Note! We don't have our own symbol table at this point, image bit
1305 are not uploaded yet! */
1306 pMyMod->num_symtab = 3;
1307 pMyMod->symtab = paSymbols;
1308 pMyMod->strtab = pchStrTab;
1309 RT_ZERO(paSymbols[0]);
1310 pchStrTab[0] = '\0';
1311 paSymbols[1].st_name = 1;
1312 paSymbols[2].st_name = 2 + RTStrPrintf(&pchStrTab[paSymbols[1].st_name], cchName + sizeof("_start"),
1313 "%s_start", pImage->szName);
1314 RTStrPrintf(&pchStrTab[paSymbols[2].st_name], cchName + sizeof("_end"), "%s_end", pImage->szName);
1315 paSymbols[1].st_info = 't';
1316 paSymbols[2].st_info = 'b';
1317 paSymbols[1].st_other = 0;
1318 paSymbols[2].st_other = 0;
1319 paSymbols[1].st_shndx = 0;
1320 paSymbols[2].st_shndx = 0;
1321 paSymbols[1].st_value = (uintptr_t)pImage->pvImage;
1322 paSymbols[2].st_value = (uintptr_t)pImage->pvImage + pImage->cbImageBits - 1;
1323 paSymbols[1].st_size = pImage->cbImageBits - 1;
1324 paSymbols[2].st_size = 1;
1325# endif
1326 /* No arguments, but seems its always non-NULL so put empty string there. */
1327 pMyMod->args = "";
1328
1329# ifdef CONFIG_SMP
1330 /* No per CPU data. */
1331 pMyMod->percpu = NULL;
1332 pMyMod->percpu_size = 0;
1333# endif
1334# ifdef CONFIG_TRACEPOINTS
1335 /* No tracepoints we like to share. */
1336 pMyMod->num_tracepoints = 0;
1337 pMyMod->tracepoints_ptrs = NULL;
1338#endif
1339# ifdef HAVE_JUMP_LABEL
1340 /* No jump lable stuff either. */
1341 pMyMod->jump_entries = NULL;
1342 pMyMod->num_jump_entries = 0;
1343# endif
1344# ifdef CONFIG_TRACING
1345 pMyMod->num_trace_bprintk_fmt = 0;
1346 pMyMod->trace_bprintk_fmt_start = NULL;
1347# endif
1348# ifdef CONFIG_EVENT_TRACING
1349 pMyMod->trace_events = NULL;
1350 pMyMod->num_trace_events = 0;
1351# endif
1352# ifdef CONFIG_FTRACE_MCOUNT_RECORD
1353 pMyMod->num_ftrace_callsites = 0;
1354 pMyMod->ftrace_callsites = NULL;
1355# endif
1356# ifdef CONFIG_MODULE_UNLOAD
1357 /* Dependency lists, not worth sharing */
1358 INIT_LIST_HEAD(&pMyMod->source_list);
1359 INIT_LIST_HEAD(&pMyMod->target_list);
1360
1361 /* Nobody waiting and no exit function. */
1362# if RTLNX_VER_MAX(3,13,0)
1363 pMyMod->waiter = NULL;
1364# endif
1365 pMyMod->exit = NULL;
1366
1367 /* References, very important as we must not allow the module
1368 to be unloaded using rmmod. */
1369# if RTLNX_VER_MIN(3,19,0)
1370 atomic_set(&pMyMod->refcnt, 42);
1371# else
1372 pMyMod->refptr = alloc_percpu(struct module_ref);
1373 if (pMyMod->refptr)
1374 {
1375 int iCpu;
1376 for_each_possible_cpu(iCpu)
1377 {
1378 per_cpu_ptr(pMyMod->refptr, iCpu)->decs = 0;
1379 per_cpu_ptr(pMyMod->refptr, iCpu)->incs = 1;
1380 }
1381 }
1382 else
1383 rc = VERR_NO_MEMORY;
1384# endif
1385# endif
1386# ifdef CONFIG_CONSTRUCTORS
1387 /* No constructors. */
1388 pMyMod->ctors = NULL;
1389 pMyMod->num_ctors = 0;
1390# endif
1391 if (RT_SUCCESS(rc))
1392 {
1393 bool fIsModText;
1394
1395 /*
1396 * Add the module to the list.
1397 */
1398 mutex_lock(&module_mutex);
1399 list_add_rcu(&pMyMod->list, &pSelfMod->list);
1400 pImage->pLnxModHack = pMyMod;
1401# ifdef CONFIG_MODULES_TREE_LOOKUP
1402 g_pfnModTreeInsert(&pMyMod->mtn_core); /* __mod_tree_insert */
1403# endif
1404 mutex_unlock(&module_mutex);
1405
1406 /*
1407 * Test it.
1408 */
1409 mutex_lock(&module_mutex);
1410 pTestModByName = find_module(pMyMod->name);
1411 pTestMod = __module_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 4);
1412 fIsModText = __module_text_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 2);
1413 mutex_unlock(&module_mutex);
1414 if ( pTestMod == pMyMod
1415 && pTestModByName == pMyMod
1416 && fIsModText)
1417 printk(KERN_ERR "vboxdrv: fake module works for '%s' (%#lx to %#lx)\n",
1418 pMyMod->name, (unsigned long)paSymbols[1].st_value, (unsigned long)paSymbols[2].st_value);
1419 else
1420 printk(KERN_ERR "vboxdrv: failed to find fake module (pTestMod=%p, pTestModByName=%p, pMyMod=%p, fIsModText=%d)\n",
1421 pTestMod, pTestModByName, pMyMod, fIsModText);
1422 }
1423 else
1424 RTMemFree(pMyMod);
1425 }
1426
1427 IPRT_LINUX_RESTORE_EFL_AC();
1428#else
1429 pImage->pLnxModHack = NULL;
1430#endif
1431 NOREF(pDevExt); NOREF(pImage);
1432}
1433
1434
1435void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1436{
1437#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
1438 struct module *pMyMod = pImage->pLnxModHack;
1439 pImage->pLnxModHack = NULL;
1440 if (pMyMod)
1441 {
1442 /*
1443 * Remove the fake module list entry and free it.
1444 */
1445 IPRT_LINUX_SAVE_EFL_AC();
1446 mutex_lock(&module_mutex);
1447 list_del_rcu(&pMyMod->list);
1448# ifdef CONFIG_MODULES_TREE_LOOKUP
1449 g_pfnModTreeRemove(&pMyMod->mtn_core);
1450# endif
1451 synchronize_sched();
1452 mutex_unlock(&module_mutex);
1453
1454# if RTLNX_VER_MAX(3,19,0)
1455 free_percpu(pMyMod->refptr);
1456# endif
1457 RTMemFree(pMyMod);
1458 IPRT_LINUX_RESTORE_EFL_AC();
1459 }
1460
1461#else
1462 Assert(pImage->pLnxModHack == NULL);
1463#endif
1464 NOREF(pDevExt); NOREF(pImage);
1465}
1466
1467
1468int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage,
1469 const char *pszSymbol, size_t cchSymbol, void **ppvSymbol)
1470{
1471#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
1472# error "implement me!"
1473#endif
1474 RT_NOREF(pDevExt, pImage, pszSymbol, cchSymbol, ppvSymbol);
1475 return VERR_WRONG_ORDER;
1476}
1477
1478
1479void VBOXCALL supdrvOSLdrRetainWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1480{
1481 struct module *pLnxMod = (struct module *)pImage->pvWrappedNative;
1482 Assert(!pImage->fLnxWrapperRef);
1483 AssertReturnVoid(pLnxMod);
1484 pImage->fLnxWrapperRef = try_module_get(pLnxMod);
1485 RT_NOREF(pDevExt);
1486}
1487
1488
1489void VBOXCALL supdrvOSLdrReleaseWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1490{
1491 if (pImage->fLnxWrapperRef)
1492 {
1493 struct module *pLnxMod = (struct module *)pImage->pvWrappedNative;
1494 pImage->fLnxWrapperRef = false;
1495 module_put(pLnxMod);
1496 }
1497 RT_NOREF(pDevExt);
1498}
1499
1500
1501#ifdef SUPDRV_WITH_MSR_PROBER
1502
1503int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
1504{
1505# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1506 uint32_t u32Low, u32High;
1507 int rc;
1508
1509 IPRT_LINUX_SAVE_EFL_AC();
1510 if (idCpu == NIL_RTCPUID)
1511 rc = rdmsr_safe(uMsr, &u32Low, &u32High);
1512 else if (RTMpIsCpuOnline(idCpu))
1513 rc = rdmsr_safe_on_cpu(idCpu, uMsr, &u32Low, &u32High);
1514 else
1515 return VERR_CPU_OFFLINE;
1516 IPRT_LINUX_RESTORE_EFL_AC();
1517 if (rc == 0)
1518 {
1519 *puValue = RT_MAKE_U64(u32Low, u32High);
1520 return VINF_SUCCESS;
1521 }
1522 return VERR_ACCESS_DENIED;
1523# else
1524 return VERR_NOT_SUPPORTED;
1525# endif
1526}
1527
1528
1529int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
1530{
1531# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1532 int rc;
1533
1534 IPRT_LINUX_SAVE_EFL_AC();
1535 if (idCpu == NIL_RTCPUID)
1536 rc = wrmsr_safe(uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
1537 else if (RTMpIsCpuOnline(idCpu))
1538 rc = wrmsr_safe_on_cpu(idCpu, uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
1539 else
1540 return VERR_CPU_OFFLINE;
1541 IPRT_LINUX_RESTORE_EFL_AC();
1542
1543 if (rc == 0)
1544 return VINF_SUCCESS;
1545 return VERR_ACCESS_DENIED;
1546# else
1547 return VERR_NOT_SUPPORTED;
1548# endif
1549}
1550
1551# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1552/**
1553 * Worker for supdrvOSMsrProberModify.
1554 */
1555static DECLCALLBACK(void) supdrvLnxMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1556{
1557 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
1558 register uint32_t uMsr = pReq->u.In.uMsr;
1559 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
1560 uint64_t uBefore;
1561 uint64_t uWritten;
1562 uint64_t uAfter;
1563 int rcBefore, rcWrite, rcAfter, rcRestore;
1564 RTCCUINTREG fOldFlags;
1565
1566 /* Initialize result variables. */
1567 uBefore = uWritten = uAfter = 0;
1568 rcWrite = rcAfter = rcRestore = -EIO;
1569
1570 /*
1571 * Do the job.
1572 */
1573 fOldFlags = ASMIntDisableFlags();
1574 ASMCompilerBarrier(); /* paranoia */
1575 if (!fFaster)
1576 ASMWriteBackAndInvalidateCaches();
1577
1578 rcBefore = rdmsrl_safe(uMsr, &uBefore);
1579 if (rcBefore >= 0)
1580 {
1581 register uint64_t uRestore = uBefore;
1582 uWritten = uRestore;
1583 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
1584 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
1585
1586 rcWrite = wrmsr_safe(uMsr, RT_LODWORD(uWritten), RT_HIDWORD(uWritten));
1587 rcAfter = rdmsrl_safe(uMsr, &uAfter);
1588 rcRestore = wrmsr_safe(uMsr, RT_LODWORD(uRestore), RT_HIDWORD(uRestore));
1589
1590 if (!fFaster)
1591 {
1592 ASMWriteBackAndInvalidateCaches();
1593 ASMReloadCR3();
1594 ASMNopPause();
1595 }
1596 }
1597
1598 ASMCompilerBarrier(); /* paranoia */
1599 ASMSetFlags(fOldFlags);
1600
1601 /*
1602 * Write out the results.
1603 */
1604 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1605 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1606 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1607 pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
1608 pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
1609 pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
1610 pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
1611 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1612}
1613# endif
1614
1615
1616int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1617{
1618# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
1619 if (idCpu == NIL_RTCPUID)
1620 {
1621 supdrvLnxMsrProberModifyOnCpu(idCpu, pReq, NULL);
1622 return VINF_SUCCESS;
1623 }
1624 return RTMpOnSpecific(idCpu, supdrvLnxMsrProberModifyOnCpu, pReq, NULL);
1625# else
1626 return VERR_NOT_SUPPORTED;
1627# endif
1628}
1629
1630#endif /* SUPDRV_WITH_MSR_PROBER */
1631
1632
1633/**
1634 * Converts a supdrv error code to an linux error code.
1635 *
1636 * @returns corresponding linux error code.
1637 * @param rc IPRT status code.
1638 */
1639static int VBoxDrvLinuxErr2LinuxErr(int rc)
1640{
1641 switch (rc)
1642 {
1643 case VINF_SUCCESS: return 0;
1644 case VERR_GENERAL_FAILURE: return -EACCES;
1645 case VERR_INVALID_PARAMETER: return -EINVAL;
1646 case VERR_INVALID_MAGIC: return -EILSEQ;
1647 case VERR_INVALID_HANDLE: return -ENXIO;
1648 case VERR_INVALID_POINTER: return -EFAULT;
1649 case VERR_LOCK_FAILED: return -ENOLCK;
1650 case VERR_ALREADY_LOADED: return -EEXIST;
1651 case VERR_PERMISSION_DENIED: return -EPERM;
1652 case VERR_VERSION_MISMATCH: return -ENOSYS;
1653 case VERR_IDT_FAILED: return -1000;
1654 }
1655
1656 return -EPERM;
1657}
1658
1659
1660SUPR0DECL(int) SUPR0HCPhysToVirt(RTHCPHYS HCPhys, void **ppv)
1661{
1662 AssertReturn(!(HCPhys & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
1663 AssertReturn(HCPhys != NIL_RTHCPHYS, VERR_INVALID_POINTER);
1664 /* Would've like to use valid_phys_addr_range for this test, but it isn't exported. */
1665 AssertReturn((HCPhys | PAGE_OFFSET_MASK) < __pa(high_memory), VERR_INVALID_POINTER);
1666 *ppv = phys_to_virt(HCPhys);
1667 return VINF_SUCCESS;
1668}
1669SUPR0_EXPORT_SYMBOL(SUPR0HCPhysToVirt);
1670
1671
1672RTDECL(int) SUPR0PrintfV(const char *pszFormat, va_list va)
1673{
1674 char szMsg[512];
1675 IPRT_LINUX_SAVE_EFL_AC();
1676
1677 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
1678 szMsg[sizeof(szMsg) - 1] = '\0';
1679
1680 printk("%s", szMsg);
1681
1682 IPRT_LINUX_RESTORE_EFL_AC();
1683 return 0;
1684}
1685SUPR0_EXPORT_SYMBOL(SUPR0PrintfV);
1686
1687
1688SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
1689{
1690 uint32_t fFlags = 0;
1691 /* Note! bird 2023-10-20: Apparently, with CONFIG_PAX_KERNEXEC these days,
1692 not only is the regular GDT read-only, but the one returned by
1693 get_current_gdt_rw() is also read-only despite the name.
1694
1695 We don't know exactly when this started, or if it was always like
1696 this, but getting hold of the relevant patches isn't all that
1697 straight forward any longer it seems (which is weird for linux
1698 patches), so, we've just enabled slow-mode for all PAX_KERNEXEC
1699 kernels regardless of kernel version.
1700
1701 Looking at grsecurity patch for 4.9.9, it looks like the writable
1702 GDT stuff never worked with PaX/grsec.
1703 */
1704#ifdef CONFIG_PAX_KERNEXEC
1705 fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY;
1706#elif RTLNX_VER_MIN(4,12,0)
1707 fFlags |= SUPKERNELFEATURES_GDT_NEED_WRITABLE;
1708#endif
1709
1710#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
1711 fFlags |= SUPKERNELFEATURES_SMAP;
1712#elif defined(CONFIG_X86_SMAP)
1713 if (ASMGetCR4() & X86_CR4_SMAP)
1714 fFlags |= SUPKERNELFEATURES_SMAP;
1715#endif
1716 return fFlags;
1717}
1718SUPR0_EXPORT_SYMBOL(SUPR0GetKernelFeatures);
1719
1720
1721SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook)
1722{
1723 RT_NOREF(fCtxHook);
1724#if RTLNX_VER_MIN(4,19,0) /* Going back to 4.19.0 for better coverage, we
1725 probably only need 5.17.7+ in the end. */
1726 /*
1727 * HACK ALERT!
1728 *
1729 * We'd like to use the old __kernel_fpu_begin() API which was removed in
1730 * early 2019, because we typically run with preemption enabled and have an
1731 * preemption hook installed which will call kernel_fpu_end() in case we're
1732 * scheduled out after getting in here. The preemption hook is almost
1733 * useless if we run with preemption disabled.
1734 *
1735 * For the case where the kernel does not have preemption hooks, we get here
1736 * with preemption already disabled and one more count doesn't make any
1737 * difference.
1738 *
1739 * So, after the kernel_fpu_begin() call we undo the implicit preempt_disable()
1740 * call it does, so the preemption hook can do its work and the VBox user has
1741 * a more responsive system.
1742 *
1743 * See @bugref{10209#c12} and onwards for more details.
1744 */
1745 Assert(fCtxHook || !RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1746 kernel_fpu_begin();
1747# if 0 /* Always do it for now for better test coverage. */
1748 if (fCtxHook)
1749# endif
1750 preempt_enable();
1751 return false; /** @todo Not sure if we have license to use any extended state, or
1752 * if we're limited to the SSE & x87 FPU. If it's the former,
1753 * we should return @a true and the caller can skip
1754 * saving+restoring the host state and save some time. */
1755#else
1756 return false;
1757#endif
1758}
1759SUPR0_EXPORT_SYMBOL(SUPR0FpuBegin);
1760
1761
1762SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook)
1763{
1764 RT_NOREF(fCtxHook);
1765#if RTLNX_VER_MIN(4,19,0)
1766 /* HACK ALERT! See SUPR0FpuBegin for an explanation of this. */
1767 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1768# if 0 /* Always do it for now for better test coverage. */
1769 if (fCtxHook)
1770# endif
1771 preempt_disable();
1772 kernel_fpu_end();
1773#endif
1774}
1775SUPR0_EXPORT_SYMBOL(SUPR0FpuEnd);
1776
1777
1778int VBOXCALL supdrvOSGetCurrentGdtRw(RTHCUINTPTR *pGdtRw)
1779{
1780#if RTLNX_VER_MIN(4,12,0) && !defined(CONFIG_PAX_KERNEXEC)
1781 *pGdtRw = (RTHCUINTPTR)get_current_gdt_rw();
1782 return VINF_SUCCESS;
1783#else
1784 return VERR_NOT_IMPLEMENTED;
1785#endif
1786}
1787
1788
1789module_init(VBoxDrvLinuxInit);
1790module_exit(VBoxDrvLinuxUnload);
1791
1792MODULE_AUTHOR(VBOX_VENDOR);
1793MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
1794MODULE_LICENSE("GPL");
1795#ifdef MODULE_VERSION
1796MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV) " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
1797#endif
1798
1799module_param(force_async_tsc, int, 0444);
1800MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1801
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use