diff options
Diffstat (limited to 'src/VBox/HostDrivers/Support/testcase')
18 files changed, 3439 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/Support/testcase/Makefile.kmk b/src/VBox/HostDrivers/Support/testcase/Makefile.kmk new file mode 100644 index 00000000..4014c3d7 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/Makefile.kmk @@ -0,0 +1,138 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the SUPLib testcases. +# + +# +# Copyright (C) 2006-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL) only, as it comes in the "COPYING.CDDL" file of the +# VirtualBox OSE 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. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + +PROGRAMS += \ + SUPInstall \ + SUPUninstall \ + SUPLoggerCtl +ifdef VBOX_WITH_TESTCASES + if defined(VBOX_WITH_HARDENING) +PROGRAMS += \ + tstSupVerify + endif + if !defined(VBOX_WITH_HARDENING) || "$(KBUILD_TARGET)" != "win" +PROGRAMS += \ + tstPage \ + tstContiguous \ + tstInit \ + tstInt \ + tstLow \ + tstPin \ + tstGetPagingMode \ + tstSupLoadModule \ + tstSupSem \ + tstSupSem-Zombie \ + tstSupTscDelta + endif +PROGRAMS.win += \ + tstNtQueryStuff +endif # VBOX_WITH_TESTCASES + +SUPInstall_TEMPLATE = VBOXR3EXE +SUPInstall_SOURCES = SUPInstall.cpp +SUPInstall_LIBS = $(LIB_RUNTIME) + +SUPUninstall_TEMPLATE = VBOXR3EXE +SUPUninstall_SOURCES = SUPUninstall.cpp +SUPUninstall_LIBS = $(LIB_RUNTIME) + +SUPLoggerCtl_TEMPLATE = VBOXR3EXE +SUPLoggerCtl_SOURCES = SUPLoggerCtl.cpp +SUPLoggerCtl_LIBS = $(LIB_RUNTIME) + +tstInt_TEMPLATE = VBOXR3EXE +tstInt_SOURCES = tstInt.cpp +tstInt_LIBS = $(LIB_RUNTIME) + +tstContiguous_TEMPLATE= VBOXR3TSTEXE +tstContiguous_SOURCES = tstContiguous.cpp + +tstInit_TEMPLATE = VBOXR3TSTEXE +tstInit_SOURCES = tstInit.cpp + +tstLow_TEMPLATE = VBOXR3TSTEXE +tstLow_SOURCES = tstLow.cpp + +tstNtQueryStuff_TEMPLATE = VBOXR3TSTEXE +tstNtQueryStuff_SDKS = VBOX_NTDLL +tstNtQueryStuff_SOURCES = tstNtQueryStuff.cpp + +tstPin_TEMPLATE = VBOXR3TSTEXE +tstPin_SOURCES = tstPin.cpp + +tstPage_TEMPLATE = VBOXR3TSTEXE +tstPage_SOURCES = tstPage.cpp + +# +# tstGIP-2 +# +ifdef VBOX_WITH_TESTCASES + if defined(VBOX_WITH_HARDENING) && "$(KBUILD_TARGET)" == "win" + PROGRAMS += tstGIP-2Hardened + DLLS += tstGIP-2 + else + PROGRAMS += tstGIP-2 + endif +endif + +tstGIP-2Hardened_TEMPLATE = VBoxR3HardenedTstExe +tstGIP-2Hardened_DEFS = PROGRAM_NAME_STR=\"tstGIP-2\" +tstGIP-2Hardened_SOURCES = ../SUPR3HardenedMainTemplateTestcase.cpp +tstGIP-2Hardened_NAME = tstGIP-2 + +if defined(VBOX_WITH_HARDENING) && "$(KBUILD_TARGET)" == "win" + tstGIP-2_TEMPLATE := VBoxR3HardenedTstDll +else + tstGIP-2_TEMPLATE := VBOXR3TSTEXE +endif +tstGIP-2_SOURCES = tstGIP-2.cpp + +tstGetPagingMode_TEMPLATE = VBOXR3TSTEXE +tstGetPagingMode_SOURCES = tstGetPagingMode.cpp + +tstSupLoadModule_TEMPLATE = VBOXR3TSTEXE +tstSupLoadModule_SOURCES = tstSupLoadModule.cpp + +tstSupSem_TEMPLATE = VBOXR3TSTEXE +tstSupSem_SOURCES = tstSupSem.cpp + +tstSupSem-Zombie_TEMPLATE = VBOXR3TSTEXE +tstSupSem-Zombie_SOURCES = tstSupSem-Zombie.cpp + +tstSupTscDelta_TEMPLATE = VBOXR3TSTEXE +tstSupTscDelta_SOURCES = tstSupTscDelta.cpp + +# For testing supR3HardenedVerifyFile on windows. +tstSupVerify_TEMPLATE = VBOXR3TSTEXE +tstSupVerify_SOURCES = tstSupVerify.cpp + + + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp b/src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp new file mode 100644 index 00000000..60f16141 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/SUPInstall.cpp @@ -0,0 +1,59 @@ +/* $Id: SUPInstall.cpp $ */ +/** @file + * SUPInstall - Driver Install + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <VBox/err.h> +#include <iprt/initterm.h> +#include <iprt/message.h> + + +int main(int argc, char **argv) +{ + RTR3InitExeNoArguments(0); + if (argc != 1) + return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments"); + NOREF(argv); + + int rc = SUPR3Install(); + if (RT_SUCCESS(rc)) + { + if (rc == VINF_SUCCESS) + RTMsgInfo("Installed successfully!"); + else if (rc == VINF_ALREADY_INITIALIZED) + RTMsgInfo("Already loaded."); + else if (rc == VWRN_ALREADY_EXISTS) + RTMsgInfo("Service already existed; started successfully."); + else + RTMsgInfo("Unexpected status: %Rrc", rc); + return RTEXITCODE_SUCCESS; + } + return RTMsgErrorExit(RTEXITCODE_FAILURE, "installation failed. rc=%Rrc", rc); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/SUPLoggerCtl.cpp b/src/VBox/HostDrivers/Support/testcase/SUPLoggerCtl.cpp new file mode 100644 index 00000000..ac70003e --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/SUPLoggerCtl.cpp @@ -0,0 +1,178 @@ +/* $Id: SUPLoggerCtl.cpp $ */ +/** @file + * SUPLoggerCtl - Support Driver Logger Control. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/buildconfig.h> +#include <iprt/initterm.h> +#include <iprt/getopt.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/ctype.h> +#include <iprt/errcore.h> + + +/** + * Prints the usage. + * @returns 1. + */ +static int usage(void) +{ + RTPrintf("usage: SUPLoggerCtl [-f|--flags <flags-settings>] \\\n" + " [-g|--groups <groups-settings>] \\\n" + " [-d|--dest <destination-specifiers>] \\\n" + " [-l|--which <release|debug>] \\\n" + " [-o|--what <set|create|destroy>]\n" + " or: SUPLoggerCtl <-h|--help>\n" + "\n" + ); + return 1; +} + + +int main(int argc, char **argv) +{ + RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); + + /* + * Options are mandatory. + */ + if (argc <= 1) + return usage(); + + /* + * Parse the options. + */ + static const RTGETOPTDEF s_aOptions[] = + { + { "--flags", 'f', RTGETOPT_REQ_STRING }, + { "--groups", 'g', RTGETOPT_REQ_STRING }, + { "--dest", 'd', RTGETOPT_REQ_STRING }, + { "--what", 'o', RTGETOPT_REQ_STRING }, + { "--which", 'l', RTGETOPT_REQ_STRING }, + }; + + const char *pszFlags = ""; + const char *pszGroups = ""; + const char *pszDest = ""; + SUPLOGGER enmWhich = SUPLOGGER_DEBUG; + enum + { + kSupLoggerCtl_Set, kSupLoggerCtl_Create, kSupLoggerCtl_Destroy + } enmWhat = kSupLoggerCtl_Set; + + int ch; + RTGETOPTUNION Val; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); + while ((ch = RTGetOpt(&GetState, &Val))) + { + switch (ch) + { + case 'f': + pszFlags = Val.psz; + break; + + case 'g': + pszGroups = Val.psz; + break; + + case 'd': + pszDest = Val.psz; + break; + + case 'o': + if (!strcmp(Val.psz, "set")) + enmWhat = kSupLoggerCtl_Set; + else if (!strcmp(Val.psz, "create")) + enmWhat = kSupLoggerCtl_Create; + else if (!strcmp(Val.psz, "destroy")) + enmWhat = kSupLoggerCtl_Destroy; + else + { + RTStrmPrintf(g_pStdErr, "SUPLoggerCtl: error: Unknown operation '%s'.\n", Val.psz); + return 1; + } + break; + + case 'l': + if (!strcmp(Val.psz, "debug")) + enmWhich = SUPLOGGER_DEBUG; + else if (!strcmp(Val.psz, "release")) + enmWhich = SUPLOGGER_RELEASE; + else + { + RTStrmPrintf(g_pStdErr, "SUPLoggerCtl: error: Unknown logger '%s'.\n", Val.psz); + return 1; + } + break; + + case 'h': + return usage(); + + case 'V': + RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()); + return 0; + + case VINF_GETOPT_NOT_OPTION: + RTStrmPrintf(g_pStdErr, "SUPLoggerCtl: error: Unexpected argument '%s'.\n", Val.psz); + return 1; + + default: + return RTGetOptPrintError(ch, &Val); + } + } + + /* + * Do the requested job. + */ + int rc; + switch (enmWhat) + { + case kSupLoggerCtl_Set: + rc = SUPR3LoggerSettings(enmWhich, pszFlags, pszGroups, pszDest); + break; + case kSupLoggerCtl_Create: + rc = SUPR3LoggerCreate(enmWhich, pszFlags, pszGroups, pszDest); + break; + case kSupLoggerCtl_Destroy: + rc = SUPR3LoggerDestroy(enmWhich); + break; + default: + rc = VERR_INTERNAL_ERROR; + break; + } + if (RT_SUCCESS(rc)) + RTPrintf("SUPLoggerCtl: Success\n"); + else + RTStrmPrintf(g_pStdErr, "SUPLoggerCtl: error: rc=%Rrc\n", rc); + + return RT_SUCCESS(rc) ? 0 : 1; +} + diff --git a/src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp b/src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp new file mode 100644 index 00000000..127de87f --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/SUPUninstall.cpp @@ -0,0 +1,53 @@ +/* $Id: SUPUninstall.cpp $ */ +/** @file + * SUPUninstall - Driver Uninstall. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/message.h> + + +int main(int argc, char **argv) +{ + RTR3InitExeNoArguments(0); + if (argc != 1) + return RTMsgErrorExit(RTEXITCODE_SYNTAX, "This utility takes no arguments\n"); + NOREF(argv); + + int rc = SUPR3Uninstall(); + if (RT_SUCCESS(rc)) + { + RTMsgInfo("uninstalled successfully"); + return RTEXITCODE_SUCCESS; + } + return RTMsgErrorExit(RTEXITCODE_FAILURE, "uninstallation failed. rc=%Rrc", rc); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp b/src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp new file mode 100644 index 00000000..fcb41537 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstContiguous.cpp @@ -0,0 +1,108 @@ +/* $Id: tstContiguous.cpp $ */ +/** @file + * SUP Testcase - Contiguous Memory Interface (ring-3). + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <VBox/param.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <stdlib.h> +#include <string.h> + + +int main(int argc, char **argv) +{ + int rc; + int rcRet = 0; + + RTR3InitExe(argc, &argv, 0); + rc = SUPR3Init(NULL); + RTPrintf("tstContiguous: SUPR3Init -> rc=%Rrc\n", rc); + rcRet += rc != 0; + if (!rc) + { + /* + * Allocate a bit of contiguous memory. + */ + RTHCPHYS HCPhys; + void *pv = SUPR3ContAlloc(8, NULL, &HCPhys); + rcRet += pv == NULL || HCPhys == 0; + if (pv && HCPhys) + { + memset(pv, 0xff, PAGE_SIZE * 8); + pv = SUPR3ContAlloc(5, NULL, &HCPhys); + rcRet += pv == NULL || HCPhys == 0; + if (pv && HCPhys) + { + memset(pv, 0x7f, PAGE_SIZE * 5); + rc = SUPR3ContFree(pv, 5); + rcRet += rc != 0; + if (rc) + RTPrintf("tstContiguous: SUPR3ContFree failed! rc=%Rrc\n", rc); + + void *apv[128]; + for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) + { + apv[i] = SUPR3ContAlloc(1 + (i % 11), NULL, &HCPhys); + if (!apv[i]) + { + RTPrintf("tstContiguous: i=%d: failed to allocate %d pages", i, 1 + (i % 11)); +#if defined(RT_ARCH_X86) && defined(RT_OS_LINUX) + /* With 32-bit address spaces it's sometimes difficult + * to find bigger chunks of contiguous memory */ + if (i % 11 > 7) + RTPrintf(" => ignoring (32-bit host)"); + else +#endif + rcRet++; + RTPrintf("\n"); + } + } + for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) + if (apv[i]) + { + rc = SUPR3ContFree(apv[i], 1 + (i % 11)); + rcRet += rc != 0; + if (rc) + RTPrintf("tstContiguous: i=%d SUPR3ContFree failed! rc=%Rrc\n", i, rc); + } + } + else + RTPrintf("tstContiguous: SUPR3ContAlloc (2nd) failed!\n"); + } + else + RTPrintf("tstContiguous: SUPR3ContAlloc failed!\n"); + + rc = SUPR3Term(false /*fForced*/); + RTPrintf("tstContiguous: SUPR3Term -> rc=%Rrc\n", rc); + rcRet += rc != 0; + } + + return rcRet ? 1 : 0; +} diff --git a/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp b/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp new file mode 100644 index 00000000..4342db46 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp @@ -0,0 +1,343 @@ +/* $Id: tstGIP-2.cpp $ */ +/** @file + * SUP Testcase - Global Info Page interface (ring 3). + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> +#include <VBox/param.h> +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/alloc.h> +#include <iprt/thread.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/initterm.h> +#include <iprt/getopt.h> +#include <iprt/x86.h> + + +/** + * Entry point. + */ +extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv) +{ + RTR3InitExe(argc, &argv, 0); + + /* + * Parse args + */ + static const RTGETOPTDEF g_aOptions[] = + { + { "--iterations", 'i', RTGETOPT_REQ_INT32 }, + { "--hex", 'h', RTGETOPT_REQ_NOTHING }, + { "--decimal", 'd', RTGETOPT_REQ_NOTHING }, + { "--spin", 's', RTGETOPT_REQ_NOTHING }, + { "--reference", 'r', RTGETOPT_REQ_UINT64 }, /* reference value of CpuHz, display the + * CpuHz deviation in a separate column. */ + { "--notestmode", 't', RTGETOPT_REQ_NOTHING } /* don't run GIP in test-mode (atm, test-mode + * implies updating GIP CpuHz even when invariant) */ + }; + + bool fHex = true; + bool fSpin = false; + bool fCompat = true; + bool fTestMode = true; + int ch; + uint32_t cIterations = 40; + uint64_t uCpuHzRef = UINT64_MAX; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + switch (ch) + { + case 'i': + cIterations = ValueUnion.u32; + break; + + case 'd': + fHex = false; + break; + + case 'h': + fHex = true; + break; + + case 's': + fSpin = true; + break; + + case 'r': + uCpuHzRef = ValueUnion.u64; + break; + + case 't': + fTestMode = false; + break; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + + /* + * Init + */ + PSUPDRVSESSION pSession = NIL_RTR0PTR; + int rc = SUPR3Init(&pSession); + if (RT_SUCCESS(rc)) + { + if (g_pSUPGlobalInfoPage) + { + uint64_t uCpuHzOverallDeviation = 0; + uint32_t cCpuHzNotCompat = 0; + int64_t iCpuHzMaxDeviation = 0; + int32_t cCpuHzOverallDevCnt = 0; + uint32_t cCpuHzChecked = 0; + + /* Pick current CpuHz as the reference if none was specified. */ + if (uCpuHzRef == UINT64_MAX) + uCpuHzRef = SUPGetCpuHzFromGip(g_pSUPGlobalInfoPage); + + if ( fTestMode + && g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC) + SUPR3GipSetFlags(SUPGIP_FLAGS_TESTING_ENABLE, UINT32_MAX); + + RTPrintf("tstGIP-2: u32Mode=%d (%s) fTestMode=%RTbool u32Version=%#x fGetGipCpu=%#RX32\n", + g_pSUPGlobalInfoPage->u32Mode, + SUPGetGIPModeName(g_pSUPGlobalInfoPage), + fTestMode, + g_pSUPGlobalInfoPage->u32Version, + g_pSUPGlobalInfoPage->fGetGipCpu); + RTPrintf("tstGIP-2: cCpus=%d cPossibleCpus=%d cPossibleCpuGroups=%d cPresentCpus=%d cOnlineCpus=%d idCpuMax=%#x\n", + g_pSUPGlobalInfoPage->cCpus, + g_pSUPGlobalInfoPage->cPossibleCpus, + g_pSUPGlobalInfoPage->cPossibleCpuGroups, + g_pSUPGlobalInfoPage->cPresentCpus, + g_pSUPGlobalInfoPage->cOnlineCpus, + g_pSUPGlobalInfoPage->idCpuMax); + RTPrintf("tstGIP-2: u32UpdateHz=%RU32 u32UpdateIntervalNS=%RU32 u64NanoTSLastUpdateHz=%RX64 u64CpuHz=%RU64 uCpuHzRef=%RU64\n", + g_pSUPGlobalInfoPage->u32UpdateHz, + g_pSUPGlobalInfoPage->u32UpdateIntervalNS, + g_pSUPGlobalInfoPage->u64NanoTSLastUpdateHz, + g_pSUPGlobalInfoPage->u64CpuHz, + uCpuHzRef); + for (uint32_t iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++) + if (g_pSUPGlobalInfoPage->aCPUs[iCpu].enmState != SUPGIPCPUSTATE_INVALID) + { + SUPGIPCPU const *pGipCpu = &g_pSUPGlobalInfoPage->aCPUs[iCpu]; + RTPrintf("tstGIP-2: aCPU[%u]: enmState=%d iCpuSet=%u idCpu=%#010x iCpuGroup=%u iCpuGroupMember=%u idApic=%#x\n", + iCpu, pGipCpu->enmState, pGipCpu->iCpuSet, pGipCpu->idCpu, pGipCpu->iCpuGroup, + pGipCpu->iCpuGroupMember, pGipCpu->idApic); + } + + RTPrintf(fHex + ? "tstGIP-2: it: u64NanoTS delta u64TSC UpIntTSC H TransId CpuHz %sTSC Interval History...\n" + : "tstGIP-2: it: u64NanoTS delta u64TSC UpIntTSC H TransId CpuHz %sTSC Interval History...\n", + uCpuHzRef ? " CpuHz deviation Compat " : ""); + static SUPGIPCPU s_aaCPUs[2][256]; + for (uint32_t i = 0; i < cIterations; i++) + { + /* Copy the data. */ + memcpy(&s_aaCPUs[i & 1][0], &g_pSUPGlobalInfoPage->aCPUs[0], g_pSUPGlobalInfoPage->cCpus * sizeof(g_pSUPGlobalInfoPage->aCPUs[0])); + + /* Display it & find something to spin on. */ + uint32_t u32TransactionId = 0; + uint32_t volatile *pu32TransactionId = NULL; + for (unsigned iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++) + if (g_pSUPGlobalInfoPage->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE) + { + char szCpuHzDeviation[32]; + PSUPGIPCPU pPrevCpu = &s_aaCPUs[!(i & 1)][iCpu]; + PSUPGIPCPU pCpu = &s_aaCPUs[i & 1][iCpu]; + if (uCpuHzRef) + { + /* Only CPU 0 is updated for invariant & sync modes, see supdrvGipUpdate(). */ + if ( iCpu == 0 + || g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_ASYNC_TSC) + { + /* Wait until the history validation code takes effect. */ + if (pCpu->u32TransactionId > 23 + (8 * 2) + 1) + { + int64_t iCpuHzDeviation = pCpu->u64CpuHz - uCpuHzRef; + uint64_t uCpuHzDeviation = RT_ABS(iCpuHzDeviation); + bool fCurHzCompat = SUPIsTscFreqCompatibleEx(uCpuHzRef, pCpu->u64CpuHz, false /*fRelax*/); + if (uCpuHzDeviation <= 999999999) + { + if (RT_ABS(iCpuHzDeviation) > RT_ABS(iCpuHzMaxDeviation)) + iCpuHzMaxDeviation = iCpuHzDeviation; + uCpuHzOverallDeviation += uCpuHzDeviation; + cCpuHzOverallDevCnt++; + uint32_t uPct = (uint32_t)(uCpuHzDeviation * 100000 / uCpuHzRef + 5); + RTStrPrintf(szCpuHzDeviation, sizeof(szCpuHzDeviation), "%10RI64%3d.%02d%% %RTbool ", + iCpuHzDeviation, uPct / 1000, (uPct % 1000) / 10, fCurHzCompat); + } + else + { + RTStrPrintf(szCpuHzDeviation, sizeof(szCpuHzDeviation), "%17s %RTbool ", "?", + fCurHzCompat); + } + + if (!fCurHzCompat) + ++cCpuHzNotCompat; + fCompat &= fCurHzCompat; + ++cCpuHzChecked; + } + else + RTStrPrintf(szCpuHzDeviation, sizeof(szCpuHzDeviation), "%25s ", "priming"); + } + else + RTStrPrintf(szCpuHzDeviation, sizeof(szCpuHzDeviation), "%25s ", ""); + } + else + szCpuHzDeviation[0] = '\0'; + RTPrintf(fHex + ? "tstGIP-2: %4d/%d: %016llx %09llx %016llx %08x %d %08x %15llu %s%08x %08x %08x %08x %08x %08x %08x %08x (%d)\n" + : "tstGIP-2: %4d/%d: %016llu %09llu %016llu %010u %d %010u %15llu %s%08x %08x %08x %08x %08x %08x %08x %08x (%d)\n", + i, iCpu, + pCpu->u64NanoTS, + i ? pCpu->u64NanoTS - pPrevCpu->u64NanoTS : 0, + pCpu->u64TSC, + pCpu->u32UpdateIntervalTSC, + pCpu->iTSCHistoryHead, + pCpu->u32TransactionId, + pCpu->u64CpuHz, + szCpuHzDeviation, + pCpu->au32TSCHistory[0], + pCpu->au32TSCHistory[1], + pCpu->au32TSCHistory[2], + pCpu->au32TSCHistory[3], + pCpu->au32TSCHistory[4], + pCpu->au32TSCHistory[5], + pCpu->au32TSCHistory[6], + pCpu->au32TSCHistory[7], + pCpu->cErrors); + if (!pu32TransactionId) + { + pu32TransactionId = &g_pSUPGlobalInfoPage->aCPUs[iCpu].u32TransactionId; + u32TransactionId = pCpu->u32TransactionId; + } + } + + /* Wait a bit / spin. */ + if (!fSpin) + RTThreadSleep(9); + else + { + if (pu32TransactionId) + { + uint32_t uTmp; + while ( u32TransactionId == (uTmp = *pu32TransactionId) + || (uTmp & 1)) + ASMNopPause(); + } + else + RTThreadSleep(1); + } + } + + /* + * Display TSC deltas. + * + * First iterative over the APIC ID array to get mostly consistent CPUID to APIC ID mapping. + * Then iterate over the offline CPUs. It is possible that there's a race between the online/offline + * states between the two iterations, but that cannot be helped from ring-3 anyway and not a biggie. + */ + RTPrintf("tstGIP-2: TSC deltas:\n"); + RTPrintf("tstGIP-2: idApic: i64TSCDelta\n"); + for (unsigned i = 0; i < RT_ELEMENTS(g_pSUPGlobalInfoPage->aiCpuFromApicId); i++) + { + uint16_t iCpu = g_pSUPGlobalInfoPage->aiCpuFromApicId[i]; + if (iCpu != UINT16_MAX) + { + RTPrintf("tstGIP-2: %7d: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic, + g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta); + } + } + + for (unsigned iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++) + if (g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic == UINT16_MAX) + RTPrintf("tstGIP-2: offline: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta); + + RTPrintf("tstGIP-2: enmUseTscDelta=%d fGetGipCpu=%#x\n", + g_pSUPGlobalInfoPage->enmUseTscDelta, g_pSUPGlobalInfoPage->fGetGipCpu); + if (uCpuHzRef) + { + if (cCpuHzOverallDevCnt) + { + uint32_t uPct = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5); + RTPrintf("tstGIP-2: Average CpuHz deviation: %d.%02d%%\n", + uPct / 1000, (uPct % 1000) / 10); + + uint32_t uMaxPct = (uint32_t)(RT_ABS(iCpuHzMaxDeviation) * 100000 / uCpuHzRef + 5); + RTPrintf("tstGIP-2: Maximum CpuHz deviation: %d.%02d%% (%RI64 ticks)\n", + uMaxPct / 1000, (uMaxPct % 1000) / 10, iCpuHzMaxDeviation); + } + else + { + RTPrintf("tstGIP-2: Average CpuHz deviation: ??.??\n"); + RTPrintf("tstGIP-2: Average CpuHz deviation: ??.??\n"); + } + + RTPrintf("tstGIP-2: CpuHz compatibility: %RTbool (incompatible %u of %u times w/ %RU64 Hz - %s GIP)\n", fCompat, + cCpuHzNotCompat, cCpuHzChecked, uCpuHzRef, SUPGetGIPModeName(g_pSUPGlobalInfoPage)); + + if ( !fCompat + && g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC) + rc = -1; + } + + /* Disable GIP test mode. */ + if (fTestMode) + SUPR3GipSetFlags(0, ~SUPGIP_FLAGS_TESTING_ENABLE); + } + else + { + RTPrintf("tstGIP-2: g_pSUPGlobalInfoPage is NULL\n"); + rc = -1; + } + + SUPR3Term(false /*fForced*/); + } + else + RTPrintf("tstGIP-2: SUPR3Init failed: %Rrc\n", rc); + return !!rc; +} + +#if !defined(VBOX_WITH_HARDENING) || !defined(RT_OS_WINDOWS) +/** + * Main entry point. + */ +int main(int argc, char **argv) +{ + return TrustedMain(argc, argv); +} +#endif + diff --git a/src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp b/src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp new file mode 100644 index 00000000..7f9ec12b --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstGetPagingMode.cpp @@ -0,0 +1,94 @@ +/* $Id: tstGetPagingMode.cpp $ */ +/** @file + * SUP Testcase - Host paging mode interface (ring 3). + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> + + +int main(int argc, char **argv) +{ + int rc; + RTR3InitExe(argc, &argv, 0); + rc = SUPR3Init(NULL); + if (RT_SUCCESS(rc)) + { + SUPPAGINGMODE enmMode = SUPR3GetPagingMode(); + switch (enmMode) + { + case SUPPAGINGMODE_INVALID: + RTPrintf("SUPPAGINGMODE_INVALID\n"); + break; + case SUPPAGINGMODE_32_BIT: + RTPrintf("SUPPAGINGMODE_32_BIT\n"); + break; + case SUPPAGINGMODE_32_BIT_GLOBAL: + RTPrintf("SUPPAGINGMODE_32_BIT_GLOBAL\n"); + break; + case SUPPAGINGMODE_PAE: + RTPrintf("SUPPAGINGMODE_PAE\n"); + break; + case SUPPAGINGMODE_PAE_GLOBAL: + RTPrintf("SUPPAGINGMODE_PAE_GLOBAL\n"); + break; + case SUPPAGINGMODE_PAE_NX: + RTPrintf("SUPPAGINGMODE_PAE_NX\n"); + break; + case SUPPAGINGMODE_PAE_GLOBAL_NX: + RTPrintf("SUPPAGINGMODE_PAE_GLOBAL_NX\n"); + break; + case SUPPAGINGMODE_AMD64: + RTPrintf("SUPPAGINGMODE_AMD64\n"); + break; + case SUPPAGINGMODE_AMD64_GLOBAL: + RTPrintf("SUPPAGINGMODE_AMD64_GLOBAL\n"); + break; + case SUPPAGINGMODE_AMD64_NX: + RTPrintf("SUPPAGINGMODE_AMD64_NX\n"); + break; + case SUPPAGINGMODE_AMD64_GLOBAL_NX: + RTPrintf("SUPPAGINGMODE_AMD64_GLOBAL_NX\n"); + break; + default: + RTPrintf("Unknown mode %d\n", enmMode); + rc = VERR_INTERNAL_ERROR; + break; + } + + int rc2 = SUPR3Term(false /*fForced*/); + RTPrintf("SUPR3Term -> rc=%Rrc\n", rc2); + } + else + RTPrintf("SUPR3Init -> rc=%Rrc\n", rc); + + return !RT_SUCCESS(rc); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstInit.cpp b/src/VBox/HostDrivers/Support/testcase/tstInit.cpp new file mode 100644 index 00000000..1eb5c918 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstInit.cpp @@ -0,0 +1,51 @@ +/* $Id: tstInit.cpp $ */ +/** @file + * SUP Testcase - Support Library initialization and termination. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> + + +int main(int argc, char **argv) +{ + int rc; + RTR3InitExe(argc, &argv, 0); + rc = SUPR3Init(NULL); + RTPrintf("tstInit: SUPR3Init -> rc=%Rrc\n", rc); + if (!rc) + { + rc = SUPR3Term(false /*fForced*/); + RTPrintf("tstInit: SUPR3Term -> rc=%Rrc\n", rc); + } + + return rc; +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstInt.cpp b/src/VBox/HostDrivers/Support/testcase/tstInt.cpp new file mode 100644 index 00000000..d5cacbc2 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstInt.cpp @@ -0,0 +1,226 @@ +/* $Id: tstInt.cpp $ */ +/** @file + * SUP Testcase - Test the interrupt gate feature of the support library. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <VBox/vmm/vm.h> +#include <VBox/vmm/vmm.h> +#include <VBox/vmm/gvmm.h> +#include <iprt/errcore.h> +#include <VBox/param.h> +#include <iprt/asm-amd64-x86.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/alloc.h> +#include <iprt/time.h> +#include <iprt/path.h> + + +int main(int argc, char **argv) +{ + int rcRet = 0; + int i; + int rc; + int cIterations = argc > 1 ? RTStrToUInt32(argv[1]) : 32; + if (cIterations == 0) + cIterations = 64; + + /* + * Init. + */ + RTR3InitExe(argc, &argv, 0); + PSUPDRVSESSION pSession; + rc = SUPR3Init(&pSession); + rcRet += rc != 0; + RTPrintf("tstInt: SUPR3Init -> rc=%Rrc\n", rc); + char szFile[RTPATH_MAX]; + if (!rc) + { + rc = RTPathExecDir(szFile, sizeof(szFile) - sizeof("/VMMR0.r0")); + } + char szAbsFile[RTPATH_MAX]; + if (RT_SUCCESS(rc)) + { + strcat(szFile, "/VMMR0.r0"); + rc = RTPathAbs(szFile, szAbsFile, sizeof(szAbsFile)); + } + if (RT_SUCCESS(rc)) + { + /* + * Load VMM code. + */ + rc = SUPR3LoadVMM(szAbsFile); + if (RT_SUCCESS(rc)) + { + /* + * Create a tiny dummy VM so we can do NOP calls into it using the fast I/O control path. + */ + GVMMCREATEVMREQ CreateVMReq; + CreateVMReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; + CreateVMReq.Hdr.cbReq = sizeof(CreateVMReq); + CreateVMReq.pSession = pSession; + CreateVMReq.pVMR0 = NIL_RTR0PTR; + CreateVMReq.pVMR3 = NULL; + CreateVMReq.cCpus = 1; + rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_GVMM_CREATE_VM, 0, &CreateVMReq.Hdr); + if (RT_SUCCESS(rc)) + { + PVM pVM = CreateVMReq.pVMR3; + AssertRelease(VALID_PTR(pVM)); + AssertRelease(pVM->pVMR0 == CreateVMReq.pVMR0); + AssertRelease(pVM->pSession == pSession); + AssertRelease(pVM->cCpus == 1); + AssertRelease(pVM->offVMCPU == RT_UOFFSETOF(VM, aCpus)); + pVM->enmVMState = VMSTATE_CREATED; + PVMR0 const pVMR0 = pVM->pVMR0; + + rc = SUPR3SetVMForFastIOCtl(pVM->pVMR0); + if (!rc) + { + /* + * Call VMM code with invalid function. + */ + for (i = cIterations; i > 0; i--) + { + rc = SUPR3CallVMMR0(pVMR0, NIL_VMCPUID, VMMR0_DO_SLOW_NOP, NULL); + if (rc != VINF_SUCCESS) + { + RTPrintf("tstInt: SUPR3CallVMMR0 -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i); + rcRet++; + break; + } + } + RTPrintf("tstInt: Performed SUPR3CallVMMR0 %d times (rc=%Rrc)\n", cIterations, rc); + + /* + * The fast path. + */ + if (rc == VINF_SUCCESS) + { + RTTimeNanoTS(); + uint64_t StartTS = RTTimeNanoTS(); + uint64_t StartTick = ASMReadTSC(); + uint64_t MinTicks = UINT64_MAX; + for (i = 0; i < 1000000; i++) + { + uint64_t OneStartTick = ASMReadTSC(); + rc = SUPR3CallVMMR0Fast(pVMR0, VMMR0_DO_NOP, 0); + uint64_t Ticks = ASMReadTSC() - OneStartTick; + if (Ticks < MinTicks) + MinTicks = Ticks; + + if (RT_UNLIKELY(rc != VINF_SUCCESS)) + { + RTPrintf("tstInt: SUPR3CallVMMR0Fast -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i); + rcRet++; + break; + } + } + uint64_t Ticks = ASMReadTSC() - StartTick; + uint64_t NanoSecs = RTTimeNanoTS() - StartTS; + + RTPrintf("tstInt: SUPR3CallVMMR0Fast - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n", + i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks); + + /* + * The ordinary path. + */ + RTTimeNanoTS(); + StartTS = RTTimeNanoTS(); + StartTick = ASMReadTSC(); + MinTicks = UINT64_MAX; + for (i = 0; i < 1000000; i++) + { + uint64_t OneStartTick = ASMReadTSC(); + rc = SUPR3CallVMMR0Ex(pVMR0, NIL_VMCPUID, VMMR0_DO_SLOW_NOP, 0, NULL); + uint64_t OneTicks = ASMReadTSC() - OneStartTick; + if (OneTicks < MinTicks) + MinTicks = OneTicks; + + if (RT_UNLIKELY(rc != VINF_SUCCESS)) + { + RTPrintf("tstInt: SUPR3CallVMMR0Ex -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i); + rcRet++; + break; + } + } + Ticks = ASMReadTSC() - StartTick; + NanoSecs = RTTimeNanoTS() - StartTS; + + RTPrintf("tstInt: SUPR3CallVMMR0Ex - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n", + i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks); + } + } + else + { + RTPrintf("tstInt: SUPR3SetVMForFastIOCtl failed: %Rrc\n", rc); + rcRet++; + } + + rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_GVMM_DESTROY_VM, 0, NULL); + if (RT_FAILURE(rc)) + { + RTPrintf("tstInt: VMMR0_DO_GVMM_DESTROY_VM failed: %Rrc\n", rc); + rcRet++; + } + } + else + { + RTPrintf("tstInt: VMMR0_DO_GVMM_CREATE_VM failed\n"); + rcRet++; + } + + /* + * Unload VMM. + */ + rc = SUPR3UnloadVMM(); + if (rc) + { + RTPrintf("tstInt: SUPR3UnloadVMM failed with rc=%Rrc\n", rc); + rcRet++; + } + } + else + { + RTPrintf("tstInt: SUPR3LoadVMM failed with rc=%Rrc\n", rc); + rcRet++; + } + + /* + * Terminate. + */ + rc = SUPR3Term(false /*fForced*/); + rcRet += rc != 0; + RTPrintf("tstInt: SUPR3Term -> rc=%Rrc\n", rc); + } + + return !!rc; +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstLow.cpp b/src/VBox/HostDrivers/Support/testcase/tstLow.cpp new file mode 100644 index 00000000..23522cd3 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstLow.cpp @@ -0,0 +1,154 @@ +/* $Id: tstLow.cpp $ */ +/** @file + * SUP Testcase - Low (<4GB) Memory Allocate interface (ring 3). + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <VBox/param.h> +#include <iprt/errcore.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/string.h> + + +int main(int argc, char **argv) +{ + int rc; + int rcRet = 0; + + RTR3InitExe(argc, &argv, 0); + RTPrintf("tstLow: TESTING...\n"); + + rc = SUPR3Init(NULL); + if (RT_SUCCESS(rc)) + { + /* + * Allocate a bit of contiguous memory. + */ + SUPPAGE aPages0[128]; + void *pvPages0 = (void *)0x77777777; + memset(&aPages0[0], 0x8f, sizeof(aPages0)); + rc = SUPR3LowAlloc(RT_ELEMENTS(aPages0), &pvPages0, NULL, aPages0); + if (RT_SUCCESS(rc)) + { + /* check that the pages are below 4GB and valid. */ + for (unsigned iPage = 0; iPage < RT_ELEMENTS(aPages0); iPage++) + { + RTPrintf("%-4d: Phys=%RHp Reserved=%p\n", iPage, aPages0[iPage].Phys, aPages0[iPage].uReserved); + if (aPages0[iPage].uReserved != 0) + { + rcRet++; + RTPrintf("tstLow: error: aPages0[%d].uReserved=%#x expected 0!\n", iPage, aPages0[iPage].uReserved); + } + if ( aPages0[iPage].Phys >= _4G + || (aPages0[iPage].Phys & PAGE_OFFSET_MASK)) + { + rcRet++; + RTPrintf("tstLow: error: aPages0[%d].Phys=%RHp!\n", iPage, aPages0[iPage].Phys); + } + } + if (!rcRet) + { + for (unsigned iPage = 0; iPage < RT_ELEMENTS(aPages0); iPage++) + memset((char *)pvPages0 + iPage * PAGE_SIZE, iPage, PAGE_SIZE); + for (unsigned iPage = 0; iPage < RT_ELEMENTS(aPages0); iPage++) + for (uint8_t *pu8 = (uint8_t *)pvPages0 + iPage * PAGE_SIZE, *pu8End = pu8 + PAGE_SIZE; pu8 < pu8End; pu8++) + if (*pu8 != (uint8_t)iPage) + { + RTPrintf("tstLow: error: invalid page content %02x != %02x. iPage=%u off=%#x\n", + *pu8, (uint8_t)iPage, iPage, (uintptr_t)pu8 & PAGE_OFFSET_MASK); + rcRet++; + } + } + SUPR3LowFree(pvPages0, RT_ELEMENTS(aPages0)); + } + else + { + RTPrintf("SUPR3LowAlloc(%d,,) failed -> rc=%Rrc\n", RT_ELEMENTS(aPages0), rc); + rcRet++; + } + + /* + * Allocate odd amounts in from 1 to 127. + */ + for (unsigned cPages = 1; cPages <= 127; cPages++) + { + SUPPAGE aPages1[128]; + void *pvPages1 = (void *)0x77777777; + memset(&aPages1[0], 0x8f, sizeof(aPages1)); + rc = SUPR3LowAlloc(cPages, &pvPages1, NULL, aPages1); + if (RT_SUCCESS(rc)) + { + /* check that the pages are below 4GB and valid. */ + for (unsigned iPage = 0; iPage < cPages; iPage++) + { + RTPrintf("%-4d::%-4d: Phys=%RHp Reserved=%p\n", cPages, iPage, aPages1[iPage].Phys, aPages1[iPage].uReserved); + if (aPages1[iPage].uReserved != 0) + { + rcRet++; + RTPrintf("tstLow: error: aPages1[%d].uReserved=%#x expected 0!\n", iPage, aPages1[iPage].uReserved); + } + if ( aPages1[iPage].Phys >= _4G + || (aPages1[iPage].Phys & PAGE_OFFSET_MASK)) + { + rcRet++; + RTPrintf("tstLow: error: aPages1[%d].Phys=%RHp!\n", iPage, aPages1[iPage].Phys); + } + } + if (!rcRet) + { + for (unsigned iPage = 0; iPage < cPages; iPage++) + memset((char *)pvPages1 + iPage * PAGE_SIZE, iPage, PAGE_SIZE); + for (unsigned iPage = 0; iPage < cPages; iPage++) + for (uint8_t *pu8 = (uint8_t *)pvPages1 + iPage * PAGE_SIZE, *pu8End = pu8 + PAGE_SIZE; pu8 < pu8End; pu8++) + if (*pu8 != (uint8_t)iPage) + { + RTPrintf("tstLow: error: invalid page content %02x != %02x. iPage=%p off=%#x\n", + *pu8, (uint8_t)iPage, iPage, (uintptr_t)pu8 & PAGE_OFFSET_MASK); + rcRet++; + } + } + SUPR3LowFree(pvPages1, cPages); + } + else + { + RTPrintf("SUPR3LowAlloc(%d,,) failed -> rc=%Rrc\n", cPages, rc); + rcRet++; + } + } + + } + else + { + RTPrintf("SUPR3Init -> rc=%Rrc\n", rc); + rcRet++; + } + + + return rcRet; +} diff --git a/src/VBox/HostDrivers/Support/testcase/tstNtQueryStuff.cpp b/src/VBox/HostDrivers/Support/testcase/tstNtQueryStuff.cpp new file mode 100644 index 00000000..e115fb5a --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstNtQueryStuff.cpp @@ -0,0 +1,430 @@ +/* $Id: tstNtQueryStuff.cpp $ */ +/** @file + * SUP Testcase - Exploring some NT Query APIs. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/nt/nt-and-windows.h> +#include <iprt/test.h> +#include <iprt/string.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct FLAGDESC +{ + ULONG f; + const char *psz; +} FLAGDESC; +typedef const FLAGDESC *PCFLAGDESC; + + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static RTTEST g_hTest = NIL_RTTEST; +static HANDLE g_hProcess = NULL; + + +static char *stringifyAppend(char *pszBuf, size_t *pcbBuf, const char *pszAppend, bool fWithSpace) +{ + size_t cchAppend = strlen(pszAppend); + if (cchAppend + 1 + fWithSpace <= *pcbBuf) + { + if (fWithSpace) + { + *pszBuf++ = ' '; + *pcbBuf += 1; + } + memcpy(pszBuf, pszAppend, cchAppend + 1); + *pcbBuf -= cchAppend; + pszBuf += cchAppend; + } + + return pszBuf; +} + + +static char *stringifyAppendUnknownFlags(uint32_t fFlags, char *pszBuf, size_t *pcbBuf, bool fWithSpace) +{ + for (unsigned iBit = 0; iBit < 32; iBit++) + if (fFlags & RT_BIT_32(iBit)) + { + char szTmp[32]; /* lazy bird */ + RTStrPrintf(szTmp, sizeof(szTmp), "BIT(%d)", iBit); + pszBuf = stringifyAppend(pszBuf, pcbBuf, szTmp, fWithSpace); + fWithSpace = true; + } + + return pszBuf; +} + + +static char *stringifyFlags(uint32_t fFlags, char *pszBuf, size_t cbBuf, PCFLAGDESC paFlagDesc, size_t cFlagDesc) +{ + char *pszBufStart = pszBuf; + if (fFlags) + { + for (size_t i = 0; i < cFlagDesc; i++) + { + if (fFlags & paFlagDesc[i].f) + { + fFlags &= ~paFlagDesc[i].f; + pszBuf = stringifyAppend(pszBuf, &cbBuf, paFlagDesc[i].psz, pszBuf != pszBufStart); + } + } + + if (fFlags) + stringifyAppendUnknownFlags(fFlags, pszBuf, &cbBuf, pszBuf != pszBufStart); + } + else + { + pszBuf[0] = '0'; + pszBuf[1] = '\0'; + } + return pszBufStart; +} + + +static char *stringifyMemType(uint32_t fType, char *pszBuf, size_t cbBuf) +{ + static const FLAGDESC s_aMemTypes[] = + { + { MEM_PRIVATE, "PRIVATE" }, + { MEM_MAPPED, "MAPPED" }, + { MEM_IMAGE, "IMAGE" }, + }; + return stringifyFlags(fType, pszBuf, cbBuf, s_aMemTypes, RT_ELEMENTS(s_aMemTypes)); +} + + +static char *stringifyMemState(uint32_t fState, char *pszBuf, size_t cbBuf) +{ + static const FLAGDESC s_aMemStates[] = + { + { MEM_FREE, "FREE" }, + { MEM_COMMIT, "COMMIT" }, + { MEM_RESERVE, "RESERVE" }, + { MEM_DECOMMIT, "DECOMMMIT" }, + }; + return stringifyFlags(fState, pszBuf, cbBuf, s_aMemStates, RT_ELEMENTS(s_aMemStates)); +} + + +static char *stringifyMemProt(uint32_t fProt, char *pszBuf, size_t cbBuf) +{ + static const FLAGDESC s_aProtections[] = + { + { PAGE_NOACCESS, "NOACCESS" }, + { PAGE_READONLY, "READONLY" }, + { PAGE_READWRITE, "READWRITE" }, + { PAGE_WRITECOPY, "WRITECOPY" }, + { PAGE_EXECUTE, "EXECUTE" }, + { PAGE_EXECUTE_READ, "EXECUTE_READ" }, + { PAGE_EXECUTE_READWRITE, "EXECUTE_READWRITE" }, + { PAGE_EXECUTE_WRITECOPY, "EXECUTE_WRITECOPY" }, + { PAGE_GUARD, "GUARD" }, + { PAGE_NOCACHE, "NOCACHE" }, + { PAGE_WRITECOMBINE, "WRITECOMBINE" }, + + }; + return stringifyFlags(fProt, pszBuf, cbBuf, s_aProtections, RT_ELEMENTS(s_aProtections)); +} + + + +static void tstQueryVirtualMemory(void) +{ + RTTestISub("NtQueryVirtualMemory"); + + uintptr_t cbAdvance = 0; + uintptr_t uPtrWhere = 0; + for (;;) + { + SIZE_T cbActual = 0; + MEMORY_BASIC_INFORMATION MemInfo = { 0, 0, 0, 0, 0, 0, 0 }; + NTSTATUS rcNt = NtQueryVirtualMemory(g_hProcess, + (void const *)uPtrWhere, + MemoryBasicInformation, + &MemInfo, + sizeof(MemInfo), + &cbActual); + if (!NT_SUCCESS(rcNt)) + { + RTTestIPrintf(RTTESTLVL_ALWAYS, "%p: rcNt=%#x\n", uPtrWhere, rcNt); + break; + } + + /* stringify the memory state. */ + char szMemType[1024]; + char szMemState[1024]; + char szMemProt[1024]; + char szAllocProt[1024]; + + if ( MemInfo.AllocationBase != NULL + && MemInfo.AllocationBase == MemInfo.BaseAddress + && MemInfo.Protect != MemInfo.AllocationProtect) + RTTestIPrintf(RTTESTLVL_ALWAYS, "\n"); + + RTTestIPrintf(RTTESTLVL_ALWAYS, "%p-%p %-8s %-8s %-12s", + MemInfo.BaseAddress, (uintptr_t)MemInfo.BaseAddress + MemInfo.RegionSize - 1, + stringifyMemType(MemInfo.Type, szMemType, sizeof(szMemType)), + stringifyMemState(MemInfo.State, szMemState, sizeof(szMemState)), + stringifyMemProt(MemInfo.Protect, szMemProt, sizeof(szMemProt)) + ); + if ((uintptr_t)MemInfo.AllocationBase != 0) + { + if (MemInfo.AllocationBase != MemInfo.BaseAddress) + RTTestIPrintf(RTTESTLVL_ALWAYS, " %p", MemInfo.AllocationBase); + else + RTTestIPrintf(RTTESTLVL_ALWAYS, " %s", stringifyMemProt(MemInfo.AllocationProtect, szAllocProt, sizeof(szAllocProt))); + } + RTTestIPrintf(RTTESTLVL_ALWAYS, "\n"); + + if ((uintptr_t)MemInfo.BaseAddress != uPtrWhere) + RTTestIPrintf(RTTESTLVL_ALWAYS, " !Warning! Queried %p got BaseAddress=%p!\n", + uPtrWhere, MemInfo.BaseAddress); + + /* Image or mapped, then try get a file name. */ + if (MemInfo.Type == MEM_IMAGE || MemInfo.Type == MEM_MAPPED) + { + union + { + MEMORY_SECTION_NAME Core; + WCHAR awcPadding[UNICODE_STRING_MAX_CHARS + (sizeof(UNICODE_STRING_MAX_CHARS) + 1) / sizeof(WCHAR)]; + } uBuf; + RT_ZERO(uBuf); + uBuf.Core.SectionFileName.Length = UNICODE_STRING_MAX_CHARS * 2; + uBuf.Core.SectionFileName.MaximumLength = UNICODE_STRING_MAX_CHARS * 2; + uBuf.Core.SectionFileName.Buffer = &uBuf.Core.NameBuffer[0]; + + cbActual = 0; + rcNt = NtQueryVirtualMemory(g_hProcess, + (void const *)uPtrWhere, + MemorySectionName, + &uBuf, + sizeof(uBuf), + &cbActual); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, " %.*ls\n", + uBuf.Core.SectionFileName.Length / 2, uBuf.Core.SectionFileName.Buffer); + else + { + RTTestIPrintf(RTTESTLVL_ALWAYS, "%p: MemorySectionName - rcNt=%#x\n", uPtrWhere, rcNt); + RTTESTI_CHECK(rcNt == STATUS_FILE_INVALID && MemInfo.Type == MEM_MAPPED); + } + } + + /* Advance. */ + cbAdvance = MemInfo.RegionSize; + //cbAdvance = 0; + if (uPtrWhere + cbAdvance <= uPtrWhere) + break; + uPtrWhere += MemInfo.RegionSize; + } +} + + +static void tstQueryInformationProcess(void) +{ + RTTestISub("NtQueryInformationProcess"); + + NTSTATUS rcNt; + + /* Basic info */ + PROCESS_BASIC_INFORMATION BasicInfo; + RT_ZERO(BasicInfo); + DWORD cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessBasicInformation, + &BasicInfo, sizeof(BasicInfo), &cbActual); + RTTESTI_CHECK_MSG(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt)); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "BasicInfo:\n" + " UniqueProcessId = %#x (%6d)\n" + " InheritedFromUniqueProcessId = %#x (%6d)\n" + " ExitStatus = %#x\n" + " PebBaseAddress = %p\n" + " AffinityMask = %#zx\n" + " BasePriority = %#zx\n" + , + BasicInfo.UniqueProcessId, BasicInfo.UniqueProcessId, + BasicInfo.InheritedFromUniqueProcessId, BasicInfo.InheritedFromUniqueProcessId, + BasicInfo.ExitStatus, + BasicInfo.PebBaseAddress, + BasicInfo.AffinityMask, + BasicInfo.BasePriority + ); + + /* Debugger present? */ + DWORD_PTR uPtr = ~(DWORD_PTR)0; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessDebugPort, + &uPtr, sizeof(uPtr), &cbActual); + RTTESTI_CHECK_MSG(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt)); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessDebugPort: %p\n", uPtr); + + /* Debug object handle, whatever that is... */ + uPtr = ~(DWORD_PTR)0; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessDebugObjectHandle, + &uPtr, sizeof(uPtr), &cbActual); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessDebugObjectHandle: %p\n", uPtr); + else if (rcNt == STATUS_PORT_NOT_SET) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessDebugObjectHandle: rcNt=%#x (STATUS_PORT_NOT_SET)\n", uPtr); + else + RTTESTI_CHECK_MSG(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt)); + + /* 32-bit app on 64-bit host? */ + uPtr = ~(DWORD_PTR)0; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessWow64Information, + &uPtr, sizeof(uPtr), &cbActual); + RTTESTI_CHECK_MSG(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt)); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessWow64Information: %p\n", uPtr); + + /* Process image name (NT). */ + struct + { + UNICODE_STRING UniStr; + WCHAR awBuffer[UNICODE_STRING_MAX_CHARS]; + } StrBuf; + RT_ZERO(StrBuf); + StrBuf.UniStr.Length = UNICODE_STRING_MAX_CHARS * 2; + StrBuf.UniStr.MaximumLength = UNICODE_STRING_MAX_CHARS * 2; + StrBuf.UniStr.Buffer = &StrBuf.awBuffer[0]; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessImageFileName, + &StrBuf, sizeof(StrBuf), &cbActual); + RTTESTI_CHECK_MSG(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt)); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessImageFileName: len=%u\n %.*ls\n", + StrBuf.UniStr.Length, StrBuf.UniStr.Length, StrBuf.UniStr.Buffer); + + /* Process image name (Win32) - Not available on Windows 2003. */ + RT_ZERO(StrBuf); + StrBuf.UniStr.Length = UNICODE_STRING_MAX_CHARS * 2; + StrBuf.UniStr.MaximumLength = UNICODE_STRING_MAX_CHARS * 2; + StrBuf.UniStr.Buffer = &StrBuf.awBuffer[0]; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessImageFileNameWin32, + &StrBuf, sizeof(StrBuf), &cbActual); + if (rcNt != STATUS_INVALID_INFO_CLASS) + { + RTTESTI_CHECK_MSG(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt)); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessImageFileNameWin32: len=%u\n %.*ls\n", + StrBuf.UniStr.Length, StrBuf.UniStr.Length, StrBuf.UniStr.Buffer); + } + else + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessImageFileNameWin32: Not supported (STATUS_INVALID_INFO_CLASS).\n"); + + /* Process image mapping - Not available on Windows 2003. */ + uPtr = ~(DWORD_PTR)0; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessImageFileMapping, + &uPtr, sizeof(uPtr), &cbActual); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessImageFileMapping: %p\n", uPtr); + else if (rcNt == STATUS_OBJECT_TYPE_MISMATCH) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessImageFileMapping: rcNt=%#x (STATUS_OBJECT_TYPE_MISMATCH)\n", rcNt); + else if (rcNt == STATUS_INVALID_INFO_CLASS) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessImageFileMapping: Not supported (STATUS_INVALID_INFO_CLASS).\n"); + else + RTTestIFailed("ProcessImageFileMapping: rcNt=%#x\n", rcNt); + + + /* Handles. Broken for 64-bit input. */ + uint32_t u32 = UINT32_MAX; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessHandleCount, + &u32, sizeof(u32), &cbActual); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessHandleCount: %#x (%d)\n", u32, u32); + else + RTTestIFailed("ProcessHandleCount: rcNt=%#x\n", rcNt); + + /* Execute flags. */ +#if 0 /* fails... wrong process handle? */ + u32 = ~(DWORD_PTR)0; + cbActual = 0; + rcNt = NtQueryInformationProcess(g_hProcess, + ProcessExecuteFlags, + &u32, sizeof(u32), &cbActual); + if (NT_SUCCESS(rcNt)) + RTTestIPrintf(RTTESTLVL_ALWAYS, "ProcessExecuteFlags: %#p\n", u32); + else + RTTestIFailed("ProcessExecuteFlags: rcNt=%#x\n", rcNt); +#endif + + /** @todo ProcessImageInformation */ +} + + +int main(int argc, char **argv) +{ + RTEXITCODE rcExit = RTTestInitAndCreate("tstNtQueryStuff", &g_hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + RTTestBanner(g_hTest); + + g_hProcess = GetCurrentProcess(); + if (argc >= 2 && argv[1][0] != '-') + { + const char *pszPid = argv[1]; + uint32_t idPid = RTStrToInt32(pszPid); + + uint32_t fAccess = PROCESS_QUERY_INFORMATION; + if (argc >= 3) + fAccess = RTStrToInt32(argv[2]); + + g_hProcess = OpenProcess(fAccess, FALSE, idPid); + if (g_hProcess == NULL) + { + RTTestIFailed("Error %u opening process %u (%s)\n", GetLastError(), idPid, pszPid); + return RTTestSummaryAndDestroy(g_hTest); + } + } + + tstQueryVirtualMemory(); + tstQueryInformationProcess(); + + return RTTestSummaryAndDestroy(g_hTest); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstPage.cpp b/src/VBox/HostDrivers/Support/testcase/tstPage.cpp new file mode 100644 index 00000000..3ce2e237 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstPage.cpp @@ -0,0 +1,91 @@ +/* $Id: tstPage.cpp $ */ +/** @file + * SUP Testcase - Page allocation interface (ring 3). + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <VBox/param.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <string.h> + + +int main(int argc, char **argv) +{ + int cErrors = 0; + + RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); + int rc = SUPR3Init(NULL); + cErrors += rc != 0; + if (!rc) + { + void *pv; + rc = SUPR3PageAlloc(1, &pv); + cErrors += rc != 0; + if (!rc) + { + memset(pv, 0xff, PAGE_SIZE); + rc = SUPR3PageFree(pv, 1); + cErrors += rc != 0; + if (rc) + RTPrintf("tstPage: SUPR3PageFree() failed rc=%Rrc\n", rc); + } + else + RTPrintf("tstPage: SUPR3PageAlloc(1,) failed rc=%Rrc\n", rc); + + /* + * Big chunk. + */ + rc = SUPR3PageAlloc(1023, &pv); + cErrors += rc != 0; + if (!rc) + { + memset(pv, 0xfe, 1023 << PAGE_SHIFT); + rc = SUPR3PageFree(pv, 1023); + cErrors += rc != 0; + if (rc) + RTPrintf("tstPage: SUPR3PageFree() failed rc=%Rrc\n", rc); + } + else + RTPrintf("tstPage: SUPR3PageAlloc(1,) failed rc=%Rrc\n", rc); + + + //rc = SUPR3Term(); + cErrors += rc != 0; + if (rc) + RTPrintf("tstPage: SUPR3Term failed rc=%Rrc\n", rc); + } + else + RTPrintf("tstPage: SUPR3Init failed rc=%Rrc\n", rc); + + if (!cErrors) + RTPrintf("tstPage: SUCCESS\n"); + else + RTPrintf("tstPage: FAILURE - %d errors\n", cErrors); + return !!cErrors; +} diff --git a/src/VBox/HostDrivers/Support/testcase/tstPin.cpp b/src/VBox/HostDrivers/Support/testcase/tstPin.cpp new file mode 100644 index 00000000..1c9e6d92 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstPin.cpp @@ -0,0 +1,210 @@ +/* $Id: tstPin.cpp $ */ +/** @file + * SUP Testcase - Memory locking interface (ring 3). + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <VBox/param.h> +#include <iprt/errcore.h> +#include <iprt/initterm.h> +#include <iprt/stream.h> +#include <iprt/thread.h> +#include <iprt/string.h> + +#include "../SUPLibInternal.h" + + +int main(int argc, char **argv) +{ + int rc; + int rcRet = 0; + RTHCPHYS HCPhys; + + RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); + rc = SUPR3Init(NULL); + RTPrintf("SUPR3Init -> rc=%d\n", rc); + rcRet += rc != 0; + if (!rc) + { + /* + * Simple test. + */ + void *pv; + rc = SUPR3PageAlloc(1, &pv); + AssertRC(rc); + RTPrintf("pv=%p\n", pv); + SUPPAGE aPages[1]; + rc = supR3PageLock(pv, 1, &aPages[0]); + RTPrintf("rc=%d pv=%p aPages[0]=%RHp\n", rc, pv, aPages[0]); + RTThreadSleep(1500); +#if 0 + RTPrintf("Unlocking...\n"); + RTThreadSleep(250); + rc = SUPPageUnlock(pv); + RTPrintf("rc=%d\n", rc); + RTThreadSleep(1500); +#endif + + /* + * More extensive. + */ + static struct + { + void *pv; + void *pvAligned; + SUPPAGE aPages[16]; + } aPinnings[500]; + for (unsigned i = 0; i < sizeof(aPinnings) / sizeof(aPinnings[0]); i++) + { + aPinnings[i].pv = NULL; + SUPR3PageAlloc(0x10000 >> PAGE_SHIFT, &aPinnings[i].pv); + aPinnings[i].pvAligned = RT_ALIGN_P(aPinnings[i].pv, PAGE_SIZE); + rc = supR3PageLock(aPinnings[i].pvAligned, 0xf000 >> PAGE_SHIFT, &aPinnings[i].aPages[0]); + if (!rc) + { + RTPrintf("i=%d: pvAligned=%p pv=%p:\n", i, aPinnings[i].pvAligned, aPinnings[i].pv); + memset(aPinnings[i].pv, 0xfa, 0x10000); + unsigned c4GPluss = 0; + for (unsigned j = 0; j < (0xf000 >> PAGE_SHIFT); j++) + if (aPinnings[i].aPages[j].Phys >= _4G) + { + RTPrintf("%2d: vrt=%p phys=%RHp\n", j, (char *)aPinnings[i].pvAligned + (j << PAGE_SHIFT), aPinnings[i].aPages[j].Phys); + c4GPluss++; + } + RTPrintf("i=%d: c4GPluss=%d\n", i, c4GPluss); + } + else + { + RTPrintf("SUPPageLock -> rc=%d\n", rc); + rcRet++; + SUPR3PageFree(aPinnings[i].pv, 0x10000 >> PAGE_SHIFT); + aPinnings[i].pv = aPinnings[i].pvAligned = NULL; + break; + } + } + + for (unsigned i = 0; i < sizeof(aPinnings) / sizeof(aPinnings[0]); i += 2) + { + if (aPinnings[i].pvAligned) + { + rc = supR3PageUnlock(aPinnings[i].pvAligned); + if (rc) + { + RTPrintf("SUPPageUnlock(%p) -> rc=%d\n", aPinnings[i].pvAligned, rc); + rcRet++; + } + memset(aPinnings[i].pv, 0xaf, 0x10000); + } + } + + for (unsigned i = 0; i < sizeof(aPinnings) / sizeof(aPinnings[0]); i += 2) + { + if (aPinnings[i].pv) + { + memset(aPinnings[i].pv, 0xcc, 0x10000); + SUPR3PageFree(aPinnings[i].pv, 0x10000 >> PAGE_SHIFT); + aPinnings[i].pv = NULL; + } + } + + + /* + * Allocate a bit of contiguous memory. + */ + pv = SUPR3ContAlloc(RT_ALIGN_Z(15003, PAGE_SIZE) >> PAGE_SHIFT, NULL, &HCPhys); + rcRet += pv == NULL || HCPhys == 0; + if (pv && HCPhys) + { + RTPrintf("SUPR3ContAlloc(15003) -> HCPhys=%llx pv=%p\n", HCPhys, pv); + void *pv0 = pv; + memset(pv0, 0xaf, 15003); + pv = SUPR3ContAlloc(RT_ALIGN_Z(12999, PAGE_SIZE) >> PAGE_SHIFT, NULL, &HCPhys); + rcRet += pv == NULL || HCPhys == 0; + if (pv && HCPhys) + { + RTPrintf("SUPR3ContAlloc(12999) -> HCPhys=%llx pv=%p\n", HCPhys, pv); + memset(pv, 0xbf, 12999); + rc = SUPR3ContFree(pv, RT_ALIGN_Z(12999, PAGE_SIZE) >> PAGE_SHIFT); + rcRet += rc != 0; + if (rc) + RTPrintf("SUPR3ContFree failed! rc=%d\n", rc); + } + else + RTPrintf("SUPR3ContAlloc (2nd) failed!\n"); + memset(pv0, 0xaf, 15003); + /* pv0 is intentionally not freed! */ + } + else + RTPrintf("SUPR3ContAlloc failed!\n"); + + /* + * Allocate a big chunk of virtual memory and then lock it. + */ + #define BIG_SIZE 72*1024*1024 + #define BIG_SIZEPP (BIG_SIZE + PAGE_SIZE) + pv = NULL; + SUPR3PageAlloc(BIG_SIZEPP >> PAGE_SHIFT, &pv); + if (pv) + { + static SUPPAGE s_aPages[BIG_SIZE >> PAGE_SHIFT]; + void *pvAligned = RT_ALIGN_P(pv, PAGE_SIZE); + rc = supR3PageLock(pvAligned, BIG_SIZE >> PAGE_SHIFT, &s_aPages[0]); + if (!rc) + { + /* dump */ + RTPrintf("SUPPageLock(%p,%d,) succeeded!\n", pvAligned, BIG_SIZE); + memset(pv, 0x42, BIG_SIZEPP); + #if 0 + for (unsigned j = 0; j < (BIG_SIZE >> PAGE_SHIFT); j++) + RTPrintf("%2d: vrt=%p phys=%08x\n", j, (char *)pvAligned + (j << PAGE_SHIFT), (uintptr_t)s_aPages[j].pvPhys); + #endif + + /* unlock */ + rc = supR3PageUnlock(pvAligned); + if (rc) + { + RTPrintf("SUPPageUnlock(%p) -> rc=%d\n", pvAligned, rc); + rcRet++; + } + memset(pv, 0xcc, BIG_SIZEPP); + } + else + { + RTPrintf("SUPPageLock(%p) -> rc=%d\n", pvAligned, rc); + rcRet++; + } + SUPR3PageFree(pv, BIG_SIZEPP >> PAGE_SHIFT); + } + + rc = SUPR3Term(false /*fForced*/); + RTPrintf("SUPR3Term -> rc=%d\n", rc); + rcRet += rc != 0; + } + + return rcRet; +} diff --git a/src/VBox/HostDrivers/Support/testcase/tstSupLoadModule.cpp b/src/VBox/HostDrivers/Support/testcase/tstSupLoadModule.cpp new file mode 100644 index 00000000..ab45551a --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstSupLoadModule.cpp @@ -0,0 +1,118 @@ +/* $Id: tstSupLoadModule.cpp $ */ +/** @file + * SUP Testcase - Test SUPR3LoadModule. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> + +#include <iprt/getopt.h> +#include <iprt/initterm.h> +#include <iprt/mem.h> +#include <iprt/message.h> +#include <iprt/path.h> +#include <iprt/stream.h> + + +int main(int argc, char **argv) +{ + /* + * Init. + */ + int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + + /* + * Process arguments. + */ + static const RTGETOPTDEF s_aOptions[] = + { + { "--keep", 'k', RTGETOPT_REQ_NOTHING }, + { "--no-keep", 'n', RTGETOPT_REQ_NOTHING }, + }; + + bool fKeepLoaded = false; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + switch (ch) + { + case VINF_GETOPT_NOT_OPTION: + { + void *pvImageBase; + RTERRINFOSTATIC ErrInfo; + RTErrInfoInitStatic(&ErrInfo); + rc = SUPR3LoadModule(ValueUnion.psz, RTPathFilename(ValueUnion.psz), &pvImageBase, &ErrInfo.Core); + if (RT_FAILURE(rc)) + { + RTMsgError("%Rrc when attempting to load '%s': %s\n", rc, ValueUnion.psz, ErrInfo.Core.pszMsg); + return 1; + } + RTPrintf("Loaded '%s' at %p\n", ValueUnion.psz, pvImageBase); + + if (!fKeepLoaded) + { + rc = SUPR3FreeModule(pvImageBase); + if (RT_FAILURE(rc)) + { + RTMsgError("%Rrc when attempting to load '%s'\n", rc, ValueUnion.psz); + return 1; + } + } + break; + } + + case 'k': + fKeepLoaded = true; + break; + + case 'n': + fKeepLoaded = false; + break; + + case 'h': + RTPrintf("%s [mod1 [mod2...]]\n", argv[0]); + return 1; + + case 'V': + RTPrintf("$Revision: 127855 $\n"); + return 0; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + + return 0; +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstSupSem-Zombie.cpp b/src/VBox/HostDrivers/Support/testcase/tstSupSem-Zombie.cpp new file mode 100644 index 00000000..7344b403 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstSupSem-Zombie.cpp @@ -0,0 +1,222 @@ +/* $Id: tstSupSem-Zombie.cpp $ */ +/** @file + * Support Library Testcase - Ring-3 Semaphore interface - Zombie bugs. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> + +#include <VBox/param.h> +#include <iprt/env.h> +#include <iprt/errcore.h> +#include <iprt/initterm.h> +#include <iprt/process.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/test.h> +#include <iprt/time.h> +#include <iprt/thread.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +static PSUPDRVSESSION g_pSession; +static RTTEST g_hTest; + + + +static DECLCALLBACK(int) tstSupSemSRETimed(RTTHREAD hSelf, void *pvUser) +{ + SUPSEMEVENT hEvent = (SUPSEMEVENT)pvUser; + RTThreadUserSignal(hSelf); + int rc = SUPSemEventWaitNoResume(g_pSession, hEvent, 120*1000); + AssertReleaseMsgFailed(("%Rrc\n", rc)); + return rc; +} + + +static DECLCALLBACK(int) tstSupSemMRETimed(RTTHREAD hSelf, void *pvUser) +{ + SUPSEMEVENTMULTI hEventMulti = (SUPSEMEVENTMULTI)pvUser; + RTThreadUserSignal(hSelf); + int rc = SUPSemEventMultiWaitNoResume(g_pSession, hEventMulti, 120*1000); + AssertReleaseMsgFailed(("%Rrc\n", rc)); + return rc; +} + + +static DECLCALLBACK(int) tstSupSemSREInf(RTTHREAD hSelf, void *pvUser) +{ + SUPSEMEVENT hEvent = (SUPSEMEVENT)pvUser; + RTThreadUserSignal(hSelf); + int rc = SUPSemEventWaitNoResume(g_pSession, hEvent, RT_INDEFINITE_WAIT); + AssertReleaseMsgFailed(("%Rrc\n", rc)); + return rc; +} + + +static DECLCALLBACK(int) tstSupSemMREInf(RTTHREAD hSelf, void *pvUser) +{ + SUPSEMEVENTMULTI hEventMulti = (SUPSEMEVENTMULTI)pvUser; + RTThreadUserSignal(hSelf); + int rc = SUPSemEventMultiWaitNoResume(g_pSession, hEventMulti, RT_INDEFINITE_WAIT); + AssertReleaseMsgFailed(("%Rrc\n", rc)); + return rc; +} + +static int mainChild(void) +{ + /* + * Init. + */ + int rc = RTR3InitExeNoArguments(RTR3INIT_FLAGS_SUPLIB); + if (RT_FAILURE(rc)) + { + RTPrintf("tstSupSem-Zombie-Child: fatal error: RTR3InitExeNoArguments failed with rc=%Rrc\n", rc); + return 1; + } + + RTTEST hTest; + rc = RTTestCreate("tstSupSem-Zombie-Child", &hTest); + if (RT_FAILURE(rc)) + { + RTPrintf("tstSupSem-Zombie-Child: fatal error: RTTestCreate failed with rc=%Rrc\n", rc); + return 1; + } + g_hTest = hTest; + + PSUPDRVSESSION pSession; + rc = SUPR3Init(&pSession); + if (RT_FAILURE(rc)) + { + RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc); + return RTTestSummaryAndDestroy(hTest); + } + g_pSession = pSession; + + /* + * A semaphore of each kind and throw a bunch of threads on them. + */ + SUPSEMEVENT hEvent = NIL_SUPSEMEVENT; + RTTESTI_CHECK_RC(rc = SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + if (RT_SUCCESS(rc)) + { + SUPSEMEVENTMULTI hEventMulti = NIL_SUPSEMEVENT; + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); + if (RT_SUCCESS(rc)) + { + for (uint32_t cThreads = 0; cThreads < 5; cThreads++) + { + RTTHREAD hThread; + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemSRETimed, (void *)hEvent, 0, RTTHREADTYPE_TIMER, 0 /*fFlags*/, "IntSRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemMRETimed, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, 0 /*fFlags*/, "IntMRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemSREInf, (void *)hEvent, 0, RTTHREADTYPE_TIMER, 0 /*fFlags*/, "IntSRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemMREInf, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, 0 /*fFlags*/, "IntMRE"), VINF_SUCCESS); + RTThreadSleep(2); + } + RTThreadSleep(50); + + /* + * This is where the test really starts... + */ + return 0; + } + } + + return RTTestSummaryAndDestroy(hTest); +} + + +/** + * The parent main routine. + * @param argv0 The executable name (or whatever). + */ +static int mainParent(const char *argv0) +{ + /* + * Init. + */ + RTTEST hTest; + int rc = RTTestInitAndCreate("tstSupSem-Zombie", &hTest); + if (rc) + return rc; + RTTestBanner(hTest); + + /* + * Spin of the child process which may or may not turn into a zombie + */ + for (uint32_t iPass = 0; iPass < 32; iPass++) + { + RTTestSubF(hTest, "Pass %u", iPass); + + RTPROCESS hProcess; + const char *apszArgs[3] = { argv0, "--child", NULL }; + RTTESTI_CHECK_RC_OK(rc = RTProcCreate(argv0, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &hProcess)); + if (RT_SUCCESS(rc)) + { + /* + * Wait for 60 seconds then give up. + */ + RTPROCSTATUS Status; + uint64_t StartTS = RTTimeMilliTS(); + for (;;) + { + rc = RTProcWait(hProcess, RTPROCWAIT_FLAGS_NOBLOCK, &Status); + if (RT_SUCCESS(rc)) + break; + uint64_t cElapsed = RTTimeMilliTS() - StartTS; + if (cElapsed > 60*1000) + break; + RTThreadSleep(cElapsed < 60 ? 30 : cElapsed < 200 ? 10 : 100); + } + RTTESTI_CHECK_RC_OK(rc); + if ( RT_SUCCESS(rc) + && ( Status.enmReason != RTPROCEXITREASON_NORMAL + || Status.iStatus != 0)) + { + RTTestIFailed("child %d (%#x) reason %d\n", Status.iStatus, Status.iStatus, Status.enmReason); + rc = VERR_PERMISSION_DENIED; + } + } + /* one zombie process is enough. */ + if (RT_FAILURE(rc)) + break; + } + + return RTTestSummaryAndDestroy(hTest); +} + + +int main(int argc, char **argv) +{ + if ( argc == 2 + && !strcmp(argv[1], "--child")) + return mainChild(); + return mainParent(argv[0]); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstSupSem.cpp b/src/VBox/HostDrivers/Support/testcase/tstSupSem.cpp new file mode 100644 index 00000000..ec89818e --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstSupSem.cpp @@ -0,0 +1,639 @@ +/* $Id: tstSupSem.cpp $ */ +/** @file + * Support Library Testcase - Ring-3 Semaphore interface. + */ + +/* + * Copyright (C) 2009-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> + +#include <VBox/param.h> +#include <iprt/err.h> +#include <iprt/initterm.h> +#include <iprt/message.h> +#include <iprt/stream.h> +#include <iprt/test.h> +#include <iprt/thread.h> +#include <iprt/process.h> +#include <iprt/env.h> +#include <iprt/string.h> +#include <iprt/time.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +static PSUPDRVSESSION g_pSession; +static RTTEST g_hTest; +static uint32_t g_cMillies; /* Used by the interruptible tests. */ + + + +static DECLCALLBACK(int) tstSupSemInterruptibleSRE(RTTHREAD hSelf, void *pvUser) +{ + SUPSEMEVENT hEvent = (SUPSEMEVENT)pvUser; + RTThreadUserSignal(hSelf); + return SUPSemEventWaitNoResume(g_pSession, hEvent, g_cMillies); +} + + +static DECLCALLBACK(int) tstSupSemInterruptibleMRE(RTTHREAD hSelf, void *pvUser) +{ + SUPSEMEVENTMULTI hEventMulti = (SUPSEMEVENTMULTI)pvUser; + RTThreadUserSignal(hSelf); + return SUPSemEventMultiWaitNoResume(g_pSession, hEventMulti, g_cMillies); +} + + +int main(int argc, char **argv) +{ + bool fSys = true; + bool fGip = false; +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + fGip = true; +#endif + + /* + * Init. + */ + int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + + if (argc == 2 && !strcmp(argv[1], "child")) + { + RTThreadSleep(300); + return 0; + } + + RTTEST hTest; + rc = RTTestCreate("tstSupSem", &hTest); + if (RT_FAILURE(rc)) + { + RTPrintf("tstSupSem: fatal error: RTTestCreate failed with rc=%Rrc\n", rc); + return 1; + } + g_hTest = hTest; + + PSUPDRVSESSION pSession; + rc = SUPR3Init(&pSession); + if (RT_FAILURE(rc)) + { + RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc); + return RTTestSummaryAndDestroy(hTest); + } + g_pSession = pSession; + RTTestBanner(hTest); + + /* + * Basic API checks. + */ + RTTestSub(hTest, "Single Release Event (SRE) API"); + SUPSEMEVENT hEvent = NIL_SUPSEMEVENT; + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,20), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 20), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,1000),VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 0), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 1), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 2), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent, 8), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventWaitNoResume(pSession, hEvent,20), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VERR_INVALID_HANDLE); + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, NIL_SUPSEMEVENT), VINF_SUCCESS); + + RTTestSub(hTest, "Multiple Release Event (MRE) API"); + SUPSEMEVENTMULTI hEventMulti = NIL_SUPSEMEVENT; + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,1000), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiReset(pSession, hEventMulti), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,20), VERR_TIMEOUT); + RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEventMulti), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 0), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 1), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 2), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 8), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti, 20), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiWaitNoResume(pSession, hEventMulti,1000), VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED); + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VERR_INVALID_HANDLE); + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, NIL_SUPSEMEVENTMULTI), VINF_SUCCESS); + +#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS) + RTTestSub(hTest, "SRE Interruptibility"); + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + g_cMillies = RT_INDEFINITE_WAIT; + RTTHREAD hThread = NIL_RTTHREAD; + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); + RTThreadSleep(120); + RTThreadPoke(hThread); + int rcThread = VINF_SUCCESS; + RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + g_cMillies = 120*1000; + hThread = NIL_RTTHREAD; + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); + RTThreadSleep(120); + RTThreadPoke(hThread); + rcThread = VINF_SUCCESS; + RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + + + RTTestSub(hTest, "MRE Interruptibility"); + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); + g_cMillies = RT_INDEFINITE_WAIT; + hThread = NIL_RTTHREAD; + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntMRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); + RTThreadSleep(120); + RTThreadPoke(hThread); + rcThread = VINF_SUCCESS; + RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED); + + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEventMulti), VINF_SUCCESS); + g_cMillies = 120*1000; + hThread = NIL_RTTHREAD; + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEventMulti, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntMRE"), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadUserWait(hThread, 60*1000), VINF_SUCCESS); + RTThreadSleep(120); + RTThreadPoke(hThread); + rcThread = VINF_SUCCESS; + RTTESTI_CHECK_RC(RTThreadWait(hThread, 60*1000, &rcThread), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread, VERR_INTERRUPTED); + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEventMulti), VINF_OBJECT_DESTROYED); + + /* + * Fork test. + * Spawn a thread waiting for an event, then spawn a new child process (of + * ourselves) and make sure that this does not alter the intended behaviour + * of our event semaphore implementation (see @bugref{5090}). + */ + RTTestSub(hTest, "SRE Process Spawn"); + hThread = NIL_RTTHREAD; + g_cMillies = 120*1000; + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleSRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); + + const char *apszArgs[3] = { argv[0], "child", NULL }; + RTPROCESS Process = NIL_RTPROCESS; + RTThreadSleep(250); + RTTESTI_CHECK_RC(RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &Process), VINF_SUCCESS); + + RTThreadSleep(250); + RTTESTI_CHECK_RC(SUPSemEventSignal(pSession, hEvent), VINF_SUCCESS); + + rcThread = VERR_GENERAL_FAILURE; + RTTESTI_CHECK_RC(RTThreadWait(hThread, 120*1000, &rcThread), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS); + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + + + RTTestSub(hTest, "MRE Process Spawn"); + hThread = NIL_RTTHREAD; + g_cMillies = 120*1000; + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); + RTTESTI_CHECK_RC(RTThreadCreate(&hThread, tstSupSemInterruptibleMRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); + + RTTHREAD hThread2 = NIL_RTTHREAD; + RTTESTI_CHECK_RC(RTThreadCreate(&hThread2, tstSupSemInterruptibleMRE, (void *)hEvent, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "IntSRE"), VINF_SUCCESS); + + Process = NIL_RTPROCESS; + RTThreadSleep(250); + RTTESTI_CHECK_RC(RTProcCreate(apszArgs[0], apszArgs, RTENV_DEFAULT, 0, &Process), VINF_SUCCESS); + + RTThreadSleep(250); + RTTESTI_CHECK_RC(SUPSemEventMultiSignal(pSession, hEvent), VINF_SUCCESS); + + rcThread = VERR_GENERAL_FAILURE; + RTTESTI_CHECK_RC(RTThreadWait(hThread, 120*1000, &rcThread), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread, VINF_SUCCESS); + + int rcThread2 = VERR_GENERAL_FAILURE; + RTTESTI_CHECK_RC(RTThreadWait(hThread2, 120*1000, &rcThread2), VINF_SUCCESS); + RTTESTI_CHECK_RC(rcThread2, VINF_SUCCESS); + + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + +#endif /* !OS2 && !WINDOWS */ + + { + +#define LOOP_COUNT 20 + static unsigned const s_acMsIntervals[] = { 0, 1, 2, 3, 4, 8, 10, 16, 32 }; + if (RTTestErrorCount(hTest) == 0) + { + RTTestSub(hTest, "SRE Timeout Accuracy (ms)"); + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + + uint32_t cInterrupted = 0; + for (unsigned i = 0; i < RT_ELEMENTS(s_acMsIntervals); i++) + { + uint64_t cMs = s_acMsIntervals[i]; + uint64_t cNsMinSys = UINT64_MAX; + uint64_t cNsMin = UINT64_MAX; + uint64_t cNsTotalSys= 0; + uint64_t cNsTotal = 0; + unsigned cLoops = 0; + while (cLoops < LOOP_COUNT) + { + uint64_t u64StartSys = RTTimeSystemNanoTS(); + uint64_t u64Start = RTTimeNanoTS(); + int rcX = SUPSemEventWaitNoResume(pSession, hEvent, cMs); + uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; + uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; + + if (rcX == VERR_INTERRUPTED) + { + cInterrupted++; + continue; /* retry */ + } + if (rcX != VERR_TIMEOUT) + RTTestFailed(hTest, "%Rrc cLoops=%u cMs=%u", rcX, cLoops, cMs); + + if (cNsElapsedSys < cNsMinSys) + cNsMinSys = cNsElapsedSys; + if (cNsElapsed < cNsMin) + cNsMin = cNsElapsed; + cNsTotalSys += cNsElapsedSys; + cNsTotal += cNsElapsed; + cLoops++; + } + if (fSys) + { + RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%u ms min (clock=sys)", cMs); + RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=sys)", cMs); + } + if (fGip) + { + RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%u ms min (clock=gip)", cMs); + RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=gip)", cMs); + } + } + + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); + } + + if (RTTestErrorCount(hTest) == 0) + { + RTTestSub(hTest, "MRE Timeout Accuracy (ms)"); + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); + + uint32_t cInterrupted = 0; + for (unsigned i = 0; i < RT_ELEMENTS(s_acMsIntervals); i++) + { + uint64_t cMs = s_acMsIntervals[i]; + uint64_t cNsMinSys = UINT64_MAX; + uint64_t cNsMin = UINT64_MAX; + uint64_t cNsTotalSys= 0; + uint64_t cNsTotal = 0; + unsigned cLoops = 0; + while (cLoops < LOOP_COUNT) + { + uint64_t u64StartSys = RTTimeSystemNanoTS(); + uint64_t u64Start = RTTimeNanoTS(); + int rcX = SUPSemEventMultiWaitNoResume(pSession, hEvent, cMs); + uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; + uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; + + if (rcX == VERR_INTERRUPTED) + { + cInterrupted++; + continue; /* retry */ + } + if (rcX != VERR_TIMEOUT) + RTTestFailed(hTest, "%Rrc cLoops=%u cMs=%u", rcX, cLoops, cMs); + + if (cNsElapsedSys < cNsMinSys) + cNsMinSys = cNsElapsedSys; + if (cNsElapsed < cNsMin) + cNsMin = cNsElapsed; + cNsTotalSys += cNsElapsedSys; + cNsTotal += cNsElapsed; + cLoops++; + } + if (fSys) + { + RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%u ms min (clock=sys)", cMs); + RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=sys)", cMs); + } + if (fGip) + { + RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%u ms min (clock=gip)", cMs); + RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%u ms avg (clock=gip)", cMs); + } + } + + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); + } + } + + { + static uint32_t const s_acNsIntervals[] = + { + 0, 1000, 5000, 15000, 30000, 50000, 100000, 250000, 500000, 750000, 900000, 1500000, 2200000 + }; + + if (RTTestErrorCount(hTest) == 0) + { + RTTestSub(hTest, "SUPSemEventWaitNsRelIntr Accuracy"); + RTTestValueF(hTest, SUPSemEventGetResolution(pSession), RTTESTUNIT_NS, "SRE resolution"); + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + + uint32_t cInterrupted = 0; + for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) + { + uint64_t cNs = s_acNsIntervals[i]; + uint64_t cNsMinSys = UINT64_MAX; + uint64_t cNsMin = UINT64_MAX; + uint64_t cNsTotalSys= 0; + uint64_t cNsTotal = 0; + unsigned cLoops = 0; + while (cLoops < LOOP_COUNT) + { + uint64_t u64StartSys = RTTimeSystemNanoTS(); + uint64_t u64Start = RTTimeNanoTS(); + int rcX = SUPSemEventWaitNsRelIntr(pSession, hEvent, cNs); + uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; + uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; + + if (rcX == VERR_INTERRUPTED) + { + cInterrupted++; + continue; /* retry */ + } + if (rcX != VERR_TIMEOUT) + RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); + + if (cNsElapsedSys < cNsMinSys) + cNsMinSys = cNsElapsedSys; + if (cNsElapsed < cNsMin) + cNsMin = cNsElapsed; + cNsTotalSys += cNsElapsedSys; + cNsTotal += cNsElapsed; + cLoops++; + } + if (fSys) + { + RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); + RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); + } + if (fGip) + { + RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); + RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); + } + } + + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); + } + + if (RTTestErrorCount(hTest) == 0) + { + RTTestSub(hTest, "SUPSemEventMultiWaitNsRelIntr Accuracy"); + RTTestValueF(hTest, SUPSemEventMultiGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution"); + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); + + uint32_t cInterrupted = 0; + for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) + { + uint64_t cNs = s_acNsIntervals[i]; + uint64_t cNsMinSys = UINT64_MAX; + uint64_t cNsMin = UINT64_MAX; + uint64_t cNsTotalSys= 0; + uint64_t cNsTotal = 0; + unsigned cLoops = 0; + while (cLoops < LOOP_COUNT) + { + uint64_t u64StartSys = RTTimeSystemNanoTS(); + uint64_t u64Start = RTTimeNanoTS(); + int rcX = SUPSemEventMultiWaitNsRelIntr(pSession, hEvent, cNs); + uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; + uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; + + if (rcX == VERR_INTERRUPTED) + { + cInterrupted++; + continue; /* retry */ + } + if (rcX != VERR_TIMEOUT) + RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); + + if (cNsElapsedSys < cNsMinSys) + cNsMinSys = cNsElapsedSys; + if (cNsElapsed < cNsMin) + cNsMin = cNsElapsed; + cNsTotalSys += cNsElapsedSys; + cNsTotal += cNsElapsed; + cLoops++; + } + if (fSys) + { + RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); + RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); + } + if (fGip) + { + RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); + RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); + } + } + + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); + } + + if (RTTestErrorCount(hTest) == 0) + { + RTTestSub(hTest, "SUPSemEventWaitNsAbsIntr Accuracy"); + RTTestValueF(hTest, SUPSemEventGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution"); + RTTESTI_CHECK_RC(SUPSemEventCreate(pSession, &hEvent), VINF_SUCCESS); + + uint32_t cInterrupted = 0; + for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) + { + uint64_t cNs = s_acNsIntervals[i]; + uint64_t cNsMinSys = UINT64_MAX; + uint64_t cNsMin = UINT64_MAX; + uint64_t cNsTotalSys= 0; + uint64_t cNsTotal = 0; + unsigned cLoops = 0; + while (cLoops < LOOP_COUNT) + { + uint64_t u64StartSys = RTTimeSystemNanoTS(); + uint64_t u64Start = RTTimeNanoTS(); + uint64_t uAbsDeadline = (fGip ? u64Start : u64StartSys) + cNs; + int rcX = SUPSemEventWaitNsAbsIntr(pSession, hEvent, uAbsDeadline); + uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; + uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; + + if (rcX == VERR_INTERRUPTED) + { + cInterrupted++; + continue; /* retry */ + } + if (rcX != VERR_TIMEOUT) + RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); + + if (cNsElapsedSys < cNsMinSys) + cNsMinSys = cNsElapsedSys; + if (cNsElapsed < cNsMin) + cNsMin = cNsElapsed; + cNsTotalSys += cNsElapsedSys; + cNsTotal += cNsElapsed; + cLoops++; + } + if (fSys) + { + RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); + RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); + } + if (fGip) + { + RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); + RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); + } + } + + RTTESTI_CHECK_RC(SUPSemEventClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); + } + + + if (RTTestErrorCount(hTest) == 0) + { + RTTestSub(hTest, "SUPSemEventMultiWaitNsAbsIntr Accuracy"); + RTTestValueF(hTest, SUPSemEventMultiGetResolution(pSession), RTTESTUNIT_NS, "MRE resolution"); + RTTESTI_CHECK_RC(SUPSemEventMultiCreate(pSession, &hEvent), VINF_SUCCESS); + + uint32_t cInterrupted = 0; + for (unsigned i = 0; i < RT_ELEMENTS(s_acNsIntervals); i++) + { + uint64_t cNs = s_acNsIntervals[i]; + uint64_t cNsMinSys = UINT64_MAX; + uint64_t cNsMin = UINT64_MAX; + uint64_t cNsTotalSys= 0; + uint64_t cNsTotal = 0; + unsigned cLoops = 0; + while (cLoops < LOOP_COUNT) + { + uint64_t u64StartSys = RTTimeSystemNanoTS(); + uint64_t u64Start = RTTimeNanoTS(); + uint64_t uAbsDeadline = (fGip ? u64Start : u64StartSys) + cNs; + int rcX = SUPSemEventMultiWaitNsAbsIntr(pSession, hEvent, uAbsDeadline); + uint64_t cNsElapsedSys = RTTimeSystemNanoTS() - u64StartSys; + uint64_t cNsElapsed = RTTimeNanoTS() - u64Start; + + if (rcX == VERR_INTERRUPTED) + { + cInterrupted++; + continue; /* retry */ + } + if (rcX != VERR_TIMEOUT) + RTTestFailed(hTest, "%Rrc cLoops=%u cNs=%u", rcX, cLoops, cNs); + + if (cNsElapsedSys < cNsMinSys) + cNsMinSys = cNsElapsedSys; + if (cNsElapsed < cNsMin) + cNsMin = cNsElapsed; + cNsTotalSys += cNsElapsedSys; + cNsTotal += cNsElapsed; + cLoops++; + } + if (fSys) + { + RTTestValueF(hTest, cNsMinSys, RTTESTUNIT_NS, "%'u ns min (clock=sys)", cNs); + RTTestValueF(hTest, cNsTotalSys / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=sys)", cNs); + } + if (fGip) + { + RTTestValueF(hTest, cNsMin, RTTESTUNIT_NS, "%'u ns min (clock=gip)", cNs); + RTTestValueF(hTest, cNsTotal / cLoops, RTTESTUNIT_NS, "%'u ns avg (clock=gip)", cNs); + } + } + + RTTESTI_CHECK_RC(SUPSemEventMultiClose(pSession, hEvent), VINF_OBJECT_DESTROYED); + RTTestValueF(hTest, cInterrupted, RTTESTUNIT_OCCURRENCES, "VERR_INTERRUPTED returned"); + } + + } + + + /* + * Done. + */ + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstSupTscDelta.cpp b/src/VBox/HostDrivers/Support/testcase/tstSupTscDelta.cpp new file mode 100644 index 00000000..60086d7d --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstSupTscDelta.cpp @@ -0,0 +1,225 @@ +/* $Id: tstSupTscDelta.cpp $ */ +/** @file + * SUP Testcase - Global Info Page TSC Delta Measurement Utility. + */ + +/* + * Copyright (C) 2015-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> +#include <iprt/assert.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/getopt.h> +#include <iprt/test.h> +#include <iprt/thread.h> + + + +int main(int argc, char **argv) +{ + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitExAndCreate(argc, &argv, 0 /*fRtInit*/, "tstSupTscDelta", &hTest); + if (rcExit != RTEXITCODE_SUCCESS) + return rcExit; + + /* + * Parse args + */ + static const RTGETOPTDEF g_aOptions[] = + { + { "--iterations", 'i', RTGETOPT_REQ_INT32 }, + { "--delay", 'd', RTGETOPT_REQ_INT32 }, + }; + + uint32_t cIterations = 0; /* Currently 0 so that it doesn't upset testing. */ + uint32_t cMsSleepBetweenIterations = 10; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + switch (ch) + { + case 'd': + cMsSleepBetweenIterations = ValueUnion.u32; + break; + case 'i': + cIterations = ValueUnion.u32; + break; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + if (!cIterations) + return RTTestSkipAndDestroy(hTest, "Nothing to do. The --iterations argument is 0 or not given."); + + /* + * Init + */ + PSUPDRVSESSION pSession = NIL_RTR0PTR; + int rc = SUPR3Init(&pSession); + if (RT_SUCCESS(rc)) + { + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (pGip) + { + if (pGip->enmUseTscDelta < SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) + return RTTestSkipAndDestroy(hTest, "No deltas to play with: enmUseTscDelta=%d\n", pGip->enmUseTscDelta); + + /* + * Init stats. + */ + struct + { + int64_t iLowest; + int64_t iHighest; + int64_t iTotal; + uint64_t uAbsMin; + uint64_t uAbsMax; + uint64_t uAbsTotal; + } aCpuStats[RTCPUSET_MAX_CPUS]; + RT_ZERO(aCpuStats); + for (uint32_t i = 0; i < pGip->cCpus; i++) + { + aCpuStats[i].iLowest = INT64_MAX; + aCpuStats[i].iHighest = INT64_MIN; + aCpuStats[i].uAbsMin = UINT64_MAX; + } + + /* + * Do the work. + */ + for (uint32_t iIteration = 0; ; iIteration++) + { + /* + * Display the current deltas and gather statistics. + */ + RTPrintf("tstSupTscDelta: Iteration #%u results:", iIteration); + for (uint32_t iCpu = 0; iCpu < pGip->cCpus; iCpu++) + { + int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; + + /* print */ + if ((iCpu % 4) == 0) + RTPrintf("\ntstSupTscDelta:"); + if (pGip->aCPUs[iCpu].enmState != SUPGIPCPUSTATE_ONLINE) + RTPrintf(" %02x: offline ", iCpu); + else if (iTscDelta != INT64_MAX) + RTPrintf(" %02x: %-12lld", iCpu, iTscDelta); + else + RTPrintf(" %02x: INT64_MAX ", iCpu); + + /* stats */ + if ( iTscDelta != INT64_MAX + && pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE) + { + if (aCpuStats[iCpu].iLowest > iTscDelta) + aCpuStats[iCpu].iLowest = iTscDelta; + if (aCpuStats[iCpu].iHighest < iTscDelta) + aCpuStats[iCpu].iHighest = iTscDelta; + aCpuStats[iCpu].iTotal += iTscDelta; + + uint64_t uAbsTscDelta = iTscDelta >= 0 ? (uint64_t)iTscDelta : (uint64_t)-iTscDelta; + if (aCpuStats[iCpu].uAbsMin > uAbsTscDelta) + aCpuStats[iCpu].uAbsMin = uAbsTscDelta; + if (aCpuStats[iCpu].uAbsMax < uAbsTscDelta) + aCpuStats[iCpu].uAbsMax = uAbsTscDelta; + aCpuStats[iCpu].uAbsTotal += uAbsTscDelta; + } + } + if (((pGip->cCpus - 1) % 4) != 0) + RTPrintf("\n"); + + /* + * Done? + */ + if (iIteration + 1 >= cIterations) + break; + + /* + * Force a new measurement. + */ + RTThreadSleep(cMsSleepBetweenIterations); + for (uint32_t iCpu = 0; iCpu < pGip->cCpus; iCpu++) + if (pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE) + { + rc = SUPR3TscDeltaMeasure(pGip->aCPUs[iCpu].idCpu, false /*fAsync*/, true /*fForce*/, 64, 16 /*ms*/); + if (RT_FAILURE(rc)) + RTTestFailed(hTest, "SUPR3TscDeltaMeasure failed on %#x: %Rrc", pGip->aCPUs[iCpu].idCpu, rc); + } + } + + /* + * Display statistics that we've gathered. + */ + RTPrintf("tstSupTscDelta: Results:\n"); + int64_t iLowest = INT64_MAX; + int64_t iHighest = INT64_MIN; + int64_t iTotal = 0; + uint32_t cTotal = 0; + for (uint32_t iCpu = 0; iCpu < pGip->cCpus; iCpu++) + { + if (pGip->aCPUs[iCpu].enmState != SUPGIPCPUSTATE_ONLINE) + RTPrintf("tstSupTscDelta: %02x: offline\n", iCpu); + else + { + RTPrintf("tstSupTscDelta: %02x: lowest=%-12lld highest=%-12lld average=%-12lld spread=%-12lld\n", + iCpu, + aCpuStats[iCpu].iLowest, + aCpuStats[iCpu].iHighest, + aCpuStats[iCpu].iTotal / cIterations, + aCpuStats[iCpu].iHighest - aCpuStats[iCpu].iLowest); + RTPrintf( "tstSupTscDelta: absmin=%-12llu absmax=%-12llu absavg=%-12llu idCpu=%#4x idApic=%#4x\n", + aCpuStats[iCpu].uAbsMin, + aCpuStats[iCpu].uAbsMax, + aCpuStats[iCpu].uAbsTotal / cIterations, + pGip->aCPUs[iCpu].idCpu, + pGip->aCPUs[iCpu].idApic); + if (iLowest > aCpuStats[iCpu].iLowest) + iLowest = aCpuStats[iCpu].iLowest; + if (iHighest < aCpuStats[iCpu].iHighest) + iHighest = aCpuStats[iCpu].iHighest; + iTotal += aCpuStats[iCpu].iHighest; + cTotal += cIterations; + } + } + RTPrintf("tstSupTscDelta: all: lowest=%-12lld highest=%-12lld average=%-12lld spread=%-12lld\n", + iLowest, iHighest, iTotal / cTotal, iHighest - iLowest); + } + else + RTTestFailed(hTest, "g_pSUPGlobalInfoPage is NULL"); + + SUPR3Term(false /*fForced*/); + } + else + RTTestFailed(hTest, "SUPR3Init failed: %Rrc", rc); + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/HostDrivers/Support/testcase/tstSupVerify.cpp b/src/VBox/HostDrivers/Support/testcase/tstSupVerify.cpp new file mode 100644 index 00000000..036b7cd1 --- /dev/null +++ b/src/VBox/HostDrivers/Support/testcase/tstSupVerify.cpp @@ -0,0 +1,100 @@ +/* $Id: tstSupVerify.cpp $ */ +/** @file + * SUP Testcase - Test SUPR3HardenedVerifyPlugIn. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/sup.h> +#include <iprt/errcore.h> + +#include <iprt/getopt.h> +#include <iprt/initterm.h> +#include <iprt/mem.h> +#include <iprt/message.h> +#include <iprt/path.h> +#include <iprt/stream.h> + + +int main(int argc, char **argv) +{ + /* + * Init. + */ + int rc = RTR3InitExe(argc, &argv, 0); + if (RT_FAILURE(rc)) + return RTMsgInitFailure(rc); + rc = SUPR3HardenedVerifyInit(); + if (RT_FAILURE(rc)) + return RTMsgErrorExit(RTEXITCODE_FAILURE, "SUPR3HardenedVerifyInit failed: %Rrc", rc); + + /* + * Process arguments. + */ + static const RTGETOPTDEF s_aOptions[] = + { + { "--dummy", 'd', RTGETOPT_REQ_NOTHING }, + }; + + //bool fKeepLoaded = false; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0); + while ((ch = RTGetOpt(&GetState, &ValueUnion))) + { + switch (ch) + { + case VINF_GETOPT_NOT_OPTION: + { + RTERRINFOSTATIC ErrInfo; + RTErrInfoInitStatic(&ErrInfo); + rc = SUPR3HardenedVerifyPlugIn(ValueUnion.psz, &ErrInfo.Core); + if (RT_SUCCESS(rc)) + RTMsgInfo("SUPR3HardenedVerifyPlugIn: %Rrc for '%s'\n", rc, ValueUnion.psz); + else + RTMsgError("SUPR3HardenedVerifyPlugIn: %Rrc for '%s' ErrInfo: %s\n", + rc, ValueUnion.psz, ErrInfo.Core.pszMsg); + break; + } + + case 'h': + RTPrintf("%s [dll1 [dll2...]]\n", argv[0]); + return 1; + + case 'V': + RTPrintf("$Revision: 127855 $\n"); + return 0; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + + return 0; +} + |