VirtualBox

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

Last change on this file since 1959 was 1893, checked in by vboxsync, 18 years ago

fixed another check

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