VirtualBox

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

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

SUPDrv/Lib: More hacking

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 74.9 KB
Line 
1/* $Id: SUPLib.cpp 25263 2009-12-09 05:16:39Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Common code.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/** @page pg_sup SUP - The Support Library
32 *
33 * The support library is responsible for providing facilities to load
34 * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
35 * code, to pin down physical memory, and more.
36 *
37 * The VMM Host Ring-0 code can be combined in the support driver if
38 * permitted by kernel module license policies. If it is not combined
39 * it will be externalized in a .r0 module that will be loaded using
40 * the IPRT loader.
41 *
42 * The Ring-0 calling is done thru a generic SUP interface which will
43 * tranfer an argument set and call a predefined entry point in the Host
44 * VMM Ring-0 code.
45 *
46 * See @ref grp_sup "SUP - Support APIs" for API details.
47 */
48
49/*******************************************************************************
50* Header Files *
51*******************************************************************************/
52#define LOG_GROUP LOG_GROUP_SUP
53#include <VBox/sup.h>
54#include <VBox/err.h>
55#include <VBox/param.h>
56#include <VBox/vmm.h>
57#include <VBox/log.h>
58#include <VBox/x86.h>
59
60#include <iprt/assert.h>
61#include <iprt/alloc.h>
62#include <iprt/alloca.h>
63#include <iprt/ldr.h>
64#include <iprt/asm.h>
65#include <iprt/mp.h>
66#include <iprt/cpuset.h>
67#include <iprt/thread.h>
68#include <iprt/process.h>
69#include <iprt/path.h>
70#include <iprt/string.h>
71#include <iprt/env.h>
72#include <iprt/rand.h>
73
74#include "SUPLibInternal.h"
75#include "SUPDrvIOC.h"
76
77
78/*******************************************************************************
79* Defined Constants And Macros *
80*******************************************************************************/
81/** R0 VMM module name. */
82#define VMMR0_NAME "VMMR0"
83
84
85/*******************************************************************************
86* Structures and Typedefs *
87*******************************************************************************/
88typedef DECLCALLBACK(int) FNCALLVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg);
89typedef FNCALLVMMR0 *PFNCALLVMMR0;
90
91
92/*******************************************************************************
93* Global Variables *
94*******************************************************************************/
95/** Init counter. */
96static uint32_t g_cInits = 0;
97/** Whether we've been preinitied. */
98static bool g_fPreInited = false;
99/** The SUPLib instance data.
100 * Well, at least parts of it, specificly the parts that are being handed over
101 * via the pre-init mechanism from the hardened executable stub. */
102SUPLIBDATA g_supLibData =
103{
104 NIL_RTFILE
105#if defined(RT_OS_DARWIN)
106 , NULL
107#elif defined(RT_OS_LINUX)
108 , false
109#endif
110};
111
112/** Pointer to the Global Information Page.
113 *
114 * This pointer is valid as long as SUPLib has a open session. Anyone using
115 * the page must treat this pointer as higly volatile and not trust it beyond
116 * one transaction.
117 *
118 * @todo This will probably deserve it's own session or some other good solution...
119 */
120DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
121/** Address of the ring-0 mapping of the GIP. */
122static PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
123/** The physical address of the GIP. */
124static RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
125
126/** The negotiated cookie. */
127uint32_t g_u32Cookie = 0;
128/** The negotiated session cookie. */
129uint32_t g_u32SessionCookie;
130/** Session handle. */
131PSUPDRVSESSION g_pSession;
132/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
133static PSUPQUERYFUNCS g_pFunctions;
134
135/** VMMR0 Load Address. */
136static RTR0PTR g_pvVMMR0 = NIL_RTR0PTR;
137/** PAGE_ALLOC_EX sans kernel mapping support indicator. */
138static bool g_fSupportsPageAllocNoKernel = true;
139/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
140static uint32_t g_u32FakeMode = ~0;
141
142
143/*******************************************************************************
144* Internal Functions *
145*******************************************************************************/
146static int supInitFake(PSUPDRVSESSION *ppSession);
147static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase);
148static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
149
150
151/** Touch a range of pages. */
152DECLINLINE(void) supR3TouchPages(void *pv, size_t cPages)
153{
154 uint32_t volatile *pu32 = (uint32_t volatile *)pv;
155 while (cPages-- > 0)
156 {
157 ASMAtomicCmpXchgU32(pu32, 0, 0);
158 pu32 += PAGE_SIZE / sizeof(uint32_t);
159 }
160}
161
162
163SUPR3DECL(int) SUPR3Install(void)
164{
165 return suplibOsInstall();
166}
167
168
169SUPR3DECL(int) SUPR3Uninstall(void)
170{
171 return suplibOsUninstall();
172}
173
174
175DECLEXPORT(int) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags)
176{
177 /*
178 * The caller is kind of trustworthy, just perform some basic checks.
179 *
180 * Note! Do not do any fancy stuff here because IPRT has NOT been
181 * initialized at this point.
182 */
183 if (!VALID_PTR(pPreInitData))
184 return VERR_INVALID_POINTER;
185 if (g_fPreInited || g_cInits > 0)
186 return VERR_WRONG_ORDER;
187
188 if ( pPreInitData->u32Magic != SUPPREINITDATA_MAGIC
189 || pPreInitData->u32EndMagic != SUPPREINITDATA_MAGIC)
190 return VERR_INVALID_MAGIC;
191 if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
192 && pPreInitData->Data.hDevice == NIL_RTFILE)
193 return VERR_INVALID_HANDLE;
194 if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
195 && pPreInitData->Data.hDevice != NIL_RTFILE)
196 return VERR_INVALID_PARAMETER;
197
198 /*
199 * Hand out the data.
200 */
201 int rc = supR3HardenedRecvPreInitData(pPreInitData);
202 if (RT_FAILURE(rc))
203 return rc;
204
205 /** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
206 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
207 {
208 g_supLibData = pPreInitData->Data;
209 g_fPreInited = true;
210 }
211
212 return VINF_SUCCESS;
213}
214
215
216SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession)
217{
218 /*
219 * Perform some sanity checks.
220 * (Got some trouble with compile time member alignment assertions.)
221 */
222 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
223 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
224 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
225 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
226 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
227 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
228
229 /*
230 * Check if already initialized.
231 */
232 if (ppSession)
233 *ppSession = g_pSession;
234 if (g_cInits++ > 0)
235 return VINF_SUCCESS;
236
237 /*
238 * Check for fake mode.
239 *
240 * Fake mode is used when we're doing smoke testing and debugging.
241 * It's also useful on platforms where we haven't root access or which
242 * we haven't ported the support driver to.
243 */
244 if (g_u32FakeMode == ~0U)
245 {
246 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
247 if (psz && !strcmp(psz, "fake"))
248 ASMAtomicCmpXchgU32(&g_u32FakeMode, 1, ~0U);
249 else
250 ASMAtomicCmpXchgU32(&g_u32FakeMode, 0, ~0U);
251 }
252 if (RT_UNLIKELY(g_u32FakeMode))
253 return supInitFake(ppSession);
254
255 /*
256 * Open the support driver.
257 */
258 int rc = suplibOsInit(&g_supLibData, g_fPreInited);
259 if (RT_SUCCESS(rc))
260 {
261 /*
262 * Negotiate the cookie.
263 */
264 SUPCOOKIE CookieReq;
265 memset(&CookieReq, 0xff, sizeof(CookieReq));
266 CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
267 CookieReq.Hdr.u32SessionCookie = RTRandU32();
268 CookieReq.Hdr.cbIn = SUP_IOCTL_COOKIE_SIZE_IN;
269 CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
270 CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
271 CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
272 strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
273 CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
274#ifdef VBOX_WITH_NATIVE_R0_LOADER
275 const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00120000
276 ? 0x00120000
277 : SUPDRV_IOC_VERSION & 0xffff0000;
278#else
279 const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00100001
280 ? 0x00100001
281 : SUPDRV_IOC_VERSION & 0xffff0000;
282#endif
283 CookieReq.u.In.u32MinVersion = uMinVersion;
284 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
285 if ( RT_SUCCESS(rc)
286 && RT_SUCCESS(CookieReq.Hdr.rc))
287 {
288 if ( (CookieReq.u.Out.u32SessionVersion & 0xffff0000) == (SUPDRV_IOC_VERSION & 0xffff0000)
289 && CookieReq.u.Out.u32SessionVersion >= uMinVersion)
290 {
291 /*
292 * Query the functions.
293 */
294 PSUPQUERYFUNCS pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
295 if (pFuncsReq)
296 {
297 pFuncsReq->Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
298 pFuncsReq->Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
299 pFuncsReq->Hdr.cbIn = SUP_IOCTL_QUERY_FUNCS_SIZE_IN;
300 pFuncsReq->Hdr.cbOut = SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(CookieReq.u.Out.cFunctions);
301 pFuncsReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
302 pFuncsReq->Hdr.rc = VERR_INTERNAL_ERROR;
303 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq, SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
304 if (RT_SUCCESS(rc))
305 rc = pFuncsReq->Hdr.rc;
306 if (RT_SUCCESS(rc))
307 {
308 /*
309 * Map the GIP into userspace.
310 */
311 Assert(!g_pSUPGlobalInfoPage);
312 SUPGIPMAP GipMapReq;
313 GipMapReq.Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
314 GipMapReq.Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
315 GipMapReq.Hdr.cbIn = SUP_IOCTL_GIP_MAP_SIZE_IN;
316 GipMapReq.Hdr.cbOut = SUP_IOCTL_GIP_MAP_SIZE_OUT;
317 GipMapReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
318 GipMapReq.Hdr.rc = VERR_INTERNAL_ERROR;
319 GipMapReq.u.Out.HCPhysGip = NIL_RTHCPHYS;
320 GipMapReq.u.Out.pGipR0 = NIL_RTR0PTR;
321 GipMapReq.u.Out.pGipR3 = NULL;
322 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_MAP, &GipMapReq, SUP_IOCTL_GIP_MAP_SIZE);
323 if (RT_SUCCESS(rc))
324 rc = GipMapReq.Hdr.rc;
325 if (RT_SUCCESS(rc))
326 {
327 AssertRelease(GipMapReq.u.Out.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
328 AssertRelease(GipMapReq.u.Out.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
329
330 /*
331 * Set the globals and return success.
332 */
333 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipMapReq.u.Out.HCPhysGip);
334 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, GipMapReq.u.Out.pGipR3, NULL);
335 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
336
337 g_u32Cookie = CookieReq.u.Out.u32Cookie;
338 g_u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
339 g_pSession = CookieReq.u.Out.pSession;
340 g_pFunctions = pFuncsReq;
341 if (ppSession)
342 *ppSession = CookieReq.u.Out.pSession;
343 return VINF_SUCCESS;
344 }
345 }
346
347 /* bailout */
348 RTMemFree(pFuncsReq);
349 }
350 else
351 rc = VERR_NO_MEMORY;
352 }
353 else
354 {
355 LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
356 CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, uMinVersion));
357 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
358 }
359 }
360 else
361 {
362 if (RT_SUCCESS(rc))
363 {
364 rc = CookieReq.Hdr.rc;
365 LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
366 CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, rc));
367 if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
368 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
369 }
370 else
371 {
372 /* for pre 0x00060000 drivers */
373 LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
374 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
375 }
376 }
377
378 suplibOsTerm(&g_supLibData);
379 }
380 g_cInits--;
381
382 return rc;
383}
384
385/**
386 * Fake mode init.
387 */
388static int supInitFake(PSUPDRVSESSION *ppSession)
389{
390 Log(("SUP: Fake mode!\n"));
391 static const SUPFUNC s_aFakeFunctions[] =
392 {
393 /* name function */
394 { "SUPR0AbsIs64bit", 0 },
395 { "SUPR0Abs64bitKernelCS", 0 },
396 { "SUPR0Abs64bitKernelSS", 0 },
397 { "SUPR0Abs64bitKernelDS", 0 },
398 { "SUPR0AbsKernelCS", 8 },
399 { "SUPR0AbsKernelSS", 16 },
400 { "SUPR0AbsKernelDS", 16 },
401 { "SUPR0AbsKernelES", 16 },
402 { "SUPR0AbsKernelFS", 24 },
403 { "SUPR0AbsKernelGS", 32 },
404 { "SUPR0ComponentRegisterFactory", 0xefeefffd },
405 { "SUPR0ComponentDeregisterFactory", 0xefeefffe },
406 { "SUPR0ComponentQueryFactory", 0xefeeffff },
407 { "SUPR0ObjRegister", 0xefef0000 },
408 { "SUPR0ObjAddRef", 0xefef0001 },
409 { "SUPR0ObjAddRefEx", 0xefef0001 },
410 { "SUPR0ObjRelease", 0xefef0002 },
411 { "SUPR0ObjVerifyAccess", 0xefef0003 },
412 { "SUPR0LockMem", 0xefef0004 },
413 { "SUPR0UnlockMem", 0xefef0005 },
414 { "SUPR0ContAlloc", 0xefef0006 },
415 { "SUPR0ContFree", 0xefef0007 },
416 { "SUPR0MemAlloc", 0xefef0008 },
417 { "SUPR0MemGetPhys", 0xefef0009 },
418 { "SUPR0MemFree", 0xefef000a },
419 { "SUPR0Printf", 0xefef000b },
420 { "SUPR0GetPagingMode", 0xefef000c },
421 { "SUPR0EnableVTx", 0xefef000e },
422 { "RTMemAlloc", 0xefef000f },
423 { "RTMemAllocZ", 0xefef0010 },
424 { "RTMemFree", 0xefef0011 },
425 { "RTR0MemObjAddress", 0xefef0012 },
426 { "RTR0MemObjAddressR3", 0xefef0013 },
427 { "RTR0MemObjAllocPage", 0xefef0014 },
428 { "RTR0MemObjAllocPhysNC", 0xefef0015 },
429 { "RTR0MemObjAllocLow", 0xefef0016 },
430 { "RTR0MemObjEnterPhys", 0xefef0017 },
431 { "RTR0MemObjFree", 0xefef0018 },
432 { "RTR0MemObjGetPagePhysAddr", 0xefef0019 },
433 { "RTR0MemObjMapUser", 0xefef001a },
434 { "RTR0MemObjMapKernel", 0xefef001b },
435 { "RTR0MemObjMapKernelEx", 0xefef001c },
436 { "RTProcSelf", 0xefef001d },
437 { "RTR0ProcHandleSelf", 0xefef001e },
438 { "RTSemEventCreate", 0xefef001f },
439 { "RTSemEventSignal", 0xefef0020 },
440 { "RTSemEventWait", 0xefef0021 },
441 { "RTSemEventWaitNoResume", 0xefef0022 },
442 { "RTSemEventDestroy", 0xefef0023 },
443 { "RTSemEventMultiCreate", 0xefef0024 },
444 { "RTSemEventMultiSignal", 0xefef0025 },
445 { "RTSemEventMultiReset", 0xefef0026 },
446 { "RTSemEventMultiWait", 0xefef0027 },
447 { "RTSemEventMultiWaitNoResume", 0xefef0028 },
448 { "RTSemEventMultiDestroy", 0xefef0029 },
449 { "RTSemFastMutexCreate", 0xefef002a },
450 { "RTSemFastMutexDestroy", 0xefef002b },
451 { "RTSemFastMutexRequest", 0xefef002c },
452 { "RTSemFastMutexRelease", 0xefef002d },
453 { "RTSpinlockCreate", 0xefef002e },
454 { "RTSpinlockDestroy", 0xefef002f },
455 { "RTSpinlockAcquire", 0xefef0030 },
456 { "RTSpinlockRelease", 0xefef0031 },
457 { "RTSpinlockAcquireNoInts", 0xefef0032 },
458 { "RTSpinlockReleaseNoInts", 0xefef0033 },
459 { "RTTimeNanoTS", 0xefef0034 },
460 { "RTTimeMillieTS", 0xefef0035 },
461 { "RTTimeSystemNanoTS", 0xefef0036 },
462 { "RTTimeSystemMillieTS", 0xefef0037 },
463 { "RTThreadNativeSelf", 0xefef0038 },
464 { "RTThreadSleep", 0xefef0039 },
465 { "RTThreadYield", 0xefef003a },
466 { "RTLogDefaultInstance", 0xefef003b },
467 { "RTLogRelDefaultInstance", 0xefef003c },
468 { "RTLogSetDefaultInstanceThread", 0xefef003d },
469 { "RTLogLogger", 0xefef003e },
470 { "RTLogLoggerEx", 0xefef003f },
471 { "RTLogLoggerExV", 0xefef0040 },
472 { "AssertMsg1", 0xefef0041 },
473 { "AssertMsg2", 0xefef0042 },
474 { "RTAssertMsg1", 0xefef0043 },
475 { "RTAssertMsg2", 0xefef0044 },
476 { "RTAssertMsg2V", 0xefef0045 },
477 { "SUPR0QueryVTCaps", 0xefef0046 },
478 };
479
480 /* fake r0 functions. */
481 g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
482 if (g_pFunctions)
483 {
484 g_pFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
485 memcpy(&g_pFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
486 g_pSession = (PSUPDRVSESSION)(void *)g_pFunctions;
487 if (ppSession)
488 *ppSession = g_pSession;
489
490 /* fake the GIP. */
491 g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
492 if (g_pSUPGlobalInfoPage)
493 {
494 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
495 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
496 /* the page is supposed to be invalid, so don't set the magic. */
497 return VINF_SUCCESS;
498 }
499
500 RTMemFree(g_pFunctions);
501 g_pFunctions = NULL;
502 }
503 return VERR_NO_MEMORY;
504}
505
506
507SUPR3DECL(int) SUPR3Term(bool fForced)
508{
509 /*
510 * Verify state.
511 */
512 AssertMsg(g_cInits > 0, ("SUPR3Term() is called before SUPR3Init()!\n"));
513 if (g_cInits == 0)
514 return VERR_WRONG_ORDER;
515 if (g_cInits == 1 || fForced)
516 {
517 /*
518 * NULL the GIP pointer.
519 */
520 if (g_pSUPGlobalInfoPage)
521 {
522 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, NULL);
523 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, NULL);
524 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
525 /* just a little safe guard against threads using the page. */
526 RTThreadSleep(50);
527 }
528
529 /*
530 * Close the support driver.
531 */
532 int rc = suplibOsTerm(&g_supLibData);
533 if (rc)
534 return rc;
535
536 g_u32Cookie = 0;
537 g_u32SessionCookie = 0;
538 g_cInits = 0;
539 }
540 else
541 g_cInits--;
542
543 return 0;
544}
545
546
547SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void)
548{
549 /* fake */
550 if (RT_UNLIKELY(g_u32FakeMode))
551#ifdef RT_ARCH_AMD64
552 return SUPPAGINGMODE_AMD64_GLOBAL_NX;
553#else
554 return SUPPAGINGMODE_32_BIT_GLOBAL;
555#endif
556
557 /*
558 * Issue IOCtl to the SUPDRV kernel module.
559 */
560 SUPGETPAGINGMODE Req;
561 Req.Hdr.u32Cookie = g_u32Cookie;
562 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
563 Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
564 Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
565 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
566 Req.Hdr.rc = VERR_INTERNAL_ERROR;
567 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
568 if ( RT_FAILURE(rc)
569 || RT_FAILURE(Req.Hdr.rc))
570 {
571 LogRel(("SUPR3GetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
572 Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
573 }
574
575 return Req.u.Out.enmMode;
576}
577
578
579/**
580 * For later.
581 */
582static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
583{
584 AssertMsgFailed(("%d\n", uOperation));
585 return VERR_NOT_SUPPORTED;
586}
587
588
589SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
590{
591 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_RAW_RUN))
592 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_RAW_RUN, idCpu);
593 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_HWACC_RUN))
594 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_HWACC_RUN, idCpu);
595 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_NOP))
596 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_NOP, idCpu);
597
598 AssertMsgFailed(("%#x\n", uOperation));
599 return VERR_INTERNAL_ERROR;
600}
601
602
603SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
604{
605 /*
606 * The following operations don't belong here.
607 */
608 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
609 && uOperation != SUP_VMMR0_DO_HWACC_RUN
610 && uOperation != SUP_VMMR0_DO_NOP,
611 ("%#x\n", uOperation),
612 VERR_INTERNAL_ERROR);
613
614 /* fake */
615 if (RT_UNLIKELY(g_u32FakeMode))
616 return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
617
618 int rc;
619 if (!pReqHdr)
620 {
621 /* no data. */
622 SUPCALLVMMR0 Req;
623 Req.Hdr.u32Cookie = g_u32Cookie;
624 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
625 Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
626 Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
627 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
628 Req.Hdr.rc = VERR_INTERNAL_ERROR;
629 Req.u.In.pVMR0 = pVMR0;
630 Req.u.In.idCpu = idCpu;
631 Req.u.In.uOperation = uOperation;
632 Req.u.In.u64Arg = u64Arg;
633 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
634 if (RT_SUCCESS(rc))
635 rc = Req.Hdr.rc;
636 }
637 else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
638 {
639 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
640 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
641 const size_t cbReq = pReqHdr->cbReq;
642
643 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
644 pReq->Hdr.u32Cookie = g_u32Cookie;
645 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
646 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
647 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
648 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
649 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
650 pReq->u.In.pVMR0 = pVMR0;
651 pReq->u.In.idCpu = idCpu;
652 pReq->u.In.uOperation = uOperation;
653 pReq->u.In.u64Arg = u64Arg;
654 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
655 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
656 if (RT_SUCCESS(rc))
657 rc = pReq->Hdr.rc;
658 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
659 }
660 else /** @todo may have to remove the size limits one this request... */
661 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
662 return rc;
663}
664
665
666SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg)
667{
668 /*
669 * The following operations don't belong here.
670 */
671 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
672 && uOperation != SUP_VMMR0_DO_HWACC_RUN
673 && uOperation != SUP_VMMR0_DO_NOP,
674 ("%#x\n", uOperation),
675 VERR_INTERNAL_ERROR);
676 return SUPR3CallVMMR0Ex(pVMR0, idCpu, uOperation, (uintptr_t)pvArg, NULL);
677}
678
679
680SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0)
681{
682 if (RT_UNLIKELY(g_u32FakeMode))
683 return VINF_SUCCESS;
684
685 SUPSETVMFORFAST Req;
686 Req.Hdr.u32Cookie = g_u32Cookie;
687 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
688 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
689 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
690 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
691 Req.Hdr.rc = VERR_INTERNAL_ERROR;
692 Req.u.In.pVMR0 = pVMR0;
693 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
694 if (RT_SUCCESS(rc))
695 rc = Req.Hdr.rc;
696 return rc;
697}
698
699
700SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
701{
702 AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
703 Assert(strlen(pszService) == cchService);
704
705 /* fake */
706 if (RT_UNLIKELY(g_u32FakeMode))
707 return VERR_NOT_SUPPORTED;
708
709 int rc;
710 if (!pReqHdr)
711 {
712 /* no data. */
713 SUPCALLSERVICE Req;
714 Req.Hdr.u32Cookie = g_u32Cookie;
715 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
716 Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
717 Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
718 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
719 Req.Hdr.rc = VERR_INTERNAL_ERROR;
720 memcpy(Req.u.In.szName, pszService, cchService);
721 Req.u.In.szName[cchService] = '\0';
722 Req.u.In.uOperation = uOperation;
723 Req.u.In.u64Arg = u64Arg;
724 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
725 if (RT_SUCCESS(rc))
726 rc = Req.Hdr.rc;
727 }
728 else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
729 {
730 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
731 AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
732 const size_t cbReq = pReqHdr->cbReq;
733
734 PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
735 pReq->Hdr.u32Cookie = g_u32Cookie;
736 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
737 pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
738 pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
739 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
740 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
741 memcpy(pReq->u.In.szName, pszService, cchService);
742 pReq->u.In.szName[cchService] = '\0';
743 pReq->u.In.uOperation = uOperation;
744 pReq->u.In.u64Arg = u64Arg;
745 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
746 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
747 if (RT_SUCCESS(rc))
748 rc = pReq->Hdr.rc;
749 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
750 }
751 else /** @todo may have to remove the size limits one this request... */
752 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
753 return rc;
754}
755
756
757/**
758 * Worker for the SUPR3Logger* APIs.
759 *
760 * @returns VBox status code.
761 * @param enmWhich Which logger.
762 * @param fWhat What to do with the logger.
763 * @param pszFlags The flags settings.
764 * @param pszGroups The groups settings.
765 * @param pszDest The destionation specificier.
766 */
767static int supR3LoggerSettings(SUPLOGGER enmWhich, uint32_t fWhat, const char *pszFlags, const char *pszGroups, const char *pszDest)
768{
769 uint32_t const cchFlags = pszFlags ? (uint32_t)strlen(pszFlags) : 0;
770 uint32_t const cchGroups = pszGroups ? (uint32_t)strlen(pszGroups) : 0;
771 uint32_t const cchDest = pszDest ? (uint32_t)strlen(pszDest) : 0;
772 uint32_t const cbStrTab = cchFlags + !!cchFlags
773 + cchGroups + !!cchGroups
774 + cchDest + !!cchDest
775 + (!cchFlags && !cchGroups && !cchDest);
776
777 PSUPLOGGERSETTINGS pReq = (PSUPLOGGERSETTINGS)alloca(SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
778 pReq->Hdr.u32Cookie = g_u32Cookie;
779 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
780 pReq->Hdr.cbIn = SUP_IOCTL_LOGGER_SETTINGS_SIZE_IN(cbStrTab);
781 pReq->Hdr.cbOut = SUP_IOCTL_LOGGER_SETTINGS_SIZE_OUT;
782 pReq->Hdr.fFlags= SUPREQHDR_FLAGS_DEFAULT;
783 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
784 switch (enmWhich)
785 {
786 case SUPLOGGER_DEBUG: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_DEBUG; break;
787 case SUPLOGGER_RELEASE: pReq->u.In.fWhich = SUPLOGGERSETTINGS_WHICH_RELEASE; break;
788 default:
789 return VERR_INVALID_PARAMETER;
790 }
791 pReq->u.In.fWhat = fWhat;
792
793 uint32_t off = 0;
794 if (cchFlags)
795 {
796 pReq->u.In.offFlags = off;
797 memcpy(&pReq->u.In.szStrings[off], pszFlags, cchFlags + 1);
798 off += cchFlags + 1;
799 }
800 else
801 pReq->u.In.offFlags = cbStrTab - 1;
802
803 if (cchGroups)
804 {
805 pReq->u.In.offGroups = off;
806 memcpy(&pReq->u.In.szStrings[off], pszGroups, cchGroups + 1);
807 off += cchGroups + 1;
808 }
809 else
810 pReq->u.In.offGroups = cbStrTab - 1;
811
812 if (cchDest)
813 {
814 pReq->u.In.offDestination = off;
815 memcpy(&pReq->u.In.szStrings[off], pszDest, cchDest + 1);
816 off += cchDest + 1;
817 }
818 else
819 pReq->u.In.offDestination = cbStrTab - 1;
820
821 if (!off)
822 {
823 pReq->u.In.szStrings[0] = '\0';
824 off++;
825 }
826 Assert(off == cbStrTab);
827 Assert(pReq->u.In.szStrings[cbStrTab - 1] == '\0');
828
829
830 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOGGER_SETTINGS(cbStrTab), pReq, SUP_IOCTL_LOGGER_SETTINGS_SIZE(cbStrTab));
831 if (RT_SUCCESS(rc))
832 rc = pReq->Hdr.rc;
833 return rc;
834}
835
836
837SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
838{
839 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_SETTINGS, pszFlags, pszGroups, pszDest);
840}
841
842
843SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest)
844{
845 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_CREATE, pszFlags, pszGroups, pszDest);
846}
847
848
849SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich)
850{
851 return supR3LoggerSettings(enmWhich, SUPLOGGERSETTINGS_WHAT_DESTROY, NULL, NULL, NULL);
852}
853
854
855SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, void **ppvPages)
856{
857 /*
858 * Validate.
859 */
860 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
861 *ppvPages = NULL;
862 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
863
864 /*
865 * Call OS specific worker.
866 */
867 return suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
868}
869
870
871SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages)
872{
873 /*
874 * Validate.
875 */
876 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
877 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
878
879 /*
880 * Call OS specific worker.
881 */
882 return suplibOsPageFree(&g_supLibData, pvPages, cPages);
883}
884
885
886/**
887 * Locks down the physical memory backing a virtual memory
888 * range in the current process.
889 *
890 * @returns VBox status code.
891 * @param pvStart Start of virtual memory range.
892 * Must be page aligned.
893 * @param cPages Number of pages.
894 * @param paPages Where to store the physical page addresses returned.
895 * On entry this will point to an array of with cbMemory >> PAGE_SHIFT entries.
896 */
897SUPR3DECL(int) supR3PageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
898{
899 /*
900 * Validate.
901 */
902 AssertPtr(pvStart);
903 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
904 AssertPtr(paPages);
905
906 /* fake */
907 if (RT_UNLIKELY(g_u32FakeMode))
908 {
909 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
910 size_t iPage = cPages;
911 while (iPage-- > 0)
912 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
913 return VINF_SUCCESS;
914 }
915
916 /*
917 * Issue IOCtl to the SUPDRV kernel module.
918 */
919 int rc;
920 PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
921 if (RT_LIKELY(pReq))
922 {
923 pReq->Hdr.u32Cookie = g_u32Cookie;
924 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
925 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
926 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
927 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
928 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
929 pReq->u.In.pvR3 = pvStart;
930 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
931 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
932 if (RT_SUCCESS(rc))
933 rc = pReq->Hdr.rc;
934 if (RT_SUCCESS(rc))
935 {
936 for (uint32_t iPage = 0; iPage < cPages; iPage++)
937 {
938 paPages[iPage].uReserved = 0;
939 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
940 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
941 }
942 }
943 RTMemTmpFree(pReq);
944 }
945 else
946 rc = VERR_NO_TMP_MEMORY;
947
948 return rc;
949}
950
951
952/**
953 * Releases locked down pages.
954 *
955 * @returns VBox status code.
956 * @param pvStart Start of virtual memory range previously locked
957 * down by SUPPageLock().
958 */
959SUPR3DECL(int) supR3PageUnlock(void *pvStart)
960{
961 /*
962 * Validate.
963 */
964 AssertPtr(pvStart);
965 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
966
967 /* fake */
968 if (RT_UNLIKELY(g_u32FakeMode))
969 return VINF_SUCCESS;
970
971 /*
972 * Issue IOCtl to the SUPDRV kernel module.
973 */
974 SUPPAGEUNLOCK Req;
975 Req.Hdr.u32Cookie = g_u32Cookie;
976 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
977 Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
978 Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
979 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
980 Req.Hdr.rc = VERR_INTERNAL_ERROR;
981 Req.u.In.pvR3 = pvStart;
982 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
983 if (RT_SUCCESS(rc))
984 rc = Req.Hdr.rc;
985 return rc;
986}
987
988
989/**
990 * Fallback for SUPR3PageAllocEx on systems where RTR0MemObjPhysAllocNC isn't
991 * supported.
992 */
993static int supPagePageAllocNoKernelFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
994{
995 int rc = suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
996 if (RT_SUCCESS(rc))
997 {
998 if (!paPages)
999 paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
1000 rc = supR3PageLock(*ppvPages, cPages, paPages);
1001 if (RT_FAILURE(rc))
1002 suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
1003 }
1004 return rc;
1005}
1006
1007
1008SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages)
1009{
1010 /*
1011 * Validate.
1012 */
1013 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1014 *ppvPages = NULL;
1015 AssertPtrNullReturn(pR0Ptr, VERR_INVALID_POINTER);
1016 if (pR0Ptr)
1017 *pR0Ptr = NIL_RTR0PTR;
1018 AssertPtrNullReturn(paPages, VERR_INVALID_POINTER);
1019 AssertMsgReturn(cPages > 0 && cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, ("cPages=%zu\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1020
1021 /* fake */
1022 if (RT_UNLIKELY(g_u32FakeMode))
1023 {
1024 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1025 if (!pv)
1026 return VERR_NO_MEMORY;
1027 *ppvPages = pv;
1028 if (pR0Ptr)
1029 *pR0Ptr = (RTR0PTR)pv;
1030 if (paPages)
1031 for (size_t iPage = 0; iPage < cPages; iPage++)
1032 {
1033 paPages[iPage].uReserved = 0;
1034 paPages[iPage].Phys = (iPage + 4321) << PAGE_SHIFT;
1035 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1036 }
1037 return VINF_SUCCESS;
1038 }
1039
1040 /*
1041 * Use fallback for non-R0 mapping?
1042 */
1043 if ( !pR0Ptr
1044 && !g_fSupportsPageAllocNoKernel)
1045 return supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1046
1047 /*
1048 * Issue IOCtl to the SUPDRV kernel module.
1049 */
1050 int rc;
1051 PSUPPAGEALLOCEX pReq = (PSUPPAGEALLOCEX)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1052 if (pReq)
1053 {
1054 pReq->Hdr.u32Cookie = g_u32Cookie;
1055 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1056 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_IN;
1057 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_EX_SIZE_OUT(cPages);
1058 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1059 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1060 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1061 pReq->u.In.fKernelMapping = pR0Ptr != NULL;
1062 pReq->u.In.fUserMapping = true;
1063 pReq->u.In.fReserved0 = false;
1064 pReq->u.In.fReserved1 = false;
1065 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC_EX, pReq, SUP_IOCTL_PAGE_ALLOC_EX_SIZE(cPages));
1066 if (RT_SUCCESS(rc))
1067 {
1068 rc = pReq->Hdr.rc;
1069 if (RT_SUCCESS(rc))
1070 {
1071 *ppvPages = pReq->u.Out.pvR3;
1072 if (pR0Ptr)
1073 *pR0Ptr = pReq->u.Out.pvR0;
1074 if (paPages)
1075 for (size_t iPage = 0; iPage < cPages; iPage++)
1076 {
1077 paPages[iPage].uReserved = 0;
1078 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1079 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1080 }
1081#ifdef RT_OS_DARWIN /* HACK ALERT! */
1082 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1083#endif
1084 }
1085 else if ( rc == VERR_NOT_SUPPORTED
1086 && !pR0Ptr)
1087 {
1088 g_fSupportsPageAllocNoKernel = false;
1089 rc = supPagePageAllocNoKernelFallback(cPages, ppvPages, paPages);
1090 }
1091 }
1092
1093 RTMemTmpFree(pReq);
1094 }
1095 else
1096 rc = VERR_NO_TMP_MEMORY;
1097 return rc;
1098
1099}
1100
1101
1102SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr)
1103{
1104 /*
1105 * Validate.
1106 */
1107 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1108 AssertPtrReturn(pR0Ptr, VERR_INVALID_POINTER);
1109 Assert(!(off & PAGE_OFFSET_MASK));
1110 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1111 Assert(!fFlags);
1112 *pR0Ptr = NIL_RTR0PTR;
1113
1114 /* fake */
1115 if (RT_UNLIKELY(g_u32FakeMode))
1116 return VERR_NOT_SUPPORTED;
1117
1118 /*
1119 * Issue IOCtl to the SUPDRV kernel module.
1120 */
1121 SUPPAGEMAPKERNEL Req;
1122 Req.Hdr.u32Cookie = g_u32Cookie;
1123 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1124 Req.Hdr.cbIn = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_IN;
1125 Req.Hdr.cbOut = SUP_IOCTL_PAGE_MAP_KERNEL_SIZE_OUT;
1126 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1127 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1128 Req.u.In.pvR3 = pvR3;
1129 Req.u.In.offSub = off;
1130 Req.u.In.cbSub = cb;
1131 Req.u.In.fFlags = fFlags;
1132 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_MAP_KERNEL, &Req, SUP_IOCTL_PAGE_MAP_KERNEL_SIZE);
1133 if (RT_SUCCESS(rc))
1134 rc = Req.Hdr.rc;
1135 if (RT_SUCCESS(rc))
1136 *pR0Ptr = Req.u.Out.pvR0;
1137 return rc;
1138}
1139
1140
1141SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt)
1142{
1143 /*
1144 * Validate.
1145 */
1146 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
1147 Assert(!(off & PAGE_OFFSET_MASK));
1148 Assert(!(cb & PAGE_OFFSET_MASK) && cb);
1149 AssertReturn(!(fProt & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC)), VERR_INVALID_PARAMETER);
1150
1151 /* fake */
1152 if (RT_UNLIKELY(g_u32FakeMode))
1153 return RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1154
1155 /*
1156 * Some OSes can do this from ring-3, so try that before we
1157 * issue the IOCtl to the SUPDRV kernel module.
1158 * (Yea, this isn't very nice, but just try get the job done for now.)
1159 */
1160#if !defined(RT_OS_SOLARIS)
1161 RTMemProtect((uint8_t *)pvR3 + off, cb, fProt);
1162#endif
1163
1164 SUPPAGEPROTECT Req;
1165 Req.Hdr.u32Cookie = g_u32Cookie;
1166 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1167 Req.Hdr.cbIn = SUP_IOCTL_PAGE_PROTECT_SIZE_IN;
1168 Req.Hdr.cbOut = SUP_IOCTL_PAGE_PROTECT_SIZE_OUT;
1169 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1170 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1171 Req.u.In.pvR3 = pvR3;
1172 Req.u.In.pvR0 = R0Ptr;
1173 Req.u.In.offSub = off;
1174 Req.u.In.cbSub = cb;
1175 Req.u.In.fProt = fProt;
1176 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_PROTECT, &Req, SUP_IOCTL_PAGE_PROTECT_SIZE);
1177 if (RT_SUCCESS(rc))
1178 rc = Req.Hdr.rc;
1179 return rc;
1180}
1181
1182
1183SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
1184{
1185 /*
1186 * Validate.
1187 */
1188 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
1189 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1190
1191 /* fake */
1192 if (RT_UNLIKELY(g_u32FakeMode))
1193 {
1194 RTMemPageFree(pvPages);
1195 return VINF_SUCCESS;
1196 }
1197
1198 /*
1199 * Try normal free first, then if it fails check if we're using the fallback .
1200 * for the allocations without kernel mappings and attempt unlocking it.
1201 */
1202 NOREF(cPages);
1203 SUPPAGEFREE Req;
1204 Req.Hdr.u32Cookie = g_u32Cookie;
1205 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1206 Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
1207 Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
1208 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1209 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1210 Req.u.In.pvR3 = pvPages;
1211 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
1212 if (RT_SUCCESS(rc))
1213 {
1214 rc = Req.Hdr.rc;
1215 if ( rc == VERR_INVALID_PARAMETER
1216 && !g_fSupportsPageAllocNoKernel)
1217 {
1218 int rc2 = supR3PageUnlock(pvPages);
1219 if (RT_SUCCESS(rc2))
1220 rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
1221 }
1222 }
1223 return rc;
1224}
1225
1226
1227SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
1228{
1229 /*
1230 * Validate.
1231 */
1232 AssertPtrReturn(pHCPhys, NULL);
1233 *pHCPhys = NIL_RTHCPHYS;
1234 AssertPtrNullReturn(pR0Ptr, NULL);
1235 if (pR0Ptr)
1236 *pR0Ptr = NIL_RTR0PTR;
1237 AssertPtrNullReturn(pHCPhys, NULL);
1238 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
1239
1240 /* fake */
1241 if (RT_UNLIKELY(g_u32FakeMode))
1242 {
1243 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1244 if (pR0Ptr)
1245 *pR0Ptr = (RTR0PTR)pv;
1246 if (pHCPhys)
1247 *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
1248 return pv;
1249 }
1250
1251 /*
1252 * Issue IOCtl to the SUPDRV kernel module.
1253 */
1254 SUPCONTALLOC Req;
1255 Req.Hdr.u32Cookie = g_u32Cookie;
1256 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1257 Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
1258 Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
1259 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1260 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1261 Req.u.In.cPages = (uint32_t)cPages;
1262 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
1263 if ( RT_SUCCESS(rc)
1264 && RT_SUCCESS(Req.Hdr.rc))
1265 {
1266 *pHCPhys = Req.u.Out.HCPhys;
1267 if (pR0Ptr)
1268 *pR0Ptr = Req.u.Out.pvR0;
1269#ifdef RT_OS_DARWIN /* HACK ALERT! */
1270 supR3TouchPages(Req.u.Out.pvR3, cPages);
1271#endif
1272 return Req.u.Out.pvR3;
1273 }
1274
1275 return NULL;
1276}
1277
1278
1279SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages)
1280{
1281 /*
1282 * Validate.
1283 */
1284 if (!pv)
1285 return VINF_SUCCESS;
1286 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1287 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1288
1289 /* fake */
1290 if (RT_UNLIKELY(g_u32FakeMode))
1291 {
1292 RTMemPageFree(pv);
1293 return VINF_SUCCESS;
1294 }
1295
1296 /*
1297 * Issue IOCtl to the SUPDRV kernel module.
1298 */
1299 SUPCONTFREE Req;
1300 Req.Hdr.u32Cookie = g_u32Cookie;
1301 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1302 Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
1303 Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
1304 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1305 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1306 Req.u.In.pvR3 = pv;
1307 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
1308 if (RT_SUCCESS(rc))
1309 rc = Req.Hdr.rc;
1310 return rc;
1311}
1312
1313
1314SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
1315{
1316 /*
1317 * Validate.
1318 */
1319 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1320 *ppvPages = NULL;
1321 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
1322 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_PAGE_COUNT_OUT_OF_RANGE);
1323
1324 /* fake */
1325 if (RT_UNLIKELY(g_u32FakeMode))
1326 {
1327 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
1328 if (!*ppvPages)
1329 return VERR_NO_LOW_MEMORY;
1330
1331 /* fake physical addresses. */
1332 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
1333 size_t iPage = cPages;
1334 while (iPage-- > 0)
1335 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
1336 return VINF_SUCCESS;
1337 }
1338
1339 /*
1340 * Issue IOCtl to the SUPDRV kernel module.
1341 */
1342 int rc;
1343 PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1344 if (pReq)
1345 {
1346 pReq->Hdr.u32Cookie = g_u32Cookie;
1347 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1348 pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
1349 pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
1350 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1351 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1352 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1353 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1354 if (RT_SUCCESS(rc))
1355 rc = pReq->Hdr.rc;
1356 if (RT_SUCCESS(rc))
1357 {
1358 *ppvPages = pReq->u.Out.pvR3;
1359 if (ppvPagesR0)
1360 *ppvPagesR0 = pReq->u.Out.pvR0;
1361 if (paPages)
1362 for (size_t iPage = 0; iPage < cPages; iPage++)
1363 {
1364 paPages[iPage].uReserved = 0;
1365 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1366 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1367 Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
1368 }
1369#ifdef RT_OS_DARWIN /* HACK ALERT! */
1370 supR3TouchPages(pReq->u.Out.pvR3, cPages);
1371#endif
1372 }
1373 RTMemTmpFree(pReq);
1374 }
1375 else
1376 rc = VERR_NO_TMP_MEMORY;
1377
1378 return rc;
1379}
1380
1381
1382SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages)
1383{
1384 /*
1385 * Validate.
1386 */
1387 if (!pv)
1388 return VINF_SUCCESS;
1389 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1390 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
1391
1392 /* fake */
1393 if (RT_UNLIKELY(g_u32FakeMode))
1394 {
1395 RTMemPageFree(pv);
1396 return VINF_SUCCESS;
1397 }
1398
1399 /*
1400 * Issue IOCtl to the SUPDRV kernel module.
1401 */
1402 SUPCONTFREE Req;
1403 Req.Hdr.u32Cookie = g_u32Cookie;
1404 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1405 Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
1406 Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
1407 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1408 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1409 Req.u.In.pvR3 = pv;
1410 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
1411 if (RT_SUCCESS(rc))
1412 rc = Req.Hdr.rc;
1413 return rc;
1414}
1415
1416
1417SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
1418{
1419 /*
1420 * Quick input validation.
1421 */
1422 AssertPtr(pszFilename);
1423 AssertPtr(pszMsg);
1424 AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
1425 file is the same we verified after opening it. */
1426
1427 /*
1428 * Only do the actual check in hardened builds.
1429 */
1430#ifdef VBOX_WITH_HARDENING
1431 int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1432 if (RT_FAILURE(rc))
1433 LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
1434 return rc;
1435#else
1436 return VINF_SUCCESS;
1437#endif
1438}
1439
1440
1441SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
1442{
1443 int rc = VINF_SUCCESS;
1444#ifdef VBOX_WITH_HARDENING
1445 /*
1446 * Check that the module can be trusted.
1447 */
1448 rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1449#endif
1450 if (RT_SUCCESS(rc))
1451 rc = supLoadModule(pszFilename, pszModule, NULL, ppvImageBase);
1452 else
1453 LogRel(("SUPR3LoadModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
1454 return rc;
1455}
1456
1457
1458SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule,
1459 const char *pszSrvReqHandler, void **ppvImageBase)
1460{
1461 int rc = VINF_SUCCESS;
1462 AssertPtrReturn(pszSrvReqHandler, VERR_INVALID_PARAMETER);
1463
1464#ifdef VBOX_WITH_HARDENING
1465 /*
1466 * Check that the module can be trusted.
1467 */
1468 rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1469#endif
1470 if (RT_SUCCESS(rc))
1471 rc = supLoadModule(pszFilename, pszModule, pszSrvReqHandler, ppvImageBase);
1472 else
1473 LogRel(("SUPR3LoadServiceModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
1474 return rc;
1475}
1476
1477
1478/**
1479 * Resolve an external symbol during RTLdrGetBits().
1480 *
1481 * @returns VBox status code.
1482 * @param hLdrMod The loader module handle.
1483 * @param pszModule Module name.
1484 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
1485 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
1486 * @param pValue Where to store the symbol value (address).
1487 * @param pvUser User argument.
1488 */
1489static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
1490 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
1491{
1492 AssertPtr(pValue);
1493 AssertPtr(pvUser);
1494
1495 /*
1496 * Only SUPR0 and VMMR0.r0
1497 */
1498 if ( pszModule
1499 && *pszModule
1500#if defined(VBOX_WITH_NATIVE_R0_LOADER) && defined(RT_OS_WINDOWS)
1501 && strcmp(pszModule, "VBoxDrv.sys")
1502#else
1503 && strcmp(pszModule, "SUPR0.dll")
1504#endif
1505 && strcmp(pszModule, "VMMR0.r0"))
1506 {
1507 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
1508 return VERR_SYMBOL_NOT_FOUND;
1509 }
1510
1511 /*
1512 * No ordinals.
1513 */
1514 if (pszSymbol < (const char*)0x10000)
1515 {
1516 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pvUser, (int)(uintptr_t)pszSymbol));
1517 return VERR_SYMBOL_NOT_FOUND;
1518 }
1519
1520 /*
1521 * Lookup symbol.
1522 */
1523 /* skip the 64-bit ELF import prefix first. */
1524 if (!strncmp(pszSymbol, "SUPR0$", sizeof("SUPR0$") - 1))
1525 pszSymbol += sizeof("SUPR0$") - 1;
1526
1527 /*
1528 * Check the VMMR0.r0 module if loaded.
1529 */
1530 /** @todo call the SUPR3LoadModule caller.... */
1531 /** @todo proper reference counting and such. */
1532 if (g_pvVMMR0 != NIL_RTR0PTR)
1533 {
1534 void *pvValue;
1535 if (!SUPR3GetSymbolR0((void *)g_pvVMMR0, pszSymbol, &pvValue))
1536 {
1537 *pValue = (uintptr_t)pvValue;
1538 return VINF_SUCCESS;
1539 }
1540 }
1541
1542 /* iterate the function table. */
1543 int c = g_pFunctions->u.Out.cFunctions;
1544 PSUPFUNC pFunc = &g_pFunctions->u.Out.aFunctions[0];
1545 while (c-- > 0)
1546 {
1547 if (!strcmp(pFunc->szName, pszSymbol))
1548 {
1549 *pValue = (uintptr_t)pFunc->pfn;
1550 return VINF_SUCCESS;
1551 }
1552 pFunc++;
1553 }
1554
1555 /*
1556 * The GIP.
1557 */
1558 /** @todo R0 mapping? */
1559 if ( pszSymbol
1560 && g_pSUPGlobalInfoPage
1561 && g_pSUPGlobalInfoPageR0
1562 && !strcmp(pszSymbol, "g_SUPGlobalInfoPage"))
1563 {
1564 *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
1565 return VINF_SUCCESS;
1566 }
1567
1568 /*
1569 * Despair.
1570 */
1571 c = g_pFunctions->u.Out.cFunctions;
1572 pFunc = &g_pFunctions->u.Out.aFunctions[0];
1573 while (c-- > 0)
1574 {
1575 AssertMsg2("%d: %s\n", g_pFunctions->u.Out.cFunctions - c, pFunc->szName);
1576 pFunc++;
1577 }
1578
1579 AssertMsg2("%s is importing %s which we couldn't find\n", pvUser, pszSymbol);
1580 AssertMsgFailed(("%s is importing %s which we couldn't find\n", pvUser, pszSymbol));
1581 if (g_u32FakeMode)
1582 {
1583 *pValue = 0xdeadbeef;
1584 return VINF_SUCCESS;
1585 }
1586 return VERR_SYMBOL_NOT_FOUND;
1587}
1588
1589
1590/** Argument package for supLoadModuleCalcSizeCB. */
1591typedef struct SUPLDRCALCSIZEARGS
1592{
1593 size_t cbStrings;
1594 uint32_t cSymbols;
1595 size_t cbImage;
1596} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
1597
1598/**
1599 * Callback used to calculate the image size.
1600 * @return VINF_SUCCESS
1601 */
1602static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1603{
1604 PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
1605 if ( pszSymbol != NULL
1606 && *pszSymbol
1607 && Value <= pArgs->cbImage)
1608 {
1609 pArgs->cSymbols++;
1610 pArgs->cbStrings += strlen(pszSymbol) + 1;
1611 }
1612 return VINF_SUCCESS;
1613}
1614
1615
1616/** Argument package for supLoadModuleCreateTabsCB. */
1617typedef struct SUPLDRCREATETABSARGS
1618{
1619 size_t cbImage;
1620 PSUPLDRSYM pSym;
1621 char *pszBase;
1622 char *psz;
1623} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
1624
1625/**
1626 * Callback used to calculate the image size.
1627 * @return VINF_SUCCESS
1628 */
1629static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1630{
1631 PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
1632 if ( pszSymbol != NULL
1633 && *pszSymbol
1634 && Value <= pArgs->cbImage)
1635 {
1636 pArgs->pSym->offSymbol = (uint32_t)Value;
1637 pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
1638 pArgs->pSym++;
1639
1640 size_t cbCopy = strlen(pszSymbol) + 1;
1641 memcpy(pArgs->psz, pszSymbol, cbCopy);
1642 pArgs->psz += cbCopy;
1643 }
1644 return VINF_SUCCESS;
1645}
1646
1647
1648/**
1649 * Worker for SUPR3LoadModule().
1650 *
1651 * @returns VBox status code.
1652 * @param pszFilename Name of the VMMR0 image file
1653 */
1654static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase)
1655{
1656 int rc;
1657
1658 /*
1659 * Validate input.
1660 */
1661 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1662 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
1663 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
1664 AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
1665#ifdef VBOX_WITH_NATIVE_R0_LOADER
1666 char szAbsFilename[RT_SIZEOFMEMB(SUPLDROPEN, u.In.szFilename)];
1667 rc = RTPathAbs(pszFilename, szAbsFilename, sizeof(szAbsFilename));
1668 if (RT_FAILURE(rc))
1669 return rc;
1670 pszFilename = szAbsFilename;
1671#endif
1672
1673 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
1674 AssertReturn(!pszSrvReqHandler || !fIsVMMR0, VERR_INTERNAL_ERROR);
1675 *ppvImageBase = NULL;
1676
1677 /*
1678 * Open image file and figure its size.
1679 */
1680 RTLDRMOD hLdrMod;
1681 rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_HOST, &hLdrMod);
1682 if (!RT_SUCCESS(rc))
1683 return rc;
1684
1685 SUPLDRCALCSIZEARGS CalcArgs;
1686 CalcArgs.cbStrings = 0;
1687 CalcArgs.cSymbols = 0;
1688 CalcArgs.cbImage = RTLdrSize(hLdrMod);
1689 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
1690 if (RT_SUCCESS(rc))
1691 {
1692 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
1693 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
1694 const uint32_t cbImageWithTabs = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
1695
1696 /*
1697 * Open the R0 image.
1698 */
1699 SUPLDROPEN OpenReq;
1700 OpenReq.Hdr.u32Cookie = g_u32Cookie;
1701 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
1702 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
1703 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
1704 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1705 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
1706 OpenReq.u.In.cbImageWithTabs = cbImageWithTabs;
1707#ifdef VBOX_WITH_NATIVE_R0_LOADER
1708 OpenReq.u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
1709#endif
1710 strcpy(OpenReq.u.In.szName, pszModule);
1711#ifdef VBOX_WITH_NATIVE_R0_LOADER
1712 strcpy(OpenReq.u.In.szFilename, pszFilename);
1713#endif
1714 if (!g_u32FakeMode)
1715 {
1716 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
1717 if (RT_SUCCESS(rc))
1718 rc = OpenReq.Hdr.rc;
1719 }
1720 else
1721 {
1722 OpenReq.u.Out.fNeedsLoading = true;
1723 OpenReq.u.Out.pvImageBase = 0xef423420;
1724 }
1725 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
1726 if ( RT_SUCCESS(rc)
1727 && OpenReq.u.Out.fNeedsLoading)
1728 {
1729 /*
1730 * We need to load it.
1731 * Allocate memory for the image bits.
1732 */
1733 PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
1734 if (pLoadReq)
1735 {
1736 /*
1737 * Get the image bits.
1738 */
1739 rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
1740 supLoadModuleResolveImport, (void *)pszModule);
1741
1742 if (RT_SUCCESS(rc))
1743 {
1744 /*
1745 * Get the entry points.
1746 */
1747 RTUINTPTR VMMR0EntryInt = 0;
1748 RTUINTPTR VMMR0EntryFast = 0;
1749 RTUINTPTR VMMR0EntryEx = 0;
1750 RTUINTPTR SrvReqHandler = 0;
1751 RTUINTPTR ModuleInit = 0;
1752 RTUINTPTR ModuleTerm = 0;
1753 if (fIsVMMR0)
1754 {
1755 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
1756 if (RT_SUCCESS(rc))
1757 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
1758 if (RT_SUCCESS(rc))
1759 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
1760 }
1761 else if (pszSrvReqHandler)
1762 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, pszSrvReqHandler, &SrvReqHandler);
1763 if (RT_SUCCESS(rc))
1764 {
1765 int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
1766 if (RT_FAILURE(rc2))
1767 ModuleInit = 0;
1768
1769 rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
1770 if (RT_FAILURE(rc2))
1771 ModuleTerm = 0;
1772 }
1773 if (RT_SUCCESS(rc))
1774 {
1775 /*
1776 * Create the symbol and string tables.
1777 */
1778 SUPLDRCREATETABSARGS CreateArgs;
1779 CreateArgs.cbImage = CalcArgs.cbImage;
1780 CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab];
1781 CreateArgs.pszBase = (char *)&pLoadReq->u.In.achImage[offStrTab];
1782 CreateArgs.psz = CreateArgs.pszBase;
1783 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
1784 if (RT_SUCCESS(rc))
1785 {
1786 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
1787 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab]) <= CalcArgs.cSymbols);
1788
1789 /*
1790 * Upload the image.
1791 */
1792 pLoadReq->Hdr.u32Cookie = g_u32Cookie;
1793 pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1794 pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImageWithTabs);
1795 pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
1796 pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
1797 pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
1798
1799 pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
1800 pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
1801 if (fIsVMMR0)
1802 {
1803 pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
1804 pLoadReq->u.In.EP.VMMR0.pvVMMR0 = OpenReq.u.Out.pvImageBase;
1805 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)VMMR0EntryInt;
1806 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
1807 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
1808 }
1809 else if (pszSrvReqHandler)
1810 {
1811 pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
1812 pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
1813 pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
1814 pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
1815 pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
1816 }
1817 else
1818 pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
1819 pLoadReq->u.In.offStrTab = offStrTab;
1820 pLoadReq->u.In.cbStrTab = (uint32_t)CalcArgs.cbStrings;
1821 AssertRelease(pLoadReq->u.In.cbStrTab == CalcArgs.cbStrings);
1822#ifdef VBOX_WITH_NATIVE_R0_LOADER
1823 pLoadReq->u.In.cbImageBits = (uint32_t)CalcArgs.cbImage;
1824#endif
1825 pLoadReq->u.In.offSymbols = offSymTab;
1826 pLoadReq->u.In.cSymbols = CalcArgs.cSymbols;
1827 pLoadReq->u.In.cbImageWithTabs = cbImageWithTabs;
1828 pLoadReq->u.In.pvImageBase = OpenReq.u.Out.pvImageBase;
1829 if (!g_u32FakeMode)
1830 {
1831 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs));
1832 if (RT_SUCCESS(rc))
1833 rc = pLoadReq->Hdr.rc;
1834 }
1835 else
1836 rc = VINF_SUCCESS;
1837 if ( RT_SUCCESS(rc)
1838 || rc == VERR_ALREADY_LOADED /* A competing process. */
1839 )
1840 {
1841 LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr\n", pszModule, pszFilename,
1842 OpenReq.u.Out.pvImageBase, ModuleInit, ModuleTerm));
1843 if (fIsVMMR0)
1844 {
1845 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1846 LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
1847 VMMR0EntryEx, VMMR0EntryFast, VMMR0EntryInt));
1848 }
1849#ifdef RT_OS_WINDOWS
1850 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1851#endif
1852
1853 RTMemTmpFree(pLoadReq);
1854 RTLdrClose(hLdrMod);
1855 return VINF_SUCCESS;
1856 }
1857 }
1858 }
1859 }
1860 RTMemTmpFree(pLoadReq);
1861 }
1862 else
1863 {
1864 AssertMsgFailed(("failed to allocated %u bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImageWithTabs)));
1865 rc = VERR_NO_TMP_MEMORY;
1866 }
1867 }
1868 else if (RT_SUCCESS(rc))
1869 {
1870 if (fIsVMMR0)
1871 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1872 LogRel(("SUP: Opened %s (%s) at %#p.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase));
1873#ifdef RT_OS_WINDOWS
1874 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1875#endif
1876 }
1877 }
1878 RTLdrClose(hLdrMod);
1879 return rc;
1880}
1881
1882
1883SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase)
1884{
1885 /* fake */
1886 if (RT_UNLIKELY(g_u32FakeMode))
1887 {
1888 g_pvVMMR0 = NIL_RTR0PTR;
1889 return VINF_SUCCESS;
1890 }
1891
1892 /*
1893 * Free the requested module.
1894 */
1895 SUPLDRFREE Req;
1896 Req.Hdr.u32Cookie = g_u32Cookie;
1897 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1898 Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
1899 Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
1900 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1901 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1902 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1903 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
1904 if (RT_SUCCESS(rc))
1905 rc = Req.Hdr.rc;
1906 if ( RT_SUCCESS(rc)
1907 && (RTR0PTR)pvImageBase == g_pvVMMR0)
1908 g_pvVMMR0 = NIL_RTR0PTR;
1909 return rc;
1910}
1911
1912
1913SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
1914{
1915 *ppvValue = NULL;
1916
1917 /* fake */
1918 if (RT_UNLIKELY(g_u32FakeMode))
1919 {
1920 *ppvValue = (void *)(uintptr_t)0xdeadf00d;
1921 return VINF_SUCCESS;
1922 }
1923
1924 /*
1925 * Do ioctl.
1926 */
1927 SUPLDRGETSYMBOL Req;
1928 Req.Hdr.u32Cookie = g_u32Cookie;
1929 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1930 Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
1931 Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
1932 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1933 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1934 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1935 size_t cchSymbol = strlen(pszSymbol);
1936 if (cchSymbol >= sizeof(Req.u.In.szSymbol))
1937 return VERR_SYMBOL_NOT_FOUND;
1938 memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
1939 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
1940 if (RT_SUCCESS(rc))
1941 rc = Req.Hdr.rc;
1942 if (RT_SUCCESS(rc))
1943 *ppvValue = (void *)Req.u.Out.pvSymbol;
1944 return rc;
1945}
1946
1947
1948SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename)
1949{
1950 void *pvImageBase;
1951 return SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase);
1952}
1953
1954
1955SUPR3DECL(int) SUPR3UnloadVMM(void)
1956{
1957 return SUPR3FreeModule((void*)g_pvVMMR0);
1958}
1959
1960
1961SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
1962{
1963 if (g_pSUPGlobalInfoPage)
1964 {
1965 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1966 return VINF_SUCCESS;
1967 }
1968 *pHCPhys = NIL_RTHCPHYS;
1969 return VERR_WRONG_ORDER;
1970}
1971
1972
1973/**
1974 * Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
1975 *
1976 * @returns iprt status code.
1977 * @param pszFilename The full file name.
1978 * @param phLdrMod Where to store the handle to the loaded module.
1979 */
1980static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod)
1981{
1982#ifdef VBOX_WITH_HARDENING
1983 /*
1984 * Verify the image file.
1985 */
1986 int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1987 if (RT_FAILURE(rc))
1988 {
1989 LogRel(("supR3HardenedLdrLoadIt: Verification of \"%s\" failed, rc=%Rrc\n", pszFilename, rc));
1990 return rc;
1991 }
1992#endif
1993
1994 /*
1995 * Try load it.
1996 */
1997 return RTLdrLoad(pszFilename, phLdrMod);
1998}
1999
2000
2001SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod)
2002{
2003 /*
2004 * Validate input.
2005 */
2006 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
2007 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
2008 *phLdrMod = NIL_RTLDRMOD;
2009 AssertReturn(RTPathHavePath(pszFilename), VERR_INVALID_PARAMETER);
2010
2011 /*
2012 * Add the default extension if it's missing.
2013 */
2014 if (!RTPathHaveExt(pszFilename))
2015 {
2016 const char *pszSuff = RTLdrGetSuff();
2017 size_t cchSuff = strlen(pszSuff);
2018 size_t cchFilename = strlen(pszFilename);
2019 char *psz = (char *)alloca(cchFilename + cchSuff + 1);
2020 AssertReturn(psz, VERR_NO_TMP_MEMORY);
2021 memcpy(psz, pszFilename, cchFilename);
2022 memcpy(psz + cchFilename, pszSuff, cchSuff + 1);
2023 pszFilename = psz;
2024 }
2025
2026 /*
2027 * Pass it on to the common library loader.
2028 */
2029 return supR3HardenedLdrLoadIt(pszFilename, phLdrMod);
2030}
2031
2032
2033SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod)
2034{
2035 LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p\n", pszFilename, pszFilename, phLdrMod));
2036
2037 /*
2038 * Validate input.
2039 */
2040 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
2041 *phLdrMod = NIL_RTLDRMOD;
2042 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
2043 AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
2044
2045 /*
2046 * Check the filename.
2047 */
2048 size_t cchFilename = strlen(pszFilename);
2049 AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
2050
2051 const char *pszExt = "";
2052 size_t cchExt = 0;
2053 if (!RTPathHaveExt(pszFilename))
2054 {
2055 pszExt = RTLdrGetSuff();
2056 cchExt = strlen(pszExt);
2057 }
2058
2059 /*
2060 * Construct the private arch path and check if the file exists.
2061 */
2062 char szPath[RTPATH_MAX];
2063 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchExt - cchFilename);
2064 AssertRCReturn(rc, rc);
2065
2066 char *psz = strchr(szPath, '\0');
2067 *psz++ = RTPATH_SLASH;
2068 memcpy(psz, pszFilename, cchFilename);
2069 psz += cchFilename;
2070 memcpy(psz, pszExt, cchExt + 1);
2071
2072 if (!RTPathExists(szPath))
2073 {
2074 LogRel(("SUPR3HardenedLdrLoadAppPriv: \"%s\" not found\n", szPath));
2075 return VERR_FILE_NOT_FOUND;
2076 }
2077
2078 /*
2079 * Pass it on to SUPR3HardenedLdrLoad.
2080 */
2081 rc = SUPR3HardenedLdrLoad(szPath, phLdrMod);
2082
2083 LogFlow(("SUPR3HardenedLdrLoadAppPriv: returns %Rrc\n", rc));
2084 return rc;
2085}
2086
2087
2088SUPR3DECL(int) SUPR3QueryVTxSupported(void)
2089{
2090#ifdef RT_OS_LINUX
2091 return suplibOsQueryVTxSupported();
2092#else
2093 return VINF_SUCCESS;
2094#endif
2095}
2096
2097
2098SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps)
2099{
2100 AssertPtrReturn(pfCaps, VERR_INVALID_POINTER);
2101
2102 *pfCaps = 0;
2103
2104 /* fake */
2105 if (RT_UNLIKELY(g_u32FakeMode))
2106 return VINF_SUCCESS;
2107
2108 /*
2109 * Issue IOCtl to the SUPDRV kernel module.
2110 */
2111 SUPVTCAPS Req;
2112 Req.Hdr.u32Cookie = g_u32Cookie;
2113 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
2114 Req.Hdr.cbIn = SUP_IOCTL_VT_CAPS_SIZE_IN;
2115 Req.Hdr.cbOut = SUP_IOCTL_VT_CAPS_SIZE_OUT;
2116 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
2117 Req.Hdr.rc = VERR_INTERNAL_ERROR;
2118 Req.u.Out.Caps = 0;
2119 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_VT_CAPS, &Req, SUP_IOCTL_VT_CAPS_SIZE);
2120 if (RT_SUCCESS(rc))
2121 {
2122 rc = Req.Hdr.rc;
2123 if (RT_SUCCESS(rc))
2124 *pfCaps = Req.u.Out.Caps;
2125 }
2126 return rc;
2127}
2128
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