VirtualBox

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

Last change on this file since 88675 was 87729, checked in by vboxsync, 4 years ago

SUPDrv: Build fix. bugref:9937

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