VirtualBox

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

Last change on this file since 35650 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

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