VirtualBox

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

Last change on this file since 37112 was 36262, checked in by vboxsync, 14 years ago

SUPDrv,IPRT,++: Enabled the code for supporting up to 256 host CPUs/cores/threads.

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