VirtualBox

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

Last change on this file since 5320 was 5231, checked in by vboxsync, 17 years ago

Export the multiple release event semaphores.

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