VirtualBox

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

Last change on this file since 100307 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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

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