[22077] | 1 | /* $Id: tstInt.cpp 103432 2024-02-19 12:08:00Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[22077] | 3 | * SUP Testcase - Test the interrupt gate feature of the support library.
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[1] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
[5999] | 11 | *
|
---|
[96407] | 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
[5999] | 25 | * The contents of this file may alternatively be used under the terms
|
---|
| 26 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[5999] | 29 | * CDDL are applicable instead of those of the GPL.
|
---|
| 30 | *
|
---|
| 31 | * You may elect to license modified versions of this file under the
|
---|
| 32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 33 | *
|
---|
| 34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[1] | 35 | */
|
---|
| 36 |
|
---|
| 37 |
|
---|
[57358] | 38 | /*********************************************************************************************************************************
|
---|
| 39 | * Header Files *
|
---|
| 40 | *********************************************************************************************************************************/
|
---|
[1] | 41 | #include <VBox/sup.h>
|
---|
[35346] | 42 | #include <VBox/vmm/vmm.h>
|
---|
[67955] | 43 | #include <VBox/vmm/gvmm.h>
|
---|
[80305] | 44 | #include <VBox/vmm/vm.h>
|
---|
[76474] | 45 | #include <iprt/errcore.h>
|
---|
[1] | 46 | #include <VBox/param.h>
|
---|
[87235] | 47 | #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
|
---|
| 48 | # include <iprt/asm-amd64-x86.h>
|
---|
| 49 | #else
|
---|
| 50 | # define ASMReadTSC RTTimeSystemNanoTS
|
---|
| 51 | #endif
|
---|
[14831] | 52 | #include <iprt/initterm.h>
|
---|
[1] | 53 | #include <iprt/stream.h>
|
---|
| 54 | #include <iprt/string.h>
|
---|
[14831] | 55 | #include <iprt/alloc.h>
|
---|
| 56 | #include <iprt/time.h>
|
---|
[41429] | 57 | #include <iprt/path.h>
|
---|
[1] | 58 |
|
---|
| 59 |
|
---|
| 60 | int main(int argc, char **argv)
|
---|
| 61 | {
|
---|
| 62 | int rcRet = 0;
|
---|
[913] | 63 | int i;
|
---|
[1] | 64 | int cIterations = argc > 1 ? RTStrToUInt32(argv[1]) : 32;
|
---|
| 65 | if (cIterations == 0)
|
---|
| 66 | cIterations = 64;
|
---|
| 67 |
|
---|
| 68 | /*
|
---|
| 69 | * Init.
|
---|
| 70 | */
|
---|
[38636] | 71 | RTR3InitExe(argc, &argv, 0);
|
---|
[913] | 72 | PSUPDRVSESSION pSession;
|
---|
[103285] | 73 | int rc = SUPR3Init(&pSession);
|
---|
[13837] | 74 | RTPrintf("tstInt: SUPR3Init -> rc=%Rrc\n", rc);
|
---|
[103432] | 75 | if (RT_FAILURE(rc))
|
---|
| 76 | return 1;
|
---|
| 77 |
|
---|
[41429] | 78 | char szFile[RTPATH_MAX];
|
---|
[103432] | 79 | rc = RTPathExecDir(szFile, sizeof(szFile));
|
---|
[103285] | 80 | if (RT_SUCCESS(rc))
|
---|
[103432] | 81 | rc = RTPathAppend(szFile, sizeof(szFile), "VMMR0.r0");
|
---|
[103285] | 82 |
|
---|
[41429] | 83 | char szAbsFile[RTPATH_MAX];
|
---|
| 84 | if (RT_SUCCESS(rc))
|
---|
[103432] | 85 | rc = RTPathAbs(szFile, szAbsFile, sizeof(szAbsFile));
|
---|
[41429] | 86 | if (RT_SUCCESS(rc))
|
---|
| 87 | {
|
---|
[1] | 88 | /*
|
---|
| 89 | * Load VMM code.
|
---|
| 90 | */
|
---|
[85506] | 91 | RTERRINFOSTATIC ErrInfo;
|
---|
| 92 | rc = SUPR3LoadVMM(szAbsFile, RTErrInfoInitStatic(&ErrInfo));
|
---|
[41429] | 93 | if (RT_SUCCESS(rc))
|
---|
[1] | 94 | {
|
---|
| 95 | /*
|
---|
[67955] | 96 | * Create a tiny dummy VM so we can do NOP calls into it using the fast I/O control path.
|
---|
[1] | 97 | */
|
---|
[67955] | 98 | GVMMCREATEVMREQ CreateVMReq;
|
---|
| 99 | CreateVMReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
|
---|
| 100 | CreateVMReq.Hdr.cbReq = sizeof(CreateVMReq);
|
---|
| 101 | CreateVMReq.pSession = pSession;
|
---|
| 102 | CreateVMReq.pVMR0 = NIL_RTR0PTR;
|
---|
| 103 | CreateVMReq.pVMR3 = NULL;
|
---|
| 104 | CreateVMReq.cCpus = 1;
|
---|
| 105 | rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_GVMM_CREATE_VM, 0, &CreateVMReq.Hdr);
|
---|
[13835] | 106 | if (RT_SUCCESS(rc))
|
---|
[1] | 107 | {
|
---|
[67955] | 108 | PVM pVM = CreateVMReq.pVMR3;
|
---|
[90804] | 109 | AssertRelease(RT_VALID_PTR(pVM));
|
---|
[80305] | 110 | AssertRelease(pVM->pVMR0ForCall == CreateVMReq.pVMR0);
|
---|
[67955] | 111 | AssertRelease(pVM->pSession == pSession);
|
---|
| 112 | AssertRelease(pVM->cCpus == 1);
|
---|
[10724] | 113 | pVM->enmVMState = VMSTATE_CREATED;
|
---|
[80305] | 114 | PVMR0 const pVMR0 = CreateVMReq.pVMR0;
|
---|
[913] | 115 |
|
---|
[80305] | 116 | rc = SUPR3SetVMForFastIOCtl(pVMR0);
|
---|
[913] | 117 | if (!rc)
|
---|
[397] | 118 | {
|
---|
[913] | 119 | /*
|
---|
| 120 | * Call VMM code with invalid function.
|
---|
| 121 | */
|
---|
| 122 | for (i = cIterations; i > 0; i--)
|
---|
| 123 | {
|
---|
[20864] | 124 | rc = SUPR3CallVMMR0(pVMR0, NIL_VMCPUID, VMMR0_DO_SLOW_NOP, NULL);
|
---|
[913] | 125 | if (rc != VINF_SUCCESS)
|
---|
| 126 | {
|
---|
[20864] | 127 | RTPrintf("tstInt: SUPR3CallVMMR0 -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
|
---|
[913] | 128 | rcRet++;
|
---|
| 129 | break;
|
---|
| 130 | }
|
---|
| 131 | }
|
---|
[20864] | 132 | RTPrintf("tstInt: Performed SUPR3CallVMMR0 %d times (rc=%Rrc)\n", cIterations, rc);
|
---|
[913] | 133 |
|
---|
| 134 | /*
|
---|
[10724] | 135 | * The fast path.
|
---|
[913] | 136 | */
|
---|
[10724] | 137 | if (rc == VINF_SUCCESS)
|
---|
[913] | 138 | {
|
---|
| 139 | RTTimeNanoTS();
|
---|
| 140 | uint64_t StartTS = RTTimeNanoTS();
|
---|
| 141 | uint64_t StartTick = ASMReadTSC();
|
---|
| 142 | uint64_t MinTicks = UINT64_MAX;
|
---|
| 143 | for (i = 0; i < 1000000; i++)
|
---|
| 144 | {
|
---|
| 145 | uint64_t OneStartTick = ASMReadTSC();
|
---|
[20864] | 146 | rc = SUPR3CallVMMR0Fast(pVMR0, VMMR0_DO_NOP, 0);
|
---|
[913] | 147 | uint64_t Ticks = ASMReadTSC() - OneStartTick;
|
---|
| 148 | if (Ticks < MinTicks)
|
---|
| 149 | MinTicks = Ticks;
|
---|
| 150 |
|
---|
| 151 | if (RT_UNLIKELY(rc != VINF_SUCCESS))
|
---|
| 152 | {
|
---|
[20864] | 153 | RTPrintf("tstInt: SUPR3CallVMMR0Fast -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
|
---|
[913] | 154 | rcRet++;
|
---|
| 155 | break;
|
---|
| 156 | }
|
---|
| 157 | }
|
---|
| 158 | uint64_t Ticks = ASMReadTSC() - StartTick;
|
---|
| 159 | uint64_t NanoSecs = RTTimeNanoTS() - StartTS;
|
---|
| 160 |
|
---|
[20864] | 161 | RTPrintf("tstInt: SUPR3CallVMMR0Fast - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n",
|
---|
[913] | 162 | i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks);
|
---|
[4811] | 163 |
|
---|
| 164 | /*
|
---|
| 165 | * The ordinary path.
|
---|
| 166 | */
|
---|
| 167 | RTTimeNanoTS();
|
---|
| 168 | StartTS = RTTimeNanoTS();
|
---|
| 169 | StartTick = ASMReadTSC();
|
---|
| 170 | MinTicks = UINT64_MAX;
|
---|
| 171 | for (i = 0; i < 1000000; i++)
|
---|
| 172 | {
|
---|
| 173 | uint64_t OneStartTick = ASMReadTSC();
|
---|
[20864] | 174 | rc = SUPR3CallVMMR0Ex(pVMR0, NIL_VMCPUID, VMMR0_DO_SLOW_NOP, 0, NULL);
|
---|
[25003] | 175 | uint64_t OneTicks = ASMReadTSC() - OneStartTick;
|
---|
| 176 | if (OneTicks < MinTicks)
|
---|
| 177 | MinTicks = OneTicks;
|
---|
[4811] | 178 |
|
---|
| 179 | if (RT_UNLIKELY(rc != VINF_SUCCESS))
|
---|
| 180 | {
|
---|
[20864] | 181 | RTPrintf("tstInt: SUPR3CallVMMR0Ex -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
|
---|
[4811] | 182 | rcRet++;
|
---|
| 183 | break;
|
---|
| 184 | }
|
---|
| 185 | }
|
---|
| 186 | Ticks = ASMReadTSC() - StartTick;
|
---|
| 187 | NanoSecs = RTTimeNanoTS() - StartTS;
|
---|
| 188 |
|
---|
[20864] | 189 | RTPrintf("tstInt: SUPR3CallVMMR0Ex - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n",
|
---|
[4811] | 190 | i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks);
|
---|
[913] | 191 | }
|
---|
| 192 | }
|
---|
| 193 | else
|
---|
| 194 | {
|
---|
[20864] | 195 | RTPrintf("tstInt: SUPR3SetVMForFastIOCtl failed: %Rrc\n", rc);
|
---|
[406] | 196 | rcRet++;
|
---|
[397] | 197 | }
|
---|
[67955] | 198 |
|
---|
[80305] | 199 | rc = SUPR3CallVMMR0Ex(pVMR0, 0 /*idCpu*/, VMMR0_DO_GVMM_DESTROY_VM, 0, NULL);
|
---|
[67955] | 200 | if (RT_FAILURE(rc))
|
---|
| 201 | {
|
---|
| 202 | RTPrintf("tstInt: VMMR0_DO_GVMM_DESTROY_VM failed: %Rrc\n", rc);
|
---|
| 203 | rcRet++;
|
---|
| 204 | }
|
---|
[1] | 205 | }
|
---|
[913] | 206 | else
|
---|
| 207 | {
|
---|
[67955] | 208 | RTPrintf("tstInt: VMMR0_DO_GVMM_CREATE_VM failed\n");
|
---|
[913] | 209 | rcRet++;
|
---|
| 210 | }
|
---|
[1] | 211 |
|
---|
| 212 | /*
|
---|
| 213 | * Unload VMM.
|
---|
| 214 | */
|
---|
[20864] | 215 | rc = SUPR3UnloadVMM();
|
---|
[1] | 216 | if (rc)
|
---|
[913] | 217 | {
|
---|
[20864] | 218 | RTPrintf("tstInt: SUPR3UnloadVMM failed with rc=%Rrc\n", rc);
|
---|
[913] | 219 | rcRet++;
|
---|
| 220 | }
|
---|
[1] | 221 | }
|
---|
| 222 | else
|
---|
[913] | 223 | {
|
---|
[85506] | 224 | RTPrintf("tstInt: SUPR3LoadVMM failed with rc=%Rrc%#RTeim\n", rc, &ErrInfo.Core);
|
---|
[913] | 225 | rcRet++;
|
---|
| 226 | }
|
---|
[1] | 227 |
|
---|
| 228 | /*
|
---|
| 229 | * Terminate.
|
---|
| 230 | */
|
---|
[20864] | 231 | rc = SUPR3Term(false /*fForced*/);
|
---|
[1] | 232 | rcRet += rc != 0;
|
---|
[20864] | 233 | RTPrintf("tstInt: SUPR3Term -> rc=%Rrc\n", rc);
|
---|
[1] | 234 | }
|
---|
[103432] | 235 | else
|
---|
| 236 | {
|
---|
| 237 | RTPrintf("tstInt: Failed to construct VMMR0.r0 path: %Rrc\n", rc);
|
---|
| 238 | rcRet++;
|
---|
| 239 | }
|
---|
[1] | 240 |
|
---|
[103432] | 241 | return rcRet;
|
---|
[1] | 242 | }
|
---|
| 243 |
|
---|