VirtualBox

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

Last change on this file since 29826 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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