VirtualBox

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

Last change on this file since 14589 was 14589, checked in by vboxsync, 16 years ago

VMM,SUPLib: Updated SUPLib API spec, turned out we don't get zero-filled memory from ring-0. Switched the heap to use the new api.

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