diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
commit | 16f504a9dca3fe3b70568f67b7d41241ae485288 (patch) | |
tree | c60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/HostDrivers/Support/linux | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostDrivers/Support/linux')
16 files changed, 4026 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..5f0c1c7c --- /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-2022 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..f252bbd3 --- /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-2022 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..b7aee935 --- /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-2022 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..02f45338 --- /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-2022 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..2e3ed6f0 --- /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-2022 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..ab36dd68 --- /dev/null +++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c @@ -0,0 +1,1783 @@ +/* $Id: SUPDrv-linux.c $ */ +/** @file + * VBoxDrv - The VirtualBox Support Driver - Linux specifics. + */ + +/* + * Copyright (C) 2006-2022 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; +#ifdef CONFIG_PAX_KERNEXEC + fFlags |= SUPKERNELFEATURES_GDT_READ_ONLY; +#endif +#if 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) + *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..7955e421 --- /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-2022 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..a415c917 --- /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-2022 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..1ebad2c7 --- /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-2022 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..c4a81849 --- /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-2022 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..cecd0af7 --- /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-2022 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..b84cb2ad --- /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-2022 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..e5d38484 --- /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-2022 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..f6834304 --- /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-2022 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..84f3cc0e --- /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-2022 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=" \ +" |