VirtualBox

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

最後變更 在這個檔案從4071是 4071,由 vboxsync 提交於 18 年 前

Biggest check-in ever. New source code headers for all (C) innotek files.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette