VirtualBox

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

Last change on this file since 41147 was 41147, checked in by vboxsync, 13 years ago

SUPDrv,VMM: Tracepoints in raw-mode.

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