VirtualBox

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

Last change on this file since 4920 was 4898, checked in by vboxsync, 17 years ago

Log the address of VMMR0EntryEx into the release log. Makes debugging easier if the VMMR0.r0 module asserts somewhere.

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