VirtualBox

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

Last change on this file since 39091 was 39086, checked in by vboxsync, 13 years ago

Dis,SrvPciRaw,Sup: warning fixes.

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