summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/Support/linux
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/Support/linux')
-rw-r--r--src/VBox/HostDrivers/Support/linux/LnxPerfHack.cpp446
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile208
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile-vbox_vboxddr0.gmk43
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile-vbox_vmmr0.gmk44
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile-wrapper.gmk166
-rw-r--r--src/VBox/HostDrivers/Support/linux/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c1796
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c97
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp388
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c66
-rw-r--r--src/VBox/HostDrivers/Support/linux/SUPWrapperMod-linux.c211
-rw-r--r--src/VBox/HostDrivers/Support/linux/VBoxR0-wrapped.lds49
-rw-r--r--src/VBox/HostDrivers/Support/linux/combined-agnostic1.c99
-rw-r--r--src/VBox/HostDrivers/Support/linux/combined-agnostic2.c116
-rw-r--r--src/VBox/HostDrivers/Support/linux/combined-os-specific.c68
-rwxr-xr-xsrc/VBox/HostDrivers/Support/linux/files_vboxdrv242
16 files changed, 4039 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/Support/linux/LnxPerfHack.cpp b/src/VBox/HostDrivers/Support/linux/LnxPerfHack.cpp
new file mode 100644
index 00000000..056a2da8
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/LnxPerfHack.cpp
@@ -0,0 +1,446 @@
+/* $Id: LnxPerfHack.cpp $ */
+/** @file
+ * LnxPerfHack - Dirty hack to make perf find our .r0 modules.
+ */
+
+/*
+ * Copyright (C) 2021-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/assert.h>
+#include <iprt/file.h>
+#include <iprt/initterm.h>
+#include <iprt/getopt.h>
+#include <iprt/ldr.h>
+#include <iprt/sort.h>
+#include <iprt/string.h>
+#include <iprt/stream.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define LNXPERFILEHDR_MAGIC RT_MAKE_U64_FROM_U8('P','E','R','F','I','L','E','2')
+
+#define LNXPERF_RECORD_MMAP 1
+#define LNXPERF_RECORD_MMAP2 10
+
+#define LNXPERF_RECORD_MISC_CPUMODE_MASK UINT16_C(0x0007)
+#define LNXPERF_RECORD_MISC_CPUMODE_UNKNOWN UINT16_C(0x0000)
+#define LNXPERF_RECORD_MISC_KERNEL UINT16_C(0x0001)
+#define LNXPERF_RECORD_MISC_USER UINT16_C(0x0002)
+#define LNXPERF_RECORD_MISC_HYPERVISOR UINT16_C(0x0003)
+#define LNXPERF_RECORD_MISC_GUEST_KERNEL UINT16_C(0x0004)
+#define LNXPERF_RECORD_MISC_GUEST_USER UINT16_C(0x0005)
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** The file header. */
+typedef struct LNXPERFFILEHDR
+{
+ uint64_t uMagic; /**< LNXPERFILEHDR_MAGIC */
+ uint64_t cbHdr;
+ uint64_t cbAttr;
+ struct LNXPERFFILESECTION
+ {
+ uint64_t off, cb;
+ } Attrs, Data, EventTypes;
+ uint64_t bmAddsFeatures[256/64];
+} LNXPERFFILEHDR;
+typedef LNXPERFFILEHDR *PLNXPERFFILEHDR;
+
+
+typedef struct LNXPERFRECORDHEADER
+{
+ uint32_t uType;
+ uint16_t fMisc;
+ uint16_t cb;
+} LNXPERFRECORDHEADER;
+AssertCompileSize(LNXPERFRECORDHEADER, 8);
+typedef LNXPERFRECORDHEADER *PLNXPERFRECORDHEADER;
+
+typedef struct LNXPERFRECORDMMAP
+{
+ LNXPERFRECORDHEADER Hdr;
+ uint32_t pid;
+ uint32_t tid;
+ uint64_t uAddress;
+ uint64_t cbMapping;
+ uint64_t offFile;
+ RT_FLEXIBLE_ARRAY_EXTENSION
+ char szFilename[RT_FLEXIBLE_ARRAY];
+} LNXPERFRECORDMMAP;
+typedef LNXPERFRECORDMMAP *PLNXPERFRECORDMMAP;
+
+typedef struct MYMODULE
+{
+ uint64_t uAddress;
+ uint64_t cbMapping;
+ uint64_t offFile;
+ const char *pszName;
+ uint32_t cchName;
+ uint16_t cbRecord;
+ uint64_t offRecord;
+} MYMODULE;
+typedef MYMODULE *PMYMODULE;
+
+
+DECLCALLBACK(int) CompModuleRecordOffset(void const *pvElement1, void const *pvElement2, void *pvUser)
+{
+ PMYMODULE pLeft = (PMYMODULE)pvElement1;
+ PMYMODULE pRight = (PMYMODULE)pvElement2;
+ RT_NOREF(pvUser);
+ return pLeft->offRecord < pRight->offRecord ? -1
+ : pLeft->offRecord > pRight->offRecord ? 1 : 0;
+
+}
+
+
+DECLCALLBACK(int) CompModuleNameLengthDesc(void const *pvElement1, void const *pvElement2, void *pvUser)
+{
+ PMYMODULE pLeft = (PMYMODULE)pvElement1;
+ PMYMODULE pRight = (PMYMODULE)pvElement2;
+ RT_NOREF(pvUser);
+ return pLeft->cchName < pRight->cchName ? 1
+ : pLeft->cchName > pRight->cchName ? -1 : 0;
+}
+
+
+/** @callback_method_impl{FNRTLDRENUMSEGS} */
+static DECLCALLBACK(int) SegmentEnumCallback(RTLDRMOD hLdrMod, PCRTLDRSEG pSeg, void *pvUser)
+{
+ RT_NOREF(hLdrMod);
+ if (pSeg->pszName && RTStrStartsWith(pSeg->pszName, ".text"))
+ {
+ PMYMODULE pModEntry = (PMYMODULE)pvUser;
+ //pModEntry->offFile = pModEntry->uAddress;
+ pModEntry->uAddress += pSeg->RVA;
+ pModEntry->cbMapping = pSeg->cbMapped;
+ //pModEntry->offFile = pModEntry->uAddress - pSeg->LinkAddress;
+ pModEntry->offFile = RT_MAX(pSeg->offFile, 0);
+ return VINF_CALLBACK_RETURN;
+ }
+ return VINF_SUCCESS;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, 0);
+ if (RT_FAILURE(rc))
+ return RTMsgInitFailure(rc);
+
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--input", 'i', RTGETOPT_REQ_STRING },
+ { "--output", 'o', RTGETOPT_REQ_STRING },
+ { "--module", 'm', RTGETOPT_REQ_STRING },
+ { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+ };
+ const char *pszInput = NULL;
+ const char *pszOutput = NULL;
+ unsigned cVerbosity = 0;
+ unsigned cModules = 0;
+ MYMODULE aModules[10];
+ unsigned cSkipPatterns = 1;
+ const char *apszSkipPatterns[10] = { "*kallsyms*", };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
+ AssertRCReturn(rc, RTMsgErrorExitFailure("RTGetOptInit failed: %Rrc", rc));
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
+ {
+ switch (ch)
+ {
+ case 'i':
+ pszInput = ValueUnion.psz;
+ break;
+
+ case 'o':
+ pszOutput = ValueUnion.psz;
+ break;
+
+ case 'm':
+ {
+ if (cModules >= RT_ELEMENTS(aModules))
+ return RTMsgErrorExitFailure("Too many modules (max %u)", RT_ELEMENTS(aModules));
+ aModules[cModules].pszName = ValueUnion.psz;
+ aModules[cModules].cchName = strlen(ValueUnion.psz);
+
+ rc = RTGetOptFetchValue(&GetState, &ValueUnion, RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_HEX);
+ if (RT_FAILURE(rc))
+ return RTGetOptPrintError(rc, &ValueUnion); /*??*/
+ aModules[cModules].uAddress = ValueUnion.u64;
+
+ /* We need to find the .text section as that's what we'll be creating an mmap record for. */
+ RTERRINFOSTATIC ErrInfo;
+ RTLDRMOD hLdrMod;
+ rc = RTLdrOpenEx(aModules[cModules].pszName, RTLDR_O_FOR_DEBUG, RTLDRARCH_WHATEVER,
+ &hLdrMod, RTErrInfoInitStatic(&ErrInfo));
+ if (RT_FAILURE(rc))
+ {
+ return RTMsgErrorExitFailure("RTLdrOpenEx failed on '%s': %Rrc%#RTeim",
+ aModules[cModules].pszName, rc, &ErrInfo.Core);
+ }
+ rc = RTLdrEnumSegments(hLdrMod, SegmentEnumCallback, &aModules[cModules]);
+ if (rc != VINF_CALLBACK_RETURN)
+ return RTMsgErrorExitFailure("Failed to locate the .text section in '%s'!", aModules[cModules].pszName);
+
+ aModules[cModules].cbRecord = 0;
+ aModules[cModules].offRecord = UINT64_MAX;
+
+ cModules++;
+ break;
+ }
+
+ case 'q':
+ cVerbosity = 0;
+ break;
+
+ case 'v':
+ cVerbosity++;
+ break;
+
+ case 'h':
+ RTPrintf("usage: %s -i <perf.in> -o <perf.out> -m vmmr0.r0 <loadaddress> [-m ..] [-v]\n"
+ "\n"
+ "It is recommended to use eu-unstrip to combine the VMMR0.r0 and\n"
+ "VMMR0.debug files into a single file again.\n"
+ "\n"
+ "For the 'annotation' feature of perf to work, it is necessary to patch\n"
+ "machine__process_kernel_mmap_event() in tools/perf/utils/machine.c, adding"
+ "the following after 'map->end = map->start + ...:\n"
+ "\n"
+ "/* bird: Transfer pgoff to reloc as dso__process_kernel_symbol overwrites\n"
+ " map->pgoff with sh_offset later. Kind of ASSUMES sh_offset == sh_addr. */\n"
+ "if (event->mmap.pgoff && map->dso && !map->dso->rel)\n"
+ " map->reloc = map->start - event->mmap.pgoff;\n"
+ , argv[0]);
+ return RTEXITCODE_SUCCESS;
+
+ default:
+ return RTGetOptPrintError(ch, &ValueUnion);
+ }
+ }
+ if (!pszInput)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No input file specified");
+ if (!pszOutput)
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No output file specified");
+ if (RTFileExists(pszOutput))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Output file exists: %s", pszOutput);
+
+
+ /*
+ * Open the input file and check the header.
+ */
+ RTFILE hFile;
+ rc = RTFileOpen(&hFile, pszInput, RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("Failed to open '%s': %Rrc", pszInput, rc);
+
+ union
+ {
+ LNXPERFFILEHDR FileHdr;
+ uint8_t ab[_64K]; /* max record size */
+ } u;
+ rc = RTFileRead(hFile, &u.FileHdr, sizeof(u.FileHdr), NULL);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("Error reading file header: %Rrc", rc);
+ if (u.FileHdr.uMagic != LNXPERFILEHDR_MAGIC)
+ return RTMsgErrorExitFailure("Invalid file header magic: %.8Rhxs", &u.FileHdr.uMagic);
+ if (u.FileHdr.cbHdr != sizeof(u.FileHdr))
+ return RTMsgErrorExitFailure("Invalid file header size: %RU64, expected %zu", u.FileHdr.cbHdr, sizeof(u.FileHdr));
+ uint64_t const offData = u.FileHdr.Data.off;
+ uint64_t const cbData = u.FileHdr.Data.cb;
+
+ /*
+ * Jump to the data portion and look for suitable kmod mmap
+ * records to replace.
+ *
+ * We sort the modules in descreasing name length first to make sure
+ * not to waste voluminous records on short replacement names.
+ */
+ RTSortShell(aModules, cModules, sizeof(aModules[0]), CompModuleNameLengthDesc, NULL);
+
+ unsigned cModulesLeft = cModules ? cModules : cVerbosity > 0;
+ uint64_t offRecord = 0;
+ while (offRecord + 32 < cbData && cModulesLeft > 0)
+ {
+ size_t cbToRead = (size_t)RT_MIN(cbData - offRecord, sizeof(u));
+ rc = RTFileReadAt(hFile, offData + offRecord, &u, cbToRead, NULL);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("RTFileReadAt(,%llu,,%zu,) failed: %Rrc", offData + offRecord, cbToRead, rc);
+
+ uint64_t const offEnd = offRecord + cbToRead;
+ uint8_t *pb = u.ab;
+ while (offRecord + 32 < offEnd)
+ {
+ PLNXPERFRECORDHEADER pRecHdr = (PLNXPERFRECORDHEADER)pb;
+ uint64_t const offNext = offRecord + pRecHdr->cb;
+ if (offNext > offEnd)
+ break;
+ if ( pRecHdr->uType == LNXPERF_RECORD_MMAP
+ && (pRecHdr->fMisc & LNXPERF_RECORD_MISC_CPUMODE_MASK) == LNXPERF_RECORD_MISC_KERNEL)
+ {
+ PLNXPERFRECORDMMAP pMmapRec = (PLNXPERFRECORDMMAP)pRecHdr;
+ if (cVerbosity > 0)
+ RTMsgInfo("MMAP: %016RX64 (%016RX64) LB %012RX64 %s\n",
+ pMmapRec->uAddress, pMmapRec->offFile, pMmapRec->cbMapping, pMmapRec->szFilename);
+
+ bool fSkip = false;
+ for (unsigned i = 0; i < cSkipPatterns && !fSkip; i++)
+ fSkip = RTStrSimplePatternMatch(apszSkipPatterns[i], pMmapRec->szFilename);
+
+ if (!fSkip)
+ {
+ /* Figure the max filename length we dare to put here. */
+ size_t cchFilename = strlen(pMmapRec->szFilename);
+ cchFilename = RT_ALIGN_Z(cchFilename + 1, 8) - 1;
+
+ for (unsigned i = 0; i < cModules; i++)
+ if ( aModules[i].offRecord == UINT64_MAX
+ && aModules[i].cchName <= cchFilename)
+ {
+ aModules[i].cbRecord = pRecHdr->cb;
+ aModules[i].offRecord = offData + offRecord;
+ cModulesLeft--;
+ if (cVerbosity > 0)
+ RTMsgInfo("Will replace module %s at offset %RU64 with %s\n",
+ pMmapRec->szFilename, offRecord, aModules[i].pszName);
+ break;
+ }
+ }
+ }
+
+ /* Advance */
+ pb += pRecHdr->cb;
+ offRecord = offNext;
+ }
+ }
+
+ /*
+ * Only proceed if we found insertion points for all specified modules.
+ */
+ if (cModulesLeft)
+ {
+ if (cModules)
+ {
+ RTMsgError("Unable to find suitable targets for:\n");
+ for (unsigned i = 0; i < cModules; i++)
+ if (aModules[i].offRecord == UINT64_MAX)
+ RTMsgError(" %s\n", aModules[i].pszName);
+ }
+ else
+ RTMsgError("No modules given, so nothing to do.\n");
+ return RTEXITCODE_FAILURE;
+ }
+
+ /*
+ * Sort the modules by record offset to simplify the copying.
+ */
+ RTSortShell(aModules, cModules, sizeof(aModules[0]), CompModuleRecordOffset, NULL);
+
+ RTFILE hOutFile;
+ rc = RTFileOpen(&hOutFile, pszOutput, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("Failed to creating '%s' for the output: %Rrc", pszOutput, rc);
+
+ unsigned iModule = 0;
+ uint64_t offNext = aModules[0].offRecord;
+ uint64_t off = 0;
+ for (;;)
+ {
+ Assert(off <= offNext);
+
+ /* Read a chunk of data. Records we modify are read separately. */
+ size_t cbToRead = RT_MIN(offNext - off, sizeof(u));
+ if (cbToRead == 0)
+ cbToRead = aModules[iModule].cbRecord;
+ size_t cbActual = 0;
+ rc = RTFileReadAt(hFile, off, &u, cbToRead, &cbActual);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("Error reading %zu bytes at %RU64 in '%s': %Rrc", cbToRead, off, pszInput, rc);
+
+ /* EOF? */
+ if (cbActual == 0)
+ break;
+
+ /* A record we wish to modify? */
+ if (off == offNext)
+ {
+ if (cbActual != aModules[iModule].cbRecord)
+ return RTMsgErrorExitFailure("Internal error: cbActual=%zu cbRecord=%u off=%RU64\n",
+ cbActual, aModules[iModule].cbRecord, off);
+
+ PLNXPERFRECORDMMAP pMmapRec = (PLNXPERFRECORDMMAP)&u.ab[0];
+ strcpy(pMmapRec->szFilename, aModules[iModule].pszName);
+ pMmapRec->uAddress = aModules[iModule].uAddress;
+ pMmapRec->cbMapping = aModules[iModule].cbMapping;
+ pMmapRec->offFile = aModules[iModule].offFile;
+ RTMsgInfo("Done: %s\n", pMmapRec->szFilename);
+
+ iModule++;
+ if (iModule < cModules)
+ offNext = aModules[iModule].offRecord;
+ else
+ offNext = UINT64_MAX;
+ }
+
+ /* Write out the data. */
+ rc = RTFileWrite(hOutFile, &u, cbActual, NULL);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("Error writing %zu bytes at %RU64 to '%s': %Rrc", cbActual, off, pszOutput, rc);
+
+ /* Advance.*/
+ off += cbActual;
+ }
+
+ if (iModule != cModules)
+ return RTMsgErrorExitFailure("Internal error: iModule=%u cModules=%u\n", iModule, cModules);
+
+ rc = RTFileClose(hOutFile);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExitFailure("Error closing output file '%s': %Rrc", pszOutput, rc);
+
+ return RTEXITCODE_SUCCESS;
+}
+
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile b/src/VBox/HostDrivers/Support/linux/Makefile
new file mode 100644
index 00000000..900bcbd7
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile
@@ -0,0 +1,208 @@
+# $Id: Makefile $
+## @file
+# Makefile for the VirtualBox Linux Host Driver.
+#
+
+#
+# Copyright (C) 2006-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+# Linux kbuild sets this to our source directory if we are called from there
+obj ?= $(CURDIR)
+include $(obj)/Makefile-header.gmk
+VBOXDRV_DIR := $(VBOX_MODULE_SRC_DIR)
+
+VBOXMOD_NAME = vboxdrv
+VBOXMOD_OBJS = \
+ linux/SUPDrv-linux.o \
+ SUPDrv.o \
+ SUPDrvGip.o \
+ SUPDrvSem.o \
+ SUPDrvTracer.o \
+ SUPLibAll.o \
+ common/string/strformatrt.o
+
+ifndef VBOX_WITHOUT_COMBINED_SOURCES
+VBOXMOD_OBJS += \
+ combined-agnostic1.o \
+ combined-agnostic2.o \
+ combined-os-specific.o
+else # VBOX_WITHOUT_COMBINED_SOURCES
+VBOXMOD_OBJS += \
+ r0drv/alloc-r0drv.o \
+ r0drv/initterm-r0drv.o \
+ r0drv/memobj-r0drv.o \
+ r0drv/mpnotification-r0drv.o \
+ r0drv/powernotification-r0drv.o \
+ r0drv/linux/assert-r0drv-linux.o \
+ r0drv/linux/alloc-r0drv-linux.o \
+ r0drv/linux/initterm-r0drv-linux.o \
+ r0drv/linux/memobj-r0drv-linux.o \
+ r0drv/linux/memuserkernel-r0drv-linux.o \
+ r0drv/linux/mp-r0drv-linux.o \
+ r0drv/linux/mpnotification-r0drv-linux.o \
+ r0drv/linux/process-r0drv-linux.o \
+ r0drv/linux/rtStrFormatKernelAddress-r0drv-linux.o \
+ r0drv/linux/semevent-r0drv-linux.o \
+ r0drv/linux/semeventmulti-r0drv-linux.o \
+ r0drv/linux/semfastmutex-r0drv-linux.o \
+ r0drv/linux/semmutex-r0drv-linux.o \
+ r0drv/linux/spinlock-r0drv-linux.o \
+ r0drv/linux/thread-r0drv-linux.o \
+ r0drv/linux/thread2-r0drv-linux.o \
+ r0drv/linux/threadctxhooks-r0drv-linux.o \
+ r0drv/linux/time-r0drv-linux.o \
+ r0drv/linux/timer-r0drv-linux.o \
+ r0drv/generic/semspinmutex-r0drv-generic.o \
+ common/alloc/alloc.o \
+ common/checksum/crc32.o \
+ common/checksum/ipv4.o \
+ common/checksum/ipv6.o \
+ common/err/RTErrConvertFromErrno.o \
+ common/err/RTErrConvertToErrno.o \
+ common/err/errinfo.o \
+ common/log/log.o \
+ common/log/logellipsis.o \
+ common/log/logrel.o \
+ common/log/logrelellipsis.o \
+ common/log/logcom.o \
+ common/log/logformat.o \
+ common/log/RTLogCreateEx.o \
+ common/misc/RTAssertMsg1Weak.o \
+ common/misc/RTAssertMsg2.o \
+ common/misc/RTAssertMsg2Add.o \
+ common/misc/RTAssertMsg2AddWeak.o \
+ common/misc/RTAssertMsg2AddWeakV.o \
+ common/misc/RTAssertMsg2Weak.o \
+ common/misc/RTAssertMsg2WeakV.o \
+ common/misc/assert.o \
+ common/misc/handletable.o \
+ common/misc/handletablectx.o \
+ common/misc/thread.o \
+ common/string/RTStrCat.o \
+ common/string/RTStrCopy.o \
+ common/string/RTStrCopyEx.o \
+ common/string/RTStrCopyP.o \
+ common/string/RTStrEnd.o \
+ common/string/RTStrNCmp.o \
+ common/string/RTStrNLen.o \
+ common/string/stringalloc.o \
+ common/string/strformat.o \
+ common/string/RTStrFormat.o \
+ common/string/strformatnum.o \
+ common/string/strformattype.o \
+ common/string/strprintf.o \
+ common/string/strprintf-ellipsis.o \
+ common/string/strprintf2.o \
+ common/string/strprintf2-ellipsis.o \
+ common/string/strtonum.o \
+ common/table/avlpv.o \
+ common/time/time.o \
+ r0drv/linux/RTLogWriteDebugger-r0drv-linux.o \
+ generic/RTAssertShouldPanic-generic.o \
+ generic/RTLogWriteStdErr-stub-generic.o \
+ generic/RTLogWriteStdOut-stub-generic.o \
+ generic/RTLogWriteUser-generic.o \
+ generic/RTMpGetArraySize-generic.o \
+ generic/RTMpGetCoreCount-generic.o \
+ generic/RTSemEventWait-2-ex-generic.o \
+ generic/RTSemEventWaitNoResume-2-ex-generic.o \
+ generic/RTSemEventMultiWait-2-ex-generic.o \
+ generic/RTSemEventMultiWaitNoResume-2-ex-generic.o \
+ generic/RTTimerCreate-generic.o \
+ generic/errvars-generic.o \
+ generic/mppresent-generic.o \
+ generic/uuid-generic.o \
+ VBox/log-vbox.o \
+ VBox/RTLogWriteVmm-amd64-x86.o
+ ifeq ($(VBOX_KBUILD_TARGET_ARCH),amd64)
+VBOXMOD_OBJS += common/alloc/heapsimple.o
+ endif
+endif # VBOX_WITHOUT_COMBINED_SOURCES
+ifeq ($(VBOX_KBUILD_TARGET_ARCH),x86)
+VBOXMOD_OBJS += \
+ math/gcc/divdi3.o \
+ math/gcc/divmoddi4.o \
+ math/gcc/moddi3.o \
+ math/gcc/qdivrem.o \
+ math/gcc/udivdi3.o \
+ math/gcc/udivmoddi4.o \
+ math/gcc/divdi3.o \
+ math/gcc/umoddi3.o
+endif
+ifdef VBOX_WITH_NATIVE_DTRACE
+VBOXMOD_OBJS += SUPDrvDTrace.o
+endif
+
+VBOXMOD_INCL = \
+ $(VBOXDRV_DIR) \
+ $(VBOXDRV_DIR)include \
+ $(VBOXDRV_DIR)r0drv/linux
+ifdef VBOX_WITH_NATIVE_DTRACE
+VBOXMOD_INCL += \
+ /usr/include/linux \
+ /usr/include
+endif
+
+VBOXMOD_DEFS = \
+ RT_OS_LINUX \
+ IN_RING0 \
+ IN_RT_R0 \
+ IN_SUP_R0 \
+ VBOX \
+ RT_WITH_VBOX \
+ VBOX_WITH_HARDENING \
+ SUPDRV_WITH_RELEASE_LOGGER \
+ VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV \
+ IPRT_WITHOUT_EFLAGS_AC_PRESERVING \
+ VBOX_WITH_64_BITS_GUESTS # <-- must be consistent with Config.kmk!
+ifndef CONFIG_VBOXDRV_FIXEDMAJOR
+VBOXMOD_DEFS += CONFIG_VBOXDRV_AS_MISC
+endif
+ifdef VBOX_WITH_NATIVE_DTRACE
+VBOXMOD_DEFS += VBOX_WITH_NATIVE_DTRACE
+endif
+ifdef VBOX_WITH_TEXT_MODMEM_HACK
+VBOXMOD_DEFS += RTMEMALLOC_EXEC_HEAP VBOX_WITH_TEXT_MODMEM_HACK
+endif
+VBOXMOD_CFLAGS = -include $(VBOXDRV_DIR)include/VBox/SUPDrvMangling.h \
+ -fno-omit-frame-pointer -fno-pie -Wno-declaration-after-statement
+
+
+include $(obj)/Makefile-footer.gmk
+
+check: $(VBOXMOD_0_TARGET)
+ @if ! readelf -p __ksymtab_strings vboxdrv.ko | grep -E "\[.*\] *(RT|g_..*RT.*)"; then \
+ echo "All exported IPRT symbols are properly renamed!"; \
+ else \
+ echo "error: Some exported IPRT symbols was not properly renamed! See above." >&2; \
+ false; \
+ fi
+
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile-vbox_vboxddr0.gmk b/src/VBox/HostDrivers/Support/linux/Makefile-vbox_vboxddr0.gmk
new file mode 100644
index 00000000..08c7f604
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile-vbox_vboxddr0.gmk
@@ -0,0 +1,43 @@
+# $Id: Makefile-vbox_vboxddr0.gmk $
+## @file
+# Makefile for the VBoxDDR0.r0 wrapper module.
+#
+
+#
+# Copyright (C) 2021-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+VBOXMOD_NAME := vbox_vboxddr0
+WRAPPED_MODULE_NAME := VBoxDDR0
+WRAPPED_MODULE_FLAGS := 0
+WRAPPER_NEED_VMMR0 := yes
+
+include $(dir $(lastword $(MAKEFILE_LIST)))Makefile-wrapper.gmk
+
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile-vbox_vmmr0.gmk b/src/VBox/HostDrivers/Support/linux/Makefile-vbox_vmmr0.gmk
new file mode 100644
index 00000000..c338d025
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile-vbox_vmmr0.gmk
@@ -0,0 +1,44 @@
+# $Id: Makefile-vbox_vmmr0.gmk $
+## @file
+# Makefile for the VMMR0.r0 wrapper module.
+#
+
+#
+# Copyright (C) 2021-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+VBOXMOD_NAME := vbox_vmmr0
+WRAPPED_MODULE_NAME := VMMR0
+WRAPPED_MODULE_FLAGS := SUPLDRWRAPPEDMODULE_F_VMMR0
+WRAPPED_MODULE_IS_VMMR0 := yes
+WRAPPED_MODULE_LINUX_EXPORTS := yes
+
+include $(dir $(lastword $(MAKEFILE_LIST)))Makefile-wrapper.gmk
+
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile-wrapper.gmk b/src/VBox/HostDrivers/Support/linux/Makefile-wrapper.gmk
new file mode 100644
index 00000000..a47d55be
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile-wrapper.gmk
@@ -0,0 +1,166 @@
+# $Id: Makefile-wrapper.gmk $
+## @file
+# Makefile template for a wrapper module.
+#
+
+#
+# Copyright (C) 2006-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+# Check template parameters.
+ifndef WRAPPED_MODULE_NAME
+$(error WRAPPED_MODULE_NAME not defined)
+endif
+ifndef VBOXMOD_NAME
+$(error VBOXMOD_NAME not defined)
+endif
+
+
+# Linux kbuild sets this to our source directory if we are called from there
+ifndef VBOX_MODULE_SRC_DIR
+ VBOX_MODULE_SRC_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))/
+endif
+VBOXDRV_DIR := $(abspath $(VBOX_MODULE_SRC_DIR)../vboxdrv/)/
+VBOX_VMMR0_DIR := $(abspath $(VBOX_MODULE_SRC_DIR)../vbox_vmmr0/)/
+include $(VBOXDRV_DIR)Makefile-header.gmk
+
+# All of these wrappers depend on
+ifndef KBUILD_EXTRA_SYMBOLS
+KBUILD_EXTRA_SYMBOLS := $(VBOXDRV_DIR)Module.symvers
+ ifdef WRAPPER_NEED_VMMR0
+KBUILD_EXTRA_SYMBOLS += $(VBOX_VMMR0_DIR)Module.symvers
+ endif
+endif
+
+VBOXMOD_OBJS = \
+ SUPWrapperMod-linux.o \
+ $(WRAPPED_MODULE_NAME).o
+
+VBOXMOD_INCL = \
+ $(VBOXDRV_DIR) \
+ $(VBOXDRV_DIR)include \
+ $(VBOXDRV_DIR)r0drv/linux
+
+VBOXMOD_DEFS += \
+ RT_OS_LINUX \
+ IN_RING0 \
+ IN_RT_R0 \
+ IN_SUP_R0 \
+ VBOX \
+ \
+ WRAPPED_MODULE_NAME=\"$(WRAPPED_MODULE_NAME).r0\" \
+ WRAPPED_MODULE_SYMBOL_INCLUDE=\"$(WRAPPED_MODULE_NAME)-symbols.h\"
+ifdef WRAPPED_MODULE_FLAGS
+VBOXMOD_DEFS += WRAPPED_MODULE_FLAGS="$(WRAPPED_MODULE_FLAGS)"
+endif
+ifdef WRAPPED_MODULE_LINUX_EXPORTS
+VBOXMOD_DEFS += WRAPPED_MODULE_LINUX_EXPORTS
+endif
+ifdef WRAPPED_MODULE_SRV_REQ_HANDLER
+VBOXMOD_DEFS += WRAPPED_MODULE_SRV_REQ_HANDLER="$(WRAPPED_MODULE_SRV_REQ_HANDLER)"
+endif
+ifdef WRAPPED_MODULE_IS_VMMR0
+VBOXMOD_DEFS += WRAPPED_MODULE_VMMR0_ENTRY_FAST=VMMR0EntryFast
+VBOXMOD_DEFS += WRAPPED_MODULE_VMMR0_ENTRY_EX=VMMR0EntryEx
+endif
+ifdef WRAPPED_MODULE_NO_INIT
+VBOXMOD_DEFS += WRAPPED_MODULE_INIT=NULL
+endif
+ifdef WRAPPED_MODULE_NO_TERM
+VBOXMOD_DEFS += WRAPPED_MODULE_TERM=NULL
+endif
+ifdef WRAPPED_MODULE_LICENSE_PROPRIETARY
+VBOXMOD_DEFS += WRAPPED_MODULE_LICENSE_PROPRIETARY
+endif
+
+VBOXMOD_CFLAGS = -include $(VBOXDRV_DIR)include/VBox/SUPDrvMangling.h \
+ -fno-omit-frame-pointer -fno-pie -Wno-declaration-after-statement
+
+## @todo cleanup
+
+include $(VBOXDRV_DIR)Makefile-footer.gmk
+
+
+#
+# Custom rules (some of this could later be done before install).
+#
+SUPWrapperMod-linux.c \
+$(VBOX_MODULE_SRC_DIR)SUPWrapperMod-linux.c \
+$(VBOX_MODULE_SRC_DIR)SUPWrapperMod-linux.o \
+: $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME)-symbols.h
+
+$(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME)-symbols.h: \
+ $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).r0 \
+ $(VBOX_MODULE_SRC_DIR)Makefile-wrapper.gmk \
+ $(VBOX_MODULE_SRC_DIR)Makefile
+ rm -f -- "$@" "$@-tmp1" "$@-tmp2"
+ objdump --syms "$<" > "$@-tmp1"
+ sed -e '/[[:space:]].hidden[[:space:]]/d' \
+ -e '/[[:space:]]\*UND\*[[:space:]]/d' \
+ -e '/[[:space:]]vboxr0mod_/d' \
+ -e '/^[[:xdigit:]][[:xdigit:]]*[[:space:]][gu]/!d' \
+ -e 's/^\([[:xdigit:]]*\)[[:space:]].*000[[:xdigit:]]*[[:space:]]\([_a-zA-Z].*\)$$/SYMBOL_ENTRY(\2)/' \
+ -e '/SYMBOL_ENTRY(ModuleInit)/d' \
+ -e '/SYMBOL_ENTRY(ModuleTerm)/d' \
+ "$@-tmp1" > "$@-tmp2"
+ sort "$@-tmp2" > "$@"
+ rm -f -- "$@-tmp1" "$@-tmp2"
+
+
+$(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).mangle-symbols: \
+ $(VBOXDRV_DIR)Module.symvers \
+ $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME)-symbols.h \
+ $(VBOX_MODULE_SRC_DIR)Makefile-wrapper.gmk \
+ $(VBOX_MODULE_SRC_DIR)Makefile
+ sed -e 's/SYMBOL_ENTRY(\([^)]*\))/\/\1 VBoxHost_\1\/d/' \
+ "$(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME)-symbols.h" \
+ > "$@-ignore.sed"
+ sed -e '/[[:space:]]VBoxHost_/!d' \
+ -e 's/^0x[[:xdigit:]]*[[:space:]]VBoxHost_\([^[:space:]]*\)[[:space:]].*$$/\1 VBoxHost_\1/' \
+ -f "$@-ignore.sed" \
+ "$<" \
+ > "$@"
+
+$(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).o: \
+ $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).r0 \
+ $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).debug \
+ $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).mangle-symbols \
+ $(VBOX_MODULE_SRC_DIR)Makefile-wrapper.gmk \
+ $(VBOX_MODULE_SRC_DIR)Makefile \
+ $(if $(CONFIG_UNWINDER_ORC),$(objtool_dep),)
+ rm -f -- "$@" "$@-tmp"
+ eu-unstrip -o "$@-tmp" $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).r0 $(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).debug
+ objcopy --redefine-syms=$(VBOX_MODULE_SRC_DIR)$(WRAPPED_MODULE_NAME).mangle-symbols "$@-tmp" "$@"
+ rm -f -- "$@-tmp"
+ifdef CONFIG_UNWINDER_ORC # Must generate the ORC sections.
+ $(__objtool_obj) $(objtool_args) $@
+endif
+ touch $(VBOX_MODULE_SRC_DIR).$(WRAPPED_MODULE_NAME).o.cmd
+
diff --git a/src/VBox/HostDrivers/Support/linux/Makefile.kup b/src/VBox/HostDrivers/Support/linux/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/Makefile.kup
diff --git a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
new file mode 100644
index 00000000..2a77412c
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c
@@ -0,0 +1,1796 @@
+/* $Id: SUPDrv-linux.c $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Linux specifics.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP_DRV
+#include "../SUPDrvInternal.h"
+#include "the-linux-kernel.h"
+#include "version-generated.h"
+#include "product-generated.h"
+#include "revision-generated.h"
+
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/initterm.h>
+#include <iprt/process.h>
+#include <iprt/thread.h>
+#include <VBox/err.h>
+#include <iprt/mem.h>
+#include <VBox/log.h>
+#include <iprt/mp.h>
+
+/** @todo figure out the exact version number */
+#if RTLNX_VER_MIN(2,6,16)
+# include <iprt/power.h>
+# define VBOX_WITH_SUSPEND_NOTIFICATION
+#endif
+
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+# include <linux/platform_device.h>
+#endif
+#if (RTLNX_VER_MIN(2,6,28)) && defined(SUPDRV_WITH_MSR_PROBER)
+# define SUPDRV_LINUX_HAS_SAFE_MSR_API
+# include <asm/msr.h>
+#endif
+
+#include <asm/desc.h>
+
+#include <iprt/asm-amd64-x86.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* check kernel version */
+# ifndef SUPDRV_AGNOSTIC
+# if RTLNX_VER_MAX(2,6,0)
+# error Unsupported kernel version!
+# endif
+# endif
+
+#ifdef CONFIG_X86_HIGH_ENTRY
+# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
+#endif
+
+/* We cannot include x86.h, so we copy the defines we need here: */
+#define X86_EFL_IF RT_BIT(9)
+#define X86_EFL_AC RT_BIT(18)
+#define X86_EFL_DF RT_BIT(10)
+#define X86_EFL_IOPL (RT_BIT(12) | RT_BIT(13))
+
+/* To include the version number of VirtualBox into kernel backtraces: */
+#define VBoxDrvLinuxVersion RT_CONCAT3(RT_CONCAT(VBOX_VERSION_MAJOR, _), \
+ RT_CONCAT(VBOX_VERSION_MINOR, _), \
+ VBOX_VERSION_BUILD)
+#define VBoxDrvLinuxIOCtl RT_CONCAT(VBoxDrvLinuxIOCtl_,VBoxDrvLinuxVersion)
+
+/* Once externally provided, this string will be printed into kernel log on
+ * module start together with the rest of versioning information. */
+#ifndef VBOX_EXTRA_VERSION_STRING
+# define VBOX_EXTRA_VERSION_STRING ""
+#endif
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+#if RTLNX_VER_MIN(5,0,0)
+/** Wrapper module list entry. */
+typedef struct SUPDRVLNXMODULE
+{
+ RTLISTNODE ListEntry;
+ struct module *pModule;
+} SUPDRVLNXMODULE;
+/** Pointer to a wrapper module list entry. */
+typedef SUPDRVLNXMODULE *PSUPDRVLNXMODULE;
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int __init VBoxDrvLinuxInit(void);
+static void __exit VBoxDrvLinuxUnload(void);
+static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp);
+static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp);
+static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
+#ifdef HAVE_UNLOCKED_IOCTL
+static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+#else
+static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
+#endif
+static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession);
+static int VBoxDrvLinuxErr2LinuxErr(int);
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+static int VBoxDrvProbe(struct platform_device *pDev);
+# if RTLNX_VER_MIN(2,6,30)
+static int VBoxDrvSuspend(struct device *pDev);
+static int VBoxDrvResume(struct device *pDev);
+# else
+static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State);
+static int VBoxDrvResume(struct platform_device *pDev);
+# endif
+static void VBoxDevRelease(struct device *pDev);
+#endif
+#if RTLNX_VER_MIN(5,0,0)
+static int supdrvLinuxLdrModuleNotifyCallback(struct notifier_block *pBlock,
+ unsigned long uModuleState, void *pvModule);
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/**
+ * Device extention & session data association structure.
+ */
+static SUPDRVDEVEXT g_DevExt;
+
+/** Module parameter.
+ * Not prefixed because the name is used by macros and the end of this file. */
+static int force_async_tsc = 0;
+
+/** The system device name. */
+#define DEVICE_NAME_SYS "vboxdrv"
+/** The user device name. */
+#define DEVICE_NAME_USR "vboxdrvu"
+
+/** The file_operations structure. */
+static struct file_operations gFileOpsVBoxDrvSys =
+{
+ owner: THIS_MODULE,
+ open: VBoxDrvLinuxCreateSys,
+ release: VBoxDrvLinuxClose,
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: VBoxDrvLinuxIOCtl,
+#else
+ ioctl: VBoxDrvLinuxIOCtl,
+#endif
+};
+
+/** The file_operations structure. */
+static struct file_operations gFileOpsVBoxDrvUsr =
+{
+ owner: THIS_MODULE,
+ open: VBoxDrvLinuxCreateUsr,
+ release: VBoxDrvLinuxClose,
+#ifdef HAVE_UNLOCKED_IOCTL
+ unlocked_ioctl: VBoxDrvLinuxIOCtl,
+#else
+ ioctl: VBoxDrvLinuxIOCtl,
+#endif
+};
+
+/** The miscdevice structure for vboxdrv. */
+static struct miscdevice gMiscDeviceSys =
+{
+ minor: MISC_DYNAMIC_MINOR,
+ name: DEVICE_NAME_SYS,
+ fops: &gFileOpsVBoxDrvSys,
+# if RTLNX_VER_MAX(2,6,18)
+ devfs_name: DEVICE_NAME_SYS,
+# endif
+};
+/** The miscdevice structure for vboxdrvu. */
+static struct miscdevice gMiscDeviceUsr =
+{
+ minor: MISC_DYNAMIC_MINOR,
+ name: DEVICE_NAME_USR,
+ fops: &gFileOpsVBoxDrvUsr,
+# if RTLNX_VER_MAX(2,6,18)
+ devfs_name: DEVICE_NAME_USR,
+# endif
+};
+
+
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+
+# if RTLNX_VER_MIN(2,6,30)
+static struct dev_pm_ops gPlatformPMOps =
+{
+ .suspend = VBoxDrvSuspend, /* before entering deep sleep */
+ .resume = VBoxDrvResume, /* after wakeup from deep sleep */
+ .freeze = VBoxDrvSuspend, /* before creating hibernation image */
+ .restore = VBoxDrvResume, /* after waking up from hibernation */
+};
+# endif
+
+static struct platform_driver gPlatformDriver =
+{
+ .probe = VBoxDrvProbe,
+# if RTLNX_VER_MAX(2,6,30)
+ .suspend = VBoxDrvSuspend,
+ .resume = VBoxDrvResume,
+# endif
+ /** @todo .shutdown? */
+ .driver =
+ {
+ .name = "vboxdrv",
+# if RTLNX_VER_MIN(2,6,30)
+ .pm = &gPlatformPMOps,
+# endif
+ }
+};
+
+static struct platform_device gPlatformDevice =
+{
+ .name = "vboxdrv",
+ .dev =
+ {
+ .release = VBoxDevRelease
+ }
+};
+
+#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
+
+#if RTLNX_VER_MIN(5,0,0)
+/** Module load/unload notification registration record. */
+static struct notifier_block g_supdrvLinuxModuleNotifierBlock =
+{
+ .notifier_call = supdrvLinuxLdrModuleNotifyCallback,
+ .priority = 0
+};
+/** Spinlock protecting g_supdrvLinuxWrapperModuleList. */
+static spinlock_t g_supdrvLinuxWrapperModuleSpinlock;
+/** List of potential wrapper modules (PSUPDRVLNXMODULE). */
+static RTLISTANCHOR g_supdrvLinuxWrapperModuleList;
+#endif
+
+
+/** Get the kernel UID for the current process. */
+DECLINLINE(RTUID) vboxdrvLinuxKernUid(void)
+{
+#if RTLNX_VER_MIN(2,6,29)
+# if RTLNX_VER_MIN(3,5,0)
+ return __kuid_val(current->cred->uid);
+# else
+ return current->cred->uid;
+# endif
+#else
+ return current->uid;
+#endif
+}
+
+
+/** Get the kernel GID for the current process. */
+DECLINLINE(RTGID) vboxdrvLinuxKernGid(void)
+{
+#if RTLNX_VER_MIN(2,6,29)
+# if RTLNX_VER_MIN(3,5,0)
+ return __kgid_val(current->cred->gid);
+# else
+ return current->cred->gid;
+# endif
+#else
+ return current->gid;
+#endif
+}
+
+
+#ifdef VBOX_WITH_HARDENING
+/** Get the effective UID within the current user namespace. */
+DECLINLINE(RTUID) vboxdrvLinuxEuidInNs(void)
+{
+# if RTLNX_VER_MIN(2,6,29)
+# if RTLNX_VER_MIN(3,5,0)
+ return from_kuid(current_user_ns(), current->cred->euid);
+# else
+ return current->cred->euid;
+# endif
+# else
+ return current->euid;
+# endif
+}
+#endif
+
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init VBoxDrvLinuxInit(void)
+{
+ int rc;
+
+#if RTLNX_VER_MIN(5,0,0)
+ spin_lock_init(&g_supdrvLinuxWrapperModuleSpinlock);
+ RTListInit(&g_supdrvLinuxWrapperModuleList);
+#endif
+
+ /*
+ * Check for synchronous/asynchronous TSC mode.
+ */
+ printk(KERN_DEBUG "vboxdrv: Found %u processor cores/threads\n", (unsigned)RTMpGetOnlineCount());
+ rc = misc_register(&gMiscDeviceSys);
+ if (rc)
+ {
+ printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc);
+ return rc;
+ }
+ rc = misc_register(&gMiscDeviceUsr);
+ if (rc)
+ {
+ printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc);
+ misc_deregister(&gMiscDeviceSys);
+ return rc;
+ }
+ if (!rc)
+ {
+ /*
+ * Initialize the runtime.
+ * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("VBoxDrv::ModuleInit\n"));
+
+ /*
+ * Initialize the device extension.
+ */
+ rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
+ if (RT_SUCCESS(rc))
+ {
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+ rc = platform_driver_register(&gPlatformDriver);
+ if (rc == 0)
+ {
+ rc = platform_device_register(&gPlatformDevice);
+ if (rc == 0)
+#endif
+ {
+#if RTLNX_VER_MIN(5,0,0)
+ /*
+ * Register the module notifier.
+ */
+ int rc2 = register_module_notifier(&g_supdrvLinuxModuleNotifierBlock);
+ if (rc2)
+ printk(KERN_WARNING "vboxdrv: failed to register module notifier! rc2=%d\n", rc2);
+#endif
+
+
+ printk(KERN_INFO "vboxdrv: TSC mode is %s, tentative frequency %llu Hz\n",
+ SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz);
+ LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
+ printk(KERN_DEBUG "vboxdrv: Successfully loaded version "
+ VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV)
+ VBOX_EXTRA_VERSION_STRING
+ " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ")\n");
+ return rc;
+ }
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+ else
+ platform_driver_unregister(&gPlatformDriver);
+ }
+#endif
+ }
+
+ rc = -EINVAL;
+ RTR0TermForced();
+ }
+ else
+ rc = -EINVAL;
+
+ /*
+ * Failed, cleanup and return the error code.
+ */
+ }
+ misc_deregister(&gMiscDeviceSys);
+ misc_deregister(&gMiscDeviceUsr);
+ Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor));
+ return rc;
+}
+
+
+/**
+ * Unload the module.
+ */
+static void __exit VBoxDrvLinuxUnload(void)
+{
+ Log(("VBoxDrvLinuxUnload\n"));
+
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+ platform_device_unregister(&gPlatformDevice);
+ platform_driver_unregister(&gPlatformDriver);
+#endif
+
+#if RTLNX_VER_MIN(5,0,0)
+ /*
+ * Kick the list of potential wrapper modules.
+ */
+ unregister_module_notifier(&g_supdrvLinuxModuleNotifierBlock);
+
+ spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
+ while (!RTListIsEmpty(&g_supdrvLinuxWrapperModuleList))
+ {
+ PSUPDRVLNXMODULE pCur = RTListRemoveFirst(&g_supdrvLinuxWrapperModuleList, SUPDRVLNXMODULE, ListEntry);
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+
+ pCur->pModule = NULL;
+ RTMemFree(pCur);
+
+ spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
+ }
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+#endif
+
+ /*
+ * I Don't think it's possible to unload a driver which processes have
+ * opened, at least we'll blindly assume that here.
+ */
+ misc_deregister(&gMiscDeviceUsr);
+ misc_deregister(&gMiscDeviceSys);
+
+ /*
+ * Destroy GIP, delete the device extension and terminate IPRT.
+ */
+ supdrvDeleteDevExt(&g_DevExt);
+ RTR0TermForced();
+}
+
+
+/**
+ * Common open code.
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ * @param fUnrestricted Indicates which device node which was opened.
+ */
+static int vboxdrvLinuxCreateCommon(struct inode *pInode, struct file *pFilp, bool fUnrestricted)
+{
+ int rc;
+ PSUPDRVSESSION pSession;
+ Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
+
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Only root is allowed to access the unrestricted device, enforce it!
+ */
+ if ( fUnrestricted
+ && vboxdrvLinuxEuidInNs() != 0 /* root */ )
+ {
+ Log(("VBoxDrvLinuxCreate: euid=%d, expected 0 (root)\n", vboxdrvLinuxEuidInNs()));
+ return -EPERM;
+ }
+#endif /* VBOX_WITH_HARDENING */
+
+ /*
+ * Call common code for the rest.
+ */
+ rc = supdrvCreateSession(&g_DevExt, true /* fUser */, fUnrestricted, &pSession);
+ if (!rc)
+ {
+ pSession->Uid = vboxdrvLinuxKernUid();
+ pSession->Gid = vboxdrvLinuxKernGid();
+ }
+
+ pFilp->private_data = pSession;
+
+ Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
+ &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
+ RTProcSelf(), current->pid, current->comm));
+ return VBoxDrvLinuxErr2LinuxErr(rc);
+}
+
+
+/** /dev/vboxdrv. */
+static int VBoxDrvLinuxCreateSys(struct inode *pInode, struct file *pFilp)
+{
+ return vboxdrvLinuxCreateCommon(pInode, pFilp, true);
+}
+
+
+/** /dev/vboxdrvu. */
+static int VBoxDrvLinuxCreateUsr(struct inode *pInode, struct file *pFilp)
+{
+ return vboxdrvLinuxCreateCommon(pInode, pFilp, false);
+}
+
+
+/**
+ * Close device.
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
+{
+ Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
+ pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
+ supdrvSessionRelease((PSUPDRVSESSION)pFilp->private_data);
+ pFilp->private_data = NULL;
+ return 0;
+}
+
+
+#ifdef VBOX_WITH_SUSPEND_NOTIFICATION
+/**
+ * Dummy device release function. We have to provide this function,
+ * otherwise the kernel will complain.
+ *
+ * @param pDev Pointer to the platform device.
+ */
+static void VBoxDevRelease(struct device *pDev)
+{
+}
+
+/**
+ * Dummy probe function.
+ *
+ * @param pDev Pointer to the platform device.
+ */
+static int VBoxDrvProbe(struct platform_device *pDev)
+{
+ return 0;
+}
+
+/**
+ * Suspend callback.
+ * @param pDev Pointer to the platform device.
+ * @param State Message type, see Documentation/power/devices.txt.
+ * Ignored.
+ */
+# if RTLNX_VER_MIN(2,6,30) && !defined(DOXYGEN_RUNNING)
+static int VBoxDrvSuspend(struct device *pDev)
+# else
+static int VBoxDrvSuspend(struct platform_device *pDev, pm_message_t State)
+# endif
+{
+ RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
+ return 0;
+}
+
+/**
+ * Resume callback.
+ *
+ * @param pDev Pointer to the platform device.
+ */
+# if RTLNX_VER_MIN(2,6,30)
+static int VBoxDrvResume(struct device *pDev)
+# else
+static int VBoxDrvResume(struct platform_device *pDev)
+# endif
+{
+ RTPowerSignalEvent(RTPOWEREVENT_RESUME);
+ return 0;
+}
+#endif /* VBOX_WITH_SUSPEND_NOTIFICATION */
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pFilp Associated file pointer.
+ * @param uCmd The function specified to ioctl().
+ * @param ulArg The argument specified to ioctl().
+ */
+#if defined(HAVE_UNLOCKED_IOCTL) || defined(DOXYGEN_RUNNING)
+static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+#else
+static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
+#endif
+{
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFilp->private_data;
+ int rc;
+#ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
+# if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ RTCCUINTREG fSavedEfl;
+
+ /*
+ * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
+ *
+ * This isn't a problem, as there is absolutely nothing in the kernel context that
+ * depend on user context triggering cleanups. That would be pretty wild, right?
+ */
+ if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
+ {
+ SUPR0Printf("VBoxDrvLinuxIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
+ return ESPIPE;
+ }
+
+ fSavedEfl = ASMAddFlags(X86_EFL_AC);
+# else
+ stac();
+# endif
+#endif
+
+ /*
+ * Deal with the two high-speed IOCtl that takes it's arguments from
+ * the session and iCmd, and only returns a VBox status code.
+ */
+ AssertCompile(_IOC_NRSHIFT == 0 && _IOC_NRBITS == 8);
+#ifdef HAVE_UNLOCKED_IOCTL
+ if (RT_LIKELY( (unsigned int)(uCmd - SUP_IOCTL_FAST_DO_FIRST) < (unsigned int)32
+ && pSession->fUnrestricted))
+ rc = supdrvIOCtlFast(uCmd - SUP_IOCTL_FAST_DO_FIRST, ulArg, &g_DevExt, pSession);
+ else
+ rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
+#else /* !HAVE_UNLOCKED_IOCTL */
+ unlock_kernel();
+ if (RT_LIKELY( (unsigned int)(uCmd - SUP_IOCTL_FAST_DO_FIRST) < (unsigned int)32
+ && pSession->fUnrestricted))
+ rc = supdrvIOCtlFast(uCmd - SUP_IOCTL_FAST_DO_FIRST, ulArg, &g_DevExt, pSession);
+ else
+ rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg, pSession);
+ lock_kernel();
+#endif /* !HAVE_UNLOCKED_IOCTL */
+
+#ifndef VBOX_WITHOUT_EFLAGS_AC_SET_IN_VBOXDRV
+# if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ /*
+ * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
+ * accidentially modified it or some other important flag.
+ */
+ if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF))
+ != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF)) | X86_EFL_AC) ))
+ {
+ char szTmp[48];
+ RTStrPrintf(szTmp, sizeof(szTmp), "uCmd=%#x: %#x->%#x!", _IOC_NR(uCmd), (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
+ supdrvBadContext(&g_DevExt, "SUPDrv-linux.c", __LINE__, szTmp);
+ }
+ ASMSetFlags(fSavedEfl);
+# else
+ clac();
+# endif
+#endif
+ return rc;
+}
+
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pFilp Associated file pointer.
+ * @param uCmd The function specified to ioctl().
+ * @param ulArg The argument specified to ioctl().
+ * @param pSession The session instance.
+ */
+static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg, PSUPDRVSESSION pSession)
+{
+ int rc;
+ SUPREQHDR Hdr;
+ PSUPREQHDR pHdr;
+ uint32_t cbBuf;
+
+ Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
+
+ /*
+ * Read the header.
+ */
+ if (RT_FAILURE(RTR0MemUserCopyFrom(&Hdr, ulArg, sizeof(Hdr))))
+ {
+ Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x\n", ulArg, uCmd));
+ return -EFAULT;
+ }
+ if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
+ {
+ Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
+ return -EINVAL;
+ }
+
+ /*
+ * Buffer the request.
+ */
+ cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
+ if (RT_UNLIKELY(cbBuf > _1M*16))
+ {
+ Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
+ return -E2BIG;
+ }
+ if (RT_UNLIKELY(_IOC_SIZE(uCmd) ? cbBuf != _IOC_SIZE(uCmd) : Hdr.cbIn < sizeof(Hdr)))
+ {
+ Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
+ return -EINVAL;
+ }
+ pHdr = RTMemAlloc(cbBuf);
+ if (RT_UNLIKELY(!pHdr))
+ {
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x\n", cbBuf, uCmd));
+ return -ENOMEM;
+ }
+ if (RT_FAILURE(RTR0MemUserCopyFrom(pHdr, ulArg, Hdr.cbIn)))
+ {
+ Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x\n", ulArg, Hdr.cbIn, uCmd));
+ RTMemFree(pHdr);
+ return -EFAULT;
+ }
+ if (Hdr.cbIn < cbBuf)
+ RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbBuf - Hdr.cbIn);
+
+ /*
+ * Process the IOCtl.
+ */
+ rc = supdrvIOCtl(uCmd, &g_DevExt, pSession, pHdr, cbBuf);
+
+ /*
+ * Copy ioctl data and output buffer back to user space.
+ */
+ if (RT_LIKELY(!rc))
+ {
+ uint32_t cbOut = pHdr->cbOut;
+ if (RT_UNLIKELY(cbOut > cbBuf))
+ {
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
+ cbOut = cbBuf;
+ }
+ if (RT_FAILURE(RTR0MemUserCopyTo(ulArg, pHdr, cbOut)))
+ {
+ /* this is really bad! */
+ OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
+ rc = -EFAULT;
+ }
+ }
+ else
+ {
+ Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
+ rc = -EINVAL;
+ }
+ RTMemFree(pHdr);
+
+ Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
+ return rc;
+}
+
+
+/**
+ * The SUPDRV IDC entry point.
+ *
+ * @returns VBox status code, see supdrvIDC.
+ * @param uReq The request code.
+ * @param pReq The request.
+ */
+int VBOXCALL SUPDrvLinuxIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
+{
+ PSUPDRVSESSION pSession;
+
+ /*
+ * Some quick validations.
+ */
+ if (RT_UNLIKELY(!RT_VALID_PTR(pReq)))
+ return VERR_INVALID_POINTER;
+
+ pSession = pReq->pSession;
+ if (pSession)
+ {
+ if (RT_UNLIKELY(!RT_VALID_PTR(pSession)))
+ return VERR_INVALID_PARAMETER;
+ if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
+ return VERR_INVALID_PARAMETER;
+ }
+ else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
+ return VERR_INVALID_PARAMETER;
+
+ /*
+ * Do the job.
+ */
+ return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
+}
+EXPORT_SYMBOL(SUPDrvLinuxIDC);
+
+
+#if RTLNX_VER_MIN(5,0,0)
+
+/**
+ * Checks if the given module is one of our potential wrapper modules or not.
+ */
+static bool supdrvLinuxLdrIsPotentialWrapperModule(struct module const *pModule)
+{
+ if ( pModule
+ && strncmp(pModule->name, RT_STR_TUPLE("vbox_")) == 0)
+ return true;
+ return false;
+}
+
+/**
+ * Called when a kernel module changes state.
+ *
+ * We use this to listen for wrapper modules being loaded, since some evil
+ * bugger removed the find_module() export in 5.13.
+ */
+static int supdrvLinuxLdrModuleNotifyCallback(struct notifier_block *pBlock, unsigned long uModuleState, void *pvModule)
+{
+ struct module *pModule = (struct module *)pvModule;
+ switch (uModuleState)
+ {
+ case MODULE_STATE_UNFORMED: /* Setting up the module... */
+ break;
+
+ /*
+ * The module is about to have its ctors & init functions called.
+ *
+ * Add anything that looks like a wrapper module to our tracker list.
+ */
+ case MODULE_STATE_COMING:
+ if (supdrvLinuxLdrIsPotentialWrapperModule(pModule))
+ {
+ PSUPDRVLNXMODULE pTracker = (PSUPDRVLNXMODULE)RTMemAlloc(sizeof(*pTracker));
+ if (pTracker)
+ {
+ pTracker->pModule = pModule;
+ spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
+ RTListPrepend(&g_supdrvLinuxWrapperModuleList, &pTracker->ListEntry);
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+ }
+ }
+ break;
+
+ case MODULE_STATE_LIVE:
+ break;
+
+ /*
+ * The module has been uninited and is going away.
+ *
+ * Remove the tracker entry for the module, if we have one.
+ */
+ case MODULE_STATE_GOING:
+ {
+ PSUPDRVLNXMODULE pCur;
+ spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
+ RTListForEach(&g_supdrvLinuxWrapperModuleList, pCur, SUPDRVLNXMODULE, ListEntry)
+ {
+ if (pCur->pModule == pModule)
+ {
+ RTListNodeRemove(&pCur->ListEntry);
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+
+ pCur->pModule = NULL;
+ RTMemFree(pCur);
+
+ spin_lock(&g_supdrvLinuxWrapperModuleSpinlock); /* silly */
+ break;
+ }
+ }
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+ break;
+ }
+ }
+ RT_NOREF(pBlock);
+ return NOTIFY_OK;
+}
+
+/**
+ * Replacement for find_module() that's no longer exported with 5.13.
+ */
+static struct module *supdrvLinuxLdrFindModule(const char *pszLnxModName)
+{
+ PSUPDRVLNXMODULE pCur;
+
+ spin_lock(&g_supdrvLinuxWrapperModuleSpinlock);
+ RTListForEach(&g_supdrvLinuxWrapperModuleList, pCur, SUPDRVLNXMODULE, ListEntry)
+ {
+ struct module * const pModule = pCur->pModule;
+ if ( pModule
+ && strcmp(pszLnxModName, pModule->name) == 0)
+ {
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+ return pModule;
+ }
+ }
+ spin_unlock(&g_supdrvLinuxWrapperModuleSpinlock);
+ return NULL;
+}
+
+#endif /* >= 5.0.0 */
+
+
+/**
+ * Used by native wrapper modules, forwarding to supdrvLdrRegisterWrappedModule
+ * with device extension prepended to the argument list.
+ */
+SUPR0DECL(int) SUPDrvLinuxLdrRegisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo,
+ const char *pszLnxModName, void **phMod)
+{
+ AssertPtrReturn(pszLnxModName, VERR_INVALID_POINTER);
+ AssertReturn(*pszLnxModName, VERR_INVALID_NAME);
+
+ /* Locate the module structure for the caller so can later reference
+ and dereference it to prevent unloading while it is being used.
+
+ Before Linux v5.9 this could be done by address (__module_address()
+ or __module_text_address()), but someone (guess who) apparently on
+ a mission to make life miserable for out-of-tree modules or something,
+ decided it was only used by build-in code and unexported both of them.
+
+ I could find no init callouts getting a struct module pointer either,
+ nor any module name hint anywhere I could see. So, we're left with
+ hardcoding the module name via the compiler and pass it along to
+ SUPDrv so we can call find_module() here.
+
+ Sigh^2.
+
+ Update 5.13:
+ The find_module() and module_mutex symbols are no longer exported,
+ probably the doing of the same evil bugger mentioned above. So, we now
+ register a module notification callback and track the modules we're
+ interested in that way. */
+
+#if RTLNX_VER_MIN(5,0,0)
+ struct module *pLnxModule = supdrvLinuxLdrFindModule(pszLnxModName);
+ if (pLnxModule)
+ return supdrvLdrRegisterWrappedModule(&g_DevExt, pWrappedModInfo, pLnxModule, phMod);
+ printk("vboxdrv: supdrvLinuxLdrFindModule(%s) failed in SUPDrvLinuxLdrRegisterWrappedModule!\n", pszLnxModName);
+ return VERR_MODULE_NOT_FOUND;
+
+#elif RTLNX_VER_MIN(2,6,30)
+ if (mutex_lock_interruptible(&module_mutex) == 0)
+ {
+ struct module *pLnxModule = find_module(pszLnxModName);
+ mutex_unlock(&module_mutex);
+ if (pLnxModule)
+ return supdrvLdrRegisterWrappedModule(&g_DevExt, pWrappedModInfo, pLnxModule, phMod);
+ printk("vboxdrv: find_module(%s) failed in SUPDrvLinuxLdrRegisterWrappedModule!\n", pszLnxModName);
+ return VERR_MODULE_NOT_FOUND;
+ }
+ return VERR_INTERRUPTED;
+
+#else
+ printk("vboxdrv: wrapper modules are not supported on 2.6.29 and earlier. sorry.\n");
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+EXPORT_SYMBOL(SUPDrvLinuxLdrRegisterWrappedModule);
+
+
+/**
+ * Used by native wrapper modules, forwarding to supdrvLdrDeregisterWrappedModule
+ * with device extension prepended to the argument list.
+ */
+SUPR0DECL(int) SUPDrvLinuxLdrDeregisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo, void **phMod)
+{
+ return supdrvLdrDeregisterWrappedModule(&g_DevExt, pWrappedModInfo, phMod);
+}
+EXPORT_SYMBOL(SUPDrvLinuxLdrDeregisterWrappedModule);
+
+
+RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask)
+{
+#if RTLNX_VER_MIN(5,8,0)
+ unsigned long fSavedFlags;
+ local_irq_save(fSavedFlags);
+ RTCCUINTREG const uOld = cr4_read_shadow();
+ cr4_update_irqsoff(fOrMask, ~fAndMask); /* Same as this function, only it is not returning the old value. */
+ AssertMsg(cr4_read_shadow() == ((uOld & fAndMask) | fOrMask),
+ ("fOrMask=%#RTreg fAndMask=%#RTreg uOld=%#RTreg; new cr4=%#llx\n", fOrMask, fAndMask, uOld, cr4_read_shadow()));
+ local_irq_restore(fSavedFlags);
+#else
+# if RTLNX_VER_MIN(3,20,0)
+ RTCCUINTREG const uOld = this_cpu_read(cpu_tlbstate.cr4);
+# else
+ RTCCUINTREG const uOld = ASMGetCR4();
+# endif
+ RTCCUINTREG const uNew = (uOld & fAndMask) | fOrMask;
+ if (uNew != uOld)
+ {
+# if RTLNX_VER_MIN(3,20,0)
+ this_cpu_write(cpu_tlbstate.cr4, uNew);
+ __write_cr4(uNew);
+# else
+ ASMSetCR4(uNew);
+# endif
+ }
+#endif
+ return uOld;
+}
+
+
+void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
+{
+ NOREF(pDevExt);
+ NOREF(pSession);
+}
+
+
+void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
+{
+ NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
+}
+
+
+void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
+{
+ NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
+}
+
+
+/**
+ * Initializes any OS specific object creator fields.
+ */
+void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+}
+
+
+/**
+ * Checks if the session can access the object.
+ *
+ * @returns true if a decision has been made.
+ * @returns false if the default access policy should be applied.
+ *
+ * @param pObj The object in question.
+ * @param pSession The session wanting to access the object.
+ * @param pszObjName The object name, can be NULL.
+ * @param prc Where to store the result when returning true.
+ */
+bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
+{
+ NOREF(pObj);
+ NOREF(pSession);
+ NOREF(pszObjName);
+ NOREF(prc);
+ return false;
+}
+
+
+bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
+{
+ return force_async_tsc != 0;
+}
+
+
+bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
+{
+ return true;
+}
+
+
+bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
+{
+ return false;
+}
+
+
+int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
+{
+ NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
+ const uint8_t *pbImageBits, const char *pszSymbol)
+{
+ NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits); NOREF(pszSymbol);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
+{
+ NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
+ return VERR_NOT_SUPPORTED;
+}
+
+
+void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
+{
+ NOREF(pDevExt); NOREF(pImage);
+}
+
+
+/** @def VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
+ * A very crude hack for debugging using perf and dtrace.
+ *
+ * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
+ * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
+ * DO ABSOLUTELY NOT ENABLE IN PRODUCTION BUILDS! DEVELOPMENT ONLY!!
+ *
+ */
+#if 0 || defined(DOXYGEN_RUNNING)
+# define VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
+#endif
+
+#if defined(VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS) && defined(CONFIG_MODULES_TREE_LOOKUP)
+/** Whether g_pfnModTreeInsert and g_pfnModTreeRemove have been initialized.
+ * @remarks can still be NULL after init. */
+static volatile bool g_fLookedForModTreeFunctions = false;
+static void (*g_pfnModTreeInsert)(struct mod_tree_node *) = NULL; /**< __mod_tree_insert */
+static void (*g_pfnModTreeRemove)(struct mod_tree_node *) = NULL; /**< __mod_tree_remove */
+#endif
+
+
+void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
+{
+#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
+ /*
+ * This trick stops working with 4.2 when CONFIG_MODULES_TREE_LOOKUP is
+ * defined. The module lookups are done via a tree structure and we
+ * cannot get at the root of it. :-(
+ */
+# ifdef CONFIG_KALLSYMS
+ size_t const cchName = strlen(pImage->szName);
+# endif
+ struct module *pMyMod, *pSelfMod, *pTestMod, *pTestModByName;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ pImage->pLnxModHack = NULL;
+
+# ifdef CONFIG_MODULES_TREE_LOOKUP
+ /*
+ * This is pretty naive, but works for 4.2 on arch linux. I don't think we
+ * can count on finding __mod_tree_remove in all kernel builds as it's not
+ * marked noinline like __mod_tree_insert.
+ */
+ if (!g_fLookedForModTreeFunctions)
+ {
+ unsigned long ulInsert = kallsyms_lookup_name("__mod_tree_insert");
+ unsigned long ulRemove = kallsyms_lookup_name("__mod_tree_remove");
+ if (!ulInsert || !ulRemove)
+ {
+ g_fLookedForModTreeFunctions = true;
+ printk(KERN_ERR "vboxdrv: failed to locate __mod_tree_insert and __mod_tree_remove.\n");
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return;
+ }
+ *(unsigned long *)&g_pfnModTreeInsert = ulInsert;
+ *(unsigned long *)&g_pfnModTreeRemove = ulRemove;
+ ASMCompilerBarrier();
+ g_fLookedForModTreeFunctions = true;
+ }
+ else if (!g_pfnModTreeInsert || !g_pfnModTreeRemove)
+ return;
+#endif
+
+ /*
+ * Make sure we've found our own module, otherwise we cannot access the linked list.
+ */
+ mutex_lock(&module_mutex);
+ pSelfMod = find_module("vboxdrv");
+ mutex_unlock(&module_mutex);
+ if (!pSelfMod)
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return;
+ }
+
+ /*
+ * Cook up a module structure for the image.
+ * We allocate symbol and string tables in the allocation and the module to keep things simple.
+ */
+# ifdef CONFIG_KALLSYMS
+ pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod)
+ + sizeof(Elf_Sym) * 3
+ + 1 + cchName * 2 + sizeof("_start") + sizeof("_end") + 4 );
+# else
+ pMyMod = (struct module *)RTMemAllocZ(sizeof(*pMyMod));
+# endif
+ if (pMyMod)
+ {
+ int rc = VINF_SUCCESS;
+# ifdef CONFIG_KALLSYMS
+ Elf_Sym *paSymbols = (Elf_Sym *)(pMyMod + 1);
+ char *pchStrTab = (char *)(paSymbols + 3);
+# endif
+
+ pMyMod->state = MODULE_STATE_LIVE;
+ INIT_LIST_HEAD(&pMyMod->list); /* just in case */
+
+ /* Perf only matches up files with a .ko extension (maybe .ko.gz),
+ so in order for this crap to work smoothly, we append .ko to the
+ module name and require the user to create symbolic links in
+ /lib/modules/`uname -r`:
+ for i in VMMR0.r0 VBoxDDR0.r0 VBoxDD2R0.r0; do
+ sudo ln -s /mnt/scratch/vbox/svn/trunk/out/linux.amd64/debug/bin/$i /lib/modules/`uname -r`/$i.ko;
+ done */
+ RTStrPrintf(pMyMod->name, sizeof(pMyMod->name), "%s", pImage->szName);
+
+ /* sysfs bits. */
+ INIT_LIST_HEAD(&pMyMod->mkobj.kobj.entry); /* rest of kobj is already zeroed, hopefully never accessed... */
+ pMyMod->mkobj.mod = pMyMod;
+ pMyMod->mkobj.drivers_dir = NULL;
+ pMyMod->mkobj.mp = NULL;
+ pMyMod->mkobj.kobj_completion = NULL;
+
+ pMyMod->modinfo_attrs = NULL; /* hopefully not accessed after setup. */
+ pMyMod->holders_dir = NULL; /* hopefully not accessed. */
+ pMyMod->version = "N/A";
+ pMyMod->srcversion = "N/A";
+
+ /* We export no symbols. */
+ pMyMod->num_syms = 0;
+ pMyMod->syms = NULL;
+ pMyMod->crcs = NULL;
+
+ pMyMod->num_gpl_syms = 0;
+ pMyMod->gpl_syms = NULL;
+ pMyMod->gpl_crcs = NULL;
+
+ pMyMod->num_gpl_future_syms = 0;
+ pMyMod->gpl_future_syms = NULL;
+ pMyMod->gpl_future_crcs = NULL;
+
+# if CONFIG_UNUSED_SYMBOLS
+ pMyMod->num_unused_syms = 0;
+ pMyMod->unused_syms = NULL;
+ pMyMod->unused_crcs = NULL;
+
+ pMyMod->num_unused_gpl_syms = 0;
+ pMyMod->unused_gpl_syms = NULL;
+ pMyMod->unused_gpl_crcs = NULL;
+# endif
+ /* No kernel parameters either. */
+ pMyMod->kp = NULL;
+ pMyMod->num_kp = 0;
+
+# ifdef CONFIG_MODULE_SIG
+ /* Pretend ok signature. */
+ pMyMod->sig_ok = true;
+# endif
+ /* No exception table. */
+ pMyMod->num_exentries = 0;
+ pMyMod->extable = NULL;
+
+ /* No init function */
+ pMyMod->init = NULL;
+ pMyMod->module_init = NULL;
+ pMyMod->init_size = 0;
+ pMyMod->init_ro_size = 0;
+ pMyMod->init_text_size = 0;
+
+ /* The module address and size. It's all text. */
+ pMyMod->module_core = pImage->pvImage;
+ pMyMod->core_size = pImage->cbImageBits;
+ pMyMod->core_text_size = pImage->cbImageBits;
+ pMyMod->core_ro_size = pImage->cbImageBits;
+
+#ifdef CONFIG_MODULES_TREE_LOOKUP
+ /* Fill in the self pointers for the tree nodes. */
+ pMyMod->mtn_core.mod = pMyMod;
+ pMyMod->mtn_init.mod = pMyMod;
+#endif
+ /* They invented the tained bit for us, didn't they? */
+ pMyMod->taints = 1;
+
+# ifdef CONFIG_GENERIC_BUGS
+ /* No BUGs in our modules. */
+ pMyMod->num_bugs = 0;
+ INIT_LIST_HEAD(&pMyMod->bug_list);
+ pMyMod->bug_table = NULL;
+# endif
+
+# ifdef CONFIG_KALLSYMS
+ /* The core stuff is documented as only used when loading. So just zero them. */
+ pMyMod->core_num_syms = 0;
+ pMyMod->core_symtab = NULL;
+ pMyMod->core_strtab = NULL;
+
+ /* Construct a symbol table with start and end symbols.
+ Note! We don't have our own symbol table at this point, image bit
+ are not uploaded yet! */
+ pMyMod->num_symtab = 3;
+ pMyMod->symtab = paSymbols;
+ pMyMod->strtab = pchStrTab;
+ RT_ZERO(paSymbols[0]);
+ pchStrTab[0] = '\0';
+ paSymbols[1].st_name = 1;
+ paSymbols[2].st_name = 2 + RTStrPrintf(&pchStrTab[paSymbols[1].st_name], cchName + sizeof("_start"),
+ "%s_start", pImage->szName);
+ RTStrPrintf(&pchStrTab[paSymbols[2].st_name], cchName + sizeof("_end"), "%s_end", pImage->szName);
+ paSymbols[1].st_info = 't';
+ paSymbols[2].st_info = 'b';
+ paSymbols[1].st_other = 0;
+ paSymbols[2].st_other = 0;
+ paSymbols[1].st_shndx = 0;
+ paSymbols[2].st_shndx = 0;
+ paSymbols[1].st_value = (uintptr_t)pImage->pvImage;
+ paSymbols[2].st_value = (uintptr_t)pImage->pvImage + pImage->cbImageBits - 1;
+ paSymbols[1].st_size = pImage->cbImageBits - 1;
+ paSymbols[2].st_size = 1;
+# endif
+ /* No arguments, but seems its always non-NULL so put empty string there. */
+ pMyMod->args = "";
+
+# ifdef CONFIG_SMP
+ /* No per CPU data. */
+ pMyMod->percpu = NULL;
+ pMyMod->percpu_size = 0;
+# endif
+# ifdef CONFIG_TRACEPOINTS
+ /* No tracepoints we like to share. */
+ pMyMod->num_tracepoints = 0;
+ pMyMod->tracepoints_ptrs = NULL;
+#endif
+# ifdef HAVE_JUMP_LABEL
+ /* No jump lable stuff either. */
+ pMyMod->jump_entries = NULL;
+ pMyMod->num_jump_entries = 0;
+# endif
+# ifdef CONFIG_TRACING
+ pMyMod->num_trace_bprintk_fmt = 0;
+ pMyMod->trace_bprintk_fmt_start = NULL;
+# endif
+# ifdef CONFIG_EVENT_TRACING
+ pMyMod->trace_events = NULL;
+ pMyMod->num_trace_events = 0;
+# endif
+# ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ pMyMod->num_ftrace_callsites = 0;
+ pMyMod->ftrace_callsites = NULL;
+# endif
+# ifdef CONFIG_MODULE_UNLOAD
+ /* Dependency lists, not worth sharing */
+ INIT_LIST_HEAD(&pMyMod->source_list);
+ INIT_LIST_HEAD(&pMyMod->target_list);
+
+ /* Nobody waiting and no exit function. */
+# if RTLNX_VER_MAX(3,13,0)
+ pMyMod->waiter = NULL;
+# endif
+ pMyMod->exit = NULL;
+
+ /* References, very important as we must not allow the module
+ to be unloaded using rmmod. */
+# if RTLNX_VER_MIN(3,19,0)
+ atomic_set(&pMyMod->refcnt, 42);
+# else
+ pMyMod->refptr = alloc_percpu(struct module_ref);
+ if (pMyMod->refptr)
+ {
+ int iCpu;
+ for_each_possible_cpu(iCpu)
+ {
+ per_cpu_ptr(pMyMod->refptr, iCpu)->decs = 0;
+ per_cpu_ptr(pMyMod->refptr, iCpu)->incs = 1;
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+# endif
+# endif
+# ifdef CONFIG_CONSTRUCTORS
+ /* No constructors. */
+ pMyMod->ctors = NULL;
+ pMyMod->num_ctors = 0;
+# endif
+ if (RT_SUCCESS(rc))
+ {
+ bool fIsModText;
+
+ /*
+ * Add the module to the list.
+ */
+ mutex_lock(&module_mutex);
+ list_add_rcu(&pMyMod->list, &pSelfMod->list);
+ pImage->pLnxModHack = pMyMod;
+# ifdef CONFIG_MODULES_TREE_LOOKUP
+ g_pfnModTreeInsert(&pMyMod->mtn_core); /* __mod_tree_insert */
+# endif
+ mutex_unlock(&module_mutex);
+
+ /*
+ * Test it.
+ */
+ mutex_lock(&module_mutex);
+ pTestModByName = find_module(pMyMod->name);
+ pTestMod = __module_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 4);
+ fIsModText = __module_text_address((uintptr_t)pImage->pvImage + pImage->cbImageBits / 2);
+ mutex_unlock(&module_mutex);
+ if ( pTestMod == pMyMod
+ && pTestModByName == pMyMod
+ && fIsModText)
+ printk(KERN_ERR "vboxdrv: fake module works for '%s' (%#lx to %#lx)\n",
+ pMyMod->name, (unsigned long)paSymbols[1].st_value, (unsigned long)paSymbols[2].st_value);
+ else
+ printk(KERN_ERR "vboxdrv: failed to find fake module (pTestMod=%p, pTestModByName=%p, pMyMod=%p, fIsModText=%d)\n",
+ pTestMod, pTestModByName, pMyMod, fIsModText);
+ }
+ else
+ RTMemFree(pMyMod);
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+#else
+ pImage->pLnxModHack = NULL;
+#endif
+ NOREF(pDevExt); NOREF(pImage);
+}
+
+
+void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
+{
+#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS /* Not for production use!! Debugging only! */
+ struct module *pMyMod = pImage->pLnxModHack;
+ pImage->pLnxModHack = NULL;
+ if (pMyMod)
+ {
+ /*
+ * Remove the fake module list entry and free it.
+ */
+ IPRT_LINUX_SAVE_EFL_AC();
+ mutex_lock(&module_mutex);
+ list_del_rcu(&pMyMod->list);
+# ifdef CONFIG_MODULES_TREE_LOOKUP
+ g_pfnModTreeRemove(&pMyMod->mtn_core);
+# endif
+ synchronize_sched();
+ mutex_unlock(&module_mutex);
+
+# if RTLNX_VER_MAX(3,19,0)
+ free_percpu(pMyMod->refptr);
+# endif
+ RTMemFree(pMyMod);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ }
+
+#else
+ Assert(pImage->pLnxModHack == NULL);
+#endif
+ NOREF(pDevExt); NOREF(pImage);
+}
+
+
+int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage,
+ const char *pszSymbol, size_t cchSymbol, void **ppvSymbol)
+{
+#ifdef VBOX_WITH_NON_PROD_HACK_FOR_PERF_STACKS
+# error "implement me!"
+#endif
+ RT_NOREF(pDevExt, pImage, pszSymbol, cchSymbol, ppvSymbol);
+ return VERR_WRONG_ORDER;
+}
+
+
+void VBOXCALL supdrvOSLdrRetainWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
+{
+ struct module *pLnxMod = (struct module *)pImage->pvWrappedNative;
+ Assert(!pImage->fLnxWrapperRef);
+ AssertReturnVoid(pLnxMod);
+ pImage->fLnxWrapperRef = try_module_get(pLnxMod);
+ RT_NOREF(pDevExt);
+}
+
+
+void VBOXCALL supdrvOSLdrReleaseWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
+{
+ if (pImage->fLnxWrapperRef)
+ {
+ struct module *pLnxMod = (struct module *)pImage->pvWrappedNative;
+ pImage->fLnxWrapperRef = false;
+ module_put(pLnxMod);
+ }
+ RT_NOREF(pDevExt);
+}
+
+
+#ifdef SUPDRV_WITH_MSR_PROBER
+
+int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
+{
+# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
+ uint32_t u32Low, u32High;
+ int rc;
+
+ IPRT_LINUX_SAVE_EFL_AC();
+ if (idCpu == NIL_RTCPUID)
+ rc = rdmsr_safe(uMsr, &u32Low, &u32High);
+ else if (RTMpIsCpuOnline(idCpu))
+ rc = rdmsr_safe_on_cpu(idCpu, uMsr, &u32Low, &u32High);
+ else
+ return VERR_CPU_OFFLINE;
+ IPRT_LINUX_RESTORE_EFL_AC();
+ if (rc == 0)
+ {
+ *puValue = RT_MAKE_U64(u32Low, u32High);
+ return VINF_SUCCESS;
+ }
+ return VERR_ACCESS_DENIED;
+# else
+ return VERR_NOT_SUPPORTED;
+# endif
+}
+
+
+int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
+{
+# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
+ int rc;
+
+ IPRT_LINUX_SAVE_EFL_AC();
+ if (idCpu == NIL_RTCPUID)
+ rc = wrmsr_safe(uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
+ else if (RTMpIsCpuOnline(idCpu))
+ rc = wrmsr_safe_on_cpu(idCpu, uMsr, RT_LODWORD(uValue), RT_HIDWORD(uValue));
+ else
+ return VERR_CPU_OFFLINE;
+ IPRT_LINUX_RESTORE_EFL_AC();
+
+ if (rc == 0)
+ return VINF_SUCCESS;
+ return VERR_ACCESS_DENIED;
+# else
+ return VERR_NOT_SUPPORTED;
+# endif
+}
+
+# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
+/**
+ * Worker for supdrvOSMsrProberModify.
+ */
+static DECLCALLBACK(void) supdrvLnxMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
+{
+ PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
+ register uint32_t uMsr = pReq->u.In.uMsr;
+ bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
+ uint64_t uBefore;
+ uint64_t uWritten;
+ uint64_t uAfter;
+ int rcBefore, rcWrite, rcAfter, rcRestore;
+ RTCCUINTREG fOldFlags;
+
+ /* Initialize result variables. */
+ uBefore = uWritten = uAfter = 0;
+ rcWrite = rcAfter = rcRestore = -EIO;
+
+ /*
+ * Do the job.
+ */
+ fOldFlags = ASMIntDisableFlags();
+ ASMCompilerBarrier(); /* paranoia */
+ if (!fFaster)
+ ASMWriteBackAndInvalidateCaches();
+
+ rcBefore = rdmsrl_safe(uMsr, &uBefore);
+ if (rcBefore >= 0)
+ {
+ register uint64_t uRestore = uBefore;
+ uWritten = uRestore;
+ uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
+ uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
+
+ rcWrite = wrmsr_safe(uMsr, RT_LODWORD(uWritten), RT_HIDWORD(uWritten));
+ rcAfter = rdmsrl_safe(uMsr, &uAfter);
+ rcRestore = wrmsr_safe(uMsr, RT_LODWORD(uRestore), RT_HIDWORD(uRestore));
+
+ if (!fFaster)
+ {
+ ASMWriteBackAndInvalidateCaches();
+ ASMReloadCR3();
+ ASMNopPause();
+ }
+ }
+
+ ASMCompilerBarrier(); /* paranoia */
+ ASMSetFlags(fOldFlags);
+
+ /*
+ * Write out the results.
+ */
+ pReq->u.Out.uResults.Modify.uBefore = uBefore;
+ pReq->u.Out.uResults.Modify.uWritten = uWritten;
+ pReq->u.Out.uResults.Modify.uAfter = uAfter;
+ pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
+ pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
+ pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
+ pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
+ RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
+}
+# endif
+
+
+int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
+{
+# ifdef SUPDRV_LINUX_HAS_SAFE_MSR_API
+ if (idCpu == NIL_RTCPUID)
+ {
+ supdrvLnxMsrProberModifyOnCpu(idCpu, pReq, NULL);
+ return VINF_SUCCESS;
+ }
+ return RTMpOnSpecific(idCpu, supdrvLnxMsrProberModifyOnCpu, pReq, NULL);
+# else
+ return VERR_NOT_SUPPORTED;
+# endif
+}
+
+#endif /* SUPDRV_WITH_MSR_PROBER */
+
+
+/**
+ * Converts a supdrv error code to an linux error code.
+ *
+ * @returns corresponding linux error code.
+ * @param rc IPRT status code.
+ */
+static int VBoxDrvLinuxErr2LinuxErr(int rc)
+{
+ switch (rc)
+ {
+ case VINF_SUCCESS: return 0;
+ case VERR_GENERAL_FAILURE: return -EACCES;
+ case VERR_INVALID_PARAMETER: return -EINVAL;
+ case VERR_INVALID_MAGIC: return -EILSEQ;
+ case VERR_INVALID_HANDLE: return -ENXIO;
+ case VERR_INVALID_POINTER: return -EFAULT;
+ case VERR_LOCK_FAILED: return -ENOLCK;
+ case VERR_ALREADY_LOADED: return -EEXIST;
+ case VERR_PERMISSION_DENIED: return -EPERM;
+ case VERR_VERSION_MISMATCH: return -ENOSYS;
+ case VERR_IDT_FAILED: return -1000;
+ }
+
+ return -EPERM;
+}
+
+
+SUPR0DECL(int) SUPR0HCPhysToVirt(RTHCPHYS HCPhys, void **ppv)
+{
+ AssertReturn(!(HCPhys & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
+ AssertReturn(HCPhys != NIL_RTHCPHYS, VERR_INVALID_POINTER);
+ /* Would've like to use valid_phys_addr_range for this test, but it isn't exported. */
+ AssertReturn((HCPhys | PAGE_OFFSET_MASK) < __pa(high_memory), VERR_INVALID_POINTER);
+ *ppv = phys_to_virt(HCPhys);
+ return VINF_SUCCESS;
+}
+SUPR0_EXPORT_SYMBOL(SUPR0HCPhysToVirt);
+
+
+RTDECL(int) SUPR0PrintfV(const char *pszFormat, va_list va)
+{
+ char szMsg[512];
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
+ szMsg[sizeof(szMsg) - 1] = '\0';
+
+ printk("%s", szMsg);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return 0;
+}
+SUPR0_EXPORT_SYMBOL(SUPR0PrintfV);
+
+
+SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
+{
+ uint32_t fFlags = 0;
+ /* Note! bird 2023-10-20: Apparently, with CONFIG_PAX_KERNEXEC these days,
+ not only is the regular GDT read-only, but the one returned by
+ get_current_gdt_rw() is also read-only despite the name.
+
+ We don't know exactly when this started, or if it was always like
+ this, but getting hold of the relevant patches isn't all that
+ straight forward any longer it seems (which is weird for linux
+ patches), so, we've just enabled slow-mode for all PAX_KERNEXEC
+ kernels regardless of kernel version.
+
+ Looking at grsecurity patch for 4.9.9, it looks like the writable
+ GDT stuff never worked with PaX/grsec.
+ */
+#ifdef CONFIG_PAX_KERNEXEC
+ fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY;
+#elif RTLNX_VER_MIN(4,12,0)
+ fFlags |= SUPKERNELFEATURES_GDT_NEED_WRITABLE;
+#endif
+
+#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
+ fFlags |= SUPKERNELFEATURES_SMAP;
+#elif defined(CONFIG_X86_SMAP)
+ if (ASMGetCR4() & X86_CR4_SMAP)
+ fFlags |= SUPKERNELFEATURES_SMAP;
+#endif
+ return fFlags;
+}
+SUPR0_EXPORT_SYMBOL(SUPR0GetKernelFeatures);
+
+
+SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook)
+{
+ RT_NOREF(fCtxHook);
+#if RTLNX_VER_MIN(4,19,0) /* Going back to 4.19.0 for better coverage, we
+ probably only need 5.17.7+ in the end. */
+ /*
+ * HACK ALERT!
+ *
+ * We'd like to use the old __kernel_fpu_begin() API which was removed in
+ * early 2019, because we typically run with preemption enabled and have an
+ * preemption hook installed which will call kernel_fpu_end() in case we're
+ * scheduled out after getting in here. The preemption hook is almost
+ * useless if we run with preemption disabled.
+ *
+ * For the case where the kernel does not have preemption hooks, we get here
+ * with preemption already disabled and one more count doesn't make any
+ * difference.
+ *
+ * So, after the kernel_fpu_begin() call we undo the implicit preempt_disable()
+ * call it does, so the preemption hook can do its work and the VBox user has
+ * a more responsive system.
+ *
+ * See @bugref{10209#c12} and onwards for more details.
+ */
+ Assert(fCtxHook || !RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+ kernel_fpu_begin();
+# if 0 /* Always do it for now for better test coverage. */
+ if (fCtxHook)
+# endif
+ preempt_enable();
+ return false; /** @todo Not sure if we have license to use any extended state, or
+ * if we're limited to the SSE & x87 FPU. If it's the former,
+ * we should return @a true and the caller can skip
+ * saving+restoring the host state and save some time. */
+#else
+ return false;
+#endif
+}
+SUPR0_EXPORT_SYMBOL(SUPR0FpuBegin);
+
+
+SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook)
+{
+ RT_NOREF(fCtxHook);
+#if RTLNX_VER_MIN(4,19,0)
+ /* HACK ALERT! See SUPR0FpuBegin for an explanation of this. */
+ Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+# if 0 /* Always do it for now for better test coverage. */
+ if (fCtxHook)
+# endif
+ preempt_disable();
+ kernel_fpu_end();
+#endif
+}
+SUPR0_EXPORT_SYMBOL(SUPR0FpuEnd);
+
+
+int VBOXCALL supdrvOSGetCurrentGdtRw(RTHCUINTPTR *pGdtRw)
+{
+#if RTLNX_VER_MIN(4,12,0) && !defined(CONFIG_PAX_KERNEXEC)
+ *pGdtRw = (RTHCUINTPTR)get_current_gdt_rw();
+ return VINF_SUCCESS;
+#else
+ return VERR_NOT_IMPLEMENTED;
+#endif
+}
+
+
+module_init(VBoxDrvLinuxInit);
+module_exit(VBoxDrvLinuxUnload);
+
+MODULE_AUTHOR(VBOX_VENDOR);
+MODULE_DESCRIPTION(VBOX_PRODUCT " Support Driver");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV) " (" RT_XSTR(SUPDRV_IOC_VERSION) ")");
+#endif
+
+module_param(force_async_tsc, int, 0444);
+MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c
new file mode 100644
index 00000000..4bb02712
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.mod.c
@@ -0,0 +1,97 @@
+/* $Id: SUPDrv-linux.mod.c $ */
+/** @file
+ * VBoxDrv - The VirtualBox Support Driver - Autogenerated Linux code.
+ *
+ * This is checked in to assist syntax checking the module.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include "SUPDrvInternal.h" /* for KBUILD_STR */
+#include "the-linux-kernel.h"
+#include <linux/vermagic.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+#undef unix
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = __stringify(KBUILD_MODNAME),
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+};
+
+static const struct modversion_info ____versions[]
+__attribute_used__
+__attribute__((section("__versions"))) = {
+ { 0, "cleanup_module" },
+ { 0, "init_module" },
+ { 0, "struct_module" },
+ { 0, "strpbrk" },
+ { 0, "__kmalloc" },
+ { 0, "mem_map" },
+ { 0, "vmalloc" },
+ { 0, "malloc_sizes" },
+ { 0, "vfree" },
+ { 0, "change_page_attr" },
+ { 0, "__might_sleep" },
+ { 0, "remap_page_range" },
+ { 0, "__alloc_pages" },
+ { 0, "printk" },
+ { 0, "__PAGE_KERNEL" },
+ { 0, "rwsem_wake" },
+ { 0, "copy_to_user" },
+ { 0, "preempt_schedule" },
+ { 0, "contig_page_data" },
+ { 0, "do_mmap_pgoff" },
+ { 0, "find_vma" },
+ { 0, "kmem_cache_alloc" },
+ { 0, "__free_pages" },
+ { 0, "do_munmap" },
+ { 0, "get_user_pages" },
+ { 0, "vsnprintf" },
+ { 0, "kfree" },
+ { 0, "memcpy" },
+ { 0, "put_page" },
+ { 0, "__up_wakeup" },
+ { 0, "__down_failed" },
+ { 0, "copy_from_user" },
+ { 0, "rwsem_down_read_failed" },
+};
+
+static const char __module_depends[]
+__attribute_used__
+__attribute__((section(".modinfo"))) =
+"depends=";
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
new file mode 100644
index 00000000..5bdcda63
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
@@ -0,0 +1,388 @@
+/* $Id: SUPLib-linux.cpp $ */
+/** @file
+ * VirtualBox Support Library - GNU/Linux specific parts.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SUP
+#ifdef IN_SUP_HARDENED_R3
+# undef DEBUG /* Warning: disables RT_STRICT */
+# undef RT_STRICT
+# ifndef LOG_DISABLED
+# define LOG_DISABLED
+# endif
+# define RTLOG_REL_DISABLED
+# include <iprt/log.h>
+#endif
+
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include <VBox/log.h>
+#include <VBox/sup.h>
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <VBox/types.h>
+#include <iprt/string.h>
+#include <iprt/system.h>
+#include <VBox/err.h>
+#include <VBox/param.h>
+#include "../SUPLibInternal.h"
+#include "../SUPDrvIOC.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** System device name. */
+#define DEVICE_NAME_SYS "/dev/vboxdrv"
+/** User device name. */
+#define DEVICE_NAME_USR "/dev/vboxdrvu"
+
+/* define MADV_DONTFORK if it's missing from the system headers. */
+#ifndef MADV_DONTFORK
+# define MADV_DONTFORK 10
+#endif
+
+
+
+DECLHIDDEN(int) suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, uint32_t fFlags, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
+{
+ RT_NOREF2(penmWhat, pErrInfo);
+
+ /*
+ * Nothing to do if pre-inited.
+ */
+ if (fPreInited)
+ return VINF_SUCCESS;
+ Assert(pThis->hDevice == (intptr_t)NIL_RTFILE);
+
+ /*
+ * Check if madvise works.
+ */
+ void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (pv == MAP_FAILED)
+ return VERR_NO_MEMORY;
+ pThis->fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
+ munmap(pv, PAGE_SIZE);
+
+ /*
+ * Driverless?
+ */
+ if (fFlags & SUPR3INIT_F_DRIVERLESS)
+ {
+ pThis->fDriverless = true;
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Try open the device.
+ */
+ const char *pszDeviceNm = fFlags & SUPR3INIT_F_UNRESTRICTED ? DEVICE_NAME_SYS : DEVICE_NAME_USR;
+ int hDevice = open(pszDeviceNm, O_RDWR, 0);
+ if (hDevice < 0)
+ {
+ /*
+ * Try load the device.
+ */
+ hDevice = open(pszDeviceNm, O_RDWR, 0);
+ if (hDevice < 0)
+ {
+ int rc;
+ switch (errno)
+ {
+ case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
+ case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
+ case EPERM:
+ case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
+ case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
+ default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
+ }
+ if (fFlags & SUPR3INIT_F_DRIVERLESS_MASK)
+ {
+ LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc - Switching to driverless mode.\n", pszDeviceNm, errno, rc));
+ pThis->fDriverless = true;
+ return VINF_SUCCESS;
+ }
+ LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", pszDeviceNm, errno, rc));
+ return rc;
+ }
+ }
+
+ /*
+ * Mark the file handle close on exec.
+ */
+ if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ close(hDevice);
+#ifdef IN_SUP_HARDENED_R3
+ return VERR_INTERNAL_ERROR;
+#else
+ return RTErrConvertFromErrno(errno);
+#endif
+ }
+
+ /*
+ * We're done.
+ */
+ pThis->hDevice = hDevice;
+ pThis->fUnrestricted = RT_BOOL(fFlags & SUPR3INIT_F_UNRESTRICTED);
+ return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) suplibOsTerm(PSUPLIBDATA pThis)
+{
+ /*
+ * Close the device if it's actually open.
+ */
+ if (pThis->hDevice != (intptr_t)NIL_RTFILE)
+ {
+ if (close(pThis->hDevice))
+ AssertFailed();
+ pThis->hDevice = (intptr_t)NIL_RTFILE;
+ }
+
+ return 0;
+}
+
+
+#ifndef IN_SUP_HARDENED_R3
+
+DECLHIDDEN(int) suplibOsInstall(void)
+{
+ // nothing to do on Linux
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+DECLHIDDEN(int) suplibOsUninstall(void)
+{
+ // nothing to do on Linux
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+DECLHIDDEN(int) suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
+{
+ AssertMsg(pThis->hDevice != (intptr_t)NIL_RTFILE, ("SUPLIB not initiated successfully!\n"));
+ NOREF(cbReq);
+
+ /*
+ * Issue device iocontrol.
+ */
+ if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
+ return VINF_SUCCESS;
+
+ /* This is the reverse operation of the one found in SUPDrv-linux.c */
+ switch (errno)
+ {
+ case EACCES: return VERR_GENERAL_FAILURE;
+ case EINVAL: return VERR_INVALID_PARAMETER;
+ case EILSEQ: return VERR_INVALID_MAGIC;
+ case ENXIO: return VERR_INVALID_HANDLE;
+ case EFAULT: return VERR_INVALID_POINTER;
+ case ENOLCK: return VERR_LOCK_FAILED;
+ case EEXIST: return VERR_ALREADY_LOADED;
+ case EPERM: return VERR_PERMISSION_DENIED;
+ case ENOSYS: return VERR_VERSION_MISMATCH;
+ case 1000: return VERR_IDT_FAILED;
+ }
+
+ return RTErrConvertFromErrno(errno);
+}
+
+
+DECLHIDDEN(int) suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
+{
+ int rc = ioctl(pThis->hDevice, uFunction, idCpu);
+ if (rc == -1)
+ rc = -errno;
+ return rc;
+}
+
+
+DECLHIDDEN(int) suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, uint32_t fFlags, void **ppvPages)
+{
+ /*
+ * If large pages are requested, try use the MAP_HUGETBL flags. This takes
+ * pages from the reserved huge page pool (see sysctl vm.nr_hugepages) and
+ * is typically not configured. Also, when the pool is exhausted we get
+ * ENOMEM back at us. So, when it fails try again w/o MAP_HUGETLB.
+ */
+ int fMmap = MAP_PRIVATE | MAP_ANONYMOUS;
+#ifdef MAP_HUGETLB
+ if ((fFlags & SUP_PAGE_ALLOC_F_LARGE_PAGES) && !(cPages & 511))
+ fMmap |= MAP_HUGETLB;
+#endif
+
+ size_t cbMmap = cPages << PAGE_SHIFT;
+ if ( !pThis->fSysMadviseWorks
+ && (fFlags & (SUP_PAGE_ALLOC_F_FOR_LOCKING | SUP_PAGE_ALLOC_F_LARGE_PAGES)) == SUP_PAGE_ALLOC_F_FOR_LOCKING)
+ cbMmap += PAGE_SIZE * 2;
+
+ uint8_t *pbPages = (uint8_t *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, fMmap, -1, 0);
+#ifdef MAP_HUGETLB
+ if (pbPages == MAP_FAILED && (fMmap & MAP_HUGETLB))
+ {
+ /* Try again without MAP_HUGETLB if mmap fails: */
+ fMmap &= ~MAP_HUGETLB;
+ if (!pThis->fSysMadviseWorks && (fFlags & SUP_PAGE_ALLOC_F_FOR_LOCKING))
+ cbMmap = (cPages + 2) << PAGE_SHIFT;
+ pbPages = (uint8_t *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, fMmap, -1, 0);
+ }
+#endif
+ if (pbPages != MAP_FAILED)
+ {
+ if ( !(fFlags & SUP_PAGE_ALLOC_F_FOR_LOCKING)
+ || pThis->fSysMadviseWorks
+#ifdef MAP_HUGETLB
+ || (fMmap & MAP_HUGETLB)
+#endif
+ )
+ {
+ /*
+ * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
+ * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
+ * kernel seems to split bigger VMAs and that is all that we want -- later we set the
+ * VM_DONTCOPY attribute in supdrvOSLockMemOne().
+ */
+ if ( madvise(pbPages, cbMmap, MADV_DONTFORK)
+#ifdef MAP_HUGETLB
+ && !(fMmap & MAP_HUGETLB)
+#endif
+ )
+ LogRel(("SUPLib: madvise %p-%p failed\n", pbPages, cbMmap));
+
+#ifdef MADV_HUGEPAGE
+ /*
+ * Try enable transparent huge pages for the allocation if desired
+ * and we weren't able to use MAP_HUGETBL above.
+ * Note! KVM doesn't seem to benefit much from this.
+ */
+ if ( !(fMmap & MAP_HUGETLB)
+ && (fFlags & SUP_PAGE_ALLOC_F_LARGE_PAGES)
+ && !(cPages & 511)) /** @todo PORTME: x86 assumption */
+ madvise(pbPages, cbMmap, MADV_HUGEPAGE);
+#endif
+ }
+ else
+ {
+ /*
+ * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
+ * mmapped region by two unmapped pages to guarantee that there is exactly one VM
+ * area struct of the very same size as the mmap area.
+ */
+ mprotect(pbPages, PAGE_SIZE, PROT_NONE);
+ mprotect(pbPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
+ pbPages += PAGE_SHIFT;
+ }
+
+ /** @todo Dunno why we do this, really. It's a waste of time. Maybe it was
+ * to try make sure the pages were allocated or something before we locked them,
+ * so I qualified it with SUP_PAGE_ALLOC_F_FOR_LOCKING (unused) for now... */
+ if (fFlags & SUP_PAGE_ALLOC_F_FOR_LOCKING)
+ memset(pbPages, 0, cPages << PAGE_SHIFT);
+
+ *ppvPages = pbPages;
+ return VINF_SUCCESS;
+ }
+ return VERR_NO_MEMORY;
+}
+
+
+DECLHIDDEN(int) suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages)
+{
+ NOREF(pThis);
+ munmap(pvPages, cPages << PAGE_SHIFT);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Check if the host kernel supports VT-x or not.
+ *
+ * Older Linux kernels clear the VMXE bit in the CR4 register (function
+ * tlb_flush_all()) leading to a host kernel panic.
+ *
+ * @returns VBox status code (no info).
+ * @param ppszWhy Where to return explanatory message.
+ */
+DECLHIDDEN(int) suplibOsQueryVTxSupported(const char **ppszWhy)
+{
+ char szBuf[256];
+ int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szBuf, sizeof(szBuf));
+ if (RT_SUCCESS(rc))
+ {
+ char *pszNext;
+ uint32_t uA, uB, uC;
+
+ rc = RTStrToUInt32Ex(szBuf, &pszNext, 10, &uA);
+ if ( RT_SUCCESS(rc)
+ && *pszNext == '.')
+ {
+ /*
+ * new version number scheme starting with Linux 3.0
+ */
+ if (uA >= 3)
+ return VINF_SUCCESS;
+ rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uB);
+ if ( RT_SUCCESS(rc)
+ && *pszNext == '.')
+ {
+ rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uC);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t uLinuxVersion = (uA << 16) + (uB << 8) + uC;
+ if (uLinuxVersion >= (2 << 16) + (6 << 8) + 13)
+ return VINF_SUCCESS;
+ }
+ }
+ }
+ }
+
+ *ppszWhy = "Linux 2.6.13 or newer required!";
+ return VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX;
+}
+
+#endif /* !IN_SUP_HARDENED_R3 */
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c b/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c
new file mode 100644
index 00000000..3a13ebc9
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c
@@ -0,0 +1,66 @@
+/* $Id: SUPR0IdcClient-linux.c $ */
+/** @file
+ * VirtualBox Support Driver - IDC Client Lib, Linux Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "../SUPR0IdcClientInternal.h"
+#include <iprt/errcore.h>
+
+
+int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr);
+}
+
+
+int VBOXCALL supR0IdcNativeClose(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQHDR pReq)
+{
+ return supR0IdcNativeCall(pHandle, SUPDRV_IDC_REQ_DISCONNECT, pReq);
+}
+
+
+int VBOXCALL supR0IdcNativeCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, PSUPDRVIDCREQHDR pReq)
+{
+ int rc = SUPDrvLinuxIDC(iReq, pReq);
+ if (RT_SUCCESS(rc))
+ rc = pReq->rc;
+
+ NOREF(pHandle);
+ return rc;
+}
+
diff --git a/src/VBox/HostDrivers/Support/linux/SUPWrapperMod-linux.c b/src/VBox/HostDrivers/Support/linux/SUPWrapperMod-linux.c
new file mode 100644
index 00000000..75ac7606
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/SUPWrapperMod-linux.c
@@ -0,0 +1,211 @@
+/* $Id: SUPWrapperMod-linux.c $ */
+/** @file
+ * Linux .r0 wrapper module template.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define IPRT_WITHOUT_EFLAGS_AC_PRESERVING
+#include "the-linux-kernel.h"
+
+#include "version-generated.h"
+#include "product-generated.h"
+#include "revision-generated.h"
+
+#include <VBox/sup.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** @def WRAPPED_MODULE_FLAGS
+ * SUPLDRWRAPPEDMODULE_F_XXX or 0. Default: 0 */
+#ifndef WRAPPED_MODULE_FLAGS
+# define WRAPPED_MODULE_FLAGS 0
+#endif
+/** @def WRAPPED_MODULE_INIT
+ * The module init function or NULL. Default: ModuleInit */
+#ifndef WRAPPED_MODULE_INIT
+# define WRAPPED_MODULE_INIT ModuleInit
+#endif
+/** @def WRAPPED_MODULE_TERM
+ * The module termination function or NULL. Default: ModuleTerm */
+#ifndef WRAPPED_MODULE_TERM
+# define WRAPPED_MODULE_TERM ModuleTerm
+#endif
+/** @def WRAPPED_MODULE_SRV_REQ_HANDLER
+ * The service request handler function. Default: NULL */
+#ifndef WRAPPED_MODULE_SRV_REQ_HANDLER
+# define WRAPPED_MODULE_SRV_REQ_HANDLER NULL
+#endif
+/** @def WRAPPED_MODULE_VMMR0_ENTRY_FAST
+ * The VMMR0 fast entry point. Default: NULL */
+#ifndef WRAPPED_MODULE_VMMR0_ENTRY_FAST
+# define WRAPPED_MODULE_VMMR0_ENTRY_FAST NULL
+#endif
+/** @def WRAPPED_MODULE_VMMR0_ENTRY_EX
+ * The VMMR0 extended entry point. Default: NULL */
+#ifndef WRAPPED_MODULE_VMMR0_ENTRY_EX
+# define WRAPPED_MODULE_VMMR0_ENTRY_EX NULL
+#endif
+/** @def WRAPPED_MODULE_SRV_REQ_HANDLER
+ * The service request handler function. Default: NULL */
+#ifndef WRAPPED_MODULE_SRV_REQ_HANDLER
+# define WRAPPED_MODULE_SRV_REQ_HANDLER NULL
+#endif
+
+#ifdef DOXYGEN_RUNNING
+/** @def WRAPPED_MODULE_LINUX_EXPORTS
+ * Define to enabled linux exports. (Needed for VMMR0.r0 only at present.) */
+# define WRAPPED_MODULE_LINUX_EXPORTS
+#endif
+#ifdef DOXYGEN_RUNNING
+/** @def WRAPPED_MODULE_LICENSE_PROPRIETARY
+ * Define to select proprietary license instead of GPL. */
+# define WRAPPED_MODULE_LICENSE_PROPRIETARY
+#endif
+#ifdef DOXYGEN_RUNNING
+/** @def WRAPPED_MODULE_SYMBOL_INCLUDE
+ * The include with SYMBOL_ENTRY() invocations for all exported symbols. */
+# define WRAPPED_MODULE_SYMBOL_INCLUDE "iprt/cdefs.h"
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int __init VBoxWrapperModInit(void);
+static void __exit VBoxWrapperModUnload(void);
+
+
+/*
+ * Prototype the symbols:
+ */
+#undef RT_MANGLER
+#define RT_MANGLER(a_Name) a_Name /* No mangling */
+#define SYMBOL_ENTRY(a_Name) extern FNRT a_Name;
+#include WRAPPED_MODULE_SYMBOL_INCLUDE
+#undef SYMBOL_ENTRY
+
+/*
+ * Export the symbols linux style:
+ */
+#ifdef WRAPPED_MODULE_LINUX_EXPORTS
+# define SYMBOL_ENTRY(a_Name) EXPORT_SYMBOL(a_Name);
+# include WRAPPED_MODULE_SYMBOL_INCLUDE
+# undef SYMBOL_ENTRY
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+extern char vboxr0mod_start[]; /**< start of text in the .r0 module. */
+extern char vboxr0mod_end[]; /**< end of bss in the .r0 module. */
+
+/** The symbol table. */
+static SUPLDRWRAPMODSYMBOL const g_aSymbols[] =
+{
+#define SYMBOL_ENTRY(a_Name) { #a_Name, &a_Name },
+#include WRAPPED_MODULE_SYMBOL_INCLUDE
+#undef SYMBOL_ENTRY
+};
+
+/** Wrapped module registration info. */
+static SUPLDRWRAPPEDMODULE const g_WrappedMod =
+{
+ /* .uMagic = */ SUPLDRWRAPPEDMODULE_MAGIC,
+ /* .uVersion = */ SUPLDRWRAPPEDMODULE_VERSION,
+ /* .fFlags = */ WRAPPED_MODULE_FLAGS,
+ /* .pvImageStart = */ &vboxr0mod_start[0],
+ /* .pvImageEnd = */ &vboxr0mod_end[0],
+
+ /* .pfnModuleInit = */ WRAPPED_MODULE_INIT,
+ /* .pfnModuleTerm = */ WRAPPED_MODULE_TERM,
+ /* .pfnVMMR0EntryFast = */ WRAPPED_MODULE_VMMR0_ENTRY_FAST,
+ /* .pfnVMMR0EntryEx = */ WRAPPED_MODULE_VMMR0_ENTRY_EX,
+ /* .pfnSrvReqHandler = */ (PFNSUPR0SERVICEREQHANDLER)WRAPPED_MODULE_SRV_REQ_HANDLER,
+
+ /* .apSymbols = */ g_aSymbols,
+ /* .cSymbols = */ RT_ELEMENTS(g_aSymbols),
+
+ /* .szName = */ WRAPPED_MODULE_NAME,
+ /* .uEndMagic = */ SUPLDRWRAPPEDMODULE_MAGIC,
+};
+
+/** The wrapped module handle. */
+static void *g_hWrappedRegistration = NULL;
+
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init VBoxWrapperModInit(void)
+{
+ /*printk("vboxwrap/" WRAPPED_MODULE_NAME ": VBoxWrapperModInit\n");*/
+ int rc = SUPDrvLinuxLdrRegisterWrappedModule(&g_WrappedMod, KBUILD_MODNAME, &g_hWrappedRegistration);
+ if (rc == 0)
+ return 0;
+ printk("vboxwrap/" WRAPPED_MODULE_NAME ": SUPDrvLinuxRegisterWrappedModule failed: %d\n", rc);
+ return -EINVAL;
+}
+
+
+/**
+ * Unload the module.
+ */
+static void __exit VBoxWrapperModUnload(void)
+{
+ /*printk("vboxwrap/" WRAPPED_MODULE_NAME ": VBoxWrapperModUnload\n");*/
+ SUPDrvLinuxLdrDeregisterWrappedModule(&g_WrappedMod, &g_hWrappedRegistration);
+}
+
+module_init(VBoxWrapperModInit);
+module_exit(VBoxWrapperModUnload);
+
+MODULE_AUTHOR(VBOX_VENDOR);
+MODULE_DESCRIPTION(VBOX_PRODUCT " - " WRAPPED_MODULE_NAME);
+#ifndef WRAPPED_MODULE_LICENSE_PROPRIETARY
+MODULE_LICENSE("GPL");
+#else
+MODULE_LICENSE("Proprietary");
+#endif
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/linux/VBoxR0-wrapped.lds b/src/VBox/HostDrivers/Support/linux/VBoxR0-wrapped.lds
new file mode 100644
index 00000000..f414cfac
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/VBoxR0-wrapped.lds
@@ -0,0 +1,49 @@
+/* $Id: VBoxR0-wrapped.lds $ */
+/** @file
+ * Linker script augmentations for wrapped .r0.
+ */
+
+/*
+ * Copyright (C) 2021-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/* Define a symbol up close to the start of the module: */
+SECTIONS
+{
+ vboxr0mod_start = .;
+} INSERT BEFORE .text;
+
+/* Define a symbol up close to the end of the module: */
+SECTIONS
+{
+ vboxr0mod_end = .;
+} INSERT AFTER .bss;
+
diff --git a/src/VBox/HostDrivers/Support/linux/combined-agnostic1.c b/src/VBox/HostDrivers/Support/linux/combined-agnostic1.c
new file mode 100644
index 00000000..de557f80
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/combined-agnostic1.c
@@ -0,0 +1,99 @@
+/* $Id: combined-agnostic1.c $ */
+/** @file
+ * SUPDrv - Combine a bunch of OS agnostic sources into one compile unit.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#define LOG_GROUP LOG_GROUP_DEFAULT
+#include "internal/iprt.h"
+#include <VBox/log.h>
+
+#undef LOG_GROUP
+#include "r0drv/alloc-r0drv.c"
+#undef LOG_GROUP
+#include "r0drv/initterm-r0drv.c"
+#undef LOG_GROUP
+#include "r0drv/memobj-r0drv.c"
+#undef LOG_GROUP
+#include "r0drv/mpnotification-r0drv.c"
+#undef LOG_GROUP
+#include "r0drv/powernotification-r0drv.c"
+#undef LOG_GROUP
+#include "r0drv/generic/semspinmutex-r0drv-generic.c"
+#undef LOG_GROUP
+#include "common/alloc/alloc.c"
+#undef LOG_GROUP
+#include "common/checksum/crc32.c"
+#undef LOG_GROUP
+#include "common/checksum/ipv4.c"
+#undef LOG_GROUP
+#include "common/checksum/ipv6.c"
+#undef LOG_GROUP
+#include "common/err/errinfo.c"
+#undef LOG_GROUP
+#include "common/log/log.c"
+#undef LOG_GROUP
+#include "common/log/logellipsis.c"
+#undef LOG_GROUP
+#include "common/log/logrel.c"
+#undef LOG_GROUP
+#include "common/log/logrelellipsis.c"
+#undef LOG_GROUP
+#include "common/log/logcom.c"
+#undef LOG_GROUP
+#include "common/log/logformat.c"
+#undef LOG_GROUP
+#include "common/log/RTLogCreateEx.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg1Weak.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg2.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg2Add.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg2AddWeak.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg2AddWeakV.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg2Weak.c"
+#undef LOG_GROUP
+#include "common/misc/RTAssertMsg2WeakV.c"
+#undef LOG_GROUP
+#include "common/misc/assert.c"
+#undef LOG_GROUP
+#include "common/misc/handletable.c"
+#undef LOG_GROUP
+#include "common/misc/handletablectx.c"
+#undef LOG_GROUP
+#include "common/misc/thread.c"
+
diff --git a/src/VBox/HostDrivers/Support/linux/combined-agnostic2.c b/src/VBox/HostDrivers/Support/linux/combined-agnostic2.c
new file mode 100644
index 00000000..63da1a7e
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/combined-agnostic2.c
@@ -0,0 +1,116 @@
+/* $Id: combined-agnostic2.c $ */
+/** @file
+ * SUPDrv - Combine a bunch of OS agnostic sources into one compile unit.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#define LOG_GROUP LOG_GROUP_DEFAULT
+#include "internal/iprt.h"
+#include <VBox/log.h>
+
+#undef LOG_GROUP
+#include "common/string/RTStrCat.c"
+#undef LOG_GROUP
+#include "common/string/RTStrCopy.c"
+#undef LOG_GROUP
+#include "common/string/RTStrCopyEx.c"
+#undef LOG_GROUP
+#include "common/string/RTStrCopyP.c"
+#undef LOG_GROUP
+#include "common/string/RTStrEnd.c"
+#undef LOG_GROUP
+#include "common/string/RTStrNCmp.c"
+#undef LOG_GROUP
+#include "common/string/RTStrNLen.c"
+#undef LOG_GROUP
+#include "common/string/stringalloc.c"
+#undef LOG_GROUP
+#include "common/string/strformat.c"
+#undef LOG_GROUP
+#include "common/string/RTStrFormat.c"
+#undef LOG_GROUP
+#include "common/string/strformatnum.c"
+#undef LOG_GROUP
+#include "common/string/strformattype.c"
+#undef LOG_GROUP
+#include "common/string/strprintf.c"
+#undef LOG_GROUP
+#include "common/string/strprintf-ellipsis.c"
+#undef LOG_GROUP
+#include "common/string/strprintf2.c"
+#undef LOG_GROUP
+#include "common/string/strprintf2-ellipsis.c"
+#undef LOG_GROUP
+#include "common/string/strtonum.c"
+#undef LOG_GROUP
+#include "common/table/avlpv.c"
+#undef LOG_GROUP
+#include "common/time/time.c"
+#undef LOG_GROUP
+#include "generic/RTAssertShouldPanic-generic.c"
+#undef LOG_GROUP
+#include "generic/RTLogWriteStdErr-stub-generic.c"
+#undef LOG_GROUP
+#include "generic/RTLogWriteStdOut-stub-generic.c"
+#undef LOG_GROUP
+#include "generic/RTLogWriteUser-generic.c"
+#undef LOG_GROUP
+#include "generic/RTMpGetArraySize-generic.c"
+#undef LOG_GROUP
+#include "generic/RTMpGetCoreCount-generic.c"
+#undef LOG_GROUP
+#include "generic/RTSemEventWait-2-ex-generic.c"
+#undef LOG_GROUP
+#include "generic/RTSemEventWaitNoResume-2-ex-generic.c"
+#undef LOG_GROUP
+#include "generic/RTSemEventMultiWait-2-ex-generic.c"
+#undef LOG_GROUP
+#include "generic/RTSemEventMultiWaitNoResume-2-ex-generic.c"
+#undef LOG_GROUP
+#include "generic/RTTimerCreate-generic.c"
+#undef LOG_GROUP
+#include "generic/errvars-generic.c"
+#undef LOG_GROUP
+#include "generic/mppresent-generic.c"
+#undef LOG_GROUP
+#include "generic/uuid-generic.c"
+#undef LOG_GROUP
+#include "VBox/log-vbox.c"
+#undef LOG_GROUP
+#include "VBox/RTLogWriteVmm-amd64-x86.c"
+
+#ifdef RT_ARCH_AMD64
+# undef LOG_GROUP
+# include "common/alloc/heapsimple.c"
+#endif
+
diff --git a/src/VBox/HostDrivers/Support/linux/combined-os-specific.c b/src/VBox/HostDrivers/Support/linux/combined-os-specific.c
new file mode 100644
index 00000000..e08d2800
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/combined-os-specific.c
@@ -0,0 +1,68 @@
+/* $Id: combined-os-specific.c $ */
+/** @file
+ * SUPDrv - Combine a bunch of OS specific sources into one compile unit.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+#include "the-linux-kernel.h"
+
+#include "r0drv/linux/alloc-r0drv-linux.c"
+#include "r0drv/linux/assert-r0drv-linux.c"
+#include "r0drv/linux/initterm-r0drv-linux.c"
+#include "r0drv/linux/memobj-r0drv-linux.c"
+#include "r0drv/linux/memuserkernel-r0drv-linux.c"
+#include "r0drv/linux/mp-r0drv-linux.c"
+#include "r0drv/linux/mpnotification-r0drv-linux.c"
+#include "r0drv/linux/process-r0drv-linux.c"
+#undef LOG_GROUP
+#include "r0drv/linux/rtStrFormatKernelAddress-r0drv-linux.c"
+#undef LOG_GROUP
+#define LOG_GROUP RTLOGGROUP_DEFAULT
+#include "r0drv/linux/semevent-r0drv-linux.c"
+#include "r0drv/linux/semeventmulti-r0drv-linux.c"
+#include "r0drv/linux/semfastmutex-r0drv-linux.c"
+#include "r0drv/linux/semmutex-r0drv-linux.c"
+#include "r0drv/linux/spinlock-r0drv-linux.c"
+#include "r0drv/linux/thread-r0drv-linux.c"
+#include "r0drv/linux/thread2-r0drv-linux.c"
+#include "r0drv/linux/threadctxhooks-r0drv-linux.c"
+#undef LOG_GROUP
+#include "r0drv/linux/time-r0drv-linux.c"
+#undef LOG_GROUP
+#define LOG_GROUP RTLOGGROUP_DEFAULT
+#include "r0drv/linux/timer-r0drv-linux.c"
+#include "r0drv/linux/RTLogWriteDebugger-r0drv-linux.c"
+#include "common/err/RTErrConvertFromErrno.c"
+#include "common/err/RTErrConvertToErrno.c"
+
diff --git a/src/VBox/HostDrivers/Support/linux/files_vboxdrv b/src/VBox/HostDrivers/Support/linux/files_vboxdrv
new file mode 100755
index 00000000..cd8b214a
--- /dev/null
+++ b/src/VBox/HostDrivers/Support/linux/files_vboxdrv
@@ -0,0 +1,242 @@
+#!/bin/sh
+# $Id: files_vboxdrv $
+## @file
+# Shared file between Makefile.kmk and export_modules.sh.
+#
+
+#
+# Copyright (C) 2007-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+FILES_VBOXDRV_NOBIN=" \
+ ${PATH_ROOT}/include/iprt/alloc.h=>include/iprt/alloc.h \
+ ${PATH_ROOT}/include/iprt/asm.h=>include/iprt/asm.h \
+ ${PATH_ROOT}/include/iprt/asm-amd64-x86.h=>include/iprt/asm-amd64-x86.h \
+ ${PATH_ROOT}/include/iprt/asm-math.h=>include/iprt/asm-math.h \
+ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \
+ ${PATH_ROOT}/include/iprt/assertcompile.h=>include/iprt/assertcompile.h \
+ ${PATH_ROOT}/include/iprt/avl.h=>include/iprt/avl.h \
+ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \
+ ${PATH_ROOT}/include/iprt/cpuset.h=>include/iprt/cpuset.h \
+ ${PATH_ROOT}/include/iprt/crc.h=>include/iprt/crc.h \
+ ${PATH_ROOT}/include/iprt/ctype.h=>include/iprt/ctype.h \
+ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
+ ${PATH_ROOT}/include/iprt/errcore.h=>include/iprt/errcore.h \
+ ${PATH_ROOT}/include/iprt/errno.h=>include/iprt/errno.h \
+ ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+ ${PATH_ROOT}/include/iprt/handletable.h=>include/iprt/handletable.h \
+ ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
+ ${PATH_ROOT}/include/iprt/latin1.h=>include/iprt/latin1.h \
+ ${PATH_ROOT}/include/iprt/list.h=>include/iprt/list.h \
+ ${PATH_ROOT}/include/iprt/lockvalidator.h=>include/iprt/lockvalidator.h \
+ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
+ ${PATH_ROOT}/include/iprt/mangling.h=>include/iprt/mangling.h \
+ ${PATH_ROOT}/include/iprt/mem.h=>include/iprt/mem.h \
+ ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \
+ ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \
+ ${PATH_ROOT}/include/iprt/net.h=>include/iprt/net.h \
+ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \
+ ${PATH_ROOT}/include/iprt/path.h=>include/iprt/path.h \
+ ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \
+ ${PATH_ROOT}/include/iprt/process.h=>include/iprt/process.h \
+ ${PATH_ROOT}/include/iprt/rand.h=>include/iprt/rand.h \
+ ${PATH_ROOT}/include/iprt/semaphore.h=>include/iprt/semaphore.h \
+ ${PATH_ROOT}/include/iprt/spinlock.h=>include/iprt/spinlock.h \
+ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \
+ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \
+ ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \
+ ${PATH_ROOT}/include/iprt/thread.h=>include/iprt/thread.h \
+ ${PATH_ROOT}/include/iprt/time.h=>include/iprt/time.h \
+ ${PATH_ROOT}/include/iprt/timer.h=>include/iprt/timer.h \
+ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \
+ ${PATH_ROOT}/include/iprt/uint128.h=>include/iprt/uint128.h \
+ ${PATH_ROOT}/include/iprt/uint64.h=>include/iprt/uint64.h \
+ ${PATH_ROOT}/include/iprt/uni.h=>include/iprt/uni.h \
+ ${PATH_ROOT}/include/iprt/utf16.h=>include/iprt/utf16.h \
+ ${PATH_ROOT}/include/iprt/uuid.h=>include/iprt/uuid.h \
+ ${PATH_ROOT}/include/iprt/x86.h=>include/iprt/x86.h \
+ ${PATH_ROOT}/include/iprt/x86-helpers.h=>include/iprt/x86-helpers.h \
+ ${PATH_ROOT}/include/iprt/linux/version.h=>include/iprt/linux/version.h \
+ ${PATH_ROOT}/include/iprt/nocrt/limits.h=>include/iprt/nocrt/limits.h \
+ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \
+ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \
+ ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \
+ ${PATH_ROOT}/include/VBox/param.h=>include/VBox/param.h \
+ ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
+ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \
+ ${PATH_ROOT}/include/VBox/SUPDrvMangling.h=>include/VBox/SUPDrvMangling.h \
+ ${PATH_ROOT}/include/VBox/VBoxTpG.h=>include/VBox/VBoxTpG.h \
+ ${PATH_ROOT}/include/VBox/vmm/hm_vmx.h=>include/VBox/vmm/hm_vmx.h \
+ ${PATH_ROOT}/include/VBox/vmm/hm_svm.h=>include/VBox/vmm/hm_svm.h \
+ ${PATH_ROOT}/include/VBox/vmm/cpuidcall.h=>include/VBox/vmm/cpuidcall.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c=>linux/SUPDrv-linux.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/combined-agnostic1.c=>combined-agnostic1.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/combined-agnostic2.c=>combined-agnostic2.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/combined-os-specific.c=>combined-os-specific.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrv.cpp=>SUPDrv.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvGip.cpp=>SUPDrvGip.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvSem.cpp=>SUPDrvSem.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvTracer.cpp=>SUPDrvTracer.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrv-dtrace.cpp=>SUPDrvDTrace.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvIDC.h=>SUPDrvIDC.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvIOC.h=>SUPDrvIOC.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvInternal.h=>SUPDrvInternal.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPLibAll.cpp=>SUPLibAll.c \
+ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile-footer.gmk=>Makefile-footer.gmk \
+ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile-header.gmk=>Makefile-header.gmk \
+ ${PATH_ROOT}/src/VBox/Runtime/common/alloc/alloc.cpp=>common/alloc/alloc.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/alloc/heapsimple.cpp=>common/alloc/heapsimple.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/checksum/crc32.cpp=>common/checksum/crc32.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/checksum/ipv4.cpp=>common/checksum/ipv4.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/checksum/ipv6.cpp=>common/checksum/ipv6.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp=>common/err/RTErrConvertFromErrno.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/err/RTErrConvertToErrno.cpp=>common/err/RTErrConvertToErrno.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/err/errinfo.cpp=>common/err/errinfo.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/log.cpp=>common/log/log.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logellipsis.cpp=>common/log/logellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logrel.cpp=>common/log/logrel.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logrelellipsis.cpp=>common/log/logrelellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logcom.cpp=>common/log/logcom.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/logformat.cpp=>common/log/logformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/log/RTLogCreateEx.cpp=>common/log/RTLogCreateEx.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/divdi3.c=>math/gcc/divdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/divmoddi4.c=>math/gcc/divmoddi4.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/moddi3.c=>math/gcc/moddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/qdivrem.c=>math/gcc/qdivrem.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/quad.h=>math/gcc/quad.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivdi3.c=>math/gcc/udivdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivmoddi4.c=>math/gcc/udivmoddi4.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/umoddi3.c=>math/gcc/umoddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg1Weak.cpp=>common/misc/RTAssertMsg1Weak.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg2.cpp=>common/misc/RTAssertMsg2.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg2Add.cpp=>common/misc/RTAssertMsg2Add.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeak.cpp=>common/misc/RTAssertMsg2AddWeak.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg2AddWeakV.cpp=>common/misc/RTAssertMsg2AddWeakV.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg2Weak.cpp=>common/misc/RTAssertMsg2Weak.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/RTAssertMsg2WeakV.cpp=>common/misc/RTAssertMsg2WeakV.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/assert.cpp=>common/misc/assert.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/handletable.cpp=>common/misc/handletable.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/handletable.h=>common/misc/handletable.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/handletablectx.cpp=>common/misc/handletablectx.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/misc/thread.cpp=>common/misc/thread.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrCat.cpp=>common/string/RTStrCat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrCopy.cpp=>common/string/RTStrCopy.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrCopyEx.cpp=>common/string/RTStrCopyEx.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrCopyP.cpp=>common/string/RTStrCopyP.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrEnd.cpp=>common/string/RTStrEnd.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrNCmp.cpp=>common/string/RTStrNCmp.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrNLen.cpp=>common/string/RTStrNLen.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/stringalloc.cpp=>common/string/stringalloc.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformat.cpp=>common/string/strformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/RTStrFormat.cpp=>common/string/RTStrFormat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformatnum.cpp=>common/string/strformatnum.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformatrt.cpp=>common/string/strformatrt.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformattype.cpp=>common/string/strformattype.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf.cpp=>common/string/strprintf.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf-ellipsis.cpp=>common/string/strprintf-ellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf2.cpp=>common/string/strprintf2.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf2-ellipsis.cpp=>common/string/strprintf2-ellipsis.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strtonum.cpp=>common/string/strtonum.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avlpv.cpp=>common/table/avlpv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avl_Base.cpp.h=>common/table/avl_Base.cpp.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avl_Get.cpp.h=>common/table/avl_Get.cpp.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avl_GetBestFit.cpp.h=>common/table/avl_GetBestFit.cpp.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avl_RemoveBestFit.cpp.h=>common/table/avl_RemoveBestFit.cpp.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avl_DoWithAll.cpp.h=>common/table/avl_DoWithAll.cpp.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/table/avl_Destroy.cpp.h=>common/table/avl_Destroy.cpp.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/time/time.cpp=>common/time/time.c \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/assert.h=>include/internal/assert.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/initterm.h=>include/internal/initterm.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/iprt.h=>include/internal/iprt.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/lockvalidator.h=>include/internal/lockvalidator.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/magics.h=>include/internal/magics.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/mem.h=>include/internal/mem.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/memobj.h=>include/internal/memobj.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/string.h=>include/internal/string.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/sched.h=>include/internal/sched.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/process.h=>include/internal/process.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/thread.h=>include/internal/thread.h \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/time.h=>include/internal/time.h \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTAssertShouldPanic-generic.cpp=>generic/RTAssertShouldPanic-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdErr-stub-generic.cpp=>generic/RTLogWriteStdErr-stub-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp=>generic/RTLogWriteStdOut-stub-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp=>generic/RTLogWriteUser-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp=>generic/RTMpGetArraySize-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTMpGetCoreCount-generic.cpp=>generic/RTMpGetCoreCount-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWait-2-ex-generic.cpp=>generic/RTSemEventWait-2-ex-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventWaitNoResume-2-ex-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWait-2-ex-generic.cpp=>generic/RTSemEventMultiWait-2-ex-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp=>generic/RTSemEventMultiWaitNoResume-2-ex-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/errvars-generic.cpp=>generic/errvars-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/mppresent-generic.cpp=>generic/mppresent-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/alloc-r0drv.cpp=>r0drv/alloc-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/alloc-r0drv.h=>r0drv/alloc-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/initterm-r0drv.cpp=>r0drv/initterm-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/mp-r0drv.h=>r0drv/mp-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/mpnotification-r0drv.c=>r0drv/mpnotification-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/power-r0drv.h=>r0drv/power-r0drv.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/powernotification-r0drv.c=>r0drv/powernotification-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/rtStrFormatKernelAddress-r0drv-linux.c=>r0drv/linux/rtStrFormatKernelAddress-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/RTLogWriteDebugger-r0drv-linux.c=>r0drv/linux/RTLogWriteDebugger-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/assert-r0drv-linux.c=>r0drv/linux/assert-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c=>r0drv/linux/alloc-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c=>r0drv/linux/initterm-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c=>r0drv/linux/memobj-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/memuserkernel-r0drv-linux.c=>r0drv/linux/memuserkernel-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/mp-r0drv-linux.c=>r0drv/linux/mp-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/mpnotification-r0drv-linux.c=>r0drv/linux/mpnotification-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/process-r0drv-linux.c=>r0drv/linux/process-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semevent-r0drv-linux.c=>r0drv/linux/semevent-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c=>r0drv/linux/semeventmulti-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semfastmutex-r0drv-linux.c=>r0drv/linux/semfastmutex-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c=>r0drv/linux/semmutex-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/spinlock-r0drv-linux.c=>r0drv/linux/spinlock-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/string.h=>r0drv/linux/string.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>r0drv/linux/the-linux-kernel.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread-r0drv-linux.c=>r0drv/linux/thread-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/thread2-r0drv-linux.c=>r0drv/linux/thread2-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/threadctxhooks-r0drv-linux.c=>r0drv/linux/threadctxhooks-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/time-r0drv-linux.c=>r0drv/linux/time-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c=>r0drv/linux/timer-r0drv-linux.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/waitqueue-r0drv-linux.h=>r0drv/linux/waitqueue-r0drv-linux.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/semspinmutex-r0drv-generic.c=>r0drv/generic/semspinmutex-r0drv-generic.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/generic/threadctxhooks-r0drv-generic.cpp=>r0drv/generic/threadctxhooks-r0drv-generic.cpp \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/memobj-r0drv.cpp=>r0drv/memobj-r0drv.c \
+ ${PATH_ROOT}/src/VBox/Runtime/VBox/log-vbox.cpp=>VBox/log-vbox.c \
+ ${PATH_ROOT}/src/VBox/Runtime/VBox/RTLogWriteVmm-amd64-x86.cpp=>VBox/RTLogWriteVmm-amd64-x86.c \
+ ${PATH_OUT}/version-generated.h=>version-generated.h \
+ ${PATH_OUT}/revision-generated.h=>revision-generated.h \
+ ${PATH_OUT}/product-generated.h=>product-generated.h \
+"
+
+FILES_VBOXDRV_BIN=" \
+"