VirtualBox

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

Last change on this file was 109047, checked in by vboxsync, 11 days ago

SUPDrv: Make it build on linux.arm64. jiraref:VBP-1598

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette