VirtualBox

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

Last change on this file since 32504 was 32504, checked in by vboxsync, 15 years ago

SUPDrv,IPRT,VMM,DevAPIC: Added RTTimerCanDoHighResolution and exposed the RTTimer* API to the ring-0 modules. Fixed two regression from r65858 (TM + APIC).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.8 KB
Line 
1/* $Id: SUPLib.cpp 32504 2010-09-15 10:12:38Z 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 * tranfer 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/vmm.h>
53#include <VBox/log.h>
54#include <VBox/x86.h>
55
56#include <iprt/assert.h>
57#include <iprt/alloc.h>
58#include <iprt/alloca.h>
59#include <iprt/ldr.h>
60#include <iprt/asm.h>
61#include <iprt/mp.h>
62#include <iprt/cpuset.h>
63#include <iprt/thread.h>
64#include <iprt/process.h>
65#include <iprt/path.h>
66#include <iprt/string.h>
67#include <iprt/env.h>
68#include <iprt/rand.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, specificly the parts that are being handed over
97 * via the pre-init mechanism from the hardened executable stub. */
98SUPLIBDATA g_supLibData =
99{
100 NIL_RTFILE
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 higly 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 == NIL_RTFILE)
189 return VERR_INVALID_HANDLE;
190 if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
191 && pPreInitData->Data.hDevice != NIL_RTFILE)
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) == 0x00150000
271 ? 0x00150002
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 { "RTProcSelf", 0xefef001d },
427 { "RTR0ProcHandleSelf", 0xefef001e },
428 { "RTSemEventCreate", 0xefef001f },
429 { "RTSemEventSignal", 0xefef0020 },
430 { "RTSemEventWait", 0xefef0021 },
431 { "RTSemEventWaitNoResume", 0xefef0022 },
432 { "RTSemEventDestroy", 0xefef0023 },
433 { "RTSemEventMultiCreate", 0xefef0024 },
434 { "RTSemEventMultiSignal", 0xefef0025 },
435 { "RTSemEventMultiReset", 0xefef0026 },
436 { "RTSemEventMultiWait", 0xefef0027 },
437 { "RTSemEventMultiWaitNoResume", 0xefef0028 },
438 { "RTSemEventMultiDestroy", 0xefef0029 },
439 { "RTSemFastMutexCreate", 0xefef002a },
440 { "RTSemFastMutexDestroy", 0xefef002b },
441 { "RTSemFastMutexRequest", 0xefef002c },
442 { "RTSemFastMutexRelease", 0xefef002d },
443 { "RTSpinlockCreate", 0xefef002e },
444 { "RTSpinlockDestroy", 0xefef002f },
445 { "RTSpinlockAcquire", 0xefef0030 },
446 { "RTSpinlockRelease", 0xefef0031 },
447 { "RTSpinlockAcquireNoInts", 0xefef0032 },
448 { "RTSpinlockReleaseNoInts", 0xefef0033 },
449 { "RTTimeNanoTS", 0xefef0034 },
450 { "RTTimeMillieTS", 0xefef0035 },
451 { "RTTimeSystemNanoTS", 0xefef0036 },
452 { "RTTimeSystemMillieTS", 0xefef0037 },
453 { "RTThreadNativeSelf", 0xefef0038 },
454 { "RTThreadSleep", 0xefef0039 },
455 { "RTThreadYield", 0xefef003a },
456 { "RTTimerCreate", 0xefef003a },
457 { "RTTimerCreateEx", 0xefef003a },
458 { "RTTimerDestroy", 0xefef003a },
459 { "RTTimerStart", 0xefef003a },
460 { "RTTimerStop", 0xefef003a },
461 { "RTTimerGetSystemGranularity", 0xefef003a },
462 { "RTTimerRequestSystemGranularity", 0xefef003a },
463 { "RTTimerReleaseSystemGranularity", 0xefef003a },
464 { "RTTimerCanDoHighResolution", 0xefef003a },
465 { "RTLogDefaultInstance", 0xefef003b },
466 { "RTLogRelDefaultInstance", 0xefef003c },
467 { "RTLogSetDefaultInstanceThread", 0xefef003d },
468 { "RTLogLogger", 0xefef003e },
469 { "RTLogLoggerEx", 0xefef003f },
470 { "RTLogLoggerExV", 0xefef0040 },
471 { "RTAssertMsg1", 0xefef0041 },
472 { "RTAssertMsg2", 0xefef0042 },
473 { "RTAssertMsg2V", 0xefef0043 },
474 { "SUPR0QueryVTCaps", 0xefef0044 },
475 };
476
477 /* fake r0 functions. */
478 g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
479 if (g_pFunctions)
480 {
481 g_pFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
482 memcpy(&g_pFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
483 g_pSession = (PSUPDRVSESSION)(void *)g_pFunctions;
484 if (ppSession)
485 *ppSession = g_pSession;
486
487 /* fake the GIP. */
488 g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
489 if (g_pSUPGlobalInfoPage)
490 {
491 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
492 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
493 /* the page is supposed to be invalid, so don't set the magic. */
494 return VINF_SUCCESS;
495 }
496
497 RTMemFree(g_pFunctions);
498 g_pFunctions = NULL;
499 }
500 return VERR_NO_MEMORY;
501}
502
503
504SUPR3DECL(int) SUPR3Term(bool fForced)
505{
506 /*
507 * Verify state.
508 */
509 AssertMsg(g_cInits > 0, ("SUPR3Term() is called before SUPR3Init()!\n"));
510 if (g_cInits == 0)
511 return VERR_WRONG_ORDER;
512 if (g_cInits == 1 || fForced)
513 {
514 /*
515 * NULL the GIP pointer.
516 */
517 if (g_pSUPGlobalInfoPage)
518 {
519 ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPage);
520 ASMAtomicWriteNullPtr((void * volatile *)&g_pSUPGlobalInfoPageR0);
521 ASMAtomicWriteSize(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
522 /* just a little safe guard against threads using the page. */
523 RTThreadSleep(50);
524 }
525
526 /*
527 * Close the support driver.
528 */
529 int rc = suplibOsTerm(&g_supLibData);
530 if (rc)
531 return rc;
532
533 g_u32Cookie = 0;
534 g_u32SessionCookie = 0;
535 g_cInits = 0;
536 }
537 else
538 g_cInits--;
539
540 return 0;
541}
542
543
544SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void)
545{
546 /* fake */
547 if (RT_UNLIKELY(g_u32FakeMode))
548#ifdef RT_ARCH_AMD64
549 return SUPPAGINGMODE_AMD64_GLOBAL_NX;
550#else
551 return SUPPAGINGMODE_32_BIT_GLOBAL;
552#endif
553
554 /*
555 * Issue IOCtl to the SUPDRV kernel module.
556 */
557 SUPGETPAGINGMODE Req;
558 Req.Hdr.u32Cookie = g_u32Cookie;
559 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
560 Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
561 Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
562 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
563 Req.Hdr.rc = VERR_INTERNAL_ERROR;
564 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
565 if ( RT_FAILURE(rc)
566 || RT_FAILURE(Req.Hdr.rc))
567 {
568 LogRel(("SUPR3GetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
569 Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
570 }
571
572 return Req.u.Out.enmMode;
573}
574
575
576/**
577 * For later.
578 */
579static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
580{
581 AssertMsgFailed(("%d\n", uOperation));
582 return VERR_NOT_SUPPORTED;
583}
584
585
586SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
587{
588 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_RAW_RUN))
589 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_RAW_RUN, idCpu);
590 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_HWACC_RUN))
591 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_HWACC_RUN, idCpu);
592 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_NOP))
593 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_NOP, idCpu);
594
595 AssertMsgFailed(("%#x\n", uOperation));
596 return VERR_INTERNAL_ERROR;
597}
598
599
600SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
601{
602 /*
603 * The following operations don't belong here.
604 */
605 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
606 && uOperation != SUP_VMMR0_DO_HWACC_RUN
607 && uOperation != SUP_VMMR0_DO_NOP,
608 ("%#x\n", uOperation),
609 VERR_INTERNAL_ERROR);
610
611 /* fake */
612 if (RT_UNLIKELY(g_u32FakeMode))
613 return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
614
615 int rc;
616 if (!pReqHdr)
617 {
618 /* no data. */
619 SUPCALLVMMR0 Req;
620 Req.Hdr.u32Cookie = g_u32Cookie;
621 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
622 Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
623 Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
624 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
625 Req.Hdr.rc = VERR_INTERNAL_ERROR;
626 Req.u.In.pVMR0 = pVMR0;
627 Req.u.In.idCpu = idCpu;
628 Req.u.In.uOperation = uOperation;
629 Req.u.In.u64Arg = u64Arg;
630 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
631 if (RT_SUCCESS(rc))
632 rc = Req.Hdr.rc;
633 }
634 else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
635 {
636 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
637 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
638 const size_t cbReq = pReqHdr->cbReq;
639
640 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
641 pReq->Hdr.u32Cookie = g_u32Cookie;
642 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
643 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
644 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
645 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
646 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
647 pReq->u.In.pVMR0 = pVMR0;
648 pReq->u.In.idCpu = idCpu;
649 pReq->u.In.uOperation = uOperation;
650 pReq->u.In.u64Arg = u64Arg;
651 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
652 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
653 if (RT_SUCCESS(rc))
654 rc = pReq->Hdr.rc;
655 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
656 }
657 else /** @todo may have to remove the size limits one this request... */
658 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
659 return rc;
660}
661
662
663SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg)
664{
665 /*
666 * The following operations don't belong here.
667 */
668 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
669 && uOperation != SUP_VMMR0_DO_HWACC_RUN
670 && uOperation != SUP_VMMR0_DO_NOP,
671 ("%#x\n", uOperation),
672 VERR_INTERNAL_ERROR);
673 return SUPR3CallVMMR0Ex(pVMR0, idCpu, uOperation, (uintptr_t)pvArg, NULL);
674}
675
676
677SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0)
678{
679 if (RT_UNLIKELY(g_u32FakeMode))
680 return VINF_SUCCESS;
681
682 SUPSETVMFORFAST Req;
683 Req.Hdr.u32Cookie = g_u32Cookie;
684 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
685 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
686 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
687 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
688 Req.Hdr.rc = VERR_INTERNAL_ERROR;
689 Req.u.In.pVMR0 = pVMR0;
690 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
691 if (RT_SUCCESS(rc))
692 rc = Req.Hdr.rc;
693 return rc;
694}
695
696
697SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
698{
699 AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
700 Assert(strlen(pszService) == cchService);
701
702 /* fake */
703 if (RT_UNLIKELY(g_u32FakeMode))
704 return VERR_NOT_SUPPORTED;
705
706 int rc;
707 if (!pReqHdr)
708 {
709 /* no data. */
710 SUPCALLSERVICE Req;
711 Req.Hdr.u32Cookie = g_u32Cookie;
712 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
713 Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
714 Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
715 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
716 Req.Hdr.rc = VERR_INTERNAL_ERROR;
717 memcpy(Req.u.In.szName, pszService, cchService);
718 Req.u.In.szName[cchService] = '\0';
719 Req.u.In.uOperation = uOperation;
720 Req.u.In.u64Arg = u64Arg;
721 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
722 if (RT_SUCCESS(rc))
723 rc = Req.Hdr.rc;
724 }
725 else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
726 {
727 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
728 AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
729 const size_t cbReq = pReqHdr->cbReq;
730
731 PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
732 pReq->Hdr.u32Cookie = g_u32Cookie;
733 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
734 pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
735 pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
736 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
737 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
738 memcpy(pReq->u.In.szName, pszService, cchService);
739 pReq->u.In.szName[cchService] = '\0';
740 pReq->u.In.uOperation = uOperation;
741 pReq->u.In.u64Arg = u64Arg;
742 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
743 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
744 if (RT_SUCCESS(rc))
745 rc = pReq->Hdr.rc;
746 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
747 }
748 else /** @todo may have to remove the size limits one this request... */
749 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
750 return rc;
751}
752
753
754/**
755 * Worker for the SUPR3Logger* APIs.
756 *
757 * @returns VBox status code.
758 * @param enmWhich Which logger.
759 * @param fWhat What to do with the logger.
760 * @param pszFlags The flags settings.
761 * @param pszGroups The groups settings.
762 * @param pszDest The destionation specificier.
763 */
764static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
765{
766 uint32_t const cchFlags = pszFlags ? (uint32_t)strlen(pszFlags) : 0;
767 uint32_t const cchGroups = pszGroups ? (uint32_t)strlen(pszGroups) : 0;
768 uint32_t const cchDest = pszDest ? (uint32_t)strlen(pszDest) : 0;
769 uint32_t const cbStrTab = cchFlags + !!cchFlags
770 + cchGroups + !!cchGroups
771 + cchDest + !!cchDest
772 + (!cchFlags && !cchGroups && !cchDest);
773
774 PSUPLOGGERSETTINGS pReq = (PSUPLOGGERSETTINGS)alloca(SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
775 pReq->Hdr.u32Cookie = g_u32Cookie;
776 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
777 pReq->Hdr.cbIn = SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(cbStrTab);
778 pReq->Hdr.cbOut = SUP_IOCTL_LOGGER_SETTINGS_SIZE_OUT;
779 pReq->Hdr.fFlags= SUPREQHDR_FLAGS_DEFAULT;
780 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
781 switch (enmWhich)
782 {
783 case SUPLOGGER_DEBUG: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_DEBUG; break;
784 case SUPLOGGER_RELEASE: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_RELEASE; break;
785 default:
786 return VERR_INVALID_PARAMETER;
787 }
788 pReq->u.In.fWhat = fWhat;
789
790 uint32_t off = 0;
791 if (cchFlags)
792 {
793 pReq->u.In.offFlags = off;
794 memcpy(&pReq->u.In.szStrings[off], pszFlags, cchFlags + 1);
795 off += cchFlags + 1;
796 }
797 else
798 pReq->u.In.offFlags = cbStrTab - 1;
799
800 if (cchGroups)
801 {
802 pReq->u.In.offGroups = off;
803 memcpy(&pReq->u.In.szStrings[off], pszGroups, cchGroups + 1);
804 off += cchGroups + 1;
805 }
806 else
807 pReq->u.In.offGroups = cbStrTab - 1;
808
809 if (cchDest)
810 {
811 pReq->u.In.offDestination = off;
812 memcpy(&pReq->u.In.szStrings[off], pszDest, cchDest + 1);
813 off += cchDest + 1;
814 }
815 else
816 pReq->u.In.offDestination = cbStrTab - 1;
817
818 if (!off)
819 {
820 pReq->u.In.szStrings[0] = '\0';
821 off++;
822 }
823 Assert(off == cbStrTab);
824 Assert(pReq->u.In.szStrings[cbStrTab - 1] == '\0');
825
826
827 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
828 if (RT_SUCCESS(rc))
829 rc = pReq->Hdr.rc;
830 return rc;
831}
832
833
834SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
835{
836 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_SETTINGS, pszFlags, pszGroups, pszDest);
837}
838
839
840SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
841{
842 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_CREATE, pszFlags, pszGroups, pszDest);
843}
844
845
846SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich)
847{
848 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_DESTROY, NULL, NULL, NULL);
849}
850
851
852SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, void **ppvPages)
853{
854 /*
855 * Validate.
856 */
857 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
858 *ppvPages = NULL;
859 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
860
861 /*
862 * Call OS specific worker.
863 */
864 return suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
865}
866
867
868SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages)
869{
870 /*
871 * Validate.
872 */
873 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
874 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
875
876 /*
877 * Call OS specific worker.
878 */
879 return suplibOsPageFree(&g_supLibData, pvPages, cPages);
880}
881
882
883/**
884 * Locks down the physical memory backing a virtual memory
885 * range in the current process.
886 *
887 * @returns VBox status code.
888 * @param pvStart Start of virtual memory range.
889 * Must be page aligned.
890 * @param cPages Number of pages.
891 * @param paPages Where to store the physical page addresses returned.
892 * On entry this will point to an array of with cbMemory >> PAGE_SHIFT entries.
893 */
894SUPR3DECL(int) supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
895{
896 /*
897 * Validate.
898 */
899 AssertPtr(pvStart);
900 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
901 AssertPtr(paPages);
902
903 /* fake */
904 if (RT_UNLIKELY(g_u32FakeMode))
905 {
906 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
907 size_t iPage = cPages;
908 while (iPage-- > 0)
909 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
910 return VINF_SUCCESS;
911 }
912
913 /*
914 * Issue IOCtl to the SUPDRV kernel module.
915 */
916 int rc;
917 PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
918 if (RT_LIKELY(pReq))
919 {
920 pReq->Hdr.u32Cookie = g_u32Cookie;
921 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
922 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
923 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
924 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
925 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
926 pReq->u.In.pvR3 = pvStart;
927 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
928 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
929 if (RT_SUCCESS(rc))
930 rc = pReq->Hdr.rc;
931 if (RT_SUCCESS(rc))
932 {
933 for (uint32_t iPage = 0; iPage < cPages; iPage++)
934 {
935 paPages[iPage].uReserved = 0;
936 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
937 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
938 }
939 }
940 RTMemTmpFree(pReq);
941 }
942 else
943 rc = VERR_NO_TMP_MEMORY;
944
945 return rc;
946}
947
948
949/**
950 * Releases locked down pages.
951 *
952 * @returns VBox status code.
953 * @param pvStart Start of virtual memory range previously locked
954 * down by SUPPageLock().
955 */
956SUPR3DECL(int) supR3PageUnlock(void *pvStart)
957{
958 /*
959 * Validate.
960 */
961 AssertPtr(pvStart);
962 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
963
964 /* fake */
965 if (RT_UNLIKELY(g_u32FakeMode))
966 return VINF_SUCCESS;
967
968 /*
969 * Issue IOCtl to the SUPDRV kernel module.
970 */
971 SUPPAGEUNLOCK Req;
972 Req.Hdr.u32Cookie = g_u32Cookie;
973 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
974 Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
975 Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
976 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
977 Req.Hdr.rc = VERR_INTERNAL_ERROR;
978 Req.u.In.pvR3 = pvStart;
979 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
980 if (RT_SUCCESS(rc))
981 rc = Req.Hdr.rc;
982 return rc;
983}
984
985
986/**
987 * Fallback for SUPR3PageAllocEx on systems where RTR0MemObjPhysAllocNC isn't
988 * supported.
989 */
990static int supPagePageAllocNoKernelFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
991{
992 int rc = suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
993 if (RT_SUCCESS(rc))
994 {
995 if (!paPages)
996 paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
997 rc = supR3PageLock(*ppvPages, cPages, paPages);
998 if (RT_FAILURE(rc))
999 suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
1000 }
1001 return rc;
1002}
1003
1004
1005SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
1006{
1007 /*
1008 * Validate.
1009 */
1010 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1011 *ppvPages = NULL;
1012 AssertPtrNullReturn(pR0Ptr, VERR_INVALID_POINTER);
1013 if (pR0Ptr)
1014 *pR0Ptr = NIL_RTR0PTR;
1015 AssertPtrNullReturn(paPages, VERR_INVALID_POINTER);
1016 AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1017
1018 /* fake */
1019 if (RT_UNLIKELY(g_u32FakeMode))
1020 {
1021 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1022 if (!pv)
1023 return VERR_NO_MEMORY;
1024 *ppvPages = pv;
1025 if (pR0Ptr)
1026 *pR0Ptr = (RTR0PTR)pv;
1027 if (paPages)
1028 for (size_t iPage = 0; iPage < cPages; iPage++)
1029 {
1030 paPages[iPage].uReserved = 0;
1031 paPages[iPage].Phys = (iPage + 4321) << PAGE_SHIFT;
1032 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1033 }
1034 return VINF_SUCCESS;
1035 }
1036
1037 /*
1038 * Use fallback for non-R0 mapping?
1039 */
1040 if ( !pR0Ptr
1041 && !g_fSupportsPageAllocNoKernel)
1042 return supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1043
1044 /*
1045 * Issue IOCtl to the SUPDRV kernel module.
1046 */
1047 int rc;
1048 PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1049 if (pReq)
1050 {
1051 pReq->Hdr.u32Cookie = g_u32Cookie;
1052 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1053 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN;
1054 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages);
1055 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1056 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1057 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1058 pReq->u.In.fKernelMapping = pR0Ptr != NULL;
1059 pReq->u.In.fUserMapping = true;
1060 pReq->u.In.fReserved0 = false;
1061 pReq->u.In.fReserved1 = false;
1062 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1063 if (RT_SUCCESS(rc))
1064 {
1065 rc = pReq->Hdr.rc;
1066 if (RT_SUCCESS(rc))
1067 {
1068 *ppvPages = pReq->u.Out.pvR3;
1069 if (pR0Ptr)
1070 *pR0Ptr = pReq->u.Out.pvR0;
1071 if (paPages)
1072 for (size_t iPage = 0; iPage < cPages; iPage++)
1073 {
1074 paPages[iPage].uReserved = 0;
1075 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1076 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1077 }
1078#ifdef RT_OS_DARWIN /* HACK ALERT! */
1079 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1080#endif
1081 }
1082 else if ( rc == VERR_NOT_SUPPORTED
1083 && !pR0Ptr)
1084 {
1085 g_fSupportsPageAllocNoKernel = false;
1086 rc = supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1087 }
1088 }
1089
1090 RTMemTmpFree(pReq);
1091 }
1092 else
1093 rc = VERR_NO_TMP_MEMORY;
1094 return rc;
1095
1096}
1097
1098
1099SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
1100{
1101 /*
1102 * Validate.
1103 */
1104 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1105 AssertPtrReturn(pR0Ptr, VERR_INVALID_POINTER);
1106 Assert(!(off & PAGE_OFFSET_MASK));
1107 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1108 Assert(!fFlags);
1109 *pR0Ptr = NIL_RTR0PTR;
1110
1111 /* fake */
1112 if (RT_UNLIKELY(g_u32FakeMode))
1113 return VERR_NOT_SUPPORTED;
1114
1115 /*
1116 * Issue IOCtl to the SUPDRV kernel module.
1117 */
1118 SUPPAGEMAPKERNEL Req;
1119 Req.Hdr.u32Cookie = g_u32Cookie;
1120 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1121 Req.Hdr.cbIn = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN;
1122 Req.Hdr.cbOut = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT;
1123 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1124 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1125 Req.u.In.pvR3 = pvR3;
1126 Req.u.In.offSub = off;
1127 Req.u.In.cbSub = cb;
1128 Req.u.In.fFlags = fFlags;
1129 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
1130 if (RT_SUCCESS(rc))
1131 rc = Req.Hdr.rc;
1132 if (RT_SUCCESS(rc))
1133 *pR0Ptr = Req.u.Out.pvR0;
1134 return rc;
1135}
1136
1137
1138SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
1139{
1140 /*
1141 * Validate.
1142 */
1143 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1144 Assert(!(off & PAGE_OFFSET_MASK));
1145 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1146 AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
1147
1148 /* fake */
1149 if (RT_UNLIKELY(g_u32FakeMode))
1150 return RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1151
1152 /*
1153 * Some OSes can do this from ring-3, so try that before we
1154 * issue the IOCtl to the SUPDRV kernel module.
1155 * (Yea, this isn't very nice, but just try get the job done for now.)
1156 */
1157#if !defined(RT_OS_SOLARIS)
1158 RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1159#endif
1160
1161 SUPPAGEPROTECT Req;
1162 Req.Hdr.u32Cookie = g_u32Cookie;
1163 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1164 Req.Hdr.cbIn = SUP_IOCTL_PAGE_PROTECT_SIZE_IN;
1165 Req.Hdr.cbOut = SUP_IOCTL_PAGE_PROTECT_SIZE_OUT;
1166 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1167 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1168 Req.u.In.pvR3 = pvR3;
1169 Req.u.In.pvR0 = R0Ptr;
1170 Req.u.In.offSub = off;
1171 Req.u.In.cbSub = cb;
1172 Req.u.In.fProt = fProt;
1173 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_PROTECT, &Req, SUP_IOCTL_PAGE_PROTECT_SIZE);
1174 if (RT_SUCCESS(rc))
1175 rc = Req.Hdr.rc;
1176 return rc;
1177}
1178
1179
1180SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
1181{
1182 /*
1183 * Validate.
1184 */
1185 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
1186 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1187
1188 /* fake */
1189 if (RT_UNLIKELY(g_u32FakeMode))
1190 {
1191 RTMemPageFree(pvPages, cPages * PAGE_SIZE);
1192 return VINF_SUCCESS;
1193 }
1194
1195 /*
1196 * Try normal free first, then if it fails check if we're using the fallback
1197 * for the allocations without kernel mappings and attempt unlocking it.
1198 */
1199 NOREF(cPages);
1200 SUPPAGEFREE Req;
1201 Req.Hdr.u32Cookie = g_u32Cookie;
1202 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1203 Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
1204 Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
1205 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1206 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1207 Req.u.In.pvR3 = pvPages;
1208 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
1209 if (RT_SUCCESS(rc))
1210 {
1211 rc = Req.Hdr.rc;
1212 if ( rc == VERR_INVALID_PARAMETER
1213 && !g_fSupportsPageAllocNoKernel)
1214 {
1215 int rc2 = supR3PageUnlock(pvPages);
1216 if (RT_SUCCESS(rc2))
1217 rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
1218 }
1219 }
1220 return rc;
1221}
1222
1223
1224SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
1225{
1226 /*
1227 * Validate.
1228 */
1229 AssertPtrReturn(pHCPhys, NULL);
1230 *pHCPhys = NIL_RTHCPHYS;
1231 AssertPtrNullReturn(pR0Ptr, NULL);
1232 if (pR0Ptr)
1233 *pR0Ptr = NIL_RTR0PTR;
1234 AssertPtrNullReturn(pHCPhys, NULL);
1235 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
1236
1237 /* fake */
1238 if (RT_UNLIKELY(g_u32FakeMode))
1239 {
1240 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1241 if (pR0Ptr)
1242 *pR0Ptr = (RTR0PTR)pv;
1243 if (pHCPhys)
1244 *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
1245 return pv;
1246 }
1247
1248 /*
1249 * Issue IOCtl to the SUPDRV kernel module.
1250 */
1251 SUPCONTALLOC Req;
1252 Req.Hdr.u32Cookie = g_u32Cookie;
1253 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1254 Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
1255 Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
1256 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1257 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1258 Req.u.In.cPages = (uint32_t)cPages;
1259 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
1260 if ( RT_SUCCESS(rc)
1261 && RT_SUCCESS(Req.Hdr.rc))
1262 {
1263 *pHCPhys = Req.u.Out.HCPhys;
1264 if (pR0Ptr)
1265 *pR0Ptr = Req.u.Out.pvR0;
1266#ifdef RT_OS_DARWIN /* HACK ALERT! */
1267 supR3TouchPages(Req.u.Out.pvR3, cPages);
1268#endif
1269 return Req.u.Out.pvR3;
1270 }
1271
1272 return NULL;
1273}
1274
1275
1276SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages)
1277{
1278 /*
1279 * Validate.
1280 */
1281 if (!pv)
1282 return VINF_SUCCESS;
1283 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1284 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1285
1286 /* fake */
1287 if (RT_UNLIKELY(g_u32FakeMode))
1288 {
1289 RTMemPageFree(pv, cPages * PAGE_SIZE);
1290 return VINF_SUCCESS;
1291 }
1292
1293 /*
1294 * Issue IOCtl to the SUPDRV kernel module.
1295 */
1296 SUPCONTFREE Req;
1297 Req.Hdr.u32Cookie = g_u32Cookie;
1298 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1299 Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
1300 Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
1301 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1302 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1303 Req.u.In.pvR3 = pv;
1304 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
1305 if (RT_SUCCESS(rc))
1306 rc = Req.Hdr.rc;
1307 return rc;
1308}
1309
1310
1311SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
1312{
1313 /*
1314 * Validate.
1315 */
1316 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1317 *ppvPages = NULL;
1318 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
1319 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1320
1321 /* fake */
1322 if (RT_UNLIKELY(g_u32FakeMode))
1323 {
1324 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
1325 if (!*ppvPages)
1326 return VERR_NO_LOW_MEMORY;
1327
1328 /* fake physical addresses. */
1329 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
1330 size_t iPage = cPages;
1331 while (iPage-- > 0)
1332 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
1333 return VINF_SUCCESS;
1334 }
1335
1336 /*
1337 * Issue IOCtl to the SUPDRV kernel module.
1338 */
1339 int rc;
1340 PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1341 if (pReq)
1342 {
1343 pReq->Hdr.u32Cookie = g_u32Cookie;
1344 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1345 pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
1346 pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
1347 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1348 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1349 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1350 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1351 if (RT_SUCCESS(rc))
1352 rc = pReq->Hdr.rc;
1353 if (RT_SUCCESS(rc))
1354 {
1355 *ppvPages = pReq->u.Out.pvR3;
1356 if (ppvPagesR0)
1357 *ppvPagesR0 = pReq->u.Out.pvR0;
1358 if (paPages)
1359 for (size_t iPage = 0; iPage < cPages; iPage++)
1360 {
1361 paPages[iPage].uReserved = 0;
1362 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1363 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1364 Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
1365 }
1366#ifdef RT_OS_DARWIN /* HACK ALERT! */
1367 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1368#endif
1369 }
1370 RTMemTmpFree(pReq);
1371 }
1372 else
1373 rc = VERR_NO_TMP_MEMORY;
1374
1375 return rc;
1376}
1377
1378
1379SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages)
1380{
1381 /*
1382 * Validate.
1383 */
1384 if (!pv)
1385 return VINF_SUCCESS;
1386 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1387 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1388
1389 /* fake */
1390 if (RT_UNLIKELY(g_u32FakeMode))
1391 {
1392 RTMemPageFree(pv, cPages * PAGE_SIZE);
1393 return VINF_SUCCESS;
1394 }
1395
1396 /*
1397 * Issue IOCtl to the SUPDRV kernel module.
1398 */
1399 SUPCONTFREE Req;
1400 Req.Hdr.u32Cookie = g_u32Cookie;
1401 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1402 Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
1403 Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
1404 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1405 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1406 Req.u.In.pvR3 = pv;
1407 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
1408 if (RT_SUCCESS(rc))
1409 rc = Req.Hdr.rc;
1410 return rc;
1411}
1412
1413
1414SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
1415{
1416 /*
1417 * Quick input validation.
1418 */
1419 AssertPtr(pszFilename);
1420 AssertPtr(pszMsg);
1421 AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
1422 file is the same we verified after opening it. */
1423
1424 /*
1425 * Only do the actual check in hardened builds.
1426 */
1427#ifdef VBOX_WITH_HARDENING
1428 int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1429 if (RT_FAILURE(rc))
1430 LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
1431 return rc;
1432#else
1433 return VINF_SUCCESS;
1434#endif
1435}
1436
1437
1438SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
1439{
1440 int rc = VINF_SUCCESS;
1441#ifdef VBOX_WITH_HARDENING
1442 /*
1443 * Check that the module can be trusted.
1444 */
1445 rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1446#endif
1447 if (RT_SUCCESS(rc))
1448 rc = supLoadModule(pszFilename, pszModule, NULL, ppvImageBase);
1449 else
1450 LogRel(("SUPR3LoadModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
1451 return rc;
1452}
1453
1454
1455SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule,
1456 const char *pszSrvReqHandler, void **ppvImageBase)
1457{
1458 int rc = VINF_SUCCESS;
1459 AssertPtrReturn(pszSrvReqHandler, VERR_INVALID_PARAMETER);
1460
1461#ifdef VBOX_WITH_HARDENING
1462 /*
1463 * Check that the module can be trusted.
1464 */
1465 rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1466#endif
1467 if (RT_SUCCESS(rc))
1468 rc = supLoadModule(pszFilename, pszModule, pszSrvReqHandler, ppvImageBase);
1469 else
1470 LogRel(("SUPR3LoadServiceModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
1471 return rc;
1472}
1473
1474
1475/**
1476 * Resolve an external symbol during RTLdrGetBits().
1477 *
1478 * @returns VBox status code.
1479 * @param hLdrMod The loader module handle.
1480 * @param pszModule Module name.
1481 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
1482 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
1483 * @param pValue Where to store the symbol value (address).
1484 * @param pvUser User argument.
1485 */
1486static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
1487 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
1488{
1489 AssertPtr(pValue);
1490 AssertPtr(pvUser);
1491
1492 /*
1493 * Only SUPR0 and VMMR0.r0
1494 */
1495 if ( pszModule
1496 && *pszModule
1497 && strcmp(pszModule, "VBoxDrv.sys")
1498 && strcmp(pszModule, "VMMR0.r0"))
1499 {
1500 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
1501 return VERR_SYMBOL_NOT_FOUND;
1502 }
1503
1504 /*
1505 * No ordinals.
1506 */
1507 if (pszSymbol < (const char*)0x10000)
1508 {
1509 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pvUser, (int)(uintptr_t)pszSymbol));
1510 return VERR_SYMBOL_NOT_FOUND;
1511 }
1512
1513 /*
1514 * Lookup symbol.
1515 */
1516 /** @todo is this actually used??? */
1517 /* skip the 64-bit ELF import prefix first. */
1518 if (!strncmp(pszSymbol, "SUPR0$", sizeof("SUPR0$") - 1))
1519 pszSymbol += sizeof("SUPR0$") - 1;
1520
1521 /*
1522 * Check the VMMR0.r0 module if loaded.
1523 */
1524 /** @todo call the SUPR3LoadModule caller.... */
1525 /** @todo proper reference counting and such. */
1526 if (g_pvVMMR0 != NIL_RTR0PTR)
1527 {
1528 void *pvValue;
1529 if (!SUPR3GetSymbolR0((void *)g_pvVMMR0, pszSymbol, &pvValue))
1530 {
1531 *pValue = (uintptr_t)pvValue;
1532 return VINF_SUCCESS;
1533 }
1534 }
1535
1536 /* iterate the function table. */
1537 int c = g_pFunctions->u.Out.cFunctions;
1538 PSUPFUNC pFunc = &g_pFunctions->u.Out.aFunctions[0];
1539 while (c-- > 0)
1540 {
1541 if (!strcmp(pFunc->szName, pszSymbol))
1542 {
1543 *pValue = (uintptr_t)pFunc->pfn;
1544 return VINF_SUCCESS;
1545 }
1546 pFunc++;
1547 }
1548
1549 /*
1550 * The GIP.
1551 */
1552 if ( pszSymbol
1553 && g_pSUPGlobalInfoPage
1554 && g_pSUPGlobalInfoPageR0
1555 && !strcmp(pszSymbol, "g_SUPGlobalInfoPage")
1556 )
1557 {
1558 *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
1559 return VINF_SUCCESS;
1560 }
1561
1562 /*
1563 * Despair.
1564 */
1565 c = g_pFunctions->u.Out.cFunctions;
1566 pFunc = &g_pFunctions->u.Out.aFunctions[0];
1567 while (c-- > 0)
1568 {
1569 RTAssertMsg2Weak("%d: %s\n", g_pFunctions->u.Out.cFunctions - c, pFunc->szName);
1570 pFunc++;
1571 }
1572
1573 RTAssertMsg2Weak("%s is importing %s which we couldn't find\n", pvUser, pszSymbol);
1574 AssertMsgFailed(("%s is importing %s which we couldn't find\n", pvUser, pszSymbol));
1575 if (g_u32FakeMode)
1576 {
1577 *pValue = 0xdeadbeef;
1578 return VINF_SUCCESS;
1579 }
1580 return VERR_SYMBOL_NOT_FOUND;
1581}
1582
1583
1584/** Argument package for supLoadModuleCalcSizeCB. */
1585typedef struct SUPLDRCALCSIZEARGS
1586{
1587 size_t cbStrings;
1588 uint32_t cSymbols;
1589 size_t cbImage;
1590} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
1591
1592/**
1593 * Callback used to calculate the image size.
1594 * @return VINF_SUCCESS
1595 */
1596static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1597{
1598 PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
1599 if ( pszSymbol != NULL
1600 && *pszSymbol
1601 && Value <= pArgs->cbImage)
1602 {
1603 pArgs->cSymbols++;
1604 pArgs->cbStrings += strlen(pszSymbol) + 1;
1605 }
1606 return VINF_SUCCESS;
1607}
1608
1609
1610/** Argument package for supLoadModuleCreateTabsCB. */
1611typedef struct SUPLDRCREATETABSARGS
1612{
1613 size_t cbImage;
1614 PSUPLDRSYM pSym;
1615 char *pszBase;
1616 char *psz;
1617} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
1618
1619/**
1620 * Callback used to calculate the image size.
1621 * @return VINF_SUCCESS
1622 */
1623static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1624{
1625 PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
1626 if ( pszSymbol != NULL
1627 && *pszSymbol
1628 && Value <= pArgs->cbImage)
1629 {
1630 pArgs->pSym->offSymbol = (uint32_t)Value;
1631 pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
1632 pArgs->pSym++;
1633
1634 size_t cbCopy = strlen(pszSymbol) + 1;
1635 memcpy(pArgs->psz, pszSymbol, cbCopy);
1636 pArgs->psz += cbCopy;
1637 }
1638 return VINF_SUCCESS;
1639}
1640
1641
1642/**
1643 * Worker for SUPR3LoadModule().
1644 *
1645 * @returns VBox status code.
1646 * @param pszFilename Name of the VMMR0 image file
1647 */
1648static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase)
1649{
1650 int rc;
1651
1652 /*
1653 * Validate input.
1654 */
1655 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1656 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
1657 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
1658 AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
1659 char szAbsFilename[RT_SIZEOFMEMB(SUPLDROPEN, u.In.szFilename)];
1660 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
1661 if (RT_FAILURE(rc))
1662 return rc;
1663 pszFilename = szAbsFilename;
1664
1665 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
1666 AssertReturn(!pszSrvReqHandler || !fIsVMMR0, VERR_INTERNAL_ERROR);
1667 *ppvImageBase = NULL;
1668
1669 /*
1670 * Open image file and figure its size.
1671 */
1672 RTLDRMOD hLdrMod;
1673 rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_HOST, &hLdrMod);
1674 if (!RT_SUCCESS(rc))
1675 return rc;
1676
1677 SUPLDRCALCSIZEARGS CalcArgs;
1678 CalcArgs.cbStrings = 0;
1679 CalcArgs.cSymbols = 0;
1680 CalcArgs.cbImage = RTLdrSize(hLdrMod);
1681 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
1682 if (RT_SUCCESS(rc))
1683 {
1684 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
1685 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
1686 const uint32_t cbImageWithTabs = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
1687
1688 /*
1689 * Open the R0 image.
1690 */
1691 SUPLDROPEN OpenReq;
1692 OpenReq.Hdr.u32Cookie = g_u32Cookie;
1693 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
1694 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
1695 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
1696 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1697 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
1698 OpenReq.u.In.cbImageWithTabs = cbImageWithTabs;
1699 OpenReq.u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
1700 strcpy(OpenReq.u.In.szName, pszModule);
1701 strcpy(OpenReq.u.In.szFilename, pszFilename);
1702 if (!g_u32FakeMode)
1703 {
1704 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
1705 if (RT_SUCCESS(rc))
1706 rc = OpenReq.Hdr.rc;
1707 }
1708 else
1709 {
1710 OpenReq.u.Out.fNeedsLoading = true;
1711 OpenReq.u.Out.pvImageBase = 0xef423420;
1712 }
1713 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
1714 if ( RT_SUCCESS(rc)
1715 && OpenReq.u.Out.fNeedsLoading)
1716 {
1717 /*
1718 * We need to load it.
1719 * Allocate memory for the image bits.
1720 */
1721 PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
1722 if (pLoadReq)
1723 {
1724 /*
1725 * Get the image bits.
1726 */
1727 rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
1728 supLoadModuleResolveImport, (void *)pszModule);
1729
1730 if (RT_SUCCESS(rc))
1731 {
1732 /*
1733 * Get the entry points.
1734 */
1735 RTUINTPTR VMMR0EntryInt = 0;
1736 RTUINTPTR VMMR0EntryFast = 0;
1737 RTUINTPTR VMMR0EntryEx = 0;
1738 RTUINTPTR SrvReqHandler = 0;
1739 RTUINTPTR ModuleInit = 0;
1740 RTUINTPTR ModuleTerm = 0;
1741 if (fIsVMMR0)
1742 {
1743 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
1744 if (RT_SUCCESS(rc))
1745 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
1746 if (RT_SUCCESS(rc))
1747 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
1748 }
1749 else if (pszSrvReqHandler)
1750 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, pszSrvReqHandler, &SrvReqHandler);
1751 if (RT_SUCCESS(rc))
1752 {
1753 int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
1754 if (RT_FAILURE(rc2))
1755 ModuleInit = 0;
1756
1757 rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.abImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
1758 if (RT_FAILURE(rc2))
1759 ModuleTerm = 0;
1760 }
1761 if (RT_SUCCESS(rc))
1762 {
1763 /*
1764 * Create the symbol and string tables.
1765 */
1766 SUPLDRCREATETABSARGS CreateArgs;
1767 CreateArgs.cbImage = CalcArgs.cbImage;
1768 CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab];
1769 CreateArgs.pszBase = (char *)&pLoadReq->u.In.abImage[offStrTab];
1770 CreateArgs.psz = CreateArgs.pszBase;
1771 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
1772 if (RT_SUCCESS(rc))
1773 {
1774 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
1775 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.abImage[offSymTab]) <= CalcArgs.cSymbols);
1776
1777 /*
1778 * Upload the image.
1779 */
1780 pLoadReq->Hdr.u32Cookie = g_u32Cookie;
1781 pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1782 pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImageWithTabs);
1783 pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
1784 pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
1785 pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
1786
1787 pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
1788 pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
1789 if (fIsVMMR0)
1790 {
1791 pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
1792 pLoadReq->u.In.EP.VMMR0.pvVMMR0 = OpenReq.u.Out.pvImageBase;
1793 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)VMMR0EntryInt;
1794 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
1795 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
1796 }
1797 else if (pszSrvReqHandler)
1798 {
1799 pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
1800 pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
1801 pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
1802 pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
1803 pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
1804 }
1805 else
1806 pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
1807 pLoadReq->u.In.offStrTab = offStrTab;
1808 pLoadReq->u.In.cbStrTab = (uint32_t)CalcArgs.cbStrings;
1809 AssertRelease(pLoadReq->u.In.cbStrTab == CalcArgs.cbStrings);
1810 pLoadReq->u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
1811 pLoadReq->u.In.offSymbols = offSymTab;
1812 pLoadReq->u.In.cSymbols = CalcArgs.cSymbols;
1813 pLoadReq->u.In.cbImageWithTabs = cbImageWithTabs;
1814 pLoadReq->u.In.pvImageBase = OpenReq.u.Out.pvImageBase;
1815 if (!g_u32FakeMode)
1816 {
1817 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
1818 if (RT_SUCCESS(rc))
1819 rc = pLoadReq->Hdr.rc;
1820 }
1821 else
1822 rc = VINF_SUCCESS;
1823 if ( RT_SUCCESS(rc)
1824 || rc == VERR_ALREADY_LOADED /* A competing process. */
1825 )
1826 {
1827 LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr%s\n",
1828 pszModule, pszFilename, OpenReq.u.Out.pvImageBase, ModuleInit, ModuleTerm,
1829 OpenReq.u.Out.fNativeLoader ? " using the native ring-0 loader" : ""));
1830 if (fIsVMMR0)
1831 {
1832 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1833 LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
1834 VMMR0EntryEx, VMMR0EntryFast, VMMR0EntryInt));
1835 }
1836#ifdef RT_OS_WINDOWS
1837 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1838#endif
1839
1840 RTMemTmpFree(pLoadReq);
1841 RTLdrClose(hLdrMod);
1842 return VINF_SUCCESS;
1843 }
1844 }
1845 }
1846 }
1847 RTMemTmpFree(pLoadReq);
1848 }
1849 else
1850 {
1851 AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs)));
1852 rc = VERR_NO_TMP_MEMORY;
1853 }
1854 }
1855 else if (RT_SUCCESS(rc))
1856 {
1857 if (fIsVMMR0)
1858 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1859 LogRel(("SUP: Opened %s (%s) at %#p.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase,
1860 OpenReq.u.Out.fNativeLoader ? " loaded by the native ring-0 loader" : ""));
1861#ifdef RT_OS_WINDOWS
1862 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1863#endif
1864 }
1865 }
1866 RTLdrClose(hLdrMod);
1867 return rc;
1868}
1869
1870
1871SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase)
1872{
1873 /* fake */
1874 if (RT_UNLIKELY(g_u32FakeMode))
1875 {
1876 g_pvVMMR0 = NIL_RTR0PTR;
1877 return VINF_SUCCESS;
1878 }
1879
1880 /*
1881 * Free the requested module.
1882 */
1883 SUPLDRFREE Req;
1884 Req.Hdr.u32Cookie = g_u32Cookie;
1885 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1886 Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
1887 Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
1888 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1889 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1890 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1891 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
1892 if (RT_SUCCESS(rc))
1893 rc = Req.Hdr.rc;
1894 if ( RT_SUCCESS(rc)
1895 && (RTR0PTR)pvImageBase == g_pvVMMR0)
1896 g_pvVMMR0 = NIL_RTR0PTR;
1897 return rc;
1898}
1899
1900
1901SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
1902{
1903 *ppvValue = NULL;
1904
1905 /* fake */
1906 if (RT_UNLIKELY(g_u32FakeMode))
1907 {
1908 *ppvValue = (void *)(uintptr_t)0xdeadf00d;
1909 return VINF_SUCCESS;
1910 }
1911
1912 /*
1913 * Do ioctl.
1914 */
1915 SUPLDRGETSYMBOL Req;
1916 Req.Hdr.u32Cookie = g_u32Cookie;
1917 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1918 Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
1919 Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
1920 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1921 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1922 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1923 size_t cchSymbol = strlen(pszSymbol);
1924 if (cchSymbol >= sizeof(Req.u.In.szSymbol))
1925 return VERR_SYMBOL_NOT_FOUND;
1926 memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
1927 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
1928 if (RT_SUCCESS(rc))
1929 rc = Req.Hdr.rc;
1930 if (RT_SUCCESS(rc))
1931 *ppvValue = (void *)Req.u.Out.pvSymbol;
1932 return rc;
1933}
1934
1935
1936SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename)
1937{
1938 void *pvImageBase;
1939 return SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase);
1940}
1941
1942
1943SUPR3DECL(int) SUPR3UnloadVMM(void)
1944{
1945 return SUPR3FreeModule((void*)g_pvVMMR0);
1946}
1947
1948
1949SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
1950{
1951 if (g_pSUPGlobalInfoPage)
1952 {
1953 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1954 return VINF_SUCCESS;
1955 }
1956 *pHCPhys = NIL_RTHCPHYS;
1957 return VERR_WRONG_ORDER;
1958}
1959
1960
1961/**
1962 * Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
1963 *
1964 * @returns iprt status code.
1965 * @param pszFilename The full file name.
1966 * @param phLdrMod Where to store the handle to the loaded module.
1967 */
1968static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod)
1969{
1970#ifdef VBOX_WITH_HARDENING
1971 /*
1972 * Verify the image file.
1973 */
1974 int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1975 if (RT_FAILURE(rc))
1976 {
1977 LogRel(("supR3HardenedLdrLoadIt: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1978 return rc;
1979 }
1980#endif
1981
1982 /*
1983 * Try load it.
1984 */
1985 return RTLdrLoad(pszFilename, phLdrMod);
1986}
1987
1988
1989SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod)
1990{
1991 /*
1992 * Validate input.
1993 */
1994 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1995 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
1996 *phLdrMod = NIL_RTLDRMOD;
1997 AssertReturn(RTPathHavePath(pszFilename), VERR_INVALID_PARAMETER);
1998
1999 /*
2000 * Add the default extension if it's missing.
2001 */
2002 if (!RTPathHaveExt(pszFilename))
2003 {
2004 const char *pszSuff = RTLdrGetSuff();
2005 size_t cchSuff = strlen(pszSuff);
2006 size_t cchFilename = strlen(pszFilename);
2007 char *psz = (char *)alloca(cchFilename + cchSuff + 1);
2008 AssertReturn(psz, VERR_NO_TMP_MEMORY);
2009 memcpy(psz, pszFilename, cchFilename);
2010 memcpy(psz + cchFilename, pszSuff, cchSuff + 1);
2011 pszFilename = psz;
2012 }
2013
2014 /*
2015 * Pass it on to the common library loader.
2016 */
2017 return supR3HardenedLdrLoadIt(pszFilename, phLdrMod);
2018}
2019
2020
2021SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod)
2022{
2023 LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p\n", pszFilename, pszFilename, phLdrMod));
2024
2025 /*
2026 * Validate input.
2027 */
2028 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
2029 *phLdrMod = NIL_RTLDRMOD;
2030 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
2031 AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
2032
2033 /*
2034 * Check the filename.
2035 */
2036 size_t cchFilename = strlen(pszFilename);
2037 AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
2038
2039 const char *pszExt = "";
2040 size_t cchExt = 0;
2041 if (!RTPathHaveExt(pszFilename))
2042 {
2043 pszExt = RTLdrGetSuff();
2044 cchExt = strlen(pszExt);
2045 }
2046
2047 /*
2048 * Construct the private arch path and check if the file exists.
2049 */
2050 char szPath[RTPATH_MAX];
2051 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchExt - cchFilename);
2052 AssertRCReturn(rc, rc);
2053
2054 char *psz = strchr(szPath, '\0');
2055 *psz++ = RTPATH_SLASH;
2056 memcpy(psz, pszFilename, cchFilename);
2057 psz += cchFilename;
2058 memcpy(psz, pszExt, cchExt + 1);
2059
2060 if (!RTPathExists(szPath))
2061 {
2062 LogRel(("SUPR3HardenedLdrLoadAppPriv: \"%s\" not found\n", szPath));
2063 return VERR_FILE_NOT_FOUND;
2064 }
2065
2066 /*
2067 * Pass it on to SUPR3HardenedLdrLoad.
2068 */
2069 rc = SUPR3HardenedLdrLoad(szPath, phLdrMod);
2070
2071 LogFlow(("SUPR3HardenedLdrLoadAppPriv: returns %Rrc\n", rc));
2072 return rc;
2073}
2074
2075
2076SUPR3DECL(int) SUPR3QueryVTxSupported(void)
2077{
2078#ifdef RT_OS_LINUX
2079 return suplibOsQueryVTxSupported();
2080#else
2081 return VINF_SUCCESS;
2082#endif
2083}
2084
2085
2086SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps)
2087{
2088 AssertPtrReturn(pfCaps, VERR_INVALID_POINTER);
2089
2090 *pfCaps = 0;
2091
2092 /* fake */
2093 if (RT_UNLIKELY(g_u32FakeMode))
2094 return VINF_SUCCESS;
2095
2096 /*
2097 * Issue IOCtl to the SUPDRV kernel module.
2098 */
2099 SUPVTCAPS Req;
2100 Req.Hdr.u32Cookie = g_u32Cookie;
2101 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2102 Req.Hdr.cbIn = SUP_IOCTL_VT_CAPS_SIZE_IN;
2103 Req.Hdr.cbOut = SUP_IOCTL_VT_CAPS_SIZE_OUT;
2104 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2105 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2106 Req.u.Out.Caps = 0;
2107 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_VT_CAPS, &Req, SUP_IOCTL_VT_CAPS_SIZE);
2108 if (RT_SUCCESS(rc))
2109 {
2110 rc = Req.Hdr.rc;
2111 if (RT_SUCCESS(rc))
2112 *pfCaps = Req.u.Out.Caps;
2113 }
2114 return rc;
2115}
2116
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