VirtualBox

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

Last change on this file since 32740 was 32572, checked in by vboxsync, 14 years ago

VMM,SUPDrv,IPRT: More changes for related to the priodic preemption timer. (still disabled)

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

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