VirtualBox

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

Last change on this file since 2676 was 2655, checked in by vboxsync, 17 years ago

fixed a minor issue causing SUPUnloadVMM to fail with VERR_INVALID_HANDLE if VMMR0.r0 is already loaded.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use