VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPLib.cpp@ 108481

Last change on this file since 108481 was 108481, checked in by vboxsync, 2 months ago

Some minor compile fixes when targetting Linux with clang, bugref:10874

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 85.4 KB
Line 
1/* $Id: SUPLib.cpp 108481 2025-03-07 17:02:28Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Common code.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
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 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
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
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.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/** @page pg_sup SUP - The Support Library
38 *
39 * The support library is responsible for providing facilities to load
40 * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
41 * code, to pin down physical memory, and more.
42 *
43 * The VMM Host Ring-0 code can be combined in the support driver if
44 * permitted by kernel module license policies. If it is not combined
45 * it will be externalized in a .r0 module that will be loaded using
46 * the IPRT loader.
47 *
48 * The Ring-0 calling is done thru a generic SUP interface which will
49 * transfer an argument set and call a predefined entry point in the Host
50 * VMM Ring-0 code.
51 *
52 * See @ref grp_sup "SUP - Support APIs" for API details.
53 */
54
55
56/*********************************************************************************************************************************
57* Header Files *
58*********************************************************************************************************************************/
59#define LOG_GROUP LOG_GROUP_SUP
60#include <VBox/sup.h>
61#include <VBox/err.h>
62#include <VBox/param.h>
63#include <VBox/log.h>
64#include <VBox/VBoxTpG.h>
65
66#include <iprt/assert.h>
67#include <iprt/alloc.h>
68#include <iprt/alloca.h>
69#include <iprt/ldr.h>
70#include <iprt/asm.h>
71#include <iprt/mp.h>
72#include <iprt/cpuset.h>
73#include <iprt/thread.h>
74#include <iprt/process.h>
75#include <iprt/path.h>
76#include <iprt/string.h>
77#include <iprt/env.h>
78#include <iprt/rand.h>
79#include <iprt/x86.h>
80
81#include "SUPDrvIOC.h"
82#include "SUPLibInternal.h"
83
84
85/*********************************************************************************************************************************
86* Defined Constants And Macros *
87*********************************************************************************************************************************/
88/** R0 VMM module name. */
89#define VMMR0_NAME "VMMR0"
90
91
92/*********************************************************************************************************************************
93* Structures and Typedefs *
94*********************************************************************************************************************************/
95typedef DECLCALLBACKTYPE(int, FNCALLVMMR0,(PVMR0 pVMR0, unsigned uOperation, void *pvArg));
96typedef FNCALLVMMR0 *PFNCALLVMMR0;
97
98
99/*********************************************************************************************************************************
100* Global Variables *
101*********************************************************************************************************************************/
102/** Init counter. */
103static uint32_t g_cInits = 0;
104/** Whether we've been preinitied. */
105static bool g_fPreInited = false;
106/** The SUPLib instance data.
107 * Well, at least parts of it, specifically the parts that are being handed over
108 * via the pre-init mechanism from the hardened executable stub. */
109DECL_HIDDEN_DATA(SUPLIBDATA) g_supLibData =
110{
111 /*.hDevice = */ SUP_HDEVICE_NIL,
112 /*.fUnrestricted = */ true,
113 /*.fDriverless = */ false
114#if defined(RT_OS_DARWIN)
115 ,/* .uConnection = */ 0
116#elif defined(RT_OS_LINUX)
117 ,/* .fSysMadviseWorks = */ false
118#endif
119};
120
121/** Pointer to the Global Information Page.
122 *
123 * This pointer is valid as long as SUPLib has a open session. Anyone using
124 * the page must treat this pointer as highly volatile and not trust it beyond
125 * one transaction.
126 *
127 * @todo This will probably deserve it's own session or some other good solution...
128 */
129DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
130/** Address of the ring-0 mapping of the GIP. */
131PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
132/** The physical address of the GIP. */
133static RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
134
135/** The negotiated cookie. */
136DECL_HIDDEN_DATA(uint32_t) g_u32Cookie = 0;
137/** The negotiated session cookie. */
138DECL_HIDDEN_DATA(uint32_t) g_u32SessionCookie;
139/** The session version. */
140DECL_HIDDEN_DATA(uint32_t) g_uSupSessionVersion = 0;
141/** Session handle. */
142DECL_HIDDEN_DATA(PSUPDRVSESSION) g_pSession;
143/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
144DECL_HIDDEN_DATA(PSUPQUERYFUNCS) g_pSupFunctions;
145
146/** PAGE_ALLOC_EX sans kernel mapping support indicator. */
147static bool g_fSupportsPageAllocNoKernel = true;
148/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
149DECL_HIDDEN_DATA(uint32_t) g_uSupFakeMode = UINT32_MAX;
150
151
152/*********************************************************************************************************************************
153* Internal Functions *
154*********************************************************************************************************************************/
155static int supInitFake(PSUPDRVSESSION *ppSession);
156
157
158#ifdef RT_OS_DARWIN
159/** Touch a range of pages. */
160DECLINLINE(void) supR3TouchPages(void *pv, size_t cPages)
161{
162 uint32_t volatile *pu32 = (uint32_t volatile *)pv;
163 while (cPages-- > 0)
164 {
165 ASMAtomicCmpXchgU32(pu32, 0, 0);
166 pu32 += PAGE_SIZE / sizeof(uint32_t);
167 }
168}
169#endif
170
171
172SUPR3DECL(int) SUPR3Install(void)
173{
174 return suplibOsInstall();
175}
176
177
178SUPR3DECL(int) SUPR3Uninstall(void)
179{
180 return suplibOsUninstall();
181}
182
183
184DECL_NOTHROW(DECLEXPORT(int)) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags)
185{
186 /*
187 * The caller is kind of trustworthy, just perform some basic checks.
188 *
189 * Note! Do not do any fancy stuff here because IPRT has NOT been
190 * initialized at this point.
191 */
192 if (!RT_VALID_PTR(pPreInitData))
193 return VERR_INVALID_POINTER;
194 if (g_fPreInited || g_cInits > 0)
195 return VERR_WRONG_ORDER;
196
197 if ( pPreInitData->u32Magic != SUPPREINITDATA_MAGIC
198 || pPreInitData->u32EndMagic != SUPPREINITDATA_MAGIC)
199 return VERR_INVALID_MAGIC;
200 if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
201 && pPreInitData->Data.hDevice == SUP_HDEVICE_NIL
202 && !pPreInitData->Data.fDriverless)
203 return VERR_INVALID_HANDLE;
204 if ( ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
205 || pPreInitData->Data.fDriverless)
206 && pPreInitData->Data.hDevice != SUP_HDEVICE_NIL)
207 return VERR_INVALID_PARAMETER;
208
209 /*
210 * Hand out the data.
211 */
212 int rc = supR3HardenedRecvPreInitData(pPreInitData);
213 if (RT_FAILURE(rc))
214 return rc;
215
216 /** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
217 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
218 {
219 g_supLibData = pPreInitData->Data;
220 g_fPreInited = true;
221 }
222
223 return VINF_SUCCESS;
224}
225
226
227SUPR3DECL(int) SUPR3InitEx(uint32_t fFlags, PSUPDRVSESSION *ppSession)
228{
229 /*
230 * Perform some sanity checks.
231 * (Got some trouble with compile time member alignment assertions.)
232 */
233 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
234 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
235 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
236 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
237 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
238 Assert(!(RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
239
240#ifdef VBOX_WITH_DRIVERLESS_FORCED
241 fFlags |= SUPR3INIT_F_DRIVERLESS;
242 fFlags &= ~SUPR3INIT_F_UNRESTRICTED;
243#endif
244
245 /*
246 * Check if already initialized.
247 */
248 if (ppSession)
249 *ppSession = g_pSession;
250 if (g_cInits++ > 0)
251 {
252 if ( (fFlags & SUPR3INIT_F_UNRESTRICTED)
253 && !g_supLibData.fUnrestricted
254 && !g_supLibData.fDriverless)
255 {
256 g_cInits--;
257 if (ppSession)
258 *ppSession = NIL_RTR0PTR;
259 return VERR_VM_DRIVER_NOT_ACCESSIBLE; /** @todo different status code? */
260 }
261 return VINF_SUCCESS;
262 }
263
264 /*
265 * Check for fake mode.
266 *
267 * Fake mode is used when we're doing smoke testing and debugging.
268 * It's also useful on platforms where we haven't root access or which
269 * we haven't ported the support driver to.
270 */
271 if (g_uSupFakeMode == ~0U)
272 {
273 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
274 if (psz && !strcmp(psz, "fake"))
275 ASMAtomicCmpXchgU32(&g_uSupFakeMode, 1, ~0U);
276 else
277 ASMAtomicCmpXchgU32(&g_uSupFakeMode, 0, ~0U);
278 }
279 if (RT_UNLIKELY(g_uSupFakeMode))
280 return supInitFake(ppSession);
281
282 /*
283 * Open the support driver.
284 */
285 SUPINITOP enmWhat = kSupInitOp_Driver;
286 int rc = suplibOsInit(&g_supLibData, g_fPreInited, fFlags, &enmWhat, NULL);
287 if (RT_SUCCESS(rc) && !g_supLibData.fDriverless)
288 {
289 /*
290 * Negotiate the cookie.
291 */
292 SUPCOOKIE CookieReq;
293 memset(&CookieReq, 0xff, sizeof(CookieReq));
294 CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
295 CookieReq.Hdr.u32SessionCookie = RTRandU32();
296 CookieReq.Hdr.cbIn = SUP_IOCTL_COOKIE_SIZE_IN;
297 CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
298 CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
299 CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
300 strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
301 CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
302 const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00340000
303 ? 0x00340001
304 : SUPDRV_IOC_VERSION & 0xffff0000;
305 CookieReq.u.In.u32MinVersion = uMinVersion;
306 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
307 if ( RT_SUCCESS(rc)
308 && RT_SUCCESS(CookieReq.Hdr.rc))
309 {
310 g_uSupSessionVersion = CookieReq.u.Out.u32SessionVersion;
311 if ( (CookieReq.u.Out.u32SessionVersion & 0xffff0000) == (SUPDRV_IOC_VERSION & 0xffff0000)
312 && CookieReq.u.Out.u32SessionVersion >= uMinVersion)
313 {
314 /*
315 * Query the functions.
316 */
317 PSUPQUERYFUNCS pFuncsReq = NULL;
318 if (g_supLibData.fUnrestricted)
319 {
320 pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
321 if (pFuncsReq)
322 {
323 pFuncsReq->Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
324 pFuncsReq->Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
325 pFuncsReq->Hdr.cbIn = SUP_IOCTL_QUERY_FUNCS_SIZE_IN;
326 pFuncsReq->Hdr.cbOut = SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(CookieReq.u.Out.cFunctions);
327 pFuncsReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
328 pFuncsReq->Hdr.rc = VERR_INTERNAL_ERROR;
329 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq,
330 SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
331 if (RT_SUCCESS(rc))
332 rc = pFuncsReq->Hdr.rc;
333 if (RT_SUCCESS(rc))
334 {
335 /*
336 * Map the GIP into userspace.
337 */
338 Assert(!g_pSUPGlobalInfoPage);
339 SUPGIPMAP GipMapReq;
340 GipMapReq.Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
341 GipMapReq.Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
342 GipMapReq.Hdr.cbIn = SUP_IOCTL_GIP_MAP_SIZE_IN;
343 GipMapReq.Hdr.cbOut = SUP_IOCTL_GIP_MAP_SIZE_OUT;
344 GipMapReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
345 GipMapReq.Hdr.rc = VERR_INTERNAL_ERROR;
346 GipMapReq.u.Out.HCPhysGip = NIL_RTHCPHYS;
347 GipMapReq.u.Out.pGipR0 = NIL_RTR0PTR;
348 GipMapReq.u.Out.pGipR3 = NULL;
349 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_MAP, &GipMapReq, SUP_IOCTL_GIP_MAP_SIZE);
350 if (RT_SUCCESS(rc))
351 rc = GipMapReq.Hdr.rc;
352 if (RT_SUCCESS(rc))
353 {
354 /*
355 * Set the GIP globals.
356 */
357 AssertRelease(GipMapReq.u.Out.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
358 AssertRelease(GipMapReq.u.Out.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
359
360 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipMapReq.u.Out.HCPhysGip);
361 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, GipMapReq.u.Out.pGipR3, NULL);
362 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
363 }
364 }
365 }
366 else
367 rc = VERR_NO_MEMORY;
368 }
369
370 if (RT_SUCCESS(rc))
371 {
372 /*
373 * Set the globals and return success.
374 */
375 g_u32Cookie = CookieReq.u.Out.u32Cookie;
376 g_u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
377 g_pSession = CookieReq.u.Out.pSession;
378 g_pSupFunctions = pFuncsReq;
379 if (ppSession)
380 *ppSession = CookieReq.u.Out.pSession;
381 return VINF_SUCCESS;
382 }
383
384 /* bailout */
385 RTMemFree(pFuncsReq);
386 }
387 else
388 {
389 LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
390 CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, uMinVersion));
391 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
392 }
393 }
394 else
395 {
396 if (RT_SUCCESS(rc))
397 {
398 rc = CookieReq.Hdr.rc;
399 LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
400 CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, rc));
401 if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
402 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
403 }
404 else
405 {
406 /* for pre 0x00060000 drivers */
407 LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
408 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
409 }
410 }
411
412 suplibOsTerm(&g_supLibData);
413 }
414 else if (RT_SUCCESS(rc))
415 {
416 /*
417 * Driverless initialization.
418 */
419 Assert(fFlags & SUPR3INIT_F_DRIVERLESS_MASK);
420 LogRel(("SUP: In driverless mode.\n"));
421 return VINF_SUCCESS;
422 }
423
424 g_cInits--;
425
426 return rc;
427}
428
429
430SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession)
431{
432#ifndef VBOX_WITH_DRIVERLESS_FORCED
433 return SUPR3InitEx(SUPR3INIT_F_UNRESTRICTED, ppSession);
434#else
435 return SUPR3InitEx(SUPR3INIT_F_DRIVERLESS, ppSession);
436#endif
437}
438
439/**
440 * Fake mode init.
441 */
442static int supInitFake(PSUPDRVSESSION *ppSession)
443{
444 Log(("SUP: Fake mode!\n"));
445 static const SUPFUNC s_aFakeFunctions[] =
446 {
447 /* name 0, function */
448 { "SUPR0AbsIs64bit", 0, 0 },
449 { "SUPR0Abs64bitKernelCS", 0, 0 },
450 { "SUPR0Abs64bitKernelSS", 0, 0 },
451 { "SUPR0Abs64bitKernelDS", 0, 0 },
452 { "SUPR0AbsKernelCS", 0, 8 },
453 { "SUPR0AbsKernelSS", 0, 16 },
454 { "SUPR0AbsKernelDS", 0, 16 },
455 { "SUPR0AbsKernelES", 0, 16 },
456 { "SUPR0AbsKernelFS", 0, 24 },
457 { "SUPR0AbsKernelGS", 0, 32 },
458 { "SUPR0ComponentRegisterFactory", 0, 0xefeefffd },
459 { "SUPR0ComponentDeregisterFactory", 0, 0xefeefffe },
460 { "SUPR0ComponentQueryFactory", 0, 0xefeeffff },
461 { "SUPR0ObjRegister", 0, 0xefef0000 },
462 { "SUPR0ObjAddRef", 0, 0xefef0001 },
463 { "SUPR0ObjAddRefEx", 0, 0xefef0001 },
464 { "SUPR0ObjRelease", 0, 0xefef0002 },
465 { "SUPR0ObjVerifyAccess", 0, 0xefef0003 },
466 { "SUPR0LockMem", 0, 0xefef0004 },
467 { "SUPR0UnlockMem", 0, 0xefef0005 },
468 { "SUPR0ContAlloc", 0, 0xefef0006 },
469 { "SUPR0ContFree", 0, 0xefef0007 },
470 { "SUPR0MemAlloc", 0, 0xefef0008 },
471 { "SUPR0MemGetPhys", 0, 0xefef0009 },
472 { "SUPR0MemFree", 0, 0xefef000a },
473 { "SUPR0Printf", 0, 0xefef000b },
474 { "SUPR0GetPagingMode", 0, 0xefef000c },
475 { "SUPR0EnableVTx", 0, 0xefef000e },
476 { "RTMemAlloc", 0, 0xefef000f },
477 { "RTMemAllocZ", 0, 0xefef0010 },
478 { "RTMemFree", 0, 0xefef0011 },
479 { "RTR0MemObjAddress", 0, 0xefef0012 },
480 { "RTR0MemObjAddressR3", 0, 0xefef0013 },
481 { "RTR0MemObjAllocPage", 0, 0xefef0014 },
482 { "RTR0MemObjAllocPhysNC", 0, 0xefef0015 },
483 { "RTR0MemObjAllocLow", 0, 0xefef0016 },
484 { "RTR0MemObjEnterPhys", 0, 0xefef0017 },
485 { "RTR0MemObjFree", 0, 0xefef0018 },
486 { "RTR0MemObjGetPagePhysAddr", 0, 0xefef0019 },
487 { "RTR0MemObjMapUser", 0, 0xefef001a },
488 { "RTR0MemObjMapKernel", 0, 0xefef001b },
489 { "RTR0MemObjMapKernelEx", 0, 0xefef001c },
490 { "RTMpGetArraySize", 0, 0xefef001c },
491 { "RTProcSelf", 0, 0xefef001d },
492 { "RTR0ProcHandleSelf", 0, 0xefef001e },
493 { "RTSemEventCreate", 0, 0xefef001f },
494 { "RTSemEventSignal", 0, 0xefef0020 },
495 { "RTSemEventWait", 0, 0xefef0021 },
496 { "RTSemEventWaitNoResume", 0, 0xefef0022 },
497 { "RTSemEventDestroy", 0, 0xefef0023 },
498 { "RTSemEventMultiCreate", 0, 0xefef0024 },
499 { "RTSemEventMultiSignal", 0, 0xefef0025 },
500 { "RTSemEventMultiReset", 0, 0xefef0026 },
501 { "RTSemEventMultiWait", 0, 0xefef0027 },
502 { "RTSemEventMultiWaitNoResume", 0, 0xefef0028 },
503 { "RTSemEventMultiDestroy", 0, 0xefef0029 },
504 { "RTSemFastMutexCreate", 0, 0xefef002a },
505 { "RTSemFastMutexDestroy", 0, 0xefef002b },
506 { "RTSemFastMutexRequest", 0, 0xefef002c },
507 { "RTSemFastMutexRelease", 0, 0xefef002d },
508 { "RTSpinlockCreate", 0, 0xefef002e },
509 { "RTSpinlockDestroy", 0, 0xefef002f },
510 { "RTSpinlockAcquire", 0, 0xefef0030 },
511 { "RTSpinlockRelease", 0, 0xefef0031 },
512 { "RTSpinlockAcquireNoInts", 0, 0xefef0032 },
513 { "RTTimeNanoTS", 0, 0xefef0034 },
514 { "RTTimeMillieTS", 0, 0xefef0035 },
515 { "RTTimeSystemNanoTS", 0, 0xefef0036 },
516 { "RTTimeSystemMillieTS", 0, 0xefef0037 },
517 { "RTThreadNativeSelf", 0, 0xefef0038 },
518 { "RTThreadSleep", 0, 0xefef0039 },
519 { "RTThreadYield", 0, 0xefef003a },
520 { "RTTimerCreate", 0, 0xefef003a },
521 { "RTTimerCreateEx", 0, 0xefef003a },
522 { "RTTimerDestroy", 0, 0xefef003a },
523 { "RTTimerStart", 0, 0xefef003a },
524 { "RTTimerStop", 0, 0xefef003a },
525 { "RTTimerChangeInterval", 0, 0xefef003a },
526 { "RTTimerGetSystemGranularity", 0, 0xefef003a },
527 { "RTTimerRequestSystemGranularity", 0, 0xefef003a },
528 { "RTTimerReleaseSystemGranularity", 0, 0xefef003a },
529 { "RTTimerCanDoHighResolution", 0, 0xefef003a },
530 { "RTLogDefaultInstance", 0, 0xefef003b },
531 { "RTLogRelGetDefaultInstance", 0, 0xefef003c },
532 { "RTLogSetDefaultInstanceThread", 0, 0xefef003d },
533 { "RTLogLogger", 0, 0xefef003e },
534 { "RTLogLoggerEx", 0, 0xefef003f },
535 { "RTLogLoggerExV", 0, 0xefef0040 },
536 { "RTAssertMsg1", 0, 0xefef0041 },
537 { "RTAssertMsg2", 0, 0xefef0042 },
538 { "RTAssertMsg2V", 0, 0xefef0043 },
539 { "SUPR0QueryVTCaps", 0, 0xefef0044 },
540 };
541
542 /* fake r0 functions. */
543 g_pSupFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
544 if (g_pSupFunctions)
545 {
546 g_pSupFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
547 memcpy(&g_pSupFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
548 g_pSession = (PSUPDRVSESSION)(void *)g_pSupFunctions;
549 if (ppSession)
550 *ppSession = g_pSession;
551
552 /* fake the GIP. */
553 g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
554 if (g_pSUPGlobalInfoPage)
555 {
556 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
557 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
558 /* the page is supposed to be invalid, so don't set the magic. */
559 return VINF_SUCCESS;
560 }
561
562 RTMemFree(g_pSupFunctions);
563 g_pSupFunctions = NULL;
564 }
565 return VERR_NO_MEMORY;
566}
567
568
569SUPR3DECL(int) SUPR3Term(bool fForced)
570{
571 /*
572 * Verify state.
573 */
574 AssertMsg(g_cInits > 0, ("SUPR3Term() is called before SUPR3Init()!\n"));
575 if (g_cInits == 0)
576 return VERR_WRONG_ORDER;
577 if (g_cInits == 1 || fForced)
578 {
579 /*
580 * NULL the GIP pointer.
581 */
582 if (g_pSUPGlobalInfoPage)
583 {
584 ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPage);
585 ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPageR0);
586 ASMAtomicWriteU64(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
587 /* just a little safe guard against threads using the page. */
588 RTThreadSleep(50);
589 }
590
591 /*
592 * Close the support driver.
593 */
594 int rc = suplibOsTerm(&g_supLibData);
595 if (rc)
596 return rc;
597
598 g_supLibData.hDevice = SUP_HDEVICE_NIL;
599 g_supLibData.fUnrestricted = true;
600 g_supLibData.fDriverless = false;
601 g_u32Cookie = 0;
602 g_u32SessionCookie = 0;
603 g_cInits = 0;
604 }
605 else
606 g_cInits--;
607
608 return 0;
609}
610
611
612SUPR3DECL(bool) SUPR3IsDriverless(void)
613{
614 /* Assert(g_cInits > 0); - tstSSM does not initialize SUP, but SSM calls to
615 check status, so return driverless if not initialized. */
616 return g_supLibData.fDriverless || g_cInits == 0;
617}
618
619
620SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void)
621{
622 /*
623 * Deal with driverless first.
624 */
625 if (g_supLibData.fDriverless)
626#if defined(RT_ARCH_AMD64)
627 return SUPPAGINGMODE_AMD64_GLOBAL_NX;
628#elif defined(RT_ARCH_X86)
629 return SUPPAGINGMODE_32_BIT_GLOBAL;
630#else
631 return SUPPAGINGMODE_INVALID;
632#endif
633
634 /*
635 * Issue IOCtl to the SUPDRV kernel module.
636 */
637 SUPGETPAGINGMODE Req;
638 Req.Hdr.u32Cookie = g_u32Cookie;
639 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
640 Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
641 Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
642 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
643 Req.Hdr.rc = VERR_INTERNAL_ERROR;
644 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
645 if ( RT_FAILURE(rc)
646 || RT_FAILURE(Req.Hdr.rc))
647 {
648 LogRel(("SUPR3GetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
649 Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
650 }
651
652 return Req.u.Out.enmMode;
653}
654
655
656/**
657 * For later.
658 */
659static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
660{
661 AssertMsgFailed(("%d\n", uOperation)); NOREF(pVMR0); NOREF(uOperation); NOREF(u64Arg); NOREF(pReqHdr);
662 return VERR_NOT_SUPPORTED;
663}
664
665
666SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
667{
668 NOREF(pVMR0);
669 static const uintptr_t s_auFunctions[3] =
670 {
671 SUP_IOCTL_FAST_DO_HM_RUN,
672 SUP_IOCTL_FAST_DO_NEM_RUN,
673 SUP_IOCTL_FAST_DO_NOP,
674 };
675 AssertCompile(SUP_VMMR0_DO_HM_RUN == 0);
676 AssertCompile(SUP_VMMR0_DO_NEM_RUN == 1);
677 AssertCompile(SUP_VMMR0_DO_NOP == 2);
678 AssertMsgReturn(uOperation < RT_ELEMENTS(s_auFunctions), ("%#x\n", uOperation), VERR_INTERNAL_ERROR);
679 return suplibOsIOCtlFast(&g_supLibData, s_auFunctions[uOperation], idCpu);
680}
681
682
683SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
684{
685 /*
686 * The following operations don't belong here.
687 */
688 AssertMsgReturn( uOperation != SUP_VMMR0_DO_HM_RUN
689 && uOperation != SUP_VMMR0_DO_NEM_RUN
690 && uOperation != SUP_VMMR0_DO_NOP,
691 ("%#x\n", uOperation),
692 VERR_INTERNAL_ERROR);
693
694 /* fake */
695 if (RT_UNLIKELY(g_uSupFakeMode))
696 return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
697
698 int rc;
699 if (!pReqHdr)
700 {
701 /* no data. */
702 SUPCALLVMMR0 Req;
703 Req.Hdr.u32Cookie = g_u32Cookie;
704 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
705 Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
706 Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
707 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
708 Req.Hdr.rc = VERR_INTERNAL_ERROR;
709 Req.u.In.pVMR0 = pVMR0;
710 Req.u.In.idCpu = idCpu;
711 Req.u.In.uOperation = uOperation;
712 Req.u.In.u64Arg = u64Arg;
713 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
714 if (RT_SUCCESS(rc))
715 rc = Req.Hdr.rc;
716 }
717 else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
718 {
719 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
720 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
721 const size_t cbReq = pReqHdr->cbReq;
722
723 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
724 pReq->Hdr.u32Cookie = g_u32Cookie;
725 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
726 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
727 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
728 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
729 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
730 pReq->u.In.pVMR0 = pVMR0;
731 pReq->u.In.idCpu = idCpu;
732 pReq->u.In.uOperation = uOperation;
733 pReq->u.In.u64Arg = u64Arg;
734 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
735 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
736 if (RT_SUCCESS(rc))
737 rc = pReq->Hdr.rc;
738 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
739 }
740 else if (pReqHdr->cbReq <= _512K)
741 {
742 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
743 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
744 const size_t cbReq = pReqHdr->cbReq;
745
746 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)RTMemTmpAlloc(SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
747 pReq->Hdr.u32Cookie = g_u32Cookie;
748 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
749 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_BIG_SIZE_IN(cbReq);
750 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_BIG_SIZE_OUT(cbReq);
751 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
752 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
753 pReq->u.In.pVMR0 = pVMR0;
754 pReq->u.In.idCpu = idCpu;
755 pReq->u.In.uOperation = uOperation;
756 pReq->u.In.u64Arg = u64Arg;
757 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
758 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0_BIG, pReq, SUP_IOCTL_CALL_VMMR0_BIG_SIZE(cbReq));
759 if (RT_SUCCESS(rc))
760 rc = pReq->Hdr.rc;
761 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
762 RTMemTmpFree(pReq);
763 }
764 else
765 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_OUT_OF_RANGE);
766 return rc;
767}
768
769
770SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg)
771{
772 /*
773 * The following operations don't belong here.
774 */
775 AssertMsgReturn( uOperation != SUP_VMMR0_DO_HM_RUN
776 && uOperation != SUP_VMMR0_DO_NEM_RUN
777 && uOperation != SUP_VMMR0_DO_NOP,
778 ("%#x\n", uOperation),
779 VERR_INTERNAL_ERROR);
780 return SUPR3CallVMMR0Ex(pVMR0, idCpu, uOperation, (uintptr_t)pvArg, NULL);
781}
782
783
784SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0)
785{
786 if (RT_UNLIKELY(g_uSupFakeMode))
787 return VINF_SUCCESS;
788
789 SUPSETVMFORFAST Req;
790 Req.Hdr.u32Cookie = g_u32Cookie;
791 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
792 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
793 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
794 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
795 Req.Hdr.rc = VERR_INTERNAL_ERROR;
796 Req.u.In.pVMR0 = pVMR0;
797 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
798 if (RT_SUCCESS(rc))
799 rc = Req.Hdr.rc;
800 return rc;
801}
802
803
804SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
805{
806 AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
807 Assert(strlen(pszService) == cchService);
808
809 /* fake */
810 if (RT_UNLIKELY(g_uSupFakeMode))
811 return VERR_NOT_SUPPORTED;
812
813 int rc;
814 if (!pReqHdr)
815 {
816 /* no data. */
817 SUPCALLSERVICE Req;
818 Req.Hdr.u32Cookie = g_u32Cookie;
819 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
820 Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
821 Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
822 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
823 Req.Hdr.rc = VERR_INTERNAL_ERROR;
824 memcpy(Req.u.In.szName, pszService, cchService);
825 Req.u.In.szName[cchService] = '\0';
826 Req.u.In.uOperation = uOperation;
827 Req.u.In.u64Arg = u64Arg;
828 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
829 if (RT_SUCCESS(rc))
830 rc = Req.Hdr.rc;
831 }
832 else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
833 {
834 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
835 AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
836 const size_t cbReq = pReqHdr->cbReq;
837
838 PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
839 pReq->Hdr.u32Cookie = g_u32Cookie;
840 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
841 pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
842 pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
843 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
844 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
845 memcpy(pReq->u.In.szName, pszService, cchService);
846 pReq->u.In.szName[cchService] = '\0';
847 pReq->u.In.uOperation = uOperation;
848 pReq->u.In.u64Arg = u64Arg;
849 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
850 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
851 if (RT_SUCCESS(rc))
852 rc = pReq->Hdr.rc;
853 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
854 }
855 else /** @todo may have to remove the size limits one this request... */
856 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
857 return rc;
858}
859
860
861/**
862 * Worker for the SUPR3Logger* APIs.
863 *
864 * @returns VBox status code.
865 * @param enmWhich Which logger.
866 * @param fWhat What to do with the logger.
867 * @param pszFlags The flags settings.
868 * @param pszGroups The groups settings.
869 * @param pszDest The destination specificier.
870 */
871static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
872{
873 uint32_t const cchFlags = pszFlags ? (uint32_t)strlen(pszFlags) : 0;
874 uint32_t const cchGroups = pszGroups ? (uint32_t)strlen(pszGroups) : 0;
875 uint32_t const cchDest = pszDest ? (uint32_t)strlen(pszDest) : 0;
876 uint32_t const cbStrTab = cchFlags + !!cchFlags
877 + cchGroups + !!cchGroups
878 + cchDest + !!cchDest
879 + (!cchFlags && !cchGroups && !cchDest);
880
881 PSUPLOGGERSETTINGS pReq = (PSUPLOGGERSETTINGS)alloca(SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
882 pReq->Hdr.u32Cookie = g_u32Cookie;
883 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
884 pReq->Hdr.cbIn = SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(cbStrTab);
885 pReq->Hdr.cbOut = SUP_IOCTL_LOGGER_SETTINGS_SIZE_OUT;
886 pReq->Hdr.fFlags= SUPREQHDR_FLAGS_DEFAULT;
887 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
888 switch (enmWhich)
889 {
890 case SUPLOGGER_DEBUG: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_DEBUG; break;
891 case SUPLOGGER_RELEASE: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_RELEASE; break;
892 default:
893 return VERR_INVALID_PARAMETER;
894 }
895 pReq->u.In.fWhat = fWhat;
896
897 uint32_t off = 0;
898 if (cchFlags)
899 {
900 pReq->u.In.offFlags = off;
901 memcpy(&pReq->u.In.szStrings[off], pszFlags, cchFlags + 1);
902 off += cchFlags + 1;
903 }
904 else
905 pReq->u.In.offFlags = cbStrTab - 1;
906
907 if (cchGroups)
908 {
909 pReq->u.In.offGroups = off;
910 memcpy(&pReq->u.In.szStrings[off], pszGroups, cchGroups + 1);
911 off += cchGroups + 1;
912 }
913 else
914 pReq->u.In.offGroups = cbStrTab - 1;
915
916 if (cchDest)
917 {
918 pReq->u.In.offDestination = off;
919 memcpy(&pReq->u.In.szStrings[off], pszDest, cchDest + 1);
920 off += cchDest + 1;
921 }
922 else
923 pReq->u.In.offDestination = cbStrTab - 1;
924
925 if (!off)
926 {
927 pReq->u.In.szStrings[0] = '\0';
928 off++;
929 }
930 Assert(off == cbStrTab);
931 Assert(pReq->u.In.szStrings[cbStrTab - 1] == '\0');
932
933
934 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
935 if (RT_SUCCESS(rc))
936 rc = pReq->Hdr.rc;
937 return rc;
938}
939
940
941SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
942{
943 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_SETTINGS, pszFlags, pszGroups, pszDest);
944}
945
946
947SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
948{
949 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_CREATE, pszFlags, pszGroups, pszDest);
950}
951
952
953SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich)
954{
955 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_DESTROY, NULL, NULL, NULL);
956}
957
958
959SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, uint32_t fFlags, void **ppvPages)
960{
961 /*
962 * Validate.
963 */
964 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
965 *ppvPages = NULL;
966 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
967 AssertReturn(!(fFlags & ~SUP_PAGE_ALLOC_F_VALID_MASK), VERR_INVALID_FLAGS);
968
969 /*
970 * Call OS specific worker.
971 */
972 return suplibOsPageAlloc(&g_supLibData, cPages, fFlags, ppvPages);
973}
974
975
976SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages)
977{
978 /*
979 * Validate.
980 */
981 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
982 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
983
984 /*
985 * Call OS specific worker.
986 */
987 return suplibOsPageFree(&g_supLibData, pvPages, cPages);
988}
989
990
991/**
992 * Locks down the physical memory backing a virtual memory
993 * range in the current process.
994 *
995 * @returns VBox status code.
996 * @param pvStart Start of virtual memory range.
997 * Must be page aligned.
998 * @param cPages Number of pages.
999 * @param paPages Where to store the physical page addresses returned.
1000 * On entry this will point to an array of with cbMemory >> PAGE_SHIFT entries.
1001 */
1002SUPR3DECL(int) supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
1003{
1004 /*
1005 * Validate.
1006 */
1007 AssertPtr(pvStart);
1008 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
1009 AssertPtr(paPages);
1010
1011 /* fake */
1012 if (RT_UNLIKELY(g_uSupFakeMode))
1013 {
1014 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
1015 size_t iPage = cPages;
1016 while (iPage-- > 0)
1017 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
1018 return VINF_SUCCESS;
1019 }
1020
1021 /*
1022 * Issue IOCtl to the SUPDRV kernel module.
1023 */
1024 int rc;
1025 PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
1026 if (RT_LIKELY(pReq))
1027 {
1028 pReq->Hdr.u32Cookie = g_u32Cookie;
1029 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1030 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
1031 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
1032 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1033 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1034 pReq->u.In.pvR3 = pvStart;
1035 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1036 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
1037 if (RT_SUCCESS(rc))
1038 rc = pReq->Hdr.rc;
1039 if (RT_SUCCESS(rc))
1040 {
1041 for (uint32_t iPage = 0; iPage < cPages; iPage++)
1042 {
1043 paPages[iPage].uReserved = 0;
1044 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1045 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1046 }
1047 }
1048 RTMemTmpFree(pReq);
1049 }
1050 else
1051 rc = VERR_NO_TMP_MEMORY;
1052
1053 return rc;
1054}
1055
1056
1057/**
1058 * Releases locked down pages.
1059 *
1060 * @returns VBox status code.
1061 * @param pvStart Start of virtual memory range previously locked
1062 * down by SUPPageLock().
1063 */
1064SUPR3DECL(int) supR3PageUnlock(void *pvStart)
1065{
1066 /*
1067 * Validate.
1068 */
1069 AssertPtr(pvStart);
1070 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
1071
1072 /* fake */
1073 if (RT_UNLIKELY(g_uSupFakeMode))
1074 return VINF_SUCCESS;
1075
1076 /*
1077 * Issue IOCtl to the SUPDRV kernel module.
1078 */
1079 SUPPAGEUNLOCK Req;
1080 Req.Hdr.u32Cookie = g_u32Cookie;
1081 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1082 Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
1083 Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
1084 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1085 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1086 Req.u.In.pvR3 = pvStart;
1087 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
1088 if (RT_SUCCESS(rc))
1089 rc = Req.Hdr.rc;
1090 return rc;
1091}
1092
1093
1094SUPR3DECL(int) SUPR3LockDownLoader(PRTERRINFO pErrInfo)
1095{
1096 /* fake */
1097 if (RT_UNLIKELY(g_uSupFakeMode))
1098 return VINF_SUCCESS;
1099
1100 /*
1101 * Lock down the module loader interface.
1102 */
1103 SUPREQHDR ReqHdr;
1104 ReqHdr.u32Cookie = g_u32Cookie;
1105 ReqHdr.u32SessionCookie = g_u32SessionCookie;
1106 ReqHdr.cbIn = SUP_IOCTL_LDR_LOCK_DOWN_SIZE_IN;
1107 ReqHdr.cbOut = SUP_IOCTL_LDR_LOCK_DOWN_SIZE_OUT;
1108 ReqHdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1109 ReqHdr.rc = VERR_INTERNAL_ERROR;
1110 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOCK_DOWN, &ReqHdr, SUP_IOCTL_LDR_LOCK_DOWN_SIZE);
1111 if (RT_FAILURE(rc))
1112 return RTErrInfoSetF(pErrInfo, rc,
1113 "SUPR3LockDownLoader: SUP_IOCTL_LDR_LOCK_DOWN ioctl returned %Rrc", rc);
1114
1115 return ReqHdr.rc;
1116}
1117
1118
1119/**
1120 * Fallback for SUPR3PageAllocEx on systems where RTR0MemObjPhysAllocNC isn't
1121 * supported.
1122 */
1123static int supPagePageAllocNoKernelFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
1124{
1125 int rc = suplibOsPageAlloc(&g_supLibData, cPages, 0, ppvPages);
1126 if (RT_SUCCESS(rc))
1127 {
1128 Assert(ASMMemIsZero(*ppvPages, cPages << PAGE_SHIFT));
1129 if (!paPages)
1130 paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
1131 rc = supR3PageLock(*ppvPages, cPages, paPages);
1132 if (RT_FAILURE(rc))
1133 suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
1134 }
1135 return rc;
1136}
1137
1138
1139SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
1140{
1141 /*
1142 * Validate.
1143 */
1144 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1145 *ppvPages = NULL;
1146 AssertPtrNullReturn(pR0Ptr, VERR_INVALID_POINTER);
1147 if (pR0Ptr)
1148 *pR0Ptr = NIL_RTR0PTR;
1149 AssertPtrNullReturn(paPages, VERR_INVALID_POINTER);
1150 AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1151 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
1152
1153 /*
1154 * Deal with driverless mode first.
1155 */
1156 if (g_supLibData.fDriverless)
1157 {
1158 int rc = SUPR3PageAlloc(cPages, 0 /*fFlags*/, ppvPages);
1159 Assert(RT_FAILURE(rc) || ASMMemIsZero(*ppvPages, cPages << PAGE_SHIFT));
1160 if (pR0Ptr)
1161 *pR0Ptr = NIL_RTR0PTR;
1162 if (paPages)
1163 for (size_t iPage = 0; iPage < cPages; iPage++)
1164 {
1165 paPages[iPage].uReserved = 0;
1166 paPages[iPage].Phys = NIL_RTHCPHYS;
1167 }
1168 return rc;
1169 }
1170
1171 /* Check that we've got a kernel connection so rtMemSaferSupR3AllocPages
1172 can do fallback without first having to hit assertions. */
1173 if (g_supLibData.hDevice != SUP_HDEVICE_NIL)
1174 { /* likely */ }
1175 else
1176 return VERR_WRONG_ORDER;
1177
1178 /*
1179 * Use fallback for non-R0 mapping?
1180 */
1181 if ( !pR0Ptr
1182 && !g_fSupportsPageAllocNoKernel)
1183 return supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1184
1185 /*
1186 * Issue IOCtl to the SUPDRV kernel module.
1187 */
1188 int rc;
1189 PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1190 if (pReq)
1191 {
1192 pReq->Hdr.u32Cookie = g_u32Cookie;
1193 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1194 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN;
1195 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages);
1196 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1197 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1198 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1199 pReq->u.In.fKernelMapping = pR0Ptr != NULL;
1200 pReq->u.In.fUserMapping = true;
1201 pReq->u.In.fReserved0 = false;
1202 pReq->u.In.fReserved1 = false;
1203 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1204 if (RT_SUCCESS(rc))
1205 {
1206 rc = pReq->Hdr.rc;
1207 if (RT_SUCCESS(rc))
1208 {
1209 *ppvPages = pReq->u.Out.pvR3;
1210 if (pR0Ptr)
1211 {
1212 *pR0Ptr = pReq->u.Out.pvR0;
1213 Assert(ASMMemIsZero(pReq->u.Out.pvR3, cPages << PAGE_SHIFT));
1214#ifdef RT_OS_DARWIN /* HACK ALERT! */
1215 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1216#endif
1217 }
1218 else
1219 RT_BZERO(pReq->u.Out.pvR3, cPages << PAGE_SHIFT);
1220
1221 if (paPages)
1222 for (size_t iPage = 0; iPage < cPages; iPage++)
1223 {
1224 paPages[iPage].uReserved = 0;
1225 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1226 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1227 }
1228 }
1229 else if ( rc == VERR_NOT_SUPPORTED
1230 && !pR0Ptr)
1231 {
1232 g_fSupportsPageAllocNoKernel = false;
1233 rc = supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1234 }
1235 }
1236
1237 RTMemTmpFree(pReq);
1238 }
1239 else
1240 rc = VERR_NO_TMP_MEMORY;
1241 return rc;
1242
1243}
1244
1245
1246SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
1247{
1248 /*
1249 * Validate.
1250 */
1251 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1252 AssertPtrReturn(pR0Ptr, VERR_INVALID_POINTER);
1253 Assert(!(off & PAGE_OFFSET_MASK));
1254 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1255 Assert(!fFlags);
1256 *pR0Ptr = NIL_RTR0PTR;
1257
1258 /*
1259 * Not a valid operation in driverless mode.
1260 */
1261 AssertReturn(g_supLibData.fDriverless, VERR_SUP_DRIVERLESS);
1262
1263 /*
1264 * Issue IOCtl to the SUPDRV kernel module.
1265 */
1266 SUPPAGEMAPKERNEL Req;
1267 Req.Hdr.u32Cookie = g_u32Cookie;
1268 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1269 Req.Hdr.cbIn = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN;
1270 Req.Hdr.cbOut = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT;
1271 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1272 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1273 Req.u.In.pvR3 = pvR3;
1274 Req.u.In.offSub = off;
1275 Req.u.In.cbSub = cb;
1276 Req.u.In.fFlags = fFlags;
1277 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
1278 if (RT_SUCCESS(rc))
1279 rc = Req.Hdr.rc;
1280 if (RT_SUCCESS(rc))
1281 *pR0Ptr = Req.u.Out.pvR0;
1282 return rc;
1283}
1284
1285
1286SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
1287{
1288 /*
1289 * Validate.
1290 */
1291 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1292 Assert(!(off & PAGE_OFFSET_MASK));
1293 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1294 AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
1295
1296 /*
1297 * Deal with driverless mode first.
1298 */
1299 if (g_supLibData.fDriverless)
1300 return RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1301
1302 /*
1303 * Some OSes can do this from ring-3, so try that before we
1304 * issue the IOCtl to the SUPDRV kernel module.
1305 * (Yea, this isn't very nice, but just try get the job done for now.)
1306 */
1307#if !defined(RT_OS_SOLARIS)
1308 RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1309#endif
1310
1311 SUPPAGEPROTECT Req;
1312 Req.Hdr.u32Cookie = g_u32Cookie;
1313 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1314 Req.Hdr.cbIn = SUP_IOCTL_PAGE_PROTECT_SIZE_IN;
1315 Req.Hdr.cbOut = SUP_IOCTL_PAGE_PROTECT_SIZE_OUT;
1316 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1317 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1318 Req.u.In.pvR3 = pvR3;
1319 Req.u.In.pvR0 = R0Ptr;
1320 Req.u.In.offSub = off;
1321 Req.u.In.cbSub = cb;
1322 Req.u.In.fProt = fProt;
1323 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_PROTECT, &Req, SUP_IOCTL_PAGE_PROTECT_SIZE);
1324 if (RT_SUCCESS(rc))
1325 rc = Req.Hdr.rc;
1326 return rc;
1327}
1328
1329
1330SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
1331{
1332 /*
1333 * Validate.
1334 */
1335 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
1336 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1337
1338 /*
1339 * Deal with driverless mode first.
1340 */
1341 if (g_supLibData.fDriverless)
1342 {
1343 SUPR3PageFree(pvPages, cPages);
1344 return VINF_SUCCESS;
1345 }
1346
1347 /*
1348 * Try normal free first, then if it fails check if we're using the fallback
1349 * for the allocations without kernel mappings and attempt unlocking it.
1350 */
1351 NOREF(cPages);
1352 SUPPAGEFREE Req;
1353 Req.Hdr.u32Cookie = g_u32Cookie;
1354 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1355 Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
1356 Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
1357 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1358 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1359 Req.u.In.pvR3 = pvPages;
1360 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
1361 if (RT_SUCCESS(rc))
1362 {
1363 rc = Req.Hdr.rc;
1364 if ( rc == VERR_INVALID_PARAMETER
1365 && !g_fSupportsPageAllocNoKernel)
1366 {
1367 int rc2 = supR3PageUnlock(pvPages);
1368 if (RT_SUCCESS(rc2))
1369 rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
1370 }
1371 }
1372 return rc;
1373}
1374
1375
1376SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
1377{
1378 /*
1379 * Validate.
1380 */
1381 AssertPtrReturn(pHCPhys, NULL);
1382 *pHCPhys = NIL_RTHCPHYS;
1383 AssertPtrNullReturn(pR0Ptr, NULL);
1384 if (pR0Ptr)
1385 *pR0Ptr = NIL_RTR0PTR;
1386 AssertPtrNullReturn(pHCPhys, NULL);
1387 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
1388
1389 /*
1390 * Deal with driverless mode first.
1391 */
1392 if (g_supLibData.fDriverless)
1393 {
1394 void *pvPages = NULL;
1395 int rc = SUPR3PageAlloc(cPages, 0 /*fFlags*/, &pvPages);
1396 if (pR0Ptr)
1397 *pR0Ptr = NIL_RTR0PTR;
1398 if (pHCPhys)
1399 *pHCPhys = NIL_RTHCPHYS;
1400 return RT_SUCCESS(rc) ? pvPages : NULL;
1401 }
1402
1403 /*
1404 * Issue IOCtl to the SUPDRV kernel module.
1405 */
1406 SUPCONTALLOC Req;
1407 Req.Hdr.u32Cookie = g_u32Cookie;
1408 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1409 Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
1410 Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
1411 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1412 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1413 Req.u.In.cPages = (uint32_t)cPages;
1414 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
1415 if ( RT_SUCCESS(rc)
1416 && RT_SUCCESS(Req.Hdr.rc))
1417 {
1418 *pHCPhys = Req.u.Out.HCPhys;
1419 if (pR0Ptr)
1420 *pR0Ptr = Req.u.Out.pvR0;
1421#ifdef RT_OS_DARWIN /* HACK ALERT! */
1422 supR3TouchPages(Req.u.Out.pvR3, cPages);
1423#endif
1424 return Req.u.Out.pvR3;
1425 }
1426
1427 return NULL;
1428}
1429
1430
1431SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages)
1432{
1433 /*
1434 * Validate.
1435 */
1436 if (!pv)
1437 return VINF_SUCCESS;
1438 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1439 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1440
1441 /*
1442 * Deal with driverless mode first.
1443 */
1444 if (g_supLibData.fDriverless)
1445 return SUPR3PageFree(pv, cPages);
1446
1447 /*
1448 * Issue IOCtl to the SUPDRV kernel module.
1449 */
1450 SUPCONTFREE Req;
1451 Req.Hdr.u32Cookie = g_u32Cookie;
1452 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1453 Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
1454 Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
1455 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1456 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1457 Req.u.In.pvR3 = pv;
1458 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
1459 if (RT_SUCCESS(rc))
1460 rc = Req.Hdr.rc;
1461 return rc;
1462}
1463
1464
1465SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
1466{
1467 /*
1468 * Validate.
1469 */
1470 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1471 *ppvPages = NULL;
1472 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
1473 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1474
1475 /* fake */
1476 if (RT_UNLIKELY(g_uSupFakeMode))
1477 {
1478 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
1479 if (!*ppvPages)
1480 return VERR_NO_LOW_MEMORY;
1481
1482 /* fake physical addresses. */
1483 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
1484 size_t iPage = cPages;
1485 while (iPage-- > 0)
1486 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
1487 return VINF_SUCCESS;
1488 }
1489
1490 /*
1491 * Issue IOCtl to the SUPDRV kernel module.
1492 */
1493 int rc;
1494 PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1495 if (pReq)
1496 {
1497 pReq->Hdr.u32Cookie = g_u32Cookie;
1498 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1499 pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
1500 pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
1501 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1502 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1503 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1504 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1505 if (RT_SUCCESS(rc))
1506 rc = pReq->Hdr.rc;
1507 if (RT_SUCCESS(rc))
1508 {
1509 *ppvPages = pReq->u.Out.pvR3;
1510 if (ppvPagesR0)
1511 *ppvPagesR0 = pReq->u.Out.pvR0;
1512 if (paPages)
1513 for (size_t iPage = 0; iPage < cPages; iPage++)
1514 {
1515 paPages[iPage].uReserved = 0;
1516 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1517 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1518 Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
1519 }
1520#ifdef RT_OS_DARWIN /* HACK ALERT! */
1521 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1522#endif
1523 }
1524 RTMemTmpFree(pReq);
1525 }
1526 else
1527 rc = VERR_NO_TMP_MEMORY;
1528
1529 return rc;
1530}
1531
1532
1533SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages)
1534{
1535 /*
1536 * Validate.
1537 */
1538 if (!pv)
1539 return VINF_SUCCESS;
1540 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1541 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1542
1543 /* fake */
1544 if (RT_UNLIKELY(g_uSupFakeMode))
1545 {
1546 RTMemPageFree(pv, cPages * PAGE_SIZE);
1547 return VINF_SUCCESS;
1548 }
1549
1550 /*
1551 * Issue IOCtl to the SUPDRV kernel module.
1552 */
1553 SUPCONTFREE Req;
1554 Req.Hdr.u32Cookie = g_u32Cookie;
1555 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1556 Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
1557 Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
1558 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1559 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1560 Req.u.In.pvR3 = pv;
1561 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
1562 if (RT_SUCCESS(rc))
1563 rc = Req.Hdr.rc;
1564 return rc;
1565}
1566
1567
1568SUPR3DECL(int) SUPR3HardenedVerifyInit(void)
1569{
1570#ifdef RT_OS_WINDOWS
1571 if (g_cInits == 0)
1572 return suplibOsHardenedVerifyInit();
1573#endif
1574 return VINF_SUCCESS;
1575}
1576
1577
1578SUPR3DECL(int) SUPR3HardenedVerifyTerm(void)
1579{
1580#ifdef RT_OS_WINDOWS
1581 if (g_cInits == 0)
1582 return suplibOsHardenedVerifyTerm();
1583#endif
1584 return VINF_SUCCESS;
1585}
1586
1587
1588SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
1589{
1590 /*
1591 * Quick input validation.
1592 */
1593 AssertPtr(pszFilename);
1594 AssertPtr(pszMsg);
1595 AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
1596 file is the same we verified after opening it. */
1597 RT_NOREF2(pszFilename, pszMsg);
1598
1599 /*
1600 * Only do the actual check in hardened builds.
1601 */
1602#ifdef VBOX_WITH_HARDENING
1603 int rc = supR3HardenedVerifyFixedFile(pszFilename, false /* fFatal */);
1604 if (RT_FAILURE(rc))
1605 LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
1606 return rc;
1607#else
1608 return VINF_SUCCESS;
1609#endif
1610}
1611
1612
1613SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, PRTERRINFO pErrInfo)
1614{
1615 /*
1616 * Quick input validation.
1617 */
1618 AssertPtr(pszArgv0);
1619 RTErrInfoClear(pErrInfo);
1620
1621 /*
1622 * Get the executable image path as we need it for all the tests here.
1623 */
1624 char szExecPath[RTPATH_MAX];
1625 if (!RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
1626 return RTErrInfoSet(pErrInfo, VERR_INTERNAL_ERROR_2, "RTProcGetExecutablePath failed");
1627
1628 int rc;
1629 if (fInternal)
1630 {
1631 /*
1632 * Internal applications must be launched directly without any PATH
1633 * searching involved.
1634 */
1635 if (RTPathCompare(pszArgv0, szExecPath) != 0)
1636 return RTErrInfoSetF(pErrInfo, VERR_SUPLIB_INVALID_ARGV0_INTERNAL,
1637 "argv[0] does not match the executable image path: '%s' != '%s'", pszArgv0, szExecPath);
1638
1639 /*
1640 * Internal applications must reside in or under the
1641 * RTPathAppPrivateArch directory.
1642 */
1643 char szAppPrivateArch[RTPATH_MAX];
1644 rc = RTPathAppPrivateArch(szAppPrivateArch, sizeof(szAppPrivateArch));
1645 if (RT_FAILURE(rc))
1646 return RTErrInfoSetF(pErrInfo, VERR_SUPLIB_INVALID_ARGV0_INTERNAL,
1647 "RTPathAppPrivateArch failed with rc=%Rrc", rc);
1648 size_t cchAppPrivateArch = strlen(szAppPrivateArch);
1649 if ( cchAppPrivateArch >= strlen(szExecPath)
1650 || !RTPATH_IS_SLASH(szExecPath[cchAppPrivateArch]))
1651 return RTErrInfoSet(pErrInfo, VERR_SUPLIB_INVALID_INTERNAL_APP_DIR,
1652 "Internal executable does reside under RTPathAppPrivateArch");
1653 szExecPath[cchAppPrivateArch] = '\0';
1654 if (RTPathCompare(szExecPath, szAppPrivateArch) != 0)
1655 return RTErrInfoSet(pErrInfo, VERR_SUPLIB_INVALID_INTERNAL_APP_DIR,
1656 "Internal executable does reside under RTPathAppPrivateArch");
1657 szExecPath[cchAppPrivateArch] = RTPATH_SLASH;
1658 }
1659
1660#ifdef VBOX_WITH_HARDENING
1661 /*
1662 * Verify that the image file and parent directories are sane.
1663 */
1664 rc = supR3HardenedVerifyFile(szExecPath, RTHCUINTPTR_MAX, false /*fMaybe3rdParty*/, pErrInfo);
1665 if (RT_FAILURE(rc))
1666 return rc;
1667#endif
1668
1669 return VINF_SUCCESS;
1670}
1671
1672
1673SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo)
1674{
1675 /*
1676 * Quick input validation
1677 */
1678 AssertPtr(pszDirPath);
1679 RTErrInfoClear(pErrInfo);
1680
1681 /*
1682 * Only do the actual check in hardened builds.
1683 */
1684#ifdef VBOX_WITH_HARDENING
1685 int rc = supR3HardenedVerifyDir(pszDirPath, fRecursive, fCheckFiles, pErrInfo);
1686 if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
1687 LogRel(("supR3HardenedVerifyDir: Verification of \"%s\" failed, rc=%Rrc\n", pszDirPath, rc));
1688 return rc;
1689#else
1690 NOREF(pszDirPath); NOREF(fRecursive); NOREF(fCheckFiles);
1691 return VINF_SUCCESS;
1692#endif
1693}
1694
1695
1696SUPR3DECL(int) SUPR3HardenedVerifyPlugIn(const char *pszFilename, PRTERRINFO pErrInfo)
1697{
1698 /*
1699 * Quick input validation
1700 */
1701 AssertPtr(pszFilename);
1702 RTErrInfoClear(pErrInfo);
1703
1704 /*
1705 * Only do the actual check in hardened builds.
1706 */
1707#ifdef VBOX_WITH_HARDENING
1708 int rc = supR3HardenedVerifyFile(pszFilename, RTHCUINTPTR_MAX, true /*fMaybe3rdParty*/, pErrInfo);
1709 if (RT_FAILURE(rc) && !RTErrInfoIsSet(pErrInfo))
1710 LogRel(("supR3HardenedVerifyFile: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1711 return rc;
1712#else
1713 RT_NOREF1(pszFilename);
1714 return VINF_SUCCESS;
1715#endif
1716}
1717
1718
1719SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
1720{
1721 if (g_pSUPGlobalInfoPage)
1722 {
1723 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1724 return VINF_SUCCESS;
1725 }
1726 *pHCPhys = NIL_RTHCPHYS;
1727 return VERR_WRONG_ORDER;
1728}
1729
1730
1731SUPR3DECL(int) SUPR3QueryVTxSupported(const char **ppszWhy)
1732{
1733 *ppszWhy = NULL;
1734#ifdef RT_OS_LINUX
1735 return suplibOsQueryVTxSupported(ppszWhy);
1736#else
1737 return VINF_SUCCESS;
1738#endif
1739}
1740
1741
1742SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps)
1743{
1744 AssertPtrReturn(pfCaps, VERR_INVALID_POINTER);
1745
1746 *pfCaps = 0;
1747
1748 int rc;
1749 if (!g_supLibData.fDriverless)
1750 {
1751 /*
1752 * Issue IOCtl to the SUPDRV kernel module.
1753 */
1754 SUPVTCAPS Req;
1755 Req.Hdr.u32Cookie = g_u32Cookie;
1756 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1757 Req.Hdr.cbIn = SUP_IOCTL_VT_CAPS_SIZE_IN;
1758 Req.Hdr.cbOut = SUP_IOCTL_VT_CAPS_SIZE_OUT;
1759 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1760 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1761 Req.u.Out.fCaps = 0;
1762 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_VT_CAPS, &Req, SUP_IOCTL_VT_CAPS_SIZE);
1763 if (RT_SUCCESS(rc))
1764 {
1765 rc = Req.Hdr.rc;
1766 if (RT_SUCCESS(rc))
1767 *pfCaps = Req.u.Out.fCaps;
1768 }
1769 }
1770 /*
1771 * Fail this call in driverless mode.
1772 */
1773 else
1774 rc = VERR_SUP_DRIVERLESS;
1775 return rc;
1776}
1777
1778
1779SUPR3DECL(bool) SUPR3IsNemSupportedWhenNoVtxOrAmdV(void)
1780{
1781#if defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
1782 return suplibOsIsNemSupportedWhenNoVtxOrAmdV();
1783#else
1784 return false;
1785#endif
1786}
1787
1788
1789SUPR3DECL(int) SUPR3QueryMicrocodeRev(uint32_t *puMicrocodeRev)
1790{
1791 AssertPtrReturn(puMicrocodeRev, VERR_INVALID_POINTER);
1792
1793 *puMicrocodeRev = 0;
1794
1795 int rc;
1796 if (!g_supLibData.fDriverless)
1797 {
1798 /*
1799 * Issue IOCtl to the SUPDRV kernel module.
1800 */
1801 SUPUCODEREV Req;
1802 Req.Hdr.u32Cookie = g_u32Cookie;
1803 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1804 Req.Hdr.cbIn = SUP_IOCTL_UCODE_REV_SIZE_IN;
1805 Req.Hdr.cbOut = SUP_IOCTL_UCODE_REV_SIZE_OUT;
1806 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1807 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1808 Req.u.Out.MicrocodeRev = 0;
1809 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_UCODE_REV, &Req, SUP_IOCTL_UCODE_REV_SIZE);
1810 if (RT_SUCCESS(rc))
1811 {
1812 rc = Req.Hdr.rc;
1813 if (RT_SUCCESS(rc))
1814 *puMicrocodeRev = Req.u.Out.MicrocodeRev;
1815 }
1816 }
1817 /*
1818 * Just fail the call in driverless mode if there is a host specific way of
1819 * getting the information.
1820 */
1821 else
1822#if defined(RT_OS_DARWIN) && defined(RT_ARCH_AMD64)
1823 rc = suplibOsQueryMicrocodeRev(puMicrocodeRev);
1824#else
1825 rc = VERR_SUP_DRIVERLESS;
1826#endif
1827 return rc;
1828}
1829
1830
1831SUPR3DECL(int) SUPR3TracerOpen(uint32_t uCookie, uintptr_t uArg)
1832{
1833 /* fake */
1834 if (RT_UNLIKELY(g_uSupFakeMode))
1835 return VINF_SUCCESS;
1836
1837 /*
1838 * Issue IOCtl to the SUPDRV kernel module.
1839 */
1840 SUPTRACEROPEN Req;
1841 Req.Hdr.u32Cookie = g_u32Cookie;
1842 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
1843 Req.Hdr.cbIn = SUP_IOCTL_TRACER_OPEN_SIZE_IN;
1844 Req.Hdr.cbOut = SUP_IOCTL_TRACER_OPEN_SIZE_OUT;
1845 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1846 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1847 Req.u.In.uCookie = uCookie;
1848 Req.u.In.uArg = uArg;
1849 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_OPEN, &Req, SUP_IOCTL_TRACER_OPEN_SIZE);
1850 if (RT_SUCCESS(rc))
1851 rc = Req.Hdr.rc;
1852 return rc;
1853}
1854
1855
1856SUPR3DECL(int) SUPR3TracerClose(void)
1857{
1858 /* fake */
1859 if (RT_UNLIKELY(g_uSupFakeMode))
1860 return VINF_SUCCESS;
1861
1862 /*
1863 * Issue IOCtl to the SUPDRV kernel module.
1864 */
1865 SUPREQHDR Req;
1866 Req.u32Cookie = g_u32Cookie;
1867 Req.u32SessionCookie= g_u32SessionCookie;
1868 Req.cbIn = SUP_IOCTL_TRACER_OPEN_SIZE_IN;
1869 Req.cbOut = SUP_IOCTL_TRACER_OPEN_SIZE_OUT;
1870 Req.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1871 Req.rc = VERR_INTERNAL_ERROR;
1872 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_CLOSE, &Req, SUP_IOCTL_TRACER_CLOSE_SIZE);
1873 if (RT_SUCCESS(rc))
1874 rc = Req.rc;
1875 return rc;
1876}
1877
1878
1879SUPR3DECL(int) SUPR3TracerIoCtl(uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1880{
1881 /* fake */
1882 if (RT_UNLIKELY(g_uSupFakeMode))
1883 {
1884 *piRetVal = -1;
1885 return VERR_NOT_SUPPORTED;
1886 }
1887
1888 /*
1889 * Issue IOCtl to the SUPDRV kernel module.
1890 */
1891 SUPTRACERIOCTL Req;
1892 Req.Hdr.u32Cookie = g_u32Cookie;
1893 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
1894 Req.Hdr.cbIn = SUP_IOCTL_TRACER_IOCTL_SIZE_IN;
1895 Req.Hdr.cbOut = SUP_IOCTL_TRACER_IOCTL_SIZE_OUT;
1896 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1897 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1898 Req.u.In.uCmd = uCmd;
1899 Req.u.In.uArg = uArg;
1900 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_IOCTL, &Req, SUP_IOCTL_TRACER_IOCTL_SIZE);
1901 if (RT_SUCCESS(rc))
1902 {
1903 rc = Req.Hdr.rc;
1904 *piRetVal = Req.u.Out.iRetVal;
1905 }
1906 return rc;
1907}
1908
1909
1910
1911typedef struct SUPDRVTRACERSTRTAB
1912{
1913 /** Pointer to the string table. */
1914 char *pchStrTab;
1915 /** The actual string table size. */
1916 uint32_t cbStrTab;
1917 /** The original string pointers. */
1918 RTUINTPTR apszOrgFunctions[1];
1919} SUPDRVTRACERSTRTAB, *PSUPDRVTRACERSTRTAB;
1920
1921
1922/**
1923 * Destroys a string table, restoring the original pszFunction member valus.
1924 *
1925 * @param pThis The string table structure.
1926 * @param paProbeLocs32 The probe location array, 32-bit type variant.
1927 * @param paProbeLocs64 The probe location array, 64-bit type variant.
1928 * @param cProbeLocs The number of elements in the array.
1929 * @param f32Bit Set if @a paProbeLocs32 should be used, when
1930 * clear use @a paProbeLocs64.
1931 */
1932static void supr3TracerDestroyStrTab(PSUPDRVTRACERSTRTAB pThis, PVTGPROBELOC32 paProbeLocs32, PVTGPROBELOC64 paProbeLocs64,
1933 uint32_t cProbeLocs, bool f32Bit)
1934{
1935 /* Restore. */
1936 size_t i = cProbeLocs;
1937 if (f32Bit)
1938 while (i--)
1939 paProbeLocs32[i].pszFunction = (uint32_t)pThis->apszOrgFunctions[i];
1940 else
1941 while (i--)
1942 paProbeLocs64[i].pszFunction = pThis->apszOrgFunctions[i];
1943
1944 /* Free. */
1945 RTMemFree(pThis->pchStrTab);
1946 RTMemFree(pThis);
1947}
1948
1949
1950/**
1951 * Creates a string table for the pszFunction members in the probe location
1952 * array.
1953 *
1954 * This will save and replace the pszFunction members with offsets.
1955 *
1956 * @returns Pointer to a string table structure. NULL on failure.
1957 * @param paProbeLocs32 The probe location array, 32-bit type variant.
1958 * @param paProbeLocs64 The probe location array, 64-bit type variant.
1959 * @param cProbeLocs The number of elements in the array.
1960 * @param offDelta Relocation offset for the string pointers.
1961 * @param f32Bit Set if @a paProbeLocs32 should be used, when
1962 * clear use @a paProbeLocs64.
1963 */
1964static PSUPDRVTRACERSTRTAB supr3TracerCreateStrTab(PVTGPROBELOC32 paProbeLocs32,
1965 PVTGPROBELOC64 paProbeLocs64,
1966 uint32_t cProbeLocs,
1967 RTUINTPTR offDelta,
1968 bool f32Bit)
1969{
1970 if (cProbeLocs > _128K)
1971 return NULL;
1972
1973 /*
1974 * Allocate the string table structures.
1975 */
1976 size_t cbThis = RT_UOFFSETOF_DYN(SUPDRVTRACERSTRTAB, apszOrgFunctions[cProbeLocs]);
1977 PSUPDRVTRACERSTRTAB pThis = (PSUPDRVTRACERSTRTAB)RTMemAlloc(cbThis);
1978 if (!pThis)
1979 return NULL;
1980
1981 uint32_t const cHashBits = cProbeLocs * 2 - 1;
1982 uint32_t *pbmHash = (uint32_t *)RTMemAllocZ(RT_ALIGN_32(cHashBits, 64) / 8 );
1983 if (!pbmHash)
1984 {
1985 RTMemFree(pThis);
1986 return NULL;
1987 }
1988
1989 /*
1990 * Calc the max string table size and save the orignal pointers so we can
1991 * replace them later.
1992 */
1993 size_t cbMax = 1;
1994 for (uint32_t i = 0; i < cProbeLocs; i++)
1995 {
1996 pThis->apszOrgFunctions[i] = f32Bit ? paProbeLocs32[i].pszFunction : paProbeLocs64[i].pszFunction;
1997 const char *pszFunction = (const char *)(uintptr_t)(pThis->apszOrgFunctions[i] + offDelta);
1998 size_t cch = strlen(pszFunction);
1999 if (cch > _1K)
2000 {
2001 cbMax = 0;
2002 break;
2003 }
2004 cbMax += cch + 1;
2005 }
2006
2007 /* Alloc space for it. */
2008 if (cbMax > 0)
2009 pThis->pchStrTab = (char *)RTMemAlloc(cbMax);
2010 else
2011 pThis->pchStrTab = NULL;
2012 if (!pThis->pchStrTab)
2013 {
2014 RTMemFree(pbmHash);
2015 RTMemFree(pThis);
2016 return NULL;
2017 }
2018
2019 /*
2020 * Create the string table.
2021 */
2022 uint32_t off = 0;
2023 uint32_t offPrev = 0;
2024
2025 for (uint32_t i = 0; i < cProbeLocs; i++)
2026 {
2027 const char * const psz = (const char *)(uintptr_t)(pThis->apszOrgFunctions[i] + offDelta);
2028 size_t const cch = strlen(psz);
2029 uint32_t const iHashBit = RTStrHash1(psz) % cHashBits;
2030 if (ASMBitTestAndSet(pbmHash, iHashBit))
2031 {
2032 /* Often it's the most recent string. */
2033 if ( off - offPrev < cch + 1
2034 || memcmp(&pThis->pchStrTab[offPrev], psz, cch + 1))
2035 {
2036 /* It wasn't, search the entire string table. (lazy bird) */
2037 offPrev = 0;
2038 while (offPrev < off)
2039 {
2040 size_t cchCur = strlen(&pThis->pchStrTab[offPrev]);
2041 if ( cchCur == cch
2042 && !memcmp(&pThis->pchStrTab[offPrev], psz, cch + 1))
2043 break;
2044 offPrev += (uint32_t)cchCur + 1;
2045 }
2046 }
2047 }
2048 else
2049 offPrev = off;
2050
2051 /* Add the string to the table. */
2052 if (offPrev >= off)
2053 {
2054 memcpy(&pThis->pchStrTab[off], psz, cch + 1);
2055 offPrev = off;
2056 off += (uint32_t)cch + 1;
2057 }
2058
2059 /* Update the entry */
2060 if (f32Bit)
2061 paProbeLocs32[i].pszFunction = offPrev;
2062 else
2063 paProbeLocs64[i].pszFunction = offPrev;
2064 }
2065
2066 pThis->cbStrTab = off;
2067 RTMemFree(pbmHash);
2068 return pThis;
2069}
2070
2071
2072
2073SUPR3DECL(int) SUPR3TracerRegisterModule(uintptr_t hModNative, const char *pszModule, struct VTGOBJHDR *pVtgHdr,
2074 RTUINTPTR uVtgHdrAddr, uint32_t fFlags)
2075{
2076 /* Validate input. */
2077 NOREF(hModNative);
2078 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
2079 AssertReturn(!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)), VERR_SUPDRV_VTG_MAGIC);
2080 AssertPtrReturn(pszModule, VERR_INVALID_POINTER);
2081 size_t cchModule = strlen(pszModule);
2082 AssertReturn(cchModule < RT_SIZEOFMEMB(SUPTRACERUMODREG, u.In.szName), VERR_FILENAME_TOO_LONG);
2083 AssertReturn(!RTPathHavePath(pszModule), VERR_INVALID_PARAMETER);
2084 AssertReturn(fFlags == SUP_TRACER_UMOD_FLAGS_EXE || fFlags == SUP_TRACER_UMOD_FLAGS_SHARED, VERR_INVALID_PARAMETER);
2085
2086 /*
2087 * Set the probe location array offset and size members. If the size is
2088 * zero, don't bother ring-0 with it.
2089 */
2090 if (!pVtgHdr->offProbeLocs)
2091 {
2092 uint64_t u64Tmp = pVtgHdr->uProbeLocsEnd.u64 - pVtgHdr->uProbeLocs.u64;
2093 if (u64Tmp >= UINT32_MAX)
2094 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
2095 pVtgHdr->cbProbeLocs = (uint32_t)u64Tmp;
2096
2097 u64Tmp = pVtgHdr->uProbeLocs.u64 - uVtgHdrAddr;
2098 if ((int64_t)u64Tmp != (int32_t)u64Tmp)
2099 {
2100 LogRel(("SUPR3TracerRegisterModule: VERR_SUPDRV_VTG_BAD_HDR_PTR - u64Tmp=%#llx uProbeLocs=%#llx uVtgHdrAddr=%RTptr\n",
2101 u64Tmp, pVtgHdr->uProbeLocs.u64, uVtgHdrAddr));
2102 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
2103 }
2104 pVtgHdr->offProbeLocs = (int32_t)u64Tmp;
2105 }
2106
2107 if ( !pVtgHdr->cbProbeLocs
2108 || !pVtgHdr->cbProbes)
2109 return VINF_SUCCESS;
2110
2111 /*
2112 * Fake out.
2113 */
2114 if (RT_UNLIKELY(g_uSupFakeMode))
2115 return VINF_SUCCESS;
2116
2117 /*
2118 * Create a string table for the function names in the location array.
2119 * It's somewhat easier to do that here than from ring-0.
2120 */
2121 uint32_t const cProbeLocs = pVtgHdr->cbProbeLocs
2122 / (pVtgHdr->cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
2123 PVTGPROBELOC paProbeLocs = (PVTGPROBELOC)((uintptr_t)pVtgHdr + pVtgHdr->offProbeLocs);
2124 PSUPDRVTRACERSTRTAB pStrTab = supr3TracerCreateStrTab((PVTGPROBELOC32)paProbeLocs,
2125 (PVTGPROBELOC64)paProbeLocs,
2126 cProbeLocs, (uintptr_t)pVtgHdr - uVtgHdrAddr,
2127 pVtgHdr->cBits == 32);
2128 if (!pStrTab)
2129 return VERR_NO_MEMORY;
2130
2131
2132 /*
2133 * Issue IOCtl to the SUPDRV kernel module.
2134 */
2135 SUPTRACERUMODREG Req;
2136 Req.Hdr.u32Cookie = g_u32Cookie;
2137 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
2138 Req.Hdr.cbIn = SUP_IOCTL_TRACER_UMOD_REG_SIZE_IN;
2139 Req.Hdr.cbOut = SUP_IOCTL_TRACER_UMOD_REG_SIZE_OUT;
2140 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2141 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2142 Req.u.In.uVtgHdrAddr = uVtgHdrAddr;
2143 Req.u.In.R3PtrVtgHdr = pVtgHdr;
2144 Req.u.In.R3PtrStrTab = pStrTab->pchStrTab;
2145 Req.u.In.cbStrTab = pStrTab->cbStrTab;
2146 Req.u.In.fFlags = fFlags;
2147
2148 memcpy(Req.u.In.szName, pszModule, cchModule + 1);
2149 if (!RTPathHasSuffix(Req.u.In.szName))
2150 {
2151 /* Add the default suffix if none is given. */
2152 switch (fFlags & SUP_TRACER_UMOD_FLAGS_TYPE_MASK)
2153 {
2154#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
2155 case SUP_TRACER_UMOD_FLAGS_EXE:
2156 if (cchModule + sizeof(".exe") <= sizeof(Req.u.In.szName))
2157 strcpy(&Req.u.In.szName[cchModule], ".exe");
2158 break;
2159#endif
2160
2161 case SUP_TRACER_UMOD_FLAGS_SHARED:
2162 {
2163 const char *pszSuff = RTLdrGetSuff();
2164 size_t cchSuff = strlen(pszSuff);
2165 if (cchModule + cchSuff < sizeof(Req.u.In.szName))
2166 memcpy(&Req.u.In.szName[cchModule], pszSuff, cchSuff + 1);
2167 break;
2168 }
2169 }
2170 }
2171
2172 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_REG, &Req, SUP_IOCTL_TRACER_UMOD_REG_SIZE);
2173 if (RT_SUCCESS(rc))
2174 rc = Req.Hdr.rc;
2175
2176 supr3TracerDestroyStrTab(pStrTab, (PVTGPROBELOC32)paProbeLocs, (PVTGPROBELOC64)paProbeLocs,
2177 cProbeLocs, pVtgHdr->cBits == 32);
2178 return rc;
2179}
2180
2181
2182SUPR3DECL(int) SUPR3TracerDeregisterModule(struct VTGOBJHDR *pVtgHdr)
2183{
2184 /* Validate input. */
2185 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
2186 AssertReturn(!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)), VERR_SUPDRV_VTG_MAGIC);
2187
2188 /*
2189 * Don't bother if the object is empty.
2190 */
2191 if ( !pVtgHdr->cbProbeLocs
2192 || !pVtgHdr->cbProbes)
2193 return VINF_SUCCESS;
2194
2195 /*
2196 * Fake out.
2197 */
2198 if (RT_UNLIKELY(g_uSupFakeMode))
2199 return VINF_SUCCESS;
2200
2201 /*
2202 * Issue IOCtl to the SUPDRV kernel module.
2203 */
2204 SUPTRACERUMODDEREG Req;
2205 Req.Hdr.u32Cookie = g_u32Cookie;
2206 Req.Hdr.u32SessionCookie= g_u32SessionCookie;
2207 Req.Hdr.cbIn = SUP_IOCTL_TRACER_UMOD_REG_SIZE_IN;
2208 Req.Hdr.cbOut = SUP_IOCTL_TRACER_UMOD_REG_SIZE_OUT;
2209 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2210 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2211 Req.u.In.pVtgHdr = pVtgHdr;
2212
2213 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_DEREG, &Req, SUP_IOCTL_TRACER_UMOD_DEREG_SIZE);
2214 if (RT_SUCCESS(rc))
2215 rc = Req.Hdr.rc;
2216 return rc;
2217}
2218
2219
2220DECLASM(void) suplibTracerFireProbe(PVTGPROBELOC pProbeLoc, PSUPTRACERUMODFIREPROBE pReq)
2221{
2222 RT_NOREF1(pProbeLoc);
2223
2224 pReq->Hdr.u32Cookie = g_u32Cookie;
2225 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
2226 Assert(pReq->Hdr.cbIn == SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE_IN);
2227 Assert(pReq->Hdr.cbOut == SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE_OUT);
2228 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2229 pReq->Hdr.rc = VINF_SUCCESS;
2230
2231 suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TRACER_UMOD_FIRE_PROBE, pReq, SUP_IOCTL_TRACER_UMOD_FIRE_PROBE_SIZE);
2232}
2233
2234
2235SUPR3DECL(int) SUPR3MsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue, bool *pfGp)
2236{
2237 SUPMSRPROBER Req;
2238 Req.Hdr.u32Cookie = g_u32Cookie;
2239 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2240 Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
2241 Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
2242 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2243 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2244
2245 Req.u.In.enmOp = SUPMSRPROBEROP_READ;
2246 Req.u.In.uMsr = uMsr;
2247 Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
2248
2249 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
2250 if (RT_SUCCESS(rc))
2251 rc = Req.Hdr.rc;
2252 if (RT_SUCCESS(rc))
2253 {
2254 if (puValue)
2255 *puValue = Req.u.Out.uResults.Read.uValue;
2256 if (pfGp)
2257 *pfGp = Req.u.Out.uResults.Read.fGp;
2258 }
2259
2260 return rc;
2261}
2262
2263
2264SUPR3DECL(int) SUPR3MsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue, bool *pfGp)
2265{
2266 SUPMSRPROBER Req;
2267 Req.Hdr.u32Cookie = g_u32Cookie;
2268 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2269 Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
2270 Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
2271 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2272 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2273
2274 Req.u.In.enmOp = SUPMSRPROBEROP_WRITE;
2275 Req.u.In.uMsr = uMsr;
2276 Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
2277 Req.u.In.uArgs.Write.uToWrite = uValue;
2278
2279 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
2280 if (RT_SUCCESS(rc))
2281 rc = Req.Hdr.rc;
2282 if (RT_SUCCESS(rc) && pfGp)
2283 *pfGp = Req.u.Out.uResults.Write.fGp;
2284
2285 return rc;
2286}
2287
2288
2289SUPR3DECL(int) SUPR3MsrProberModify(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask,
2290 PSUPMSRPROBERMODIFYRESULT pResult)
2291{
2292 return SUPR3MsrProberModifyEx(uMsr, idCpu, fAndMask, fOrMask, false /*fFaster*/, pResult);
2293}
2294
2295
2296SUPR3DECL(int) SUPR3MsrProberModifyEx(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, bool fFaster,
2297 PSUPMSRPROBERMODIFYRESULT pResult)
2298{
2299 SUPMSRPROBER Req;
2300 Req.Hdr.u32Cookie = g_u32Cookie;
2301 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2302 Req.Hdr.cbIn = SUP_IOCTL_MSR_PROBER_SIZE_IN;
2303 Req.Hdr.cbOut = SUP_IOCTL_MSR_PROBER_SIZE_OUT;
2304 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2305 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2306
2307 Req.u.In.enmOp = fFaster ? SUPMSRPROBEROP_MODIFY_FASTER : SUPMSRPROBEROP_MODIFY;
2308 Req.u.In.uMsr = uMsr;
2309 Req.u.In.idCpu = idCpu == NIL_RTCPUID ? UINT32_MAX : idCpu;
2310 Req.u.In.uArgs.Modify.fAndMask = fAndMask;
2311 Req.u.In.uArgs.Modify.fOrMask = fOrMask;
2312
2313 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_MSR_PROBER, &Req, SUP_IOCTL_MSR_PROBER_SIZE);
2314 if (RT_SUCCESS(rc))
2315 rc = Req.Hdr.rc;
2316 if (RT_SUCCESS(rc))
2317 *pResult = Req.u.Out.uResults.Modify;
2318
2319 return rc;
2320}
2321
2322
2323SUPR3DECL(int) SUPR3ResumeSuspendedKeyboards(void)
2324{
2325#ifdef RT_OS_DARWIN
2326 /*
2327 * Issue IOCtl to the SUPDRV kernel module.
2328 */
2329 SUPREQHDR Req;
2330 Req.u32Cookie = g_u32Cookie;
2331 Req.u32SessionCookie= g_u32SessionCookie;
2332 Req.cbIn = SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE_IN;
2333 Req.cbOut = SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE_OUT;
2334 Req.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2335 Req.rc = VERR_INTERNAL_ERROR;
2336 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_RESUME_SUSPENDED_KBDS, &Req, SUP_IOCTL_RESUME_SUSPENDED_KBDS_SIZE);
2337 if (RT_SUCCESS(rc))
2338 rc = Req.rc;
2339 return rc;
2340#else /* !RT_OS_DARWIN */
2341 return VERR_NOT_SUPPORTED;
2342#endif
2343}
2344
2345
2346SUPR3DECL(int) SUPR3TscDeltaMeasure(RTCPUID idCpu, bool fAsync, bool fForce, uint8_t cRetries, uint8_t cMsWaitRetry)
2347{
2348 SUPTSCDELTAMEASURE Req;
2349 Req.Hdr.u32Cookie = g_u32Cookie;
2350 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2351 Req.Hdr.cbIn = SUP_IOCTL_TSC_DELTA_MEASURE_SIZE_IN;
2352 Req.Hdr.cbOut = SUP_IOCTL_TSC_DELTA_MEASURE_SIZE_OUT;
2353 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2354 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2355
2356 Req.u.In.cRetries = cRetries;
2357 Req.u.In.fAsync = fAsync;
2358 Req.u.In.fForce = fForce;
2359 Req.u.In.idCpu = idCpu;
2360 Req.u.In.cMsWaitRetry = cMsWaitRetry;
2361
2362 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TSC_DELTA_MEASURE, &Req, SUP_IOCTL_TSC_DELTA_MEASURE_SIZE);
2363 if (RT_SUCCESS(rc))
2364 rc = Req.Hdr.rc;
2365 return rc;
2366}
2367
2368
2369SUPR3DECL(int) SUPR3ReadTsc(uint64_t *puTsc, uint16_t *pidApic)
2370{
2371 AssertReturn(puTsc, VERR_INVALID_PARAMETER);
2372
2373 SUPTSCREAD Req;
2374 Req.Hdr.u32Cookie = g_u32Cookie;
2375 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2376 Req.Hdr.cbIn = SUP_IOCTL_TSC_READ_SIZE_IN;
2377 Req.Hdr.cbOut = SUP_IOCTL_TSC_READ_SIZE_OUT;
2378 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2379 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2380
2381 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_TSC_READ, &Req, SUP_IOCTL_TSC_READ_SIZE);
2382 if (RT_SUCCESS(rc))
2383 {
2384 rc = Req.Hdr.rc;
2385 *puTsc = Req.u.Out.u64AdjustedTsc;
2386 if (pidApic)
2387 *pidApic = Req.u.Out.idApic;
2388 }
2389 return rc;
2390}
2391
2392
2393SUPR3DECL(int) SUPR3GipSetFlags(uint32_t fOrMask, uint32_t fAndMask)
2394{
2395 AssertMsgReturn(!(fOrMask & ~SUPGIP_FLAGS_VALID_MASK),
2396 ("fOrMask=%#x ValidMask=%#x\n", fOrMask, SUPGIP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2397 AssertMsgReturn((fAndMask & ~SUPGIP_FLAGS_VALID_MASK) == ~SUPGIP_FLAGS_VALID_MASK,
2398 ("fAndMask=%#x ValidMask=%#x\n", fAndMask, SUPGIP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2399
2400 SUPGIPSETFLAGS Req;
2401 Req.Hdr.u32Cookie = g_u32Cookie;
2402 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2403 Req.Hdr.cbIn = SUP_IOCTL_GIP_SET_FLAGS_SIZE_IN;
2404 Req.Hdr.cbOut = SUP_IOCTL_GIP_SET_FLAGS_SIZE_OUT;
2405 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2406 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2407
2408 Req.u.In.fAndMask = fAndMask;
2409 Req.u.In.fOrMask = fOrMask;
2410
2411 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_SET_FLAGS, &Req, SUP_IOCTL_GIP_SET_FLAGS_SIZE);
2412 if (RT_SUCCESS(rc))
2413 rc = Req.Hdr.rc;
2414 return rc;
2415}
2416
2417
2418SUPR3DECL(int) SUPR3GetHwvirtMsrs(PSUPHWVIRTMSRS pHwvirtMsrs, bool fForceRequery)
2419{
2420 AssertReturn(pHwvirtMsrs, VERR_INVALID_PARAMETER);
2421
2422 SUPGETHWVIRTMSRS Req;
2423 Req.Hdr.u32Cookie = g_u32Cookie;
2424 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2425 Req.Hdr.cbIn = SUP_IOCTL_GET_HWVIRT_MSRS_SIZE_IN;
2426 Req.Hdr.cbOut = SUP_IOCTL_GET_HWVIRT_MSRS_SIZE_OUT;
2427 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2428 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2429
2430 Req.u.In.fForce = fForceRequery;
2431 Req.u.In.fReserved0 = false;
2432 Req.u.In.fReserved1 = false;
2433 Req.u.In.fReserved2 = false;
2434
2435 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_HWVIRT_MSRS, &Req, SUP_IOCTL_GET_HWVIRT_MSRS_SIZE);
2436 if (RT_SUCCESS(rc))
2437 {
2438 rc = Req.Hdr.rc;
2439 *pHwvirtMsrs = Req.u.Out.HwvirtMsrs;
2440 }
2441 else
2442 RT_ZERO(*pHwvirtMsrs);
2443 return rc;
2444}
2445
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette