VirtualBox

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

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

SUPDrv: expose SUPR0GetPagingMode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.2 KB
Line 
1/* $Id: SUPLib.cpp 14373 2008-11-19 19:12:26Z 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#ifdef VBOX_WITH_IDT_PATCHING
136/** The negotiated interrupt number. */
137static uint8_t g_u8Interrupt = 3;
138/** Pointer to the generated code fore calling VMMR0. */
139static PFNCALLVMMR0 g_pfnCallVMMR0;
140#endif
141/** VMMR0 Load Address. */
142static RTR0PTR g_pvVMMR0 = NIL_RTR0PTR;
143/** PAGE_ALLOC support indicator. */
144static bool g_fSupportsPageAllocLocked = true;
145/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
146static uint32_t g_u32FakeMode = ~0;
147
148
149/*******************************************************************************
150* Internal Functions *
151*******************************************************************************/
152static int supInitFake(PSUPDRVSESSION *ppSession);
153static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase);
154#ifdef VBOX_WITH_IDT_PATCHING
155static int supInstallIDTE(void);
156#endif
157static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
158
159
160SUPR3DECL(int) SUPInstall(void)
161{
162 return suplibOsInstall();
163}
164
165
166SUPR3DECL(int) SUPUninstall(void)
167{
168 return suplibOsUninstall();
169}
170
171
172DECLEXPORT(int) supR3PreInit(PSUPPREINITDATA pPreInitData, uint32_t fFlags)
173{
174 /*
175 * The caller is kind of trustworthy, just perform some basic checks.
176 *
177 * Note! Do not do any fancy stuff here because IPRT has NOT been
178 * initialized at this point.
179 */
180 if (!VALID_PTR(pPreInitData))
181 return VERR_INVALID_POINTER;
182 if (g_fPreInited || g_cInits > 0)
183 return VERR_WRONG_ORDER;
184
185 if ( pPreInitData->u32Magic != SUPPREINITDATA_MAGIC
186 || pPreInitData->u32EndMagic != SUPPREINITDATA_MAGIC)
187 return VERR_INVALID_MAGIC;
188 if ( !(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
189 && pPreInitData->Data.hDevice == NIL_RTFILE)
190 return VERR_INVALID_HANDLE;
191 if ( (fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV)
192 && pPreInitData->Data.hDevice != NIL_RTFILE)
193 return VERR_INVALID_PARAMETER;
194
195 /*
196 * Hand out the data.
197 */
198 int rc = supR3HardenedRecvPreInitData(pPreInitData);
199 if (RT_FAILURE(rc))
200 return rc;
201
202 /** @todo This may need some small restructuring later, it doesn't quite work with a root service flag... */
203 if (!(fFlags & SUPSECMAIN_FLAGS_DONT_OPEN_DEV))
204 {
205 g_supLibData = pPreInitData->Data;
206 g_fPreInited = true;
207 }
208
209 return VINF_SUCCESS;
210}
211
212
213SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession)
214{
215 /*
216 * Perform some sanity checks.
217 * (Got some trouble with compile time member alignment assertions.)
218 */
219 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz) & 0x7));
220 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs) & 0x1f));
221 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[1]) & 0x1f));
222 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64NanoTS) & 0x7));
223 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64TSC) & 0x7));
224 Assert(!(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[0].u64CpuHz) & 0x7));
225
226 /*
227 * Check if already initialized.
228 */
229 if (ppSession)
230 *ppSession = g_pSession;
231 if (g_cInits++ > 0)
232 return VINF_SUCCESS;
233
234 /*
235 * Check for fake mode.
236 *
237 * Fake mode is used when we're doing smoke testing and debugging.
238 * It's also useful on platforms where we haven't root access or which
239 * we haven't ported the support driver to.
240 */
241 if (g_u32FakeMode == ~0U)
242 {
243 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
244 if (psz && !strcmp(psz, "fake"))
245 ASMAtomicCmpXchgU32(&g_u32FakeMode, 1, ~0U);
246 else
247 ASMAtomicCmpXchgU32(&g_u32FakeMode, 0, ~0U);
248 }
249 if (RT_UNLIKELY(g_u32FakeMode))
250 return supInitFake(ppSession);
251
252 /*
253 * Open the support driver.
254 */
255 int rc = suplibOsInit(&g_supLibData, g_fPreInited);
256 if (RT_SUCCESS(rc))
257 {
258 /*
259 * Negotiate the cookie.
260 */
261 SUPCOOKIE CookieReq;
262 memset(&CookieReq, 0xff, sizeof(CookieReq));
263 CookieReq.Hdr.u32Cookie = SUPCOOKIE_INITIAL_COOKIE;
264 CookieReq.Hdr.u32SessionCookie = RTRandU32();
265 CookieReq.Hdr.cbIn = SUP_IOCTL_COOKIE_SIZE_IN;
266 CookieReq.Hdr.cbOut = SUP_IOCTL_COOKIE_SIZE_OUT;
267 CookieReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
268 CookieReq.Hdr.rc = VERR_INTERNAL_ERROR;
269 strcpy(CookieReq.u.In.szMagic, SUPCOOKIE_MAGIC);
270 CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
271 const uint32_t MinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00090000
272 ? 0x00090001
273 : SUPDRV_IOC_VERSION & 0xffff0000;
274 CookieReq.u.In.u32MinVersion = MinVersion;
275 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_COOKIE, &CookieReq, SUP_IOCTL_COOKIE_SIZE);
276 if ( RT_SUCCESS(rc)
277 && RT_SUCCESS(CookieReq.Hdr.rc))
278 {
279 if ( (CookieReq.u.Out.u32SessionVersion & 0xffff0000) == (SUPDRV_IOC_VERSION & 0xffff0000)
280 && CookieReq.u.Out.u32SessionVersion >= MinVersion)
281 {
282 /*
283 * Query the functions.
284 */
285 PSUPQUERYFUNCS pFuncsReq = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
286 if (pFuncsReq)
287 {
288 pFuncsReq->Hdr.u32Cookie = CookieReq.u.Out.u32Cookie;
289 pFuncsReq->Hdr.u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
290 pFuncsReq->Hdr.cbIn = SUP_IOCTL_QUERY_FUNCS_SIZE_IN;
291 pFuncsReq->Hdr.cbOut = SUP_IOCTL_QUERY_FUNCS_SIZE_OUT(CookieReq.u.Out.cFunctions);
292 pFuncsReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
293 pFuncsReq->Hdr.rc = VERR_INTERNAL_ERROR;
294 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_QUERY_FUNCS(CookieReq.u.Out.cFunctions), pFuncsReq, SUP_IOCTL_QUERY_FUNCS_SIZE(CookieReq.u.Out.cFunctions));
295 if (RT_SUCCESS(rc))
296 rc = pFuncsReq->Hdr.rc;
297 if (RT_SUCCESS(rc))
298 {
299 g_u32Cookie = CookieReq.u.Out.u32Cookie;
300 g_u32SessionCookie = CookieReq.u.Out.u32SessionCookie;
301 g_pSession = CookieReq.u.Out.pSession;
302 g_pFunctions = pFuncsReq;
303 if (ppSession)
304 *ppSession = CookieReq.u.Out.pSession;
305
306 /*
307 * Map the GIP into userspace.
308 * This is an optional feature, so we will ignore any failures here.
309 */
310 if (!g_pSUPGlobalInfoPage)
311 {
312 SUPGIPMAP GipMapReq;
313 GipMapReq.Hdr.u32Cookie = g_u32Cookie;
314 GipMapReq.Hdr.u32SessionCookie = g_u32SessionCookie;
315 GipMapReq.Hdr.cbIn = SUP_IOCTL_GIP_MAP_SIZE_IN;
316 GipMapReq.Hdr.cbOut = SUP_IOCTL_GIP_MAP_SIZE_OUT;
317 GipMapReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
318 GipMapReq.Hdr.rc = VERR_INTERNAL_ERROR;
319 GipMapReq.u.Out.HCPhysGip = NIL_RTHCPHYS;
320 GipMapReq.u.Out.pGipR0 = NIL_RTR0PTR;
321 GipMapReq.u.Out.pGipR3 = NULL;
322 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GIP_MAP, &GipMapReq, SUP_IOCTL_GIP_MAP_SIZE);
323 if (RT_SUCCESS(rc))
324 rc = GipMapReq.Hdr.rc;
325 if (RT_SUCCESS(rc))
326 {
327 AssertRelease(GipMapReq.u.Out.pGipR3->u32Magic == SUPGLOBALINFOPAGE_MAGIC);
328 AssertRelease(GipMapReq.u.Out.pGipR3->u32Version >= SUPGLOBALINFOPAGE_VERSION);
329 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipMapReq.u.Out.HCPhysGip);
330 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, GipMapReq.u.Out.pGipR3, NULL);
331 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipMapReq.u.Out.pGipR0, NULL);
332 }
333 }
334 return VINF_SUCCESS;
335 }
336
337 /* bailout */
338 RTMemFree(pFuncsReq);
339 }
340 else
341 rc = VERR_NO_MEMORY;
342 }
343 else
344 {
345 LogRel(("Support driver version mismatch: SessionVersion=%#x DriverVersion=%#x ClientVersion=%#x MinVersion=%#x\n",
346 CookieReq.u.Out.u32SessionVersion, CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, MinVersion));
347 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
348 }
349 }
350 else
351 {
352 if (RT_SUCCESS(rc))
353 {
354 rc = CookieReq.Hdr.rc;
355 LogRel(("Support driver version mismatch: DriverVersion=%#x ClientVersion=%#x rc=%Rrc\n",
356 CookieReq.u.Out.u32DriverVersion, SUPDRV_IOC_VERSION, rc));
357 if (rc != VERR_VM_DRIVER_VERSION_MISMATCH)
358 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
359 }
360 else
361 {
362 /* for pre 0x00060000 drivers */
363 LogRel(("Support driver version mismatch: DriverVersion=too-old ClientVersion=%#x\n", SUPDRV_IOC_VERSION));
364 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
365 }
366 }
367
368 suplibOsTerm(&g_supLibData);
369 }
370 AssertMsgFailed(("SUPR3Init() failed rc=%Rrc\n", rc));
371 g_cInits--;
372
373 return rc;
374}
375
376/**
377 * Fake mode init.
378 */
379static int supInitFake(PSUPDRVSESSION *ppSession)
380{
381 Log(("SUP: Fake mode!\n"));
382 static const SUPFUNC s_aFakeFunctions[] =
383 {
384 /* name function */
385 { "SUPR0ComponentRegisterFactory", 0xefeefffd },
386 { "SUPR0ComponentDeregisterFactory", 0xefeefffe },
387 { "SUPR0ComponentQueryFactory", 0xefeeffff },
388 { "SUPR0ObjRegister", 0xefef0000 },
389 { "SUPR0ObjAddRef", 0xefef0001 },
390 { "SUPR0ObjRelease", 0xefef0002 },
391 { "SUPR0ObjVerifyAccess", 0xefef0003 },
392 { "SUPR0LockMem", 0xefef0004 },
393 { "SUPR0UnlockMem", 0xefef0005 },
394 { "SUPR0ContAlloc", 0xefef0006 },
395 { "SUPR0ContFree", 0xefef0007 },
396 { "SUPR0MemAlloc", 0xefef0008 },
397 { "SUPR0MemGetPhys", 0xefef0009 },
398 { "SUPR0MemFree", 0xefef000a },
399 { "SUPR0Printf", 0xefef000b },
400 { "SUPR0GetPagingMode", 0xefef000c },
401 { "RTMemAlloc", 0xefef000d },
402 { "RTMemAllocZ", 0xefef000e },
403 { "RTMemFree", 0xefef000f },
404 { "RTR0MemObjAddress", 0xefef0010 },
405 { "RTR0MemObjAddressR3", 0xefef0011 },
406 { "RTR0MemObjAllocPage", 0xefef0012 },
407 { "RTR0MemObjAllocPhysNC", 0xefef0013 },
408 { "RTR0MemObjAllocLow", 0xefef0014 },
409 { "RTR0MemObjFree", 0xefef0015 },
410 { "RTR0MemObjGetPagePhysAddr", 0xefef0016 },
411 { "RTR0MemObjMapUser", 0xefef0017 },
412 { "RTProcSelf", 0xefef0038 },
413 { "RTR0ProcHandleSelf", 0xefef0039 },
414 { "RTSemEventCreate", 0xefef0018 },
415 { "RTSemEventSignal", 0xefef0019 },
416 { "RTSemEventWait", 0xefef001a },
417 { "RTSemEventWaitNoResume", 0xefef001b },
418 { "RTSemEventDestroy", 0xefef001c },
419 { "RTSemEventMultiCreate", 0xefef001d },
420 { "RTSemEventMultiSignal", 0xefef001e },
421 { "RTSemEventMultiReset", 0xefef001f },
422 { "RTSemEventMultiWait", 0xefef0020 },
423 { "RTSemEventMultiWaitNoResume", 0xefef0021 },
424 { "RTSemEventMultiDestroy", 0xefef0022 },
425 { "RTSemFastMutexCreate", 0xefef0023 },
426 { "RTSemFastMutexDestroy", 0xefef0024 },
427 { "RTSemFastMutexRequest", 0xefef0025 },
428 { "RTSemFastMutexRelease", 0xefef0026 },
429 { "RTSpinlockCreate", 0xefef0027 },
430 { "RTSpinlockDestroy", 0xefef0028 },
431 { "RTSpinlockAcquire", 0xefef0029 },
432 { "RTSpinlockRelease", 0xefef002a },
433 { "RTSpinlockAcquireNoInts", 0xefef002b },
434 { "RTSpinlockReleaseNoInts", 0xefef002c },
435 { "RTTimeNanoTS", 0xefef002d },
436 { "RTTimeMillieTS", 0xefef002e },
437 { "RTTimeSystemNanoTS", 0xefef002f },
438 { "RTTimeSystemMillieTS", 0xefef0030 },
439 { "RTThreadNativeSelf", 0xefef0031 },
440 { "RTThreadSleep", 0xefef0032 },
441 { "RTThreadYield", 0xefef0033 },
442 { "RTLogDefaultInstance", 0xefef0034 },
443 { "RTLogRelDefaultInstance", 0xefef0035 },
444 { "RTLogSetDefaultInstanceThread", 0xefef0036 },
445 { "RTLogLogger", 0xefef0037 },
446 { "RTLogLoggerEx", 0xefef0038 },
447 { "RTLogLoggerExV", 0xefef0039 },
448 { "AssertMsg1", 0xefef003a },
449 { "AssertMsg2", 0xefef003b },
450 };
451
452 /* fake r0 functions. */
453 g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
454 if (g_pFunctions)
455 {
456 g_pFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
457 memcpy(&g_pFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
458 g_pSession = (PSUPDRVSESSION)(void *)g_pFunctions;
459 if (ppSession)
460 *ppSession = g_pSession;
461#ifdef VBOX_WITH_IDT_PATCHING
462 Assert(g_u8Interrupt == 3);
463#endif
464
465 /* fake the GIP. */
466 g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
467 if (g_pSUPGlobalInfoPage)
468 {
469 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
470 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
471 /* the page is supposed to be invalid, so don't set the magic. */
472 return VINF_SUCCESS;
473 }
474
475 RTMemFree(g_pFunctions);
476 g_pFunctions = NULL;
477 }
478 return VERR_NO_MEMORY;
479}
480
481
482SUPR3DECL(int) SUPTerm(bool fForced)
483{
484 /*
485 * Verify state.
486 */
487 AssertMsg(g_cInits > 0, ("SUPTerm() is called before SUPR3Init()!\n"));
488 if (g_cInits == 0)
489 return VERR_WRONG_ORDER;
490 if (g_cInits == 1 || fForced)
491 {
492 /*
493 * NULL the GIP pointer.
494 */
495 if (g_pSUPGlobalInfoPage)
496 {
497 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, NULL);
498 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, NULL);
499 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
500 /* just a little safe guard against threads using the page. */
501 RTThreadSleep(50);
502 }
503
504 /*
505 * Close the support driver.
506 */
507 int rc = suplibOsTerm(&g_supLibData);
508 if (rc)
509 return rc;
510
511 g_u32Cookie = 0;
512 g_u32SessionCookie = 0;
513#ifdef VBOX_WITH_IDT_PATCHING
514 g_u8Interrupt = 3;
515#endif
516 g_cInits = 0;
517 }
518 else
519 g_cInits--;
520
521 return 0;
522}
523
524
525SUPR3DECL(SUPPAGINGMODE) SUPGetPagingMode(void)
526{
527 /* fake */
528 if (RT_UNLIKELY(g_u32FakeMode))
529#ifdef RT_ARCH_AMD64
530 return SUPPAGINGMODE_AMD64_GLOBAL_NX;
531#else
532 return SUPPAGINGMODE_32_BIT_GLOBAL;
533#endif
534
535 /*
536 * Issue IOCtl to the SUPDRV kernel module.
537 */
538 SUPGETPAGINGMODE Req;
539 Req.Hdr.u32Cookie = g_u32Cookie;
540 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
541 Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
542 Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
543 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
544 Req.Hdr.rc = VERR_INTERNAL_ERROR;
545 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
546 if ( RT_FAILURE(rc)
547 || RT_FAILURE(Req.Hdr.rc))
548 {
549 LogRel(("SUPGetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
550 Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
551 }
552
553 return Req.u.Out.enmMode;
554}
555
556
557/**
558 * For later.
559 */
560static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
561{
562 AssertMsgFailed(("%d\n", uOperation));
563 return VERR_NOT_SUPPORTED;
564}
565
566
567SUPR3DECL(int) SUPCallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, unsigned idCpu)
568{
569 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_RAW_RUN))
570 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_RAW_RUN, idCpu);
571 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_HWACC_RUN))
572 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_HWACC_RUN, idCpu);
573 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_NOP))
574 return suplibOsIOCtlFast(&g_supLibData, SUP_IOCTL_FAST_DO_NOP, idCpu);
575
576 AssertMsgFailed(("%#x\n", uOperation));
577 return VERR_INTERNAL_ERROR;
578}
579
580
581SUPR3DECL(int) SUPCallVMMR0Ex(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
582{
583 /*
584 * The following operations don't belong here.
585 */
586 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
587 && uOperation != SUP_VMMR0_DO_HWACC_RUN
588 && uOperation != SUP_VMMR0_DO_NOP,
589 ("%#x\n", uOperation),
590 VERR_INTERNAL_ERROR);
591
592 /* fake */
593 if (RT_UNLIKELY(g_u32FakeMode))
594 return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
595
596 int rc;
597 if (!pReqHdr)
598 {
599 /* no data. */
600 SUPCALLVMMR0 Req;
601 Req.Hdr.u32Cookie = g_u32Cookie;
602 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
603 Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
604 Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
605 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
606 Req.Hdr.rc = VERR_INTERNAL_ERROR;
607 Req.u.In.pVMR0 = pVMR0;
608 Req.u.In.uOperation = uOperation;
609 Req.u.In.u64Arg = u64Arg;
610 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
611 if (RT_SUCCESS(rc))
612 rc = Req.Hdr.rc;
613 }
614 else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
615 {
616 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
617 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
618 const size_t cbReq = pReqHdr->cbReq;
619
620 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
621 pReq->Hdr.u32Cookie = g_u32Cookie;
622 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
623 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
624 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
625 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
626 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
627 pReq->u.In.pVMR0 = pVMR0;
628 pReq->u.In.uOperation = uOperation;
629 pReq->u.In.u64Arg = u64Arg;
630 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
631 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
632 if (RT_SUCCESS(rc))
633 rc = pReq->Hdr.rc;
634 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
635 }
636 else /** @todo may have to remove the size limits one this request... */
637 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
638 return rc;
639}
640
641
642SUPR3DECL(int) SUPCallVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg)
643{
644#if defined(VBOX_WITH_IDT_PATCHING)
645 return g_pfnCallVMMR0(pVMR0, uOperation, pvArg);
646
647#else
648 /*
649 * The following operations don't belong here.
650 */
651 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
652 && uOperation != SUP_VMMR0_DO_HWACC_RUN
653 && uOperation != SUP_VMMR0_DO_NOP,
654 ("%#x\n", uOperation),
655 VERR_INTERNAL_ERROR);
656 return SUPCallVMMR0Ex(pVMR0, uOperation, (uintptr_t)pvArg, NULL);
657#endif
658}
659
660
661SUPR3DECL(int) SUPSetVMForFastIOCtl(PVMR0 pVMR0)
662{
663 if (RT_UNLIKELY(g_u32FakeMode))
664 return VINF_SUCCESS;
665
666 SUPSETVMFORFAST Req;
667 Req.Hdr.u32Cookie = g_u32Cookie;
668 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
669 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
670 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
671 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
672 Req.Hdr.rc = VERR_INTERNAL_ERROR;
673 Req.u.In.pVMR0 = pVMR0;
674 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
675 if (RT_SUCCESS(rc))
676 rc = Req.Hdr.rc;
677 return rc;
678}
679
680
681SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
682{
683 AssertReturn(cchService < RT_SIZEOFMEMB(SUPCALLSERVICE, u.In.szName), VERR_INVALID_PARAMETER);
684 Assert(strlen(pszService) == cchService);
685
686 /* fake */
687 if (RT_UNLIKELY(g_u32FakeMode))
688 return VERR_NOT_SUPPORTED;
689
690 int rc;
691 if (!pReqHdr)
692 {
693 /* no data. */
694 SUPCALLSERVICE Req;
695 Req.Hdr.u32Cookie = g_u32Cookie;
696 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
697 Req.Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(0);
698 Req.Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(0);
699 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
700 Req.Hdr.rc = VERR_INTERNAL_ERROR;
701 memcpy(Req.u.In.szName, pszService, cchService);
702 Req.u.In.szName[cchService] = '\0';
703 Req.u.In.uOperation = uOperation;
704 Req.u.In.u64Arg = u64Arg;
705 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(0), &Req, SUP_IOCTL_CALL_SERVICE_SIZE(0));
706 if (RT_SUCCESS(rc))
707 rc = Req.Hdr.rc;
708 }
709 else if (SUP_IOCTL_CALL_SERVICE_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
710 {
711 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
712 AssertReturn(pReqHdr->u32Magic == SUPR0SERVICEREQHDR_MAGIC, VERR_INVALID_MAGIC);
713 const size_t cbReq = pReqHdr->cbReq;
714
715 PSUPCALLSERVICE pReq = (PSUPCALLSERVICE)alloca(SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
716 pReq->Hdr.u32Cookie = g_u32Cookie;
717 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
718 pReq->Hdr.cbIn = SUP_IOCTL_CALL_SERVICE_SIZE_IN(cbReq);
719 pReq->Hdr.cbOut = SUP_IOCTL_CALL_SERVICE_SIZE_OUT(cbReq);
720 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
721 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
722 memcpy(pReq->u.In.szName, pszService, cchService);
723 pReq->u.In.szName[cchService] = '\0';
724 pReq->u.In.uOperation = uOperation;
725 pReq->u.In.u64Arg = u64Arg;
726 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
727 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CALL_SERVICE(cbReq), pReq, SUP_IOCTL_CALL_SERVICE_SIZE(cbReq));
728 if (RT_SUCCESS(rc))
729 rc = pReq->Hdr.rc;
730 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
731 }
732 else /** @todo may have to remove the size limits one this request... */
733 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
734 return rc;
735}
736
737
738SUPR3DECL(int) SUPPageAlloc(size_t cPages, void **ppvPages)
739{
740 /*
741 * Validate.
742 */
743 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
744 *ppvPages = NULL;
745 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
746
747#ifdef RT_OS_WINDOWS
748 /*
749 * Temporary hack for windows until we've sorted out the
750 * locked memory that doesn't need to be accessible from kernel space.
751 */
752 return SUPPageAllocLockedEx(cPages, ppvPages, NULL);
753#else
754 /*
755 * Call OS specific worker.
756 */
757 return suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
758#endif
759}
760
761
762SUPR3DECL(int) SUPPageFree(void *pvPages, size_t cPages)
763{
764 /*
765 * Validate.
766 */
767 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
768 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
769
770#ifdef RT_OS_WINDOWS
771 /*
772 * Temporary hack for windows, see above.
773 */
774 return SUPPageFreeLocked(pvPages, cPages);
775#else
776 /*
777 * Call OS specific worker.
778 */
779 return suplibOsPageFree(&g_supLibData, pvPages, cPages);
780#endif
781}
782
783
784SUPR3DECL(int) SUPPageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
785{
786 /*
787 * Validate.
788 */
789 AssertPtr(pvStart);
790 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
791 AssertPtr(paPages);
792
793 /* fake */
794 if (RT_UNLIKELY(g_u32FakeMode))
795 {
796 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
797 size_t iPage = cPages;
798 while (iPage-- > 0)
799 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
800 return VINF_SUCCESS;
801 }
802
803 /*
804 * Issue IOCtl to the SUPDRV kernel module.
805 */
806 int rc;
807 PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
808 if (RT_LIKELY(pReq))
809 {
810 pReq->Hdr.u32Cookie = g_u32Cookie;
811 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
812 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
813 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
814 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
815 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
816 pReq->u.In.pvR3 = pvStart;
817 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
818 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
819 if (RT_SUCCESS(rc))
820 rc = pReq->Hdr.rc;
821 if (RT_SUCCESS(rc))
822 {
823 for (uint32_t iPage = 0; iPage < cPages; iPage++)
824 {
825 paPages[iPage].uReserved = 0;
826 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
827 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
828 }
829 }
830 RTMemTmpFree(pReq);
831 }
832 else
833 rc = VERR_NO_TMP_MEMORY;
834
835 return rc;
836}
837
838
839SUPR3DECL(int) SUPPageUnlock(void *pvStart)
840{
841 /*
842 * Validate.
843 */
844 AssertPtr(pvStart);
845 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
846
847 /* fake */
848 if (RT_UNLIKELY(g_u32FakeMode))
849 return VINF_SUCCESS;
850
851 /*
852 * Issue IOCtl to the SUPDRV kernel module.
853 */
854 SUPPAGEUNLOCK Req;
855 Req.Hdr.u32Cookie = g_u32Cookie;
856 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
857 Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
858 Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
859 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
860 Req.Hdr.rc = VERR_INTERNAL_ERROR;
861 Req.u.In.pvR3 = pvStart;
862 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
863 if (RT_SUCCESS(rc))
864 rc = Req.Hdr.rc;
865 return rc;
866}
867
868
869SUPR3DECL(int) SUPPageAllocLocked(size_t cPages, void **ppvPages)
870{
871 return SUPPageAllocLockedEx(cPages, ppvPages, NULL);
872}
873
874
875/**
876 * Fallback for SUPPageAllocLockedEx on systems where RTR0MemObjPhysAllocNC isn't supported.
877 */
878static int supPageAllocLockedFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
879{
880 int rc = suplibOsPageAlloc(&g_supLibData, cPages, ppvPages);
881 if (RT_SUCCESS(rc))
882 {
883 if (!paPages)
884 paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
885 rc = SUPPageLock(*ppvPages, cPages, paPages);
886 if (RT_FAILURE(rc))
887 suplibOsPageFree(&g_supLibData, *ppvPages, cPages);
888 }
889 return rc;
890}
891
892
893SUPR3DECL(int) SUPPageAllocLockedEx(size_t cPages, void **ppvPages, PSUPPAGE paPages)
894{
895 /*
896 * Validate.
897 */
898 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
899 *ppvPages = NULL;
900 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
901
902 /* fake */
903 if (RT_UNLIKELY(g_u32FakeMode))
904 {
905 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
906 if (!*ppvPages)
907 return VERR_NO_MEMORY;
908 if (paPages)
909 for (size_t iPage = 0; iPage < cPages; iPage++)
910 {
911 paPages[iPage].uReserved = 0;
912 paPages[iPage].Phys = (iPage + 1234) << PAGE_SHIFT;
913 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
914 }
915 return VINF_SUCCESS;
916 }
917
918 /* use fallback? */
919 if (!g_fSupportsPageAllocLocked)
920 return supPageAllocLockedFallback(cPages, ppvPages, paPages);
921
922 /*
923 * Issue IOCtl to the SUPDRV kernel module.
924 */
925 int rc;
926 PSUPPAGEALLOC pReq = (PSUPPAGEALLOC)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_SIZE(cPages));
927 if (pReq)
928 {
929 pReq->Hdr.u32Cookie = g_u32Cookie;
930 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
931 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_SIZE_IN;
932 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_SIZE_OUT(cPages);
933 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
934 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
935 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
936 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_ALLOC, pReq, SUP_IOCTL_PAGE_ALLOC_SIZE(cPages));
937 if (RT_SUCCESS(rc))
938 {
939 rc = pReq->Hdr.rc;
940 if (RT_SUCCESS(rc))
941 {
942 *ppvPages = pReq->u.Out.pvR3;
943 if (paPages)
944 for (size_t iPage = 0; iPage < cPages; iPage++)
945 {
946 paPages[iPage].uReserved = 0;
947 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
948 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
949 }
950 }
951 else if (rc == VERR_NOT_SUPPORTED)
952 {
953 g_fSupportsPageAllocLocked = false;
954 rc = supPageAllocLockedFallback(cPages, ppvPages, paPages);
955 }
956 }
957
958 RTMemTmpFree(pReq);
959 }
960 else
961 rc = VERR_NO_TMP_MEMORY;
962 return rc;
963}
964
965
966SUPR3DECL(int) SUPPageFreeLocked(void *pvPages, size_t cPages)
967{
968 /*
969 * Validate.
970 */
971 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
972 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
973
974 /* fake */
975 if (RT_UNLIKELY(g_u32FakeMode))
976 {
977 RTMemPageFree(pvPages);
978 return VINF_SUCCESS;
979 }
980
981 /*
982 * Issue IOCtl to the SUPDRV kernel module.
983 */
984 int rc;
985 if (g_fSupportsPageAllocLocked)
986 {
987 SUPPAGEFREE Req;
988 Req.Hdr.u32Cookie = g_u32Cookie;
989 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
990 Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
991 Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
992 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
993 Req.Hdr.rc = VERR_INTERNAL_ERROR;
994 Req.u.In.pvR3 = pvPages;
995 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
996 if (RT_SUCCESS(rc))
997 rc = Req.Hdr.rc;
998 }
999 else
1000 {
1001 /* fallback */
1002 rc = SUPPageUnlock(pvPages);
1003 if (RT_SUCCESS(rc))
1004 rc = suplibOsPageFree(&g_supLibData, pvPages, cPages);
1005 }
1006 return rc;
1007}
1008
1009
1010SUPR3DECL(void *) SUPContAlloc(size_t cPages, PRTHCPHYS pHCPhys)
1011{
1012 return SUPContAlloc2(cPages, NIL_RTR0PTR, pHCPhys);
1013}
1014
1015
1016SUPR3DECL(void *) SUPContAlloc2(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
1017{
1018 /*
1019 * Validate.
1020 */
1021 AssertPtrReturn(pHCPhys, NULL);
1022 *pHCPhys = NIL_RTHCPHYS;
1023 AssertPtrNullReturn(pR0Ptr, NULL);
1024 if (pR0Ptr)
1025 *pR0Ptr = NIL_RTR0PTR;
1026 AssertPtrNullReturn(pHCPhys, NULL);
1027 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
1028
1029 /* fake */
1030 if (RT_UNLIKELY(g_u32FakeMode))
1031 {
1032 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
1033 if (pR0Ptr)
1034 *pR0Ptr = (RTR0PTR)pv;
1035 if (pHCPhys)
1036 *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
1037 return pv;
1038 }
1039
1040 /*
1041 * Issue IOCtl to the SUPDRV kernel module.
1042 */
1043 SUPCONTALLOC Req;
1044 Req.Hdr.u32Cookie = g_u32Cookie;
1045 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1046 Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
1047 Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
1048 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1049 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1050 Req.u.In.cPages = (uint32_t)cPages;
1051 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
1052 if ( RT_SUCCESS(rc)
1053 && RT_SUCCESS(Req.Hdr.rc))
1054 {
1055 *pHCPhys = Req.u.Out.HCPhys;
1056 if (pR0Ptr)
1057 *pR0Ptr = Req.u.Out.pvR0;
1058 return Req.u.Out.pvR3;
1059 }
1060
1061 return NULL;
1062}
1063
1064
1065SUPR3DECL(int) SUPContFree(void *pv, size_t cPages)
1066{
1067 /*
1068 * Validate.
1069 */
1070 if (!pv)
1071 return VINF_SUCCESS;
1072 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1073 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
1074
1075 /* fake */
1076 if (RT_UNLIKELY(g_u32FakeMode))
1077 {
1078 RTMemPageFree(pv);
1079 return VINF_SUCCESS;
1080 }
1081
1082 /*
1083 * Issue IOCtl to the SUPDRV kernel module.
1084 */
1085 SUPCONTFREE Req;
1086 Req.Hdr.u32Cookie = g_u32Cookie;
1087 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1088 Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
1089 Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
1090 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1091 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1092 Req.u.In.pvR3 = pv;
1093 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
1094 if (RT_SUCCESS(rc))
1095 rc = Req.Hdr.rc;
1096 return rc;
1097}
1098
1099
1100SUPR3DECL(int) SUPLowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
1101{
1102 /*
1103 * Validate.
1104 */
1105 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
1106 *ppvPages = NULL;
1107 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
1108 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_INVALID_PARAMETER);
1109
1110 /* fake */
1111 if (RT_UNLIKELY(g_u32FakeMode))
1112 {
1113 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
1114 if (!*ppvPages)
1115 return VERR_NO_LOW_MEMORY;
1116
1117 /* fake physical addresses. */
1118 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
1119 size_t iPage = cPages;
1120 while (iPage-- > 0)
1121 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
1122 return VINF_SUCCESS;
1123 }
1124
1125 /*
1126 * Issue IOCtl to the SUPDRV kernel module.
1127 */
1128 int rc;
1129 PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1130 if (pReq)
1131 {
1132 pReq->Hdr.u32Cookie = g_u32Cookie;
1133 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1134 pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
1135 pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
1136 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1137 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1138 pReq->u.In.cPages = (uint32_t)cPages; AssertRelease(pReq->u.In.cPages == cPages);
1139 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1140 if (RT_SUCCESS(rc))
1141 rc = pReq->Hdr.rc;
1142 if (RT_SUCCESS(rc))
1143 {
1144 *ppvPages = pReq->u.Out.pvR3;
1145 if (ppvPagesR0)
1146 *ppvPagesR0 = pReq->u.Out.pvR0;
1147 if (paPages)
1148 for (size_t iPage = 0; iPage < cPages; iPage++)
1149 {
1150 paPages[iPage].uReserved = 0;
1151 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1152 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1153 Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
1154 }
1155 }
1156 RTMemTmpFree(pReq);
1157 }
1158 else
1159 rc = VERR_NO_TMP_MEMORY;
1160
1161 return rc;
1162}
1163
1164
1165SUPR3DECL(int) SUPLowFree(void *pv, size_t cPages)
1166{
1167 /*
1168 * Validate.
1169 */
1170 if (!pv)
1171 return VINF_SUCCESS;
1172 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1173 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
1174
1175 /* fake */
1176 if (RT_UNLIKELY(g_u32FakeMode))
1177 {
1178 RTMemPageFree(pv);
1179 return VINF_SUCCESS;
1180 }
1181
1182 /*
1183 * Issue IOCtl to the SUPDRV kernel module.
1184 */
1185 SUPCONTFREE Req;
1186 Req.Hdr.u32Cookie = g_u32Cookie;
1187 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1188 Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
1189 Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
1190 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1191 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1192 Req.u.In.pvR3 = pv;
1193 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
1194 if (RT_SUCCESS(rc))
1195 rc = Req.Hdr.rc;
1196 return rc;
1197}
1198
1199
1200SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszMsg, PRTFILE phFile)
1201{
1202 /*
1203 * Quick input validation.
1204 */
1205 AssertPtr(pszFilename);
1206 AssertPtr(pszMsg);
1207 AssertReturn(!phFile, VERR_NOT_IMPLEMENTED); /** @todo Implement this. The deal is that we make sure the
1208 file is the same we verified after opening it. */
1209
1210 /*
1211 * Only do the actual check in hardened builds.
1212 */
1213#ifdef VBOX_WITH_HARDENING
1214 int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1215 if (RT_FAILURE(rc))
1216 LogRel(("SUPR3HardenedVerifyFile: %s: Verification of \"%s\" failed, rc=%Rrc\n", pszMsg, pszFilename, rc));
1217 return rc;
1218#else
1219 return VINF_SUCCESS;
1220#endif
1221}
1222
1223
1224SUPR3DECL(int) SUPLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
1225{
1226 int rc = VINF_SUCCESS;
1227#ifdef VBOX_WITH_HARDENING
1228 /*
1229 * Check that the module can be trusted.
1230 */
1231 rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1232#endif
1233 if (RT_SUCCESS(rc))
1234 {
1235 /*
1236 * Load the module.
1237 * If it's VMMR0.r0 we need to install the IDTE.
1238 */
1239 rc = supLoadModule(pszFilename, pszModule, NULL, ppvImageBase);
1240#ifdef VBOX_WITH_IDT_PATCHING
1241 if ( RT_SUCCESS(rc)
1242 && !strcmp(pszModule, "VMMR0.r0"))
1243 {
1244 rc = supInstallIDTE();
1245 if (RT_FAILURE(rc))
1246 SUPFreeModule(*ppvImageBase);
1247 }
1248#endif /* VBOX_WITH_IDT_PATCHING */
1249 }
1250 else
1251 LogRel(("SUPLoadModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
1252 return rc;
1253}
1254
1255
1256SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule,
1257 const char *pszSrvReqHandler, void **ppvImageBase)
1258{
1259 int rc = VINF_SUCCESS;
1260 AssertPtrReturn(pszSrvReqHandler, VERR_INVALID_PARAMETER);
1261
1262#ifdef VBOX_WITH_HARDENING
1263 /*
1264 * Check that the module can be trusted.
1265 */
1266 rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
1267#endif
1268 if (RT_SUCCESS(rc))
1269 {
1270 /*
1271 * Load the module.
1272 * If it's VMMR0.r0 we need to install the IDTE.
1273 */
1274 rc = supLoadModule(pszFilename, pszModule, pszSrvReqHandler, ppvImageBase);
1275 }
1276 else
1277 LogRel(("SUPR3LoadServiceModule: Verification of \"%s\" failed, rc=%Rrc\n", rc));
1278 return rc;
1279}
1280
1281
1282#ifdef VBOX_WITH_IDT_PATCHING
1283/**
1284 * Generates the code for calling the interrupt gate.
1285 *
1286 * @returns VBox status code.
1287 * g_pfnCallVMMR0 is changed on success.
1288 * @param u8Interrupt The interrupt number.
1289 */
1290static int suplibGenerateCallVMMR0(uint8_t u8Interrupt)
1291{
1292 /*
1293 * Allocate memory.
1294 */
1295 uint8_t *pb = (uint8_t *)RTMemExecAlloc(256);
1296 AssertReturn(pb, VERR_NO_MEMORY);
1297 memset(pb, 0xcc, 256);
1298 Assert(!g_pfnCallVMMR0);
1299 g_pfnCallVMMR0 = *(PFNCALLVMMR0*)&pb;
1300
1301 /*
1302 * Generate the code.
1303 */
1304#ifdef RT_ARCH_AMD64
1305 /*
1306 * reg params:
1307 * <GCC> <MSC> <argument>
1308 * rdi rcx pVMR0
1309 * esi edx uOperation
1310 * rdx r8 pvArg
1311 *
1312 * eax eax [g_u32Gookie]
1313 */
1314 *pb++ = 0xb8; /* mov eax, <g_u32Cookie> */
1315 *(uint32_t *)pb = g_u32Cookie;
1316 pb += sizeof(uint32_t);
1317
1318 *pb++ = 0xcd; /* int <u8Interrupt> */
1319 *pb++ = u8Interrupt;
1320
1321 *pb++ = 0xc3; /* ret */
1322
1323#else
1324 /*
1325 * x86 stack:
1326 * 0 saved esi
1327 * 0 4 ret
1328 * 4 8 pVM
1329 * 8 c uOperation
1330 * c 10 pvArg
1331 */
1332 *pb++ = 0x56; /* push esi */
1333
1334 *pb++ = 0x8b; /* mov eax, [pVM] */
1335 *pb++ = 0x44;
1336 *pb++ = 0x24;
1337 *pb++ = 0x08; /* esp+08h */
1338
1339 *pb++ = 0x8b; /* mov edx, [uOperation] */
1340 *pb++ = 0x54;
1341 *pb++ = 0x24;
1342 *pb++ = 0x0c; /* esp+0ch */
1343
1344 *pb++ = 0x8b; /* mov ecx, [pvArg] */
1345 *pb++ = 0x4c;
1346 *pb++ = 0x24;
1347 *pb++ = 0x10; /* esp+10h */
1348
1349 *pb++ = 0xbe; /* mov esi, <g_u32Cookie> */
1350 *(uint32_t *)pb = g_u32Cookie;
1351 pb += sizeof(uint32_t);
1352
1353 *pb++ = 0xcd; /* int <u8Interrupt> */
1354 *pb++ = u8Interrupt;
1355
1356 *pb++ = 0x5e; /* pop esi */
1357
1358 *pb++ = 0xc3; /* ret */
1359#endif
1360
1361 return VINF_SUCCESS;
1362}
1363
1364
1365/**
1366 * Installs the IDTE patch.
1367 *
1368 * @return VBox status code.
1369 */
1370static int supInstallIDTE(void)
1371{
1372 /* already installed? */
1373 if (g_u8Interrupt != 3 || g_u32FakeMode)
1374 return VINF_SUCCESS;
1375
1376 int rc = VINF_SUCCESS;
1377 const RTCPUID cCpus = RTMpGetCount();
1378 if (cCpus <= 1)
1379 {
1380 /* UNI */
1381 SUPIDTINSTALL Req;
1382 Req.Hdr.u32Cookie = g_u32Cookie;
1383 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1384 Req.Hdr.cbIn = SUP_IOCTL_IDT_INSTALL_SIZE_IN;
1385 Req.Hdr.cbOut = SUP_IOCTL_IDT_INSTALL_SIZE_OUT;
1386 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1387 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1388 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_IDT_INSTALL, &Req, SUP_IOCTL_IDT_INSTALL_SIZE);
1389 if (RT_SUCCESS(rc))
1390 rc = Req.Hdr.rc;
1391 if (RT_SUCCESS(rc))
1392 {
1393 g_u8Interrupt = Req.u.Out.u8Idt;
1394 rc = suplibGenerateCallVMMR0(Req.u.Out.u8Idt);
1395 }
1396 }
1397 else
1398 {
1399 /* SMP */
1400 uint64_t u64AffMaskSaved = RTThreadGetAffinity();
1401 RTCPUSET OnlineSet;
1402 uint64_t u64AffMaskPatched = RTCpuSetToU64(RTMpGetOnlineSet(&OnlineSet)) & u64AffMaskSaved;
1403 unsigned cCpusPatched = 0;
1404 AssertLogRelReturn(cCpus < 64, VERR_INTERNAL_ERROR);
1405
1406 for (int i = 0; i < 64; i++)
1407 {
1408 /* Skip absent and inactive processors. */
1409 uint64_t u64Mask = 1ULL << i;
1410 if (!(u64Mask & u64AffMaskPatched))
1411 continue;
1412
1413 /* Change CPU */
1414 int rc2 = RTThreadSetAffinity(u64Mask);
1415 if (RT_FAILURE(rc2))
1416 {
1417 u64AffMaskPatched &= ~u64Mask;
1418 LogRel(("SUPLoadVMM: Failed to set affinity to cpu no. %d, rc=%Rrc.\n", i, rc2));
1419 continue;
1420 }
1421
1422 /* Patch the CPU. */
1423 SUPIDTINSTALL Req;
1424 Req.Hdr.u32Cookie = g_u32Cookie;
1425 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1426 Req.Hdr.cbIn = SUP_IOCTL_IDT_INSTALL_SIZE_IN;
1427 Req.Hdr.cbOut = SUP_IOCTL_IDT_INSTALL_SIZE_OUT;
1428 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1429 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1430 rc2 = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_IDT_INSTALL, &Req, SUP_IOCTL_IDT_INSTALL_SIZE);
1431 if (RT_SUCCESS(rc2))
1432 rc2 = Req.Hdr.rc;
1433 if (RT_SUCCESS(rc2))
1434 {
1435 if (!cCpusPatched)
1436 {
1437 g_u8Interrupt = Req.u.Out.u8Idt;
1438 rc2 = suplibGenerateCallVMMR0(Req.u.Out.u8Idt);
1439 if (RT_FAILURE(rc2))
1440 {
1441 LogRel(("suplibGenerateCallVMMR0 failed with rc=%Rrc.\n", i, rc2));
1442 rc = rc2;
1443 }
1444 }
1445 else
1446 Assert(g_u8Interrupt == Req.u.Out.u8Idt);
1447 cCpusPatched++;
1448 }
1449 else
1450 {
1451
1452 LogRel(("SUPLoadVMM: Failed to patch cpu no. %d, rc=%Rrc.\n", i, rc2));
1453 if (RT_SUCCESS(rc))
1454 rc = rc2;
1455 }
1456 }
1457
1458 /* Fail if no CPUs was patched! */
1459 if (RT_SUCCESS(rc) && cCpusPatched <= 0)
1460 rc = VERR_GENERAL_FAILURE;
1461 /* Ignore failures if a CPU was patched. */
1462 else if (RT_FAILURE(rc) && cCpusPatched > 0)
1463 rc = VINF_SUCCESS;
1464
1465 /* Set/restore the thread affinity. */
1466 if (RT_SUCCESS(rc))
1467 {
1468 rc = RTThreadSetAffinity(u64AffMaskPatched);
1469 AssertRC(rc);
1470 }
1471 else
1472 {
1473 int rc2 = RTThreadSetAffinity(u64AffMaskSaved);
1474 AssertRC(rc2);
1475 }
1476 }
1477 return rc;
1478}
1479#endif /* VBOX_WITH_IDT_PATCHING */
1480
1481
1482/**
1483 * Resolve an external symbol during RTLdrGetBits().
1484 *
1485 * @returns VBox status code.
1486 * @param hLdrMod The loader module handle.
1487 * @param pszModule Module name.
1488 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
1489 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
1490 * @param pValue Where to store the symbol value (address).
1491 * @param pvUser User argument.
1492 */
1493static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
1494 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
1495{
1496 AssertPtr(pValue);
1497 AssertPtr(pvUser);
1498
1499 /*
1500 * Only SUPR0 and VMMR0.r0
1501 */
1502 if ( pszModule
1503 && *pszModule
1504 && strcmp(pszModule, "SUPR0.dll")
1505 && strcmp(pszModule, "VMMR0.r0"))
1506 {
1507 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
1508 return VERR_SYMBOL_NOT_FOUND;
1509 }
1510
1511 /*
1512 * No ordinals.
1513 */
1514 if (pszSymbol < (const char*)0x10000)
1515 {
1516 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pvUser, (int)(uintptr_t)pszSymbol));
1517 return VERR_SYMBOL_NOT_FOUND;
1518 }
1519
1520 /*
1521 * Lookup symbol.
1522 */
1523 /* skip the 64-bit ELF import prefix first. */
1524 if (!strncmp(pszSymbol, "SUPR0$", sizeof("SUPR0$") - 1))
1525 pszSymbol += sizeof("SUPR0$") - 1;
1526
1527 /*
1528 * Check the VMMR0.r0 module if loaded.
1529 */
1530 /** @todo call the SUPLoadModule caller.... */
1531 /** @todo proper reference counting and such. */
1532 if (g_pvVMMR0 != NIL_RTR0PTR)
1533 {
1534 void *pvValue;
1535 if (!SUPGetSymbolR0((void *)g_pvVMMR0, pszSymbol, &pvValue))
1536 {
1537 *pValue = (uintptr_t)pvValue;
1538 return VINF_SUCCESS;
1539 }
1540 }
1541
1542 /* iterate the function table. */
1543 int c = g_pFunctions->u.Out.cFunctions;
1544 PSUPFUNC pFunc = &g_pFunctions->u.Out.aFunctions[0];
1545 while (c-- > 0)
1546 {
1547 if (!strcmp(pFunc->szName, pszSymbol))
1548 {
1549 *pValue = (uintptr_t)pFunc->pfn;
1550 return VINF_SUCCESS;
1551 }
1552 pFunc++;
1553 }
1554
1555 /*
1556 * The GIP.
1557 */
1558 /** @todo R0 mapping? */
1559 if ( pszSymbol
1560 && g_pSUPGlobalInfoPage
1561 && g_pSUPGlobalInfoPageR0
1562 && !strcmp(pszSymbol, "g_SUPGlobalInfoPage"))
1563 {
1564 *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
1565 return VINF_SUCCESS;
1566 }
1567
1568 /*
1569 * Despair.
1570 */
1571 c = g_pFunctions->u.Out.cFunctions;
1572 pFunc = &g_pFunctions->u.Out.aFunctions[0];
1573 while (c-- > 0)
1574 {
1575 AssertMsg2("%d: %s\n", g_pFunctions->u.Out.cFunctions - c, pFunc->szName);
1576 pFunc++;
1577 }
1578
1579 AssertMsg2("%s is importing %s which we couldn't find\n", pvUser, pszSymbol);
1580 AssertMsgFailed(("%s is importing %s which we couldn't find\n", pvUser, pszSymbol));
1581 if (g_u32FakeMode)
1582 {
1583 *pValue = 0xdeadbeef;
1584 return VINF_SUCCESS;
1585 }
1586 return VERR_SYMBOL_NOT_FOUND;
1587}
1588
1589
1590/** Argument package for supLoadModuleCalcSizeCB. */
1591typedef struct SUPLDRCALCSIZEARGS
1592{
1593 size_t cbStrings;
1594 uint32_t cSymbols;
1595 size_t cbImage;
1596} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
1597
1598/**
1599 * Callback used to calculate the image size.
1600 * @return VINF_SUCCESS
1601 */
1602static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1603{
1604 PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
1605 if ( pszSymbol != NULL
1606 && *pszSymbol
1607 && Value <= pArgs->cbImage)
1608 {
1609 pArgs->cSymbols++;
1610 pArgs->cbStrings += strlen(pszSymbol) + 1;
1611 }
1612 return VINF_SUCCESS;
1613}
1614
1615
1616/** Argument package for supLoadModuleCreateTabsCB. */
1617typedef struct SUPLDRCREATETABSARGS
1618{
1619 size_t cbImage;
1620 PSUPLDRSYM pSym;
1621 char *pszBase;
1622 char *psz;
1623} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
1624
1625/**
1626 * Callback used to calculate the image size.
1627 * @return VINF_SUCCESS
1628 */
1629static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1630{
1631 PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
1632 if ( pszSymbol != NULL
1633 && *pszSymbol
1634 && Value <= pArgs->cbImage)
1635 {
1636 pArgs->pSym->offSymbol = (uint32_t)Value;
1637 pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
1638 pArgs->pSym++;
1639
1640 size_t cbCopy = strlen(pszSymbol) + 1;
1641 memcpy(pArgs->psz, pszSymbol, cbCopy);
1642 pArgs->psz += cbCopy;
1643 }
1644 return VINF_SUCCESS;
1645}
1646
1647
1648/**
1649 * Worker for SUPLoadModule().
1650 *
1651 * @returns VBox status code.
1652 * @param pszFilename Name of the VMMR0 image file
1653 */
1654static int supLoadModule(const char *pszFilename, const char *pszModule, const char *pszSrvReqHandler, void **ppvImageBase)
1655{
1656 /*
1657 * Validate input.
1658 */
1659 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1660 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
1661 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
1662 AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
1663
1664 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
1665 AssertReturn(!pszSrvReqHandler || !fIsVMMR0, VERR_INTERNAL_ERROR);
1666 *ppvImageBase = NULL;
1667
1668 /*
1669 * Open image file and figure its size.
1670 */
1671 RTLDRMOD hLdrMod;
1672 int rc = RTLdrOpen(pszFilename, &hLdrMod);
1673 if (!RT_SUCCESS(rc))
1674 return rc;
1675
1676 SUPLDRCALCSIZEARGS CalcArgs;
1677 CalcArgs.cbStrings = 0;
1678 CalcArgs.cSymbols = 0;
1679 CalcArgs.cbImage = RTLdrSize(hLdrMod);
1680 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
1681 if (RT_SUCCESS(rc))
1682 {
1683 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
1684 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
1685 const uint32_t cbImage = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
1686
1687 /*
1688 * Open the R0 image.
1689 */
1690 SUPLDROPEN OpenReq;
1691 OpenReq.Hdr.u32Cookie = g_u32Cookie;
1692 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
1693 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
1694 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
1695 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1696 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
1697 OpenReq.u.In.cbImage = cbImage;
1698 strcpy(OpenReq.u.In.szName, pszModule);
1699 if (!g_u32FakeMode)
1700 {
1701 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
1702 if (RT_SUCCESS(rc))
1703 rc = OpenReq.Hdr.rc;
1704 }
1705 else
1706 {
1707 OpenReq.u.Out.fNeedsLoading = true;
1708 OpenReq.u.Out.pvImageBase = 0xef423420;
1709 }
1710 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
1711 if ( RT_SUCCESS(rc)
1712 && OpenReq.u.Out.fNeedsLoading)
1713 {
1714 /*
1715 * We need to load it.
1716 * Allocate memory for the image bits.
1717 */
1718 PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(SUP_IOCTL_LDR_LOAD_SIZE(cbImage));
1719 if (pLoadReq)
1720 {
1721 /*
1722 * Get the image bits.
1723 */
1724 rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
1725 supLoadModuleResolveImport, (void *)pszModule);
1726
1727 if (RT_SUCCESS(rc))
1728 {
1729 /*
1730 * Get the entry points.
1731 */
1732 RTUINTPTR VMMR0EntryInt = 0;
1733 RTUINTPTR VMMR0EntryFast = 0;
1734 RTUINTPTR VMMR0EntryEx = 0;
1735 RTUINTPTR SrvReqHandler = 0;
1736 RTUINTPTR ModuleInit = 0;
1737 RTUINTPTR ModuleTerm = 0;
1738 if (fIsVMMR0)
1739 {
1740 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
1741 if (RT_SUCCESS(rc))
1742 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
1743 if (RT_SUCCESS(rc))
1744 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
1745 }
1746 else if (pszSrvReqHandler)
1747 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, pszSrvReqHandler, &SrvReqHandler);
1748 if (RT_SUCCESS(rc))
1749 {
1750 int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
1751 if (RT_FAILURE(rc2))
1752 ModuleInit = 0;
1753
1754 rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
1755 if (RT_FAILURE(rc2))
1756 ModuleTerm = 0;
1757 }
1758 if (RT_SUCCESS(rc))
1759 {
1760 /*
1761 * Create the symbol and string tables.
1762 */
1763 SUPLDRCREATETABSARGS CreateArgs;
1764 CreateArgs.cbImage = CalcArgs.cbImage;
1765 CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab];
1766 CreateArgs.pszBase = (char *)&pLoadReq->u.In.achImage[offStrTab];
1767 CreateArgs.psz = CreateArgs.pszBase;
1768 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
1769 if (RT_SUCCESS(rc))
1770 {
1771 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
1772 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab]) <= CalcArgs.cSymbols);
1773
1774 /*
1775 * Upload the image.
1776 */
1777 pLoadReq->Hdr.u32Cookie = g_u32Cookie;
1778 pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1779 pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImage);
1780 pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
1781 pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
1782 pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
1783
1784 pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
1785 pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
1786 if (fIsVMMR0)
1787 {
1788 pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
1789 pLoadReq->u.In.EP.VMMR0.pvVMMR0 = OpenReq.u.Out.pvImageBase;
1790 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)VMMR0EntryInt;
1791 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
1792 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
1793 }
1794 else if (pszSrvReqHandler)
1795 {
1796 pLoadReq->u.In.eEPType = SUPLDRLOADEP_SERVICE;
1797 pLoadReq->u.In.EP.Service.pfnServiceReq = (RTR0PTR)SrvReqHandler;
1798 pLoadReq->u.In.EP.Service.apvReserved[0] = NIL_RTR0PTR;
1799 pLoadReq->u.In.EP.Service.apvReserved[1] = NIL_RTR0PTR;
1800 pLoadReq->u.In.EP.Service.apvReserved[2] = NIL_RTR0PTR;
1801 }
1802 else
1803 pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
1804 pLoadReq->u.In.offStrTab = offStrTab;
1805 pLoadReq->u.In.cbStrTab = (uint32_t)CalcArgs.cbStrings;
1806 AssertRelease(pLoadReq->u.In.cbStrTab == CalcArgs.cbStrings);
1807 pLoadReq->u.In.offSymbols = offSymTab;
1808 pLoadReq->u.In.cSymbols = CalcArgs.cSymbols;
1809 pLoadReq->u.In.cbImage = cbImage;
1810 pLoadReq->u.In.pvImageBase = OpenReq.u.Out.pvImageBase;
1811 if (!g_u32FakeMode)
1812 {
1813 rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImage));
1814 if (RT_SUCCESS(rc))
1815 rc = pLoadReq->Hdr.rc;
1816 }
1817 else
1818 rc = VINF_SUCCESS;
1819 if ( RT_SUCCESS(rc)
1820 || rc == VERR_ALREADY_LOADED /* A competing process. */
1821 )
1822 {
1823 LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr\n", pszModule, pszFilename,
1824 OpenReq.u.Out.pvImageBase, ModuleInit, ModuleTerm));
1825 if (fIsVMMR0)
1826 {
1827 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1828 LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
1829 VMMR0EntryEx, VMMR0EntryFast, VMMR0EntryInt));
1830 }
1831#ifdef RT_OS_WINDOWS
1832 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1833#endif
1834
1835 RTMemTmpFree(pLoadReq);
1836 RTLdrClose(hLdrMod);
1837 return VINF_SUCCESS;
1838 }
1839 }
1840 }
1841 }
1842 RTMemTmpFree(pLoadReq);
1843 }
1844 else
1845 {
1846 AssertMsgFailed(("failed to allocated %d bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImage)));
1847 rc = VERR_NO_TMP_MEMORY;
1848 }
1849 }
1850 else if (RT_SUCCESS(rc))
1851 {
1852 if (fIsVMMR0)
1853 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1854 LogRel(("SUP: Opened %s (%s) at %#p.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase));
1855#ifdef RT_OS_WINDOWS
1856 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1857#endif
1858 }
1859 }
1860 RTLdrClose(hLdrMod);
1861 return rc;
1862}
1863
1864
1865SUPR3DECL(int) SUPFreeModule(void *pvImageBase)
1866{
1867 /* fake */
1868 if (RT_UNLIKELY(g_u32FakeMode))
1869 {
1870#ifdef VBOX_WITH_IDT_PATCHING
1871 g_u8Interrupt = 3;
1872 RTMemExecFree(*(void **)&g_pfnCallVMMR0);
1873 g_pfnCallVMMR0 = NULL;
1874#endif
1875 g_pvVMMR0 = NIL_RTR0PTR;
1876 return VINF_SUCCESS;
1877 }
1878
1879#ifdef VBOX_WITH_IDT_PATCHING
1880 /*
1881 * There is one special module. When this is freed we'll
1882 * free the IDT entry that goes with it.
1883 *
1884 * Note that we don't keep count of VMMR0.r0 loads here, so the
1885 * first unload will free it.
1886 */
1887 if ( (RTR0PTR)pvImageBase == g_pvVMMR0
1888 && g_u8Interrupt != 3)
1889 {
1890 SUPIDTREMOVE Req;
1891 Req.Hdr.u32Cookie = g_u32Cookie;
1892 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1893 Req.Hdr.cbIn = SUP_IOCTL_IDT_REMOVE_SIZE_IN;
1894 Req.Hdr.cbOut = SUP_IOCTL_IDT_REMOVE_SIZE_OUT;
1895 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1896 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1897 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_IDT_REMOVE, &Req, SUP_IOCTL_IDT_REMOVE_SIZE);
1898 if (RT_SUCCESS(rc))
1899 rc = Req.Hdr.rc;
1900 AssertRC(rc);
1901 g_u8Interrupt = 3;
1902 RTMemExecFree(*(void **)&g_pfnCallVMMR0);
1903 g_pfnCallVMMR0 = NULL;
1904 }
1905#endif /* VBOX_WITH_IDT_PATCHING */
1906
1907 /*
1908 * Free the requested module.
1909 */
1910 SUPLDRFREE Req;
1911 Req.Hdr.u32Cookie = g_u32Cookie;
1912 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1913 Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
1914 Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
1915 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1916 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1917 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1918 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
1919 if (RT_SUCCESS(rc))
1920 rc = Req.Hdr.rc;
1921 if ( RT_SUCCESS(rc)
1922 && (RTR0PTR)pvImageBase == g_pvVMMR0)
1923 g_pvVMMR0 = NIL_RTR0PTR;
1924 return rc;
1925}
1926
1927
1928SUPR3DECL(int) SUPGetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
1929{
1930 *ppvValue = NULL;
1931
1932 /* fake */
1933 if (RT_UNLIKELY(g_u32FakeMode))
1934 {
1935 *ppvValue = (void *)(uintptr_t)0xdeadf00d;
1936 return VINF_SUCCESS;
1937 }
1938
1939 /*
1940 * Do ioctl.
1941 */
1942 SUPLDRGETSYMBOL Req;
1943 Req.Hdr.u32Cookie = g_u32Cookie;
1944 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1945 Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
1946 Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
1947 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1948 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1949 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1950 size_t cchSymbol = strlen(pszSymbol);
1951 if (cchSymbol >= sizeof(Req.u.In.szSymbol))
1952 return VERR_SYMBOL_NOT_FOUND;
1953 memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
1954 int rc = suplibOsIOCtl(&g_supLibData, SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
1955 if (RT_SUCCESS(rc))
1956 rc = Req.Hdr.rc;
1957 if (RT_SUCCESS(rc))
1958 *ppvValue = (void *)Req.u.Out.pvSymbol;
1959 return rc;
1960}
1961
1962
1963SUPR3DECL(int) SUPLoadVMM(const char *pszFilename)
1964{
1965 void *pvImageBase;
1966 return SUPLoadModule(pszFilename, "VMMR0.r0", &pvImageBase);
1967}
1968
1969
1970SUPR3DECL(int) SUPUnloadVMM(void)
1971{
1972 return SUPFreeModule((void*)g_pvVMMR0);
1973}
1974
1975
1976SUPR3DECL(int) SUPGipGetPhys(PRTHCPHYS pHCPhys)
1977{
1978 if (g_pSUPGlobalInfoPage)
1979 {
1980 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1981 return VINF_SUCCESS;
1982 }
1983 *pHCPhys = NIL_RTHCPHYS;
1984 return VERR_WRONG_ORDER;
1985}
1986
1987
1988/**
1989 * Worker for SUPR3HardenedLdrLoad and SUPR3HardenedLdrLoadAppPriv.
1990 *
1991 * @returns iprt status code.
1992 * @param pszFilename The full file name.
1993 * @param phLdrMod Where to store the handle to the loaded module.
1994 */
1995static int supR3HardenedLdrLoadIt(const char *pszFilename, PRTLDRMOD phLdrMod)
1996{
1997#ifdef VBOX_WITH_HARDENING
1998 /*
1999 * Verify the image file.
2000 */
2001 int rc = supR3HardenedVerifyFile(pszFilename, false /* fFatal */);
2002 if (RT_FAILURE(rc))
2003 {
2004 LogRel(("supR3HardenedLdrLoadIt: Verification of \"%s\" failed, rc=%Rrc\n", rc));
2005 return rc;
2006 }
2007#endif
2008
2009 /*
2010 * Try load it.
2011 */
2012 return RTLdrLoad(pszFilename, phLdrMod);
2013}
2014
2015
2016SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod)
2017{
2018 /*
2019 * Validate input.
2020 */
2021 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
2022 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
2023 *phLdrMod = NIL_RTLDRMOD;
2024 AssertReturn(RTPathHavePath(pszFilename), VERR_INVALID_PARAMETER);
2025
2026 /*
2027 * Add the default extension if it's missing.
2028 */
2029 if (!RTPathHaveExt(pszFilename))
2030 {
2031 const char *pszSuff = RTLdrGetSuff();
2032 size_t cchSuff = strlen(pszSuff);
2033 size_t cchFilename = strlen(pszFilename);
2034 char *psz = (char *)alloca(cchFilename + cchSuff + 1);
2035 AssertReturn(psz, VERR_NO_TMP_MEMORY);
2036 memcpy(psz, pszFilename, cchFilename);
2037 memcpy(psz + cchFilename, pszSuff, cchSuff + 1);
2038 pszFilename = psz;
2039 }
2040
2041 /*
2042 * Pass it on to the common library loader.
2043 */
2044 return supR3HardenedLdrLoadIt(pszFilename, phLdrMod);
2045}
2046
2047
2048SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod)
2049{
2050 LogFlow(("SUPR3HardenedLdrLoadAppPriv: pszFilename=%p:{%s} phLdrMod=%p\n", pszFilename, pszFilename, phLdrMod));
2051
2052 /*
2053 * Validate input.
2054 */
2055 AssertPtrReturn(phLdrMod, VERR_INVALID_PARAMETER);
2056 *phLdrMod = NIL_RTLDRMOD;
2057 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
2058 AssertMsgReturn(!RTPathHavePath(pszFilename), ("%s\n", pszFilename), VERR_INVALID_PARAMETER);
2059
2060 /*
2061 * Check the filename.
2062 */
2063 size_t cchFilename = strlen(pszFilename);
2064 AssertMsgReturn(cchFilename < (RTPATH_MAX / 4) * 3, ("%zu\n", cchFilename), VERR_INVALID_PARAMETER);
2065
2066 const char *pszExt = "";
2067 size_t cchExt = 0;
2068 if (!RTPathHaveExt(pszFilename))
2069 {
2070 pszExt = RTLdrGetSuff();
2071 cchExt = strlen(pszExt);
2072 }
2073
2074 /*
2075 * Construct the private arch path and check if the file exists.
2076 */
2077 char szPath[RTPATH_MAX];
2078 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - 1 - cchExt - cchFilename);
2079 AssertRCReturn(rc, rc);
2080
2081 char *psz = strchr(szPath, '\0');
2082 *psz++ = RTPATH_SLASH;
2083 memcpy(psz, pszFilename, cchFilename);
2084 psz += cchFilename;
2085 memcpy(psz, pszExt, cchExt + 1);
2086
2087 if (!RTPathExists(szPath))
2088 {
2089 LogRel(("SUPR3HardenedLdrLoadAppPriv: \"%s\" not found\n", szPath));
2090 return VERR_FILE_NOT_FOUND;
2091 }
2092
2093 /*
2094 * Pass it on to SUPR3HardenedLdrLoad.
2095 */
2096 rc = SUPR3HardenedLdrLoad(szPath, phLdrMod);
2097
2098 LogFlow(("SUPR3HardenedLdrLoadAppPriv: returns %Rrc\n", rc));
2099 return rc;
2100}
2101
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