VirtualBox

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

最後變更 在這個檔案從15351是 15351,由 vboxsync 提交於 16 年 前

LogRel statement in supR3HardenedLdrLoadIt.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette