VirtualBox

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

Last change on this file since 90520 was 89370, checked in by vboxsync, 3 years ago

Host drivers: SUPDrv-linux: print revision number and optional extra version string on module load, bugref:9958.

Also, export_modules.sh was extended with --override-svn-rev
and --extra-version-string optional command line parameters in
order to get more flexibility when creating src tar for kmod SRPM
package.

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