VirtualBox

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

Last change on this file since 1249 was 1199, checked in by vboxsync, 18 years ago

make debug builds work in fake mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.0 KB
Line 
1/** @file
2 *
3 * VBox host drivers - Ring-0 support drivers - Shared code:
4 * Support library that implements the basic lowlevel OS interfaces
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/** @page pg_sup SUP - The Support Library
24 *
25 * The support library is responsible for providing facilities to load
26 * VMM Host Ring-0 code, to call Host VMM Ring-0 code from Ring-3 Host
27 * code, and to pin down physical memory.
28 *
29 * The VMM Host Ring-0 code can be combined in the support driver if
30 * permitted by kernel module license policies. If it is not combined
31 * it will be externalized in a Win32 PE binary and will use the PDM
32 * PE loader to load it into memory.
33 *
34 * The Ring-0 calling is done thru a generic SUP interface which will
35 * tranfer an argument set and call a predefined entry point in the Host
36 * VMM Ring-0 code.
37 *
38 * See @ref grp_sup "SUP - Support APIs" for API details.
39 */
40
41
42/*******************************************************************************
43* Header Files *
44*******************************************************************************/
45#define LOG_GROUP LOG_GROUP_SUP
46#include <VBox/sup.h>
47#include <VBox/err.h>
48#include <VBox/param.h>
49#ifdef VBOX_WITHOUT_IDT_PATCHING
50# include <VBox/vmm.h>
51#endif
52#include <VBox/log.h>
53
54#include <iprt/assert.h>
55#include <iprt/alloc.h>
56#include <iprt/alloca.h>
57#include <iprt/ldr.h>
58#include <iprt/asm.h>
59#include <iprt/system.h>
60#include <iprt/thread.h>
61#include <iprt/process.h>
62#include <iprt/string.h>
63#include <iprt/env.h>
64
65#include "SUPLibInternal.h"
66#include "SUPDRVIOC.h"
67
68
69
70/*******************************************************************************
71* Defined Constants And Macros *
72*******************************************************************************/
73/** R0 VMM module name. */
74#define VMMR0_NAME "VMMR0"
75
76
77/*******************************************************************************
78* Structures and Typedefs *
79*******************************************************************************/
80typedef DECLCALLBACK(int) FNCALLVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg);
81typedef FNCALLVMMR0 *PFNCALLVMMR0;
82
83
84/*******************************************************************************
85* Global Variables *
86*******************************************************************************/
87/** Pointer to the Global Information Page.
88 *
89 * This pointer is valid as long as SUPLib has a open session. Anyone using
90 * the page must treat this pointer as higly volatile and not trust it beyond
91 * one transaction.
92 *
93 * @todo This will probably deserve it's own session or some other good solution...
94 */
95DECLEXPORT(PCSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage;
96/** Address of the ring-0 mapping of the GIP. */
97static PCSUPGLOBALINFOPAGE g_pSUPGlobalInfoPageR0;
98/** The physical address of the GIP. */
99static RTHCPHYS g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS;
100
101/** The negotiated cookie. */
102uint32_t g_u32Cookie = 0;
103/** The negotiated session cookie. */
104uint32_t g_u32SessionCookie;
105/** Session handle. */
106PSUPDRVSESSION g_pSession;
107/** R0 SUP Functions used for resolving referenced to the SUPR0 module. */
108static PSUPQUERYFUNCS_OUT g_pFunctions;
109
110#ifndef VBOX_WITHOUT_IDT_PATCHING
111/** The negotiated interrupt number. */
112static uint8_t g_u8Interrupt = 3;
113/** Pointer to the generated code fore calling VMMR0. */
114static PFNCALLVMMR0 g_pfnCallVMMR0;
115#endif
116/** VMMR0 Load Address. */
117static void *g_pvVMMR0 = NULL;
118/** Init counter. */
119static unsigned g_cInits = 0;
120/** Fake mode indicator. (~0 at first, 0 or 1 after first test) */
121static uint32_t g_u32FakeMode = ~0;
122
123
124/*******************************************************************************
125* Internal Functions *
126*******************************************************************************/
127static int supInitFake(PSUPDRVSESSION *ppSession);
128static int supLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase);
129#ifndef VBOX_WITHOUT_IDT_PATCHING
130static int supInstallIDTE(void);
131#endif
132static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser);
133
134
135SUPR3DECL(int) SUPInstall(void)
136{
137 return suplibOsInstall();
138}
139
140
141SUPR3DECL(int) SUPUninstall(void)
142{
143 return suplibOsUninstall();
144}
145
146
147SUPR3DECL(int) SUPInit(PSUPDRVSESSION *ppSession /* NULL */, size_t cbReserve /* 0 */)
148{
149 /*
150 * Check if already initialized.
151 */
152 if (ppSession)
153 *ppSession = g_pSession;
154 if (g_cInits++ > 0)
155 return VINF_SUCCESS;
156
157 /*
158 * Check for fake mode.
159 *
160 * Fake mode is used when we're doing smoke testing and debugging.
161 * It's also useful on platforms where we haven't root access or which
162 * we haven't ported the support driver to.
163 */
164 if (g_u32FakeMode == ~0U)
165 {
166 const char *psz = RTEnvGet("VBOX_SUPLIB_FAKE");
167 if (psz && !strcmp(psz, "fake"))
168 ASMAtomicCmpXchgU32(&g_u32FakeMode, 1, ~0U);
169 else
170 ASMAtomicCmpXchgU32(&g_u32FakeMode, 0, ~0U);
171 }
172 if (RT_UNLIKELY(g_u32FakeMode))
173 return supInitFake(ppSession);
174
175 /**
176 * Open the support driver.
177 */
178 int rc = suplibOsInit(cbReserve);
179 if (VBOX_SUCCESS(rc))
180 {
181 /*
182 * Negotiate the cookie.
183 */
184 SUPCOOKIE_IN In;
185 SUPCOOKIE_OUT Out = {0,0};
186 strcpy(In.szMagic, SUPCOOKIE_MAGIC);
187 In.u32Version = SUPDRVIOC_VERSION;
188 rc = suplibOsIOCtl(SUP_IOCTL_COOKIE, &In, sizeof(In), &Out, sizeof(Out));
189 if (VBOX_SUCCESS(rc))
190 {
191 if (Out.u32Version == SUPDRVIOC_VERSION)
192 {
193 /*
194 * Query the functions.
195 */
196 SUPQUERYFUNCS_IN FuncsIn;
197 FuncsIn.u32Cookie = Out.u32Cookie;
198 FuncsIn.u32SessionCookie = Out.u32SessionCookie;
199 unsigned cbFuncsOut = RT_OFFSETOF(SUPQUERYFUNCS_OUT, aFunctions[Out.cFunctions]);
200 PSUPQUERYFUNCS_OUT pFuncsOut = (PSUPQUERYFUNCS_OUT)RTMemAllocZ(cbFuncsOut);
201 if (pFuncsOut)
202 {
203 rc = suplibOsIOCtl(SUP_IOCTL_QUERY_FUNCS, &FuncsIn, sizeof(FuncsIn), pFuncsOut, cbFuncsOut);
204 if (VBOX_SUCCESS(rc))
205 {
206 g_u32Cookie = Out.u32Cookie;
207 g_u32SessionCookie = Out.u32SessionCookie;
208 g_pSession = Out.pSession;
209 g_pFunctions = pFuncsOut;
210 if (ppSession)
211 *ppSession = Out.pSession;
212
213 /*
214 * Map the GIP into userspace.
215 * This is an optional feature, so we will ignore any failures here.
216 */
217 if (!g_pSUPGlobalInfoPage)
218 {
219 SUPGIPMAP_IN GipIn = {0};
220 SUPGIPMAP_OUT GipOut = {NULL, 0};
221 GipIn.u32Cookie = Out.u32Cookie;
222 GipIn.u32SessionCookie = Out.u32SessionCookie;
223 rc = suplibOsIOCtl(SUP_IOCTL_GIP_MAP, &GipIn, sizeof(GipIn), &GipOut, sizeof(GipOut));
224 if (VBOX_SUCCESS(rc))
225 {
226 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, GipOut.HCPhysGip);
227 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, (void *)GipOut.pGipR3, NULL);
228 ASMAtomicCmpXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, (void *)GipOut.pGipR0, NULL);
229 }
230 else
231 rc = VINF_SUCCESS;
232 }
233 return rc;
234 }
235 RTMemFree(pFuncsOut);
236 }
237 else
238 rc = VERR_NO_MEMORY;
239 }
240 else
241 rc = VERR_VM_DRIVER_VERSION_MISMATCH;
242 }
243
244 suplibOsTerm();
245 }
246 AssertMsgFailed(("SUPInit() failed rc=%Vrc\n", rc));
247 g_cInits--;
248
249 return rc;
250}
251
252/**
253 * Fake mode init.
254 */
255static int supInitFake(PSUPDRVSESSION *ppSession)
256{
257 Log(("SUP: Fake mode!\n"));
258 static const SUPFUNC s_aFakeFunctions[] =
259 {
260 /* name function */
261 { "SUPR0ObjRegister", (void *)0xefef0000 },
262 { "SUPR0ObjAddRef", (void *)0xefef0001 },
263 { "SUPR0ObjRelease", (void *)0xefef0002 },
264 { "SUPR0ObjVerifyAccess", (void *)0xefef0003 },
265 { "SUPR0LockMem", (void *)0xefef0004 },
266 { "SUPR0UnlockMem", (void *)0xefef0005 },
267 { "SUPR0ContAlloc", (void *)0xefef0006 },
268 { "SUPR0ContFree", (void *)0xefef0007 },
269 { "SUPR0MemAlloc", (void *)0xefef0008 },
270 { "SUPR0MemGetPhys", (void *)0xefef0009 },
271 { "SUPR0MemFree", (void *)0xefef000a },
272 { "SUPR0Printf", (void *)0xefef000b },
273 { "RTMemAlloc", (void *)0xefef000c },
274 { "RTMemAllocZ", (void *)0xefef000d },
275 { "RTMemFree", (void *)0xefef000e },
276 { "RTSemFastMutexCreate", (void *)0xefef000f },
277 { "RTSemFastMutexDestroy", (void *)0xefef0010 },
278 { "RTSemFastMutexRequest", (void *)0xefef0011 },
279 { "RTSemFastMutexRelease", (void *)0xefef0012 },
280 { "RTSemEventCreate", (void *)0xefef0013 },
281 { "RTSemEventSignal", (void *)0xefef0014 },
282 { "RTSemEventWait", (void *)0xefef0015 },
283 { "RTSemEventDestroy", (void *)0xefef0016 },
284 { "RTSpinlockCreate", (void *)0xefef0017 },
285 { "RTSpinlockDestroy", (void *)0xefef0018 },
286 { "RTSpinlockAcquire", (void *)0xefef0019 },
287 { "RTSpinlockRelease", (void *)0xefef001a },
288 { "RTSpinlockAcquireNoInts", (void *)0xefef001b },
289 { "RTSpinlockReleaseNoInts", (void *)0xefef001c },
290 { "RTThreadNativeSelf", (void *)0xefef001d },
291 { "RTThreadSleep", (void *)0xefef001e },
292 { "RTThreadYield", (void *)0xefef001f },
293 { "RTLogDefaultInstance", (void *)0xefef0020 },
294 { "RTLogRelDefaultInstance", (void *)0xefef0021 },
295 { "RTLogSetDefaultInstanceThread", (void *)0xefef0022 },
296 { "RTLogLogger", (void *)0xefef0023 },
297 { "RTLogLoggerEx", (void *)0xefef0024 },
298 { "RTLogLoggerExV", (void *)0xefef0025 },
299 { "AssertMsg1", (void *)0xefef0026 },
300 { "AssertMsg2", (void *)0xefef0027 },
301 };
302
303 /* fake r0 functions. */
304 g_pFunctions = (PSUPQUERYFUNCS_OUT)RTMemAllocZ(RT_OFFSETOF(SUPQUERYFUNCS_OUT, aFunctions[RT_ELEMENTS(s_aFakeFunctions)]));
305 if (g_pFunctions)
306 {
307 g_pFunctions->cFunctions = RT_ELEMENTS(s_aFakeFunctions);
308 memcpy(&g_pFunctions->aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
309 g_pSession = (PSUPDRVSESSION)(void *)g_pFunctions;
310 if (ppSession)
311 *ppSession = g_pSession;
312#ifndef VBOX_WITHOUT_IDT_PATCHING
313 Assert(g_u8Interrupt == 3);
314#endif
315
316 /* fake the GIP. */
317 g_pSUPGlobalInfoPage = (PCSUPGLOBALINFOPAGE)RTMemPageAlloc(PAGE_SIZE);
318 if (g_pSUPGlobalInfoPage)
319 {
320 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
321 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
322 /* the page is supposed to be invalid, so don't set the magic. */
323 return VINF_SUCCESS;
324 }
325
326 RTMemFree(g_pFunctions);
327 g_pFunctions = NULL;
328 }
329 return VERR_NO_MEMORY;
330}
331
332
333SUPR3DECL(int) SUPTerm(bool fForced)
334{
335 /*
336 * Verify state.
337 */
338 AssertMsg(g_cInits > 0, ("SUPTerm() is called before SUPInit()!\n"));
339 if (g_cInits == 0)
340 return VERR_WRONG_ORDER;
341 if (g_cInits == 1 || fForced)
342 {
343 /*
344 * NULL the GIP pointer.
345 */
346 if (g_pSUPGlobalInfoPage)
347 {
348 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, NULL);
349 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, NULL);
350 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
351 /* just a little safe guard against threads using the page. */
352 RTThreadSleep(50);
353 }
354
355 /*
356 * Close the support driver.
357 */
358 int rc = suplibOsTerm();
359 if (rc)
360 return rc;
361
362 g_u32Cookie = 0;
363 g_u32SessionCookie = 0;
364#ifndef VBOX_WITHOUT_IDT_PATCHING
365 g_u8Interrupt = 3;
366#endif
367 g_cInits = 0;
368 }
369 else
370 g_cInits--;
371
372 return 0;
373}
374
375
376SUPR3DECL(SUPPAGINGMODE) SUPGetPagingMode(void)
377{
378 /*
379 * Issue IOCtl to the SUPDRV kernel module.
380 */
381 SUPGETPAGINGMODE_IN In;
382 In.u32Cookie = g_u32Cookie;
383 In.u32SessionCookie = g_u32SessionCookie;
384 SUPGETPAGINGMODE_OUT Out = {SUPPAGINGMODE_INVALID};
385 int rc;
386 if (!g_u32FakeMode)
387 {
388 rc = suplibOsIOCtl(SUP_IOCTL_GET_PAGING_MODE, &In, sizeof(In), &Out, sizeof(Out));
389 if (VBOX_FAILURE(rc))
390 Out.enmMode = SUPPAGINGMODE_INVALID;
391 }
392 else
393 Out.enmMode = SUPPAGINGMODE_32_BIT_GLOBAL;
394
395 return Out.enmMode;
396}
397
398SUPR3DECL(int) SUPCallVMMR0Ex(PVMR0 pVMR0, unsigned uOperation, void *pvArg, unsigned cbArg)
399{
400 /*
401 * Issue IOCtl to the SUPDRV kernel module.
402 */
403 SUPCALLVMMR0_IN In;
404 In.u32Cookie = g_u32Cookie;
405 In.u32SessionCookie = g_u32SessionCookie;
406 In.pVMR0 = pVMR0;
407 In.uOperation = uOperation;
408 In.cbArg = cbArg;
409 In.pvArg = pvArg;
410 Assert(!g_u32FakeMode);
411 SUPCALLVMMR0_OUT Out = {VINF_SUCCESS};
412 int rc = suplibOsIOCtl(SUP_IOCTL_CALL_VMMR0, &In, sizeof(In), &Out, sizeof(Out));
413 if (VBOX_SUCCESS(rc))
414 rc = Out.rc;
415 return rc;
416}
417
418
419SUPR3DECL(int) SUPCallVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg)
420{
421#ifndef VBOX_WITHOUT_IDT_PATCHING
422 return g_pfnCallVMMR0(pVMR0, uOperation, pvArg);
423
424#else
425 if (RT_LIKELY(uOperation == VMMR0_DO_RAW_RUN))
426 {
427 Assert(!pvArg);
428 return suplibOSIOCtlFast(SUP_IOCTL_FAST_DO_RAW_RUN);
429 }
430 if (RT_LIKELY(uOperation == VMMR0_DO_HWACC_RUN))
431 {
432 Assert(!pvArg);
433 return suplibOSIOCtlFast(SUP_IOCTL_FAST_DO_HWACC_RUN);
434 }
435 if (uOperation == VMMR0_DO_NOP)
436 {
437 Assert(!pvArg);
438 return suplibOSIOCtlFast(SUP_IOCTL_FAST_DO_NOP);
439 }
440 return SUPCallVMMR0Ex(pVMR0, uOperation, pvArg, pvArg ? sizeof(pvArg) : 0);
441#endif
442}
443
444
445SUPR3DECL(int) SUPSetVMForFastIOCtl(PVMR0 pVMR0)
446{
447 SUPSETVMFORFAST_IN In;
448 In.u32Cookie = g_u32Cookie;
449 In.u32SessionCookie = g_u32SessionCookie;
450 In.pVMR0 = pVMR0;
451 int rc;
452 if (RT_LIKELY(!g_u32FakeMode))
453 rc = suplibOsIOCtl(SUP_IOCTL_SET_VM_FOR_FAST, &In, sizeof(In), NULL, 0);
454 else
455 rc = VINF_SUCCESS;
456 return rc;
457}
458
459
460SUPR3DECL(int) SUPPageLock(void *pvStart, size_t cbMemory, PSUPPAGE paPages)
461{
462 /*
463 * Validate.
464 */
465 AssertPtr(pvStart);
466 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
467 AssertMsg(RT_ALIGN_Z(cbMemory, PAGE_SIZE) == cbMemory, ("cbMemory (%#zx) must be page aligned\n", cbMemory));
468 AssertPtr(paPages);
469
470 /*
471 * Issue IOCtl to the SUPDRV kernel module.
472 */
473 SUPPINPAGES_IN In;
474 In.u32Cookie = g_u32Cookie;
475 In.u32SessionCookie = g_u32SessionCookie;
476 In.pv = pvStart;
477 In.cb = (uint32_t)cbMemory; AssertRelease(In.cb == cbMemory);
478 int rc;
479 if (!g_u32FakeMode)
480 {
481 PSUPPINPAGES_OUT pOut;
482 AssertCompile(sizeof(paPages[0]) == sizeof(pOut->aPages[0]));
483
484#if 0
485 const size_t cPages = cbMemory >> PAGE_SHIFT;
486 size_t cbOut = RT_OFFSETOF(SUPPINPAGES_OUT, aPages[cPages]);
487 pOut = (PSUPPINPAGES_OUT)RTMemTmpAllocZ(cbOut);
488 if (!pOut)
489 return VERR_NO_TMP_MEMORY;
490
491 rc = suplibOsIOCtl(SUP_IOCTL_PINPAGES, &In, sizeof(In), pOut, cbOut);
492 if (RT_SUCCESS(rc))
493 memcpy(paPages, &pOut->aPages[0], sizeof(paPages[0]) * cPages);
494 RTMemTmpFree(pOut);
495
496#else
497 /* a hack to save some time. */
498 pOut = (PSUPPINPAGES_OUT)(void*)paPages;
499 Assert(RT_OFFSETOF(SUPPINPAGES_OUT, aPages) == 0 && sizeof(paPages[0]) == sizeof(pOut->aPages[0]));
500 rc = suplibOsIOCtl(SUP_IOCTL_PINPAGES, &In, sizeof(In), pOut, RT_OFFSETOF(SUPPINPAGES_OUT, aPages[cbMemory >> PAGE_SHIFT]));
501#endif
502 }
503 else
504 {
505 /* fake a successfull result. */
506 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
507 unsigned iPage = (unsigned)cbMemory >> PAGE_SHIFT;
508 while (iPage-- > 0)
509 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
510 rc = VINF_SUCCESS;
511 }
512
513 return rc;
514}
515
516
517SUPR3DECL(int) SUPPageUnlock(void *pvStart)
518{
519 /*
520 * Validate.
521 */
522 AssertPtr(pvStart);
523 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
524
525 /*
526 * Issue IOCtl to the SUPDRV kernel module.
527 */
528 SUPUNPINPAGES_IN In;
529 In.u32Cookie = g_u32Cookie;
530 In.u32SessionCookie = g_u32SessionCookie;
531 In.pv = pvStart;
532 int rc;
533 if (!g_u32FakeMode)
534 rc = suplibOsIOCtl(SUP_IOCTL_UNPINPAGES, &In, sizeof(In), NULL, 0);
535 else
536 rc = VINF_SUCCESS;
537
538 return rc;
539}
540
541
542SUPR3DECL(void *) SUPContAlloc(unsigned cb, PRTHCPHYS pHCPhys)
543{
544 return SUPContAlloc2(cb, NIL_RTR0PTR, pHCPhys);
545}
546
547
548SUPR3DECL(void *) SUPContAlloc2(unsigned cb, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
549{
550 /*
551 * Validate.
552 */
553 AssertMsg(cb > 64 && cb < PAGE_SIZE * 256, ("cb=%d must be > 64 and < %d (256 pages)\n", cb, PAGE_SIZE * 256));
554 AssertPtr(pHCPhys);
555 *pHCPhys = NIL_RTHCPHYS;
556 AssertPtrNull(pR0Ptr);
557 if (pR0Ptr)
558 *pR0Ptr = NIL_RTR0PTR;
559
560 /*
561 * Issue IOCtl to the SUPDRV kernel module.
562 */
563 SUPCONTALLOC_IN In;
564 In.u32Cookie = g_u32Cookie;
565 In.u32SessionCookie = g_u32SessionCookie;
566 In.cb = RT_ALIGN_32(cb, PAGE_SIZE);
567 SUPCONTALLOC_OUT Out;
568 int rc;
569 if (!g_u32FakeMode)
570 rc = suplibOsIOCtl(SUP_IOCTL_CONT_ALLOC, &In, sizeof(In), &Out, sizeof(Out));
571 else
572 {
573 rc = SUPPageAlloc(In.cb >> PAGE_SHIFT, &Out.pvR3);
574 Out.HCPhys = (uintptr_t)Out.pvR3 + (PAGE_SHIFT * 1024);
575 Out.pvR0 = (uintptr_t)Out.pvR3;
576 }
577 if (VBOX_SUCCESS(rc))
578 {
579 *pHCPhys = (RTHCPHYS)Out.HCPhys;
580 if (pR0Ptr)
581 *pR0Ptr = Out.pvR0;
582 return Out.pvR3;
583 }
584
585 return NULL;
586}
587
588
589SUPR3DECL(int) SUPContFree(void *pv)
590{
591 /*
592 * Validate.
593 */
594 AssertPtr(pv);
595 if (!pv)
596 return VINF_SUCCESS;
597
598 /*
599 * Issue IOCtl to the SUPDRV kernel module.
600 */
601 SUPCONTFREE_IN In;
602 In.u32Cookie = g_u32Cookie;
603 In.u32SessionCookie = g_u32SessionCookie;
604 In.pv = pv;
605 int rc;
606 if (!g_u32FakeMode)
607 rc = suplibOsIOCtl(SUP_IOCTL_CONT_FREE, &In, sizeof(In), NULL, 0);
608 else
609 rc = SUPPageFree(pv);
610
611 return rc;
612}
613
614
615SUPR3DECL(int) SUPLowAlloc(unsigned cPages, void **ppvPages, PSUPPAGE paPages)
616{
617 /*
618 * Validate.
619 */
620 AssertMsg(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages));
621 AssertPtr(ppvPages);
622 *ppvPages = NULL;
623 AssertPtr(paPages);
624
625 int rc;
626 if (!g_u32FakeMode)
627 {
628 /*
629 * Issue IOCtl to the SUPDRV kernel module.
630 */
631 SUPLOWALLOC_IN In;
632 In.u32Cookie = g_u32Cookie;
633 In.u32SessionCookie = g_u32SessionCookie;
634 In.cPages = cPages;
635 size_t cbOut = RT_OFFSETOF(SUPLOWALLOC_OUT, aPages[cPages]);
636 PSUPLOWALLOC_OUT pOut = (PSUPLOWALLOC_OUT)RTMemTmpAllocZ(cbOut);
637 if (pOut)
638 {
639 rc = suplibOsIOCtl(SUP_IOCTL_LOW_ALLOC, &In, sizeof(In), pOut, cbOut);
640 if (VBOX_SUCCESS(rc))
641 {
642 *ppvPages = pOut->pvVirt;
643 AssertCompile(sizeof(paPages[0]) == sizeof(pOut->aPages[0]));
644 memcpy(paPages, &pOut->aPages[0], sizeof(paPages[0]) * cPages);
645#ifdef VBOX_STRICT
646 for (unsigned i = 0; i < cPages; i++)
647 AssertReleaseMsg( paPages[i].Phys <= 0xfffff000
648 && !(paPages[i].Phys & PAGE_OFFSET_MASK)
649 && paPages[i].Phys > 0,
650 ("[%d]=%VHp\n", paPages[i].Phys));
651#endif
652 }
653 RTMemTmpFree(pOut);
654 }
655 else
656 rc = VERR_NO_TMP_MEMORY;
657 }
658 else
659 {
660 rc = SUPPageAlloc(cPages, ppvPages);
661 if (VBOX_SUCCESS(rc))
662 {
663 /* fake physical addresses. */
664 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
665 unsigned iPage = cPages;
666 while (iPage-- > 0)
667 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
668 }
669 }
670
671 return rc;
672}
673
674
675SUPR3DECL(int) SUPLowFree(void *pv)
676{
677 /*
678 * Validate.
679 */
680 AssertPtr(pv);
681 if (!pv)
682 return VINF_SUCCESS;
683
684 /*
685 * Issue IOCtl to the SUPDRV kernel module.
686 */
687 SUPLOWFREE_IN In;
688 In.u32Cookie = g_u32Cookie;
689 In.u32SessionCookie = g_u32SessionCookie;
690 In.pv = pv;
691 int rc;
692 if (!g_u32FakeMode)
693 rc = suplibOsIOCtl(SUP_IOCTL_LOW_FREE, &In, sizeof(In), NULL, 0);
694 else
695 rc = SUPPageFree(pv);
696
697 return rc;
698}
699
700
701SUPR3DECL(int) SUPPageAlloc(size_t cPages, void **ppvPages)
702{
703 /*
704 * Validate.
705 */
706 if (cPages == 0)
707 {
708 AssertMsgFailed(("Invalid param cPages=0, must be > 0\n"));
709 return VERR_INVALID_PARAMETER;
710 }
711 AssertPtr(ppvPages);
712 if (!ppvPages)
713 return VERR_INVALID_PARAMETER;
714 *ppvPages = NULL;
715
716 /*
717 * Call OS specific worker.
718 */
719 return suplibOsPageAlloc(cPages, ppvPages);
720}
721
722
723SUPR3DECL(int) SUPPageFree(void *pvPages)
724{
725 /*
726 * Validate.
727 */
728 AssertPtr(pvPages);
729 if (!pvPages)
730 return VINF_SUCCESS;
731
732 /*
733 * Call OS specific worker.
734 */
735 return suplibOsPageFree(pvPages);
736}
737
738
739SUPR3DECL(int) SUPLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
740{
741 /*
742 * Load the module.
743 * If it's VMMR0.r0 we need to install the IDTE.
744 */
745 int rc = supLoadModule(pszFilename, pszModule, ppvImageBase);
746#ifndef VBOX_WITHOUT_IDT_PATCHING
747 if ( VBOX_SUCCESS(rc)
748 && !strcmp(pszModule, "VMMR0.r0"))
749 {
750 rc = supInstallIDTE();
751 if (VBOX_FAILURE(rc))
752 SUPFreeModule(*ppvImageBase);
753 }
754#endif /* VBOX_WITHOUT_IDT_PATCHING */
755
756 return rc;
757}
758
759
760#ifndef VBOX_WITHOUT_IDT_PATCHING
761/**
762 * Generates the code for calling the interrupt gate.
763 *
764 * @returns VBox status code.
765 * g_pfnCallVMMR0 is changed on success.
766 * @param u8Interrupt The interrupt number.
767 */
768static int suplibGenerateCallVMMR0(uint8_t u8Interrupt)
769{
770 /*
771 * Allocate memory.
772 */
773 uint8_t *pb = (uint8_t *)RTMemExecAlloc(256);
774 AssertReturn(pb, VERR_NO_MEMORY);
775 memset(pb, 0xcc, 256);
776 Assert(!g_pfnCallVMMR0);
777 g_pfnCallVMMR0 = *(PFNCALLVMMR0*)&pb;
778
779 /*
780 * Generate the code.
781 */
782#ifdef __AMD64__
783 /*
784 * reg params:
785 * <GCC> <MSC> <argument>
786 * rdi rcx pVMR0
787 * esi edx uOperation
788 * rdx r8 pvArg
789 *
790 * eax eax [g_u32Gookie]
791 */
792 *pb++ = 0xb8; /* mov eax, <g_u32Cookie> */
793 *(uint32_t *)pb = g_u32Cookie;
794 pb += sizeof(uint32_t);
795
796 *pb++ = 0xcd; /* int <u8Interrupt> */
797 *pb++ = u8Interrupt;
798
799 *pb++ = 0xc3; /* ret */
800
801#else
802 /*
803 * x86 stack:
804 * 0 saved esi
805 * 0 4 ret
806 * 4 8 pVM
807 * 8 c uOperation
808 * c 10 pvArg
809 */
810 *pb++ = 0x56; /* push esi */
811
812 *pb++ = 0x8b; /* mov eax, [pVM] */
813 *pb++ = 0x44;
814 *pb++ = 0x24;
815 *pb++ = 0x08; /* esp+08h */
816
817 *pb++ = 0x8b; /* mov edx, [uOperation] */
818 *pb++ = 0x54;
819 *pb++ = 0x24;
820 *pb++ = 0x0c; /* esp+0ch */
821
822 *pb++ = 0x8b; /* mov ecx, [pvArg] */
823 *pb++ = 0x4c;
824 *pb++ = 0x24;
825 *pb++ = 0x10; /* esp+10h */
826
827 *pb++ = 0xbe; /* mov esi, <g_u32Cookie> */
828 *(uint32_t *)pb = g_u32Cookie;
829 pb += sizeof(uint32_t);
830
831 *pb++ = 0xcd; /* int <u8Interrupt> */
832 *pb++ = u8Interrupt;
833
834 *pb++ = 0x5e; /* pop esi */
835
836 *pb++ = 0xc3; /* ret */
837#endif
838
839 return VINF_SUCCESS;
840}
841
842
843/**
844 * Installs the IDTE patch.
845 *
846 * @return VBox status code.
847 */
848static int supInstallIDTE(void)
849{
850 /* already installed? */
851 if (g_u8Interrupt != 3 || g_u32FakeMode)
852 return VINF_SUCCESS;
853
854 int rc = VINF_SUCCESS;
855 const unsigned cCpus = RTSystemProcessorGetCount();
856 if (cCpus <= 1)
857 {
858 /* UNI */
859 SUPIDTINSTALL_IN In;
860 In.u32Cookie = g_u32Cookie;
861 In.u32SessionCookie = g_u32SessionCookie;
862 SUPIDTINSTALL_OUT Out = {3};
863
864 rc = suplibOsIOCtl(SUP_IOCTL_IDT_INSTALL, &In, sizeof(In), &Out, sizeof(Out));
865 if (VBOX_SUCCESS(rc))
866 {
867 g_u8Interrupt = Out.u8Idt;
868 rc = suplibGenerateCallVMMR0(Out.u8Idt);
869 }
870 }
871 else
872 {
873 /* SMP */
874 uint64_t u64AffMaskSaved = RTThreadGetAffinity();
875 uint64_t u64AffMaskPatched = RTSystemProcessorGetActiveMask() & u64AffMaskSaved;
876 unsigned cCpusPatched = 0;
877
878 for (int i = 0; i < 64; i++)
879 {
880 /* Skip absent and inactive processors. */
881 uint64_t u64Mask = 1ULL << i;
882 if (!(u64Mask & u64AffMaskPatched))
883 continue;
884
885 /* Change CPU */
886 int rc2 = RTThreadSetAffinity(u64Mask);
887 if (VBOX_FAILURE(rc2))
888 {
889 u64AffMaskPatched &= ~u64Mask;
890 Log(("SUPLoadVMM: Failed to set affinity to cpu no. %d, rc=%Vrc.\n", i, rc2));
891 continue;
892 }
893
894 /* Patch the CPU. */
895 SUPIDTINSTALL_IN In;
896 In.u32Cookie = g_u32Cookie;
897 In.u32SessionCookie = g_u32SessionCookie;
898 SUPIDTINSTALL_OUT Out = {3};
899
900 rc2 = suplibOsIOCtl(SUP_IOCTL_IDT_INSTALL, &In, sizeof(In), &Out, sizeof(Out));
901 if (VBOX_SUCCESS(rc2))
902 {
903 if (!cCpusPatched)
904 {
905 g_u8Interrupt = Out.u8Idt;
906 rc2 = suplibGenerateCallVMMR0(Out.u8Idt);
907 if (VBOX_FAILURE(rc))
908 rc2 = rc;
909 }
910 else
911 Assert(g_u8Interrupt == Out.u8Idt);
912 cCpusPatched++;
913 }
914 else
915 {
916
917 Log(("SUPLoadVMM: Failed to patch cpu no. %d, rc=%Vrc.\n", i, rc2));
918 if (VBOX_SUCCESS(rc))
919 rc = rc2;
920 }
921 }
922
923 /* Fail if no CPUs was patched! */
924 if (VBOX_SUCCESS(rc) && cCpusPatched <= 0)
925 rc = VERR_GENERAL_FAILURE;
926 /* Ignore failures if a CPU was patched. */
927 else if (VBOX_FAILURE(rc) && cCpusPatched > 0)
928 {
929 /** @todo add an eventlog/syslog line out this. */
930 rc = VINF_SUCCESS;
931 }
932
933 /* Set/restore the thread affinity. */
934 if (VBOX_SUCCESS(rc))
935 {
936 rc = RTThreadSetAffinity(u64AffMaskPatched);
937 AssertRC(rc);
938 }
939 else
940 {
941 int rc2 = RTThreadSetAffinity(u64AffMaskSaved);
942 AssertRC(rc2);
943 }
944 }
945 return rc;
946}
947#endif /* !VBOX_WITHOUT_IDT_PATCHING */
948
949
950/**
951 * Resolve an external symbol during RTLdrGetBits().
952 *
953 * @returns VBox status code.
954 * @param hLdrMod The loader module handle.
955 * @param pszModule Module name.
956 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
957 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
958 * @param pValue Where to store the symbol value (address).
959 * @param pvUser User argument.
960 */
961static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
962 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
963{
964 AssertPtr(pValue);
965 AssertPtr(pvUser);
966
967 /*
968 * Only SUPR0 and VMMR0.r0
969 */
970 if ( pszModule
971 && *pszModule
972 && strcmp(pszModule, "SUPR0.dll")
973 && strcmp(pszModule, "VMMR0.r0"))
974 {
975 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
976 return VERR_SYMBOL_NOT_FOUND;
977 }
978
979 /*
980 * No ordinals.
981 */
982 if (pszSymbol < (const char*)0x10000)
983 {
984 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pvUser, (int)(uintptr_t)pszSymbol));
985 return VERR_SYMBOL_NOT_FOUND;
986 }
987
988 /*
989 * Lookup symbol.
990 */
991 /* skip the 64-bit ELF import prefix first. */
992 if (!strncmp(pszSymbol, "SUPR0$", sizeof("SUPR0$") - 1))
993 pszSymbol += sizeof("SUPR0$") - 1;
994
995 /* iterate the function table. */
996 int c = g_pFunctions->cFunctions;
997 PSUPFUNC pFunc = &g_pFunctions->aFunctions[0];
998 while (c-- > 0)
999 {
1000 if (!strcmp(pFunc->szName, pszSymbol))
1001 {
1002 *pValue = (uintptr_t)pFunc->pfn;
1003 return VINF_SUCCESS;
1004 }
1005 pFunc++;
1006 }
1007
1008 /*
1009 * Check the VMMR0.r0 module if loaded.
1010 */
1011 /** @todo call the SUPLoadModule caller.... */
1012 /** @todo proper reference counting and such. */
1013 if (g_pvVMMR0)
1014 {
1015 void *pvValue;
1016 if (!SUPGetSymbolR0(g_pvVMMR0, pszSymbol, &pvValue))
1017 {
1018 *pValue = (uintptr_t)pvValue;
1019 return VINF_SUCCESS;
1020 }
1021 }
1022
1023 /*
1024 * The GIP.
1025 */
1026 /** @todo R0 mapping? */
1027 if ( pszSymbol
1028 && g_pSUPGlobalInfoPage
1029 && g_pSUPGlobalInfoPageR0
1030 && !strcmp(pszSymbol, "g_SUPGlobalInfoPage"))
1031 {
1032 *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
1033 return VINF_SUCCESS;
1034 }
1035
1036 /*
1037 * Despair.
1038 */
1039 c = g_pFunctions->cFunctions;
1040 pFunc = &g_pFunctions->aFunctions[0];
1041 while (c-- > 0)
1042 {
1043 AssertMsg2("%d: %s\n", g_pFunctions->cFunctions - c, pFunc->szName);
1044 pFunc++;
1045 }
1046
1047 AssertMsgFailed(("%s is importing %s which we couldn't find\n", pvUser, pszSymbol));
1048 return VERR_SYMBOL_NOT_FOUND;
1049}
1050
1051
1052/** Argument package for supLoadModuleCalcSizeCB. */
1053typedef struct SUPLDRCALCSIZEARGS
1054{
1055 size_t cbStrings;
1056 uint32_t cSymbols;
1057 size_t cbImage;
1058} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
1059
1060/**
1061 * Callback used to calculate the image size.
1062 * @return VINF_SUCCESS
1063 */
1064static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1065{
1066 PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
1067 if ( pszSymbol != NULL
1068 && *pszSymbol
1069 && Value <= pArgs->cbImage)
1070 {
1071 pArgs->cSymbols++;
1072 pArgs->cbStrings += strlen(pszSymbol) + 1;
1073 }
1074 return VINF_SUCCESS;
1075}
1076
1077
1078/** Argument package for supLoadModuleCreateTabsCB. */
1079typedef struct SUPLDRCREATETABSARGS
1080{
1081 size_t cbImage;
1082 PSUPLDRSYM pSym;
1083 char *pszBase;
1084 char *psz;
1085} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
1086
1087/**
1088 * Callback used to calculate the image size.
1089 * @return VINF_SUCCESS
1090 */
1091static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1092{
1093 PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
1094 if ( pszSymbol != NULL
1095 && *pszSymbol
1096 && Value <= pArgs->cbImage)
1097 {
1098 pArgs->pSym->offSymbol = (uint32_t)Value;
1099 pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
1100 pArgs->pSym++;
1101
1102 size_t cbCopy = strlen(pszSymbol) + 1;
1103 memcpy(pArgs->psz, pszSymbol, cbCopy);
1104 pArgs->psz += cbCopy;
1105 }
1106 return VINF_SUCCESS;
1107}
1108
1109
1110/**
1111 * Worker for SUPLoadModule().
1112 *
1113 * @returns VBox status code.
1114 * @param pszFilename Name of the VMMR0 image file
1115 */
1116static int supLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
1117{
1118 /*
1119 * Validate input.
1120 */
1121 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1122 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
1123 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
1124 AssertReturn(strlen(pszModule) < SIZEOFMEMB(SUPLDROPEN_IN, szName), VERR_FILENAME_TOO_LONG);
1125
1126 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
1127 *ppvImageBase = NULL;
1128
1129 /*
1130 * Open image file and figure its size.
1131 */
1132 RTLDRMOD hLdrMod;
1133 int rc = RTLdrOpen(pszFilename, &hLdrMod);
1134 if (!VBOX_SUCCESS(rc))
1135 return rc;
1136
1137 SUPLDRCALCSIZEARGS CalcArgs;
1138 CalcArgs.cbStrings = 0;
1139 CalcArgs.cSymbols = 0;
1140 CalcArgs.cbImage = RTLdrSize(hLdrMod);
1141 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
1142 if (VBOX_SUCCESS(rc))
1143 {
1144 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
1145 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
1146 const uint32_t cbImage = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
1147
1148 /*
1149 * Open the R0 image.
1150 */
1151 SUPLDROPEN_IN OpenIn;
1152 OpenIn.u32Cookie = g_u32Cookie;
1153 OpenIn.u32SessionCookie = g_u32SessionCookie;
1154 OpenIn.cbImage = cbImage;
1155 strcpy(OpenIn.szName, pszModule);
1156 SUPLDROPEN_OUT OpenOut;
1157 if (!g_u32FakeMode)
1158 rc = suplibOsIOCtl(SUP_IOCTL_LDR_OPEN, &OpenIn, sizeof(OpenIn), &OpenOut, sizeof(OpenOut));
1159 else
1160 {
1161 OpenOut.fNeedsLoading = true;
1162 OpenOut.pvImageBase = (void *)0xef423420;
1163 }
1164 *ppvImageBase = OpenOut.pvImageBase;
1165 if ( VBOX_SUCCESS(rc)
1166 && OpenOut.fNeedsLoading)
1167 {
1168 /*
1169 * We need to load it.
1170 * Allocate memory for the image bits.
1171 */
1172 unsigned cbIn = RT_OFFSETOF(SUPLDRLOAD_IN, achImage[cbImage]);
1173 PSUPLDRLOAD_IN pIn = (PSUPLDRLOAD_IN)RTMemTmpAlloc(cbIn);
1174 if (pIn)
1175 {
1176 /*
1177 * Get the image bits.
1178 */
1179 rc = RTLdrGetBits(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase,
1180 supLoadModuleResolveImport, (void *)pszModule);
1181
1182 /*
1183 * Get the entry points.
1184 */
1185 RTUINTPTR VMMR0Entry = 0;
1186 RTUINTPTR ModuleInit = 0;
1187 RTUINTPTR ModuleTerm = 0;
1188 if (fIsVMMR0 && VBOX_SUCCESS(rc))
1189 rc = RTLdrGetSymbolEx(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase, "VMMR0Entry", &VMMR0Entry);
1190 if (VBOX_SUCCESS(rc))
1191 {
1192 rc = RTLdrGetSymbolEx(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase, "ModuleInit", &ModuleInit);
1193 if (VBOX_FAILURE(rc))
1194 ModuleInit = 0;
1195
1196 rc = RTLdrGetSymbolEx(hLdrMod, &pIn->achImage[0], (uintptr_t)OpenOut.pvImageBase, "ModuleTerm", &ModuleTerm);
1197 if (VBOX_FAILURE(rc))
1198 ModuleTerm = 0;
1199 }
1200
1201 /*
1202 * Create the symbol and string tables.
1203 */
1204 SUPLDRCREATETABSARGS CreateArgs;
1205 CreateArgs.cbImage = CalcArgs.cbImage;
1206 CreateArgs.pSym = (PSUPLDRSYM)&pIn->achImage[offSymTab];
1207 CreateArgs.pszBase = (char *)&pIn->achImage[offStrTab];
1208 CreateArgs.psz = CreateArgs.pszBase;
1209 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
1210 if (VBOX_SUCCESS(rc))
1211 {
1212 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
1213 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pIn->achImage[offSymTab]) <= CalcArgs.cSymbols);
1214
1215 /*
1216 * Upload the image.
1217 */
1218 pIn->u32Cookie = g_u32Cookie;
1219 pIn->u32SessionCookie = g_u32SessionCookie;
1220 pIn->pfnModuleInit = (PFNR0MODULEINIT)(uintptr_t)ModuleInit;
1221 pIn->pfnModuleTerm = (PFNR0MODULETERM)(uintptr_t)ModuleTerm;
1222 if (fIsVMMR0)
1223 {
1224 pIn->eEPType = pIn->EP_VMMR0;
1225 pIn->EP.VMMR0.pvVMMR0 = OpenOut.pvImageBase;
1226 pIn->EP.VMMR0.pvVMMR0Entry = (void *)(uintptr_t)VMMR0Entry;
1227 }
1228 else
1229 pIn->eEPType = pIn->EP_NOTHING;
1230 pIn->offStrTab = offStrTab;
1231 pIn->cbStrTab = CalcArgs.cbStrings;
1232 pIn->offSymbols = offSymTab;
1233 pIn->cSymbols = CalcArgs.cSymbols;
1234 pIn->cbImage = cbImage;
1235 pIn->pvImageBase = OpenOut.pvImageBase;
1236 if (!g_u32FakeMode)
1237 rc = suplibOsIOCtl(SUP_IOCTL_LDR_LOAD, pIn, cbIn, NULL, 0);
1238 else
1239 rc = VINF_SUCCESS;
1240 if ( VBOX_SUCCESS(rc)
1241 || rc == VERR_ALREADY_LOADED /* this is because of a competing process. */
1242 )
1243 {
1244 if (fIsVMMR0)
1245 g_pvVMMR0 = OpenOut.pvImageBase;
1246 RTMemTmpFree(pIn);
1247 RTLdrClose(hLdrMod);
1248 return VINF_SUCCESS;
1249 }
1250 }
1251 RTMemTmpFree(pIn);
1252 }
1253 else
1254 {
1255 AssertMsgFailed(("failed to allocated %d bytes for SUPLDRLOAD_IN structure!\n", cbIn));
1256 rc = VERR_NO_TMP_MEMORY;
1257 }
1258 }
1259 }
1260 RTLdrClose(hLdrMod);
1261 return rc;
1262}
1263
1264
1265SUPR3DECL(int) SUPFreeModule(void *pvImageBase)
1266{
1267 /*
1268 * There is one special module. When this is freed we'll
1269 * free the IDT entry that goes with it.
1270 *
1271 * Note that we don't keep count of VMMR0.r0 loads here, so the
1272 * first unload will free it.
1273 */
1274 if (pvImageBase == g_pvVMMR0)
1275 {
1276 /*
1277 * This is the point where we remove the IDT hook. We do
1278 * that before unloading the R0 VMM part.
1279 */
1280 if (g_u32FakeMode)
1281 {
1282#ifndef VBOX_WITHOUT_IDT_PATCHING
1283 g_u8Interrupt = 3;
1284 RTMemExecFree(*(void **)&g_pfnCallVMMR0);
1285 g_pfnCallVMMR0 = NULL;
1286#endif
1287 g_pvVMMR0 = NULL;
1288 return VINF_SUCCESS;
1289 }
1290
1291#ifndef VBOX_WITHOUT_IDT_PATCHING
1292 /*
1293 * Uninstall IDT entry.
1294 */
1295 int rc = 0;
1296 if (g_u8Interrupt != 3)
1297 {
1298 SUPIDTREMOVE_IN In;
1299 In.u32Cookie = g_u32Cookie;
1300 In.u32SessionCookie = g_u32SessionCookie;
1301 rc = suplibOsIOCtl(SUP_IOCTL_IDT_REMOVE, &In, sizeof(In), NULL, 0);
1302 g_u8Interrupt = 3;
1303 RTMemExecFree(*(void **)&g_pfnCallVMMR0);
1304 g_pfnCallVMMR0 = NULL;
1305 }
1306#endif
1307 }
1308
1309 /*
1310 * Free the requested module.
1311 */
1312 SUPLDRFREE_IN In;
1313 In.u32Cookie = g_u32Cookie;
1314 In.u32SessionCookie = g_u32SessionCookie;
1315 In.pvImageBase = pvImageBase;
1316 int rc = VINF_SUCCESS;
1317 if (!g_u32FakeMode)
1318 rc = suplibOsIOCtl(SUP_IOCTL_LDR_FREE, &In, sizeof(In), NULL, 0);
1319 if ( VBOX_SUCCESS(rc)
1320 && pvImageBase == g_pvVMMR0)
1321 g_pvVMMR0 = NULL;
1322 return rc;
1323}
1324
1325
1326SUPR3DECL(int) SUPGetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
1327{
1328 *ppvValue = NULL;
1329
1330 /*
1331 * Do ioctl.
1332 */
1333 size_t cchSymbol = strlen(pszSymbol);
1334 const size_t cbIn = RT_OFFSETOF(SUPLDRGETSYMBOL_IN, szSymbol[cchSymbol + 1]);
1335 SUPLDRGETSYMBOL_OUT Out = { NULL };
1336 PSUPLDRGETSYMBOL_IN pIn = (PSUPLDRGETSYMBOL_IN)alloca(cbIn);
1337 pIn->u32Cookie = g_u32Cookie;
1338 pIn->u32SessionCookie = g_u32SessionCookie;
1339 pIn->pvImageBase = pvImageBase;
1340 memcpy(pIn->szSymbol, pszSymbol, cchSymbol + 1);
1341 int rc;
1342 if (RT_LIKELY(!g_u32FakeMode))
1343 rc = suplibOsIOCtl(SUP_IOCTL_LDR_GET_SYMBOL, pIn, cbIn, &Out, sizeof(Out));
1344 else
1345 {
1346 rc = VINF_SUCCESS;
1347 Out.pvSymbol = (void *)0xdeadf00d;
1348 }
1349 if (VBOX_SUCCESS(rc))
1350 *ppvValue = Out.pvSymbol;
1351 return rc;
1352}
1353
1354
1355SUPR3DECL(int) SUPLoadVMM(const char *pszFilename)
1356{
1357 void *pvImageBase;
1358 return SUPLoadModule(pszFilename, "VMMR0.r0", &pvImageBase);
1359}
1360
1361
1362SUPR3DECL(int) SUPUnloadVMM(void)
1363{
1364 return SUPFreeModule(g_pvVMMR0);
1365}
1366
1367
1368SUPR3DECL(int) SUPGipGetPhys(PRTHCPHYS pHCPhys)
1369{
1370 if (g_pSUPGlobalInfoPage)
1371 {
1372 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1373 return VINF_SUCCESS;
1374 }
1375 *pHCPhys = NIL_RTHCPHYS;
1376 return VERR_WRONG_ORDER;
1377}
1378
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