VirtualBox

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

Last change on this file since 5226 was 5166, checked in by vboxsync, 18 years ago

RTSemEventWaitNoResume

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.9 KB
Line 
1/* $Id: SUPLib.cpp 5166 2007-10-05 13:32:57Z 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 { "RTSemFastMutexCreate", 0xefef0020 },
335 { "RTSemFastMutexDestroy", 0xefef0021 },
336 { "RTSemFastMutexRequest", 0xefef0022 },
337 { "RTSemFastMutexRelease", 0xefef0023 },
338 { "RTSemEventCreate", 0xefef0024 },
339 { "RTSemEventSignal", 0xefef0025 },
340 { "RTSemEventWait", 0xefef0026 },
341 { "RTSemEventWaitNoResume", 0xefef0027 },
342 { "RTSemEventDestroy", 0xefef0028 },
343 { "RTSpinlockCreate", 0xefef0029 },
344 { "RTSpinlockDestroy", 0xefef002a },
345 { "RTSpinlockAcquire", 0xefef002b },
346 { "RTSpinlockRelease", 0xefef002c },
347 { "RTSpinlockAcquireNoInts", 0xefef002d },
348 { "RTSpinlockReleaseNoInts", 0xefef002e },
349 { "RTThreadNativeSelf", 0xefef002f },
350 { "RTThreadSleep", 0xefef0030 },
351 { "RTThreadYield", 0xefef0031 },
352 { "RTLogDefaultInstance", 0xefef0032 },
353 { "RTLogRelDefaultInstance", 0xefef0033 },
354 { "RTLogSetDefaultInstanceThread", 0xefef0034 },
355 { "RTLogLogger", 0xefef0035 },
356 { "RTLogLoggerEx", 0xefef0036 },
357 { "RTLogLoggerExV", 0xefef0037 },
358 { "AssertMsg1", 0xefef0038 },
359 { "AssertMsg2", 0xefef0039 },
360 };
361
362 /* fake r0 functions. */
363 g_pFunctions = (PSUPQUERYFUNCS)RTMemAllocZ(SUP_IOCTL_QUERY_FUNCS_SIZE(RT_ELEMENTS(s_aFakeFunctions)));
364 if (g_pFunctions)
365 {
366 g_pFunctions->u.Out.cFunctions = RT_ELEMENTS(s_aFakeFunctions);
367 memcpy(&g_pFunctions->u.Out.aFunctions[0], &s_aFakeFunctions[0], sizeof(s_aFakeFunctions));
368 g_pSession = (PSUPDRVSESSION)(void *)g_pFunctions;
369 if (ppSession)
370 *ppSession = g_pSession;
371#ifdef VBOX_WITH_IDT_PATCHING
372 Assert(g_u8Interrupt == 3);
373#endif
374
375 /* fake the GIP. */
376 g_pSUPGlobalInfoPage = (PSUPGLOBALINFOPAGE)RTMemPageAllocZ(PAGE_SIZE);
377 if (g_pSUPGlobalInfoPage)
378 {
379 g_pSUPGlobalInfoPageR0 = g_pSUPGlobalInfoPage;
380 g_HCPhysSUPGlobalInfoPage = NIL_RTHCPHYS & ~(RTHCPHYS)PAGE_OFFSET_MASK;
381 /* the page is supposed to be invalid, so don't set the magic. */
382 return VINF_SUCCESS;
383 }
384
385 RTMemFree(g_pFunctions);
386 g_pFunctions = NULL;
387 }
388 return VERR_NO_MEMORY;
389}
390
391
392SUPR3DECL(int) SUPTerm(bool fForced)
393{
394 /*
395 * Verify state.
396 */
397 AssertMsg(g_cInits > 0, ("SUPTerm() is called before SUPInit()!\n"));
398 if (g_cInits == 0)
399 return VERR_WRONG_ORDER;
400 if (g_cInits == 1 || fForced)
401 {
402 /*
403 * NULL the GIP pointer.
404 */
405 if (g_pSUPGlobalInfoPage)
406 {
407 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPage, NULL);
408 ASMAtomicXchgPtr((void * volatile *)&g_pSUPGlobalInfoPageR0, NULL);
409 ASMAtomicXchgSize(&g_HCPhysSUPGlobalInfoPage, NIL_RTHCPHYS);
410 /* just a little safe guard against threads using the page. */
411 RTThreadSleep(50);
412 }
413
414 /*
415 * Close the support driver.
416 */
417 int rc = suplibOsTerm();
418 if (rc)
419 return rc;
420
421 g_u32Cookie = 0;
422 g_u32SessionCookie = 0;
423#ifdef VBOX_WITH_IDT_PATCHING
424 g_u8Interrupt = 3;
425#endif
426 g_cInits = 0;
427 }
428 else
429 g_cInits--;
430
431 return 0;
432}
433
434
435SUPR3DECL(SUPPAGINGMODE) SUPGetPagingMode(void)
436{
437 /* fake */
438 if (RT_UNLIKELY(g_u32FakeMode))
439#ifdef RT_ARCH_AMD64
440 return SUPPAGINGMODE_AMD64_GLOBAL_NX;
441#else
442 return SUPPAGINGMODE_32_BIT_GLOBAL;
443#endif
444
445 /*
446 * Issue IOCtl to the SUPDRV kernel module.
447 */
448 SUPGETPAGINGMODE Req;
449 Req.Hdr.u32Cookie = g_u32Cookie;
450 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
451 Req.Hdr.cbIn = SUP_IOCTL_GET_PAGING_MODE_SIZE_IN;
452 Req.Hdr.cbOut = SUP_IOCTL_GET_PAGING_MODE_SIZE_OUT;
453 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
454 Req.Hdr.rc = VERR_INTERNAL_ERROR;
455 int rc = suplibOsIOCtl(SUP_IOCTL_GET_PAGING_MODE, &Req, SUP_IOCTL_GET_PAGING_MODE_SIZE);
456 if ( RT_FAILURE(rc)
457 || RT_FAILURE(Req.Hdr.rc))
458 {
459 LogRel(("SUPGetPagingMode: %Rrc %Rrc\n", rc, Req.Hdr.rc));
460 Req.u.Out.enmMode = SUPPAGINGMODE_INVALID;
461 }
462
463 return Req.u.Out.enmMode;
464}
465
466
467/**
468 * For later.
469 */
470static int supCallVMMR0ExFake(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
471{
472 AssertMsgFailed(("%d\n", uOperation));
473 return VERR_NOT_SUPPORTED;
474}
475
476
477SUPR3DECL(int) SUPCallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation)
478{
479 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_RAW_RUN))
480 return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_RAW_RUN);
481 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_HWACC_RUN))
482 return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_HWACC_RUN);
483 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_NOP))
484 return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_NOP);
485
486 AssertMsgFailed(("%#x\n", uOperation));
487 return VERR_INTERNAL_ERROR;
488}
489
490
491SUPR3DECL(int) SUPCallVMMR0Ex(PVMR0 pVMR0, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
492{
493#if 0 /* temp hack. */
494 /*
495 * The following operations don't belong here.
496 */
497 AssertMsgReturn( uOperation != SUP_VMMR0_DO_RAW_RUN
498 && uOperation != SUP_VMMR0_DO_HWACC_RUN
499 && uOperation != SUP_VMMR0_DO_NOP,
500 ("%#x\n", uOperation),
501 VERR_INTERNAL_ERROR);
502#else
503 if ( ( uOperation == SUP_VMMR0_DO_RAW_RUN
504 || uOperation == SUP_VMMR0_DO_HWACC_RUN
505 || uOperation == SUP_VMMR0_DO_NOP)
506 && !pReqHdr
507 && !u64Arg)
508 return (int) SUPCallVMMR0Fast(pVMR0, uOperation);
509#endif
510
511 /* fake */
512 if (RT_UNLIKELY(g_u32FakeMode))
513 return supCallVMMR0ExFake(pVMR0, uOperation, u64Arg, pReqHdr);
514
515 int rc;
516 if (!pReqHdr)
517 {
518 /* no data. */
519 SUPCALLVMMR0 Req;
520 Req.Hdr.u32Cookie = g_u32Cookie;
521 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
522 Req.Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(0);
523 Req.Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(0);
524 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
525 Req.Hdr.rc = VERR_INTERNAL_ERROR;
526 Req.u.In.pVMR0 = pVMR0;
527 Req.u.In.uOperation = uOperation;
528 Req.u.In.u64Arg = u64Arg;
529 rc = suplibOsIOCtl(SUP_IOCTL_CALL_VMMR0(0), &Req, SUP_IOCTL_CALL_VMMR0_SIZE(0));
530 if (RT_SUCCESS(rc))
531 rc = Req.Hdr.rc;
532 }
533 else if (SUP_IOCTL_CALL_VMMR0_SIZE(pReqHdr->cbReq) < _4K) /* FreeBSD won't copy more than 4K. */
534 {
535 AssertPtrReturn(pReqHdr, VERR_INVALID_POINTER);
536 AssertReturn(pReqHdr->u32Magic == SUPVMMR0REQHDR_MAGIC, VERR_INVALID_MAGIC);
537 const size_t cbReq = pReqHdr->cbReq;
538
539 PSUPCALLVMMR0 pReq = (PSUPCALLVMMR0)alloca(SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
540 pReq->Hdr.u32Cookie = g_u32Cookie;
541 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
542 pReq->Hdr.cbIn = SUP_IOCTL_CALL_VMMR0_SIZE_IN(cbReq);
543 pReq->Hdr.cbOut = SUP_IOCTL_CALL_VMMR0_SIZE_OUT(cbReq);
544 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
545 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
546 pReq->u.In.pVMR0 = pVMR0;
547 pReq->u.In.uOperation = uOperation;
548 pReq->u.In.u64Arg = u64Arg;
549 memcpy(&pReq->abReqPkt[0], pReqHdr, cbReq);
550 rc = suplibOsIOCtl(SUP_IOCTL_CALL_VMMR0(cbReq), pReq, SUP_IOCTL_CALL_VMMR0_SIZE(cbReq));
551 if (RT_SUCCESS(rc))
552 rc = pReq->Hdr.rc;
553 memcpy(pReqHdr, &pReq->abReqPkt[0], cbReq);
554 }
555 else /** @todo may have to remove the size limits one this request... */
556 AssertMsgFailedReturn(("cbReq=%#x\n", pReqHdr->cbReq), VERR_INTERNAL_ERROR);
557 return rc;
558}
559
560
561SUPR3DECL(int) SUPCallVMMR0(PVMR0 pVMR0, unsigned uOperation, void *pvArg)
562{
563#if defined(VBOX_WITH_IDT_PATCHING)
564 return g_pfnCallVMMR0(pVMR0, uOperation, pvArg);
565
566#else
567 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_RAW_RUN))
568 {
569 Assert(!pvArg);
570 return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_RAW_RUN);
571 }
572 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_HWACC_RUN))
573 {
574 Assert(!pvArg);
575 return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_HWACC_RUN);
576 }
577 if (RT_LIKELY(uOperation == SUP_VMMR0_DO_NOP))
578 {
579 Assert(!pvArg);
580 return suplibOsIOCtlFast(SUP_IOCTL_FAST_DO_NOP);
581 }
582 return SUPCallVMMR0Ex(pVMR0, uOperation, (uintptr_t)pvArg, NULL);
583#endif
584}
585
586
587SUPR3DECL(int) SUPSetVMForFastIOCtl(PVMR0 pVMR0)
588{
589 if (RT_UNLIKELY(g_u32FakeMode))
590 return VINF_SUCCESS;
591
592 SUPSETVMFORFAST Req;
593 Req.Hdr.u32Cookie = g_u32Cookie;
594 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
595 Req.Hdr.cbIn = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_IN;
596 Req.Hdr.cbOut = SUP_IOCTL_SET_VM_FOR_FAST_SIZE_OUT;
597 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
598 Req.Hdr.rc = VERR_INTERNAL_ERROR;
599 Req.u.In.pVMR0 = pVMR0;
600 int rc = suplibOsIOCtl(SUP_IOCTL_SET_VM_FOR_FAST, &Req, SUP_IOCTL_SET_VM_FOR_FAST_SIZE);
601 if (RT_SUCCESS(rc))
602 rc = Req.Hdr.rc;
603 return rc;
604}
605
606
607SUPR3DECL(int) SUPPageAlloc(size_t cPages, void **ppvPages)
608{
609 /*
610 * Validate.
611 */
612 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
613 *ppvPages = NULL;
614 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
615
616#ifdef RT_OS_WINDOWS
617 /*
618 * Temporary hack for windows until we've sorted out the
619 * locked memory that doesn't need to be accessible from kernel space.
620 */
621 return SUPPageAllocLockedEx(cPages, ppvPages, NULL);
622#else
623 /*
624 * Call OS specific worker.
625 */
626 return suplibOsPageAlloc(cPages, ppvPages);
627#endif
628}
629
630
631SUPR3DECL(int) SUPPageFree(void *pvPages, size_t cPages)
632{
633 /*
634 * Validate.
635 */
636 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
637 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
638
639#ifdef RT_OS_WINDOWS
640 /*
641 * Temporary hack for windows, see above.
642 */
643 return SUPPageFreeLocked(pvPages, cPages);
644#else
645 /*
646 * Call OS specific worker.
647 */
648 return suplibOsPageFree(pvPages, cPages);
649#endif
650}
651
652
653SUPR3DECL(int) SUPPageLock(void *pvStart, size_t cPages, PSUPPAGE paPages)
654{
655 /*
656 * Validate.
657 */
658 AssertPtr(pvStart);
659 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
660 AssertPtr(paPages);
661
662 /* fake */
663 if (RT_UNLIKELY(g_u32FakeMode))
664 {
665 RTHCPHYS Phys = (uintptr_t)pvStart + PAGE_SIZE * 1024;
666 unsigned iPage = cPages;
667 while (iPage-- > 0)
668 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
669 return VINF_SUCCESS;
670 }
671
672 /*
673 * Issue IOCtl to the SUPDRV kernel module.
674 */
675 int rc;
676 PSUPPAGELOCK pReq = (PSUPPAGELOCK)RTMemTmpAllocZ(SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
677 if (RT_LIKELY(pReq))
678 {
679 pReq->Hdr.u32Cookie = g_u32Cookie;
680 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
681 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_LOCK_SIZE_IN;
682 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_LOCK_SIZE_OUT(cPages);
683 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
684 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
685 pReq->u.In.pvR3 = pvStart;
686 pReq->u.In.cPages = cPages; AssertRelease(pReq->u.In.cPages == cPages);
687 rc = suplibOsIOCtl(SUP_IOCTL_PAGE_LOCK, pReq, SUP_IOCTL_PAGE_LOCK_SIZE(cPages));
688 if (RT_SUCCESS(rc))
689 rc = pReq->Hdr.rc;
690 if (RT_SUCCESS(rc))
691 {
692 for (uint32_t iPage = 0; iPage < cPages; iPage++)
693 {
694 paPages[iPage].uReserved = 0;
695 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
696 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
697 }
698 }
699 RTMemTmpFree(pReq);
700 }
701 else
702 rc = VERR_NO_TMP_MEMORY;
703
704 return rc;
705}
706
707
708SUPR3DECL(int) SUPPageUnlock(void *pvStart)
709{
710 /*
711 * Validate.
712 */
713 AssertPtr(pvStart);
714 AssertMsg(RT_ALIGN_P(pvStart, PAGE_SIZE) == pvStart, ("pvStart (%p) must be page aligned\n", pvStart));
715
716 /* fake */
717 if (RT_UNLIKELY(g_u32FakeMode))
718 return VINF_SUCCESS;
719
720 /*
721 * Issue IOCtl to the SUPDRV kernel module.
722 */
723 SUPPAGEUNLOCK Req;
724 Req.Hdr.u32Cookie = g_u32Cookie;
725 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
726 Req.Hdr.cbIn = SUP_IOCTL_PAGE_UNLOCK_SIZE_IN;
727 Req.Hdr.cbOut = SUP_IOCTL_PAGE_UNLOCK_SIZE_OUT;
728 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
729 Req.Hdr.rc = VERR_INTERNAL_ERROR;
730 Req.u.In.pvR3 = pvStart;
731 int rc = suplibOsIOCtl(SUP_IOCTL_PAGE_UNLOCK, &Req, SUP_IOCTL_PAGE_UNLOCK_SIZE);
732 if (RT_SUCCESS(rc))
733 rc = Req.Hdr.rc;
734 return rc;
735}
736
737
738SUPR3DECL(int) SUPPageAllocLocked(size_t cPages, void **ppvPages)
739{
740 return SUPPageAllocLockedEx(cPages, ppvPages, NULL);
741}
742
743
744/**
745 * Fallback for SUPPageAllocLockedEx on systems where RTR0MemObjPhysAllocNC isn't supported.
746 */
747static int supPageAllocLockedFallback(size_t cPages, void **ppvPages, PSUPPAGE paPages)
748{
749 int rc = suplibOsPageAlloc(cPages, ppvPages);
750 if (RT_SUCCESS(rc))
751 {
752 if (!paPages)
753 paPages = (PSUPPAGE)alloca(sizeof(paPages[0]) * cPages);
754 rc = SUPPageLock(*ppvPages, cPages, paPages);
755 if (RT_FAILURE(rc))
756 suplibOsPageFree(*ppvPages, cPages);
757 }
758 return rc;
759}
760
761
762SUPR3DECL(int) SUPPageAllocLockedEx(size_t cPages, void **ppvPages, PSUPPAGE paPages)
763{
764 /*
765 * Validate.
766 */
767 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
768 *ppvPages = NULL;
769 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
770
771 /* fake */
772 if (RT_UNLIKELY(g_u32FakeMode))
773 {
774 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
775 if (!*ppvPages)
776 return VERR_NO_MEMORY;
777 if (paPages)
778 for (size_t iPage = 0; iPage < cPages; iPage++)
779 {
780 paPages[iPage].uReserved = 0;
781 paPages[iPage].Phys = (iPage + 1234) << PAGE_SHIFT;
782 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
783 }
784 return VINF_SUCCESS;
785 }
786
787 /* use fallback? */
788 if (!g_fSupportsPageAllocLocked)
789 return supPageAllocLockedFallback(cPages, ppvPages, paPages);
790
791 /*
792 * Issue IOCtl to the SUPDRV kernel module.
793 */
794 int rc;
795 PSUPPAGEALLOC pReq = (PSUPPAGEALLOC)RTMemTmpAllocZ(SUP_IOCTL_PAGE_ALLOC_SIZE(cPages));
796 if (pReq)
797 {
798 pReq->Hdr.u32Cookie = g_u32Cookie;
799 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
800 pReq->Hdr.cbIn = SUP_IOCTL_PAGE_ALLOC_SIZE_IN;
801 pReq->Hdr.cbOut = SUP_IOCTL_PAGE_ALLOC_SIZE_OUT(cPages);
802 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
803 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
804 pReq->u.In.cPages = cPages; AssertRelease(pReq->u.In.cPages == cPages);
805 rc = suplibOsIOCtl(SUP_IOCTL_PAGE_ALLOC, pReq, SUP_IOCTL_PAGE_ALLOC_SIZE(cPages));
806 if (RT_SUCCESS(rc))
807 {
808 rc = pReq->Hdr.rc;
809 if (RT_SUCCESS(rc))
810 {
811 *ppvPages = pReq->u.Out.pvR3;
812 if (paPages)
813 for (size_t iPage = 0; iPage < cPages; iPage++)
814 {
815 paPages[iPage].uReserved = 0;
816 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
817 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
818 }
819 }
820 else if (rc == VERR_NOT_SUPPORTED)
821 {
822 g_fSupportsPageAllocLocked = false;
823 rc = supPageAllocLockedFallback(cPages, ppvPages, paPages);
824 }
825 }
826
827 RTMemTmpFree(pReq);
828 }
829 else
830 rc = VERR_NO_TMP_MEMORY;
831 return rc;
832}
833
834
835SUPR3DECL(int) SUPPageFreeLocked(void *pvPages, size_t cPages)
836{
837 /*
838 * Validate.
839 */
840 AssertPtrReturn(pvPages, VERR_INVALID_POINTER);
841 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
842
843 /* fake */
844 if (RT_UNLIKELY(g_u32FakeMode))
845 {
846 RTMemPageFree(pvPages);
847 return VINF_SUCCESS;
848 }
849
850 /*
851 * Issue IOCtl to the SUPDRV kernel module.
852 */
853 int rc;
854 if (g_fSupportsPageAllocLocked)
855 {
856 SUPPAGEFREE Req;
857 Req.Hdr.u32Cookie = g_u32Cookie;
858 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
859 Req.Hdr.cbIn = SUP_IOCTL_PAGE_FREE_SIZE_IN;
860 Req.Hdr.cbOut = SUP_IOCTL_PAGE_FREE_SIZE_OUT;
861 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
862 Req.Hdr.rc = VERR_INTERNAL_ERROR;
863 Req.u.In.pvR3 = pvPages;
864 rc = suplibOsIOCtl(SUP_IOCTL_PAGE_FREE, &Req, SUP_IOCTL_PAGE_FREE_SIZE);
865 if (RT_SUCCESS(rc))
866 rc = Req.Hdr.rc;
867 }
868 else
869 {
870 /* fallback */
871 rc = SUPPageUnlock(pvPages);
872 if (RT_SUCCESS(rc))
873 rc = suplibOsPageFree(pvPages, cPages);
874 }
875 return rc;
876}
877
878
879SUPR3DECL(void *) SUPContAlloc(size_t cPages, PRTHCPHYS pHCPhys)
880{
881 return SUPContAlloc2(cPages, NIL_RTR0PTR, pHCPhys);
882}
883
884
885SUPR3DECL(void *) SUPContAlloc2(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys)
886{
887 /*
888 * Validate.
889 */
890 AssertPtrReturn(pHCPhys, NULL);
891 *pHCPhys = NIL_RTHCPHYS;
892 AssertPtrNullReturn(pR0Ptr, NULL);
893 if (pR0Ptr)
894 *pR0Ptr = NIL_RTR0PTR;
895 AssertPtrNullReturn(pHCPhys, NULL);
896 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), NULL);
897
898 /* fake */
899 if (RT_UNLIKELY(g_u32FakeMode))
900 {
901 void *pv = RTMemPageAllocZ(cPages * PAGE_SIZE);
902 if (pR0Ptr)
903 *pR0Ptr = (RTR0PTR)pv;
904 if (pHCPhys)
905 *pHCPhys = (uintptr_t)pv + (PAGE_SHIFT * 1024);
906 return pv;
907 }
908
909 /*
910 * Issue IOCtl to the SUPDRV kernel module.
911 */
912 SUPCONTALLOC Req;
913 Req.Hdr.u32Cookie = g_u32Cookie;
914 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
915 Req.Hdr.cbIn = SUP_IOCTL_CONT_ALLOC_SIZE_IN;
916 Req.Hdr.cbOut = SUP_IOCTL_CONT_ALLOC_SIZE_OUT;
917 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
918 Req.Hdr.rc = VERR_INTERNAL_ERROR;
919 Req.u.In.cPages = cPages;
920 int rc = suplibOsIOCtl(SUP_IOCTL_CONT_ALLOC, &Req, SUP_IOCTL_CONT_ALLOC_SIZE);
921 if ( RT_SUCCESS(rc)
922 && RT_SUCCESS(Req.Hdr.rc))
923 {
924 *pHCPhys = Req.u.Out.HCPhys;
925 if (pR0Ptr)
926 *pR0Ptr = Req.u.Out.pvR0;
927 return Req.u.Out.pvR3;
928 }
929
930 return NULL;
931}
932
933
934SUPR3DECL(int) SUPContFree(void *pv, size_t cPages)
935{
936 /*
937 * Validate.
938 */
939 if (!pv)
940 return VINF_SUCCESS;
941 AssertPtrReturn(pv, VERR_INVALID_POINTER);
942 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
943
944 /* fake */
945 if (RT_UNLIKELY(g_u32FakeMode))
946 {
947 RTMemPageFree(pv);
948 return VINF_SUCCESS;
949 }
950
951 /*
952 * Issue IOCtl to the SUPDRV kernel module.
953 */
954 SUPCONTFREE Req;
955 Req.Hdr.u32Cookie = g_u32Cookie;
956 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
957 Req.Hdr.cbIn = SUP_IOCTL_CONT_FREE_SIZE_IN;
958 Req.Hdr.cbOut = SUP_IOCTL_CONT_FREE_SIZE_OUT;
959 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
960 Req.Hdr.rc = VERR_INTERNAL_ERROR;
961 Req.u.In.pvR3 = pv;
962 int rc = suplibOsIOCtl(SUP_IOCTL_CONT_FREE, &Req, SUP_IOCTL_CONT_FREE_SIZE);
963 if (RT_SUCCESS(rc))
964 rc = Req.Hdr.rc;
965 return rc;
966}
967
968
969SUPR3DECL(int) SUPLowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages)
970{
971 /*
972 * Validate.
973 */
974 AssertPtrReturn(ppvPages, VERR_INVALID_POINTER);
975 *ppvPages = NULL;
976 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
977 AssertMsgReturn(cPages > 0 && cPages < 256, ("cPages=%d must be > 0 and < 256\n", cPages), VERR_INVALID_PARAMETER);
978
979 /* fake */
980 if (RT_UNLIKELY(g_u32FakeMode))
981 {
982 *ppvPages = RTMemPageAllocZ((size_t)cPages * PAGE_SIZE);
983 if (!*ppvPages)
984 return VERR_NO_LOW_MEMORY;
985
986 /* fake physical addresses. */
987 RTHCPHYS Phys = (uintptr_t)*ppvPages + PAGE_SIZE * 1024;
988 unsigned iPage = cPages;
989 while (iPage-- > 0)
990 paPages[iPage].Phys = Phys + (iPage << PAGE_SHIFT);
991 return VINF_SUCCESS;
992 }
993
994 /*
995 * Issue IOCtl to the SUPDRV kernel module.
996 */
997 int rc;
998 PSUPLOWALLOC pReq = (PSUPLOWALLOC)RTMemTmpAllocZ(SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
999 if (pReq)
1000 {
1001 pReq->Hdr.u32Cookie = g_u32Cookie;
1002 pReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1003 pReq->Hdr.cbIn = SUP_IOCTL_LOW_ALLOC_SIZE_IN;
1004 pReq->Hdr.cbOut = SUP_IOCTL_LOW_ALLOC_SIZE_OUT(cPages);
1005 pReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_OUT;
1006 pReq->Hdr.rc = VERR_INTERNAL_ERROR;
1007 pReq->u.In.cPages = cPages; AssertRelease(pReq->u.In.cPages == cPages);
1008 rc = suplibOsIOCtl(SUP_IOCTL_LOW_ALLOC, pReq, SUP_IOCTL_LOW_ALLOC_SIZE(cPages));
1009 if (RT_SUCCESS(rc))
1010 rc = pReq->Hdr.rc;
1011 if (RT_SUCCESS(rc))
1012 {
1013 *ppvPages = pReq->u.Out.pvR3;
1014 if (ppvPagesR0)
1015 *ppvPagesR0 = pReq->u.Out.pvR0;
1016 if (paPages)
1017 for (size_t iPage = 0; iPage < cPages; iPage++)
1018 {
1019 paPages[iPage].uReserved = 0;
1020 paPages[iPage].Phys = pReq->u.Out.aPages[iPage];
1021 Assert(!(paPages[iPage].Phys & ~X86_PTE_PAE_PG_MASK));
1022 Assert(paPages[iPage].Phys <= UINT32_C(0xfffff000));
1023 }
1024 }
1025 RTMemTmpFree(pReq);
1026 }
1027 else
1028 rc = VERR_NO_TMP_MEMORY;
1029
1030 return rc;
1031}
1032
1033
1034SUPR3DECL(int) SUPLowFree(void *pv, size_t cPages)
1035{
1036 /*
1037 * Validate.
1038 */
1039 if (!pv)
1040 return VINF_SUCCESS;
1041 AssertPtrReturn(pv, VERR_INVALID_POINTER);
1042 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
1043
1044 /* fake */
1045 if (RT_UNLIKELY(g_u32FakeMode))
1046 {
1047 RTMemPageFree(pv);
1048 return VINF_SUCCESS;
1049 }
1050
1051 /*
1052 * Issue IOCtl to the SUPDRV kernel module.
1053 */
1054 SUPCONTFREE Req;
1055 Req.Hdr.u32Cookie = g_u32Cookie;
1056 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1057 Req.Hdr.cbIn = SUP_IOCTL_LOW_FREE_SIZE_IN;
1058 Req.Hdr.cbOut = SUP_IOCTL_LOW_FREE_SIZE_OUT;
1059 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1060 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1061 Req.u.In.pvR3 = pv;
1062 int rc = suplibOsIOCtl(SUP_IOCTL_LOW_FREE, &Req, SUP_IOCTL_LOW_FREE_SIZE);
1063 if (RT_SUCCESS(rc))
1064 rc = Req.Hdr.rc;
1065 return rc;
1066}
1067
1068
1069SUPR3DECL(int) SUPLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
1070{
1071 /*
1072 * Load the module.
1073 * If it's VMMR0.r0 we need to install the IDTE.
1074 */
1075 int rc = supLoadModule(pszFilename, pszModule, ppvImageBase);
1076#ifdef VBOX_WITH_IDT_PATCHING
1077 if ( RT_SUCCESS(rc)
1078 && !strcmp(pszModule, "VMMR0.r0"))
1079 {
1080 rc = supInstallIDTE();
1081 if (RT_FAILURE(rc))
1082 SUPFreeModule(*ppvImageBase);
1083 }
1084#endif /* VBOX_WITH_IDT_PATCHING */
1085
1086 return rc;
1087}
1088
1089
1090#ifdef VBOX_WITH_IDT_PATCHING
1091/**
1092 * Generates the code for calling the interrupt gate.
1093 *
1094 * @returns VBox status code.
1095 * g_pfnCallVMMR0 is changed on success.
1096 * @param u8Interrupt The interrupt number.
1097 */
1098static int suplibGenerateCallVMMR0(uint8_t u8Interrupt)
1099{
1100 /*
1101 * Allocate memory.
1102 */
1103 uint8_t *pb = (uint8_t *)RTMemExecAlloc(256);
1104 AssertReturn(pb, VERR_NO_MEMORY);
1105 memset(pb, 0xcc, 256);
1106 Assert(!g_pfnCallVMMR0);
1107 g_pfnCallVMMR0 = *(PFNCALLVMMR0*)&pb;
1108
1109 /*
1110 * Generate the code.
1111 */
1112#ifdef RT_ARCH_AMD64
1113 /*
1114 * reg params:
1115 * <GCC> <MSC> <argument>
1116 * rdi rcx pVMR0
1117 * esi edx uOperation
1118 * rdx r8 pvArg
1119 *
1120 * eax eax [g_u32Gookie]
1121 */
1122 *pb++ = 0xb8; /* mov eax, <g_u32Cookie> */
1123 *(uint32_t *)pb = g_u32Cookie;
1124 pb += sizeof(uint32_t);
1125
1126 *pb++ = 0xcd; /* int <u8Interrupt> */
1127 *pb++ = u8Interrupt;
1128
1129 *pb++ = 0xc3; /* ret */
1130
1131#else
1132 /*
1133 * x86 stack:
1134 * 0 saved esi
1135 * 0 4 ret
1136 * 4 8 pVM
1137 * 8 c uOperation
1138 * c 10 pvArg
1139 */
1140 *pb++ = 0x56; /* push esi */
1141
1142 *pb++ = 0x8b; /* mov eax, [pVM] */
1143 *pb++ = 0x44;
1144 *pb++ = 0x24;
1145 *pb++ = 0x08; /* esp+08h */
1146
1147 *pb++ = 0x8b; /* mov edx, [uOperation] */
1148 *pb++ = 0x54;
1149 *pb++ = 0x24;
1150 *pb++ = 0x0c; /* esp+0ch */
1151
1152 *pb++ = 0x8b; /* mov ecx, [pvArg] */
1153 *pb++ = 0x4c;
1154 *pb++ = 0x24;
1155 *pb++ = 0x10; /* esp+10h */
1156
1157 *pb++ = 0xbe; /* mov esi, <g_u32Cookie> */
1158 *(uint32_t *)pb = g_u32Cookie;
1159 pb += sizeof(uint32_t);
1160
1161 *pb++ = 0xcd; /* int <u8Interrupt> */
1162 *pb++ = u8Interrupt;
1163
1164 *pb++ = 0x5e; /* pop esi */
1165
1166 *pb++ = 0xc3; /* ret */
1167#endif
1168
1169 return VINF_SUCCESS;
1170}
1171
1172
1173/**
1174 * Installs the IDTE patch.
1175 *
1176 * @return VBox status code.
1177 */
1178static int supInstallIDTE(void)
1179{
1180 /* already installed? */
1181 if (g_u8Interrupt != 3 || g_u32FakeMode)
1182 return VINF_SUCCESS;
1183
1184 int rc = VINF_SUCCESS;
1185 const unsigned cCpus = RTSystemProcessorGetCount();
1186 if (cCpus <= 1)
1187 {
1188 /* UNI */
1189 SUPIDTINSTALL Req;
1190 Req.Hdr.u32Cookie = g_u32Cookie;
1191 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1192 Req.Hdr.cbIn = SUP_IOCTL_IDT_INSTALL_SIZE_IN;
1193 Req.Hdr.cbOut = SUP_IOCTL_IDT_INSTALL_SIZE_OUT;
1194 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1195 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1196 rc = suplibOsIOCtl(SUP_IOCTL_IDT_INSTALL, &Req, SUP_IOCTL_IDT_INSTALL_SIZE);
1197 if (RT_SUCCESS(rc))
1198 rc = Req.Hdr.rc;
1199 if (RT_SUCCESS(rc))
1200 {
1201 g_u8Interrupt = Req.u.Out.u8Idt;
1202 rc = suplibGenerateCallVMMR0(Req.u.Out.u8Idt);
1203 }
1204 }
1205 else
1206 {
1207 /* SMP */
1208 uint64_t u64AffMaskSaved = RTThreadGetAffinity();
1209 uint64_t u64AffMaskPatched = RTSystemProcessorGetActiveMask() & u64AffMaskSaved;
1210 unsigned cCpusPatched = 0;
1211
1212 for (int i = 0; i < 64; i++)
1213 {
1214 /* Skip absent and inactive processors. */
1215 uint64_t u64Mask = 1ULL << i;
1216 if (!(u64Mask & u64AffMaskPatched))
1217 continue;
1218
1219 /* Change CPU */
1220 int rc2 = RTThreadSetAffinity(u64Mask);
1221 if (RT_FAILURE(rc2))
1222 {
1223 u64AffMaskPatched &= ~u64Mask;
1224 LogRel(("SUPLoadVMM: Failed to set affinity to cpu no. %d, rc=%Vrc.\n", i, rc2));
1225 continue;
1226 }
1227
1228 /* Patch the CPU. */
1229 SUPIDTINSTALL Req;
1230 Req.Hdr.u32Cookie = g_u32Cookie;
1231 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1232 Req.Hdr.cbIn = SUP_IOCTL_IDT_INSTALL_SIZE_IN;
1233 Req.Hdr.cbOut = SUP_IOCTL_IDT_INSTALL_SIZE_OUT;
1234 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1235 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1236 rc2 = suplibOsIOCtl(SUP_IOCTL_IDT_INSTALL, &Req, SUP_IOCTL_IDT_INSTALL_SIZE);
1237 if (RT_SUCCESS(rc2))
1238 rc2 = Req.Hdr.rc;
1239 if (RT_SUCCESS(rc2))
1240 {
1241 if (!cCpusPatched)
1242 {
1243 g_u8Interrupt = Req.u.Out.u8Idt;
1244 rc2 = suplibGenerateCallVMMR0(Req.u.Out.u8Idt);
1245 if (RT_FAILURE(rc2))
1246 {
1247 LogRel(("suplibGenerateCallVMMR0 failed with rc=%Vrc.\n", i, rc2));
1248 rc = rc2;
1249 }
1250 }
1251 else
1252 Assert(g_u8Interrupt == Req.u.Out.u8Idt);
1253 cCpusPatched++;
1254 }
1255 else
1256 {
1257
1258 LogRel(("SUPLoadVMM: Failed to patch cpu no. %d, rc=%Vrc.\n", i, rc2));
1259 if (RT_SUCCESS(rc))
1260 rc = rc2;
1261 }
1262 }
1263
1264 /* Fail if no CPUs was patched! */
1265 if (RT_SUCCESS(rc) && cCpusPatched <= 0)
1266 rc = VERR_GENERAL_FAILURE;
1267 /* Ignore failures if a CPU was patched. */
1268 else if (RT_FAILURE(rc) && cCpusPatched > 0)
1269 rc = VINF_SUCCESS;
1270
1271 /* Set/restore the thread affinity. */
1272 if (RT_SUCCESS(rc))
1273 {
1274 rc = RTThreadSetAffinity(u64AffMaskPatched);
1275 AssertRC(rc);
1276 }
1277 else
1278 {
1279 int rc2 = RTThreadSetAffinity(u64AffMaskSaved);
1280 AssertRC(rc2);
1281 }
1282 }
1283 return rc;
1284}
1285#endif /* VBOX_WITH_IDT_PATCHING */
1286
1287
1288/**
1289 * Resolve an external symbol during RTLdrGetBits().
1290 *
1291 * @returns VBox status code.
1292 * @param hLdrMod The loader module handle.
1293 * @param pszModule Module name.
1294 * @param pszSymbol Symbol name, NULL if uSymbol should be used.
1295 * @param uSymbol Symbol ordinal, ~0 if pszSymbol should be used.
1296 * @param pValue Where to store the symbol value (address).
1297 * @param pvUser User argument.
1298 */
1299static DECLCALLBACK(int) supLoadModuleResolveImport(RTLDRMOD hLdrMod, const char *pszModule,
1300 const char *pszSymbol, unsigned uSymbol, RTUINTPTR *pValue, void *pvUser)
1301{
1302 AssertPtr(pValue);
1303 AssertPtr(pvUser);
1304
1305 /*
1306 * Only SUPR0 and VMMR0.r0
1307 */
1308 if ( pszModule
1309 && *pszModule
1310 && strcmp(pszModule, "SUPR0.dll")
1311 && strcmp(pszModule, "VMMR0.r0"))
1312 {
1313 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitiv)\n", pvUser, pszModule));
1314 return VERR_SYMBOL_NOT_FOUND;
1315 }
1316
1317 /*
1318 * No ordinals.
1319 */
1320 if (pszSymbol < (const char*)0x10000)
1321 {
1322 AssertMsgFailed(("%s is importing by ordinal (ord=%d)\n", pvUser, (int)(uintptr_t)pszSymbol));
1323 return VERR_SYMBOL_NOT_FOUND;
1324 }
1325
1326 /*
1327 * Lookup symbol.
1328 */
1329 /* skip the 64-bit ELF import prefix first. */
1330 if (!strncmp(pszSymbol, "SUPR0$", sizeof("SUPR0$") - 1))
1331 pszSymbol += sizeof("SUPR0$") - 1;
1332
1333 /*
1334 * Check the VMMR0.r0 module if loaded.
1335 */
1336 /** @todo call the SUPLoadModule caller.... */
1337 /** @todo proper reference counting and such. */
1338 if (g_pvVMMR0 != NIL_RTR0PTR)
1339 {
1340 void *pvValue;
1341 if (!SUPGetSymbolR0((void *)g_pvVMMR0, pszSymbol, &pvValue))
1342 {
1343 *pValue = (uintptr_t)pvValue;
1344 return VINF_SUCCESS;
1345 }
1346 }
1347
1348 /* iterate the function table. */
1349 int c = g_pFunctions->u.Out.cFunctions;
1350 PSUPFUNC pFunc = &g_pFunctions->u.Out.aFunctions[0];
1351 while (c-- > 0)
1352 {
1353 if (!strcmp(pFunc->szName, pszSymbol))
1354 {
1355 *pValue = (uintptr_t)pFunc->pfn;
1356 return VINF_SUCCESS;
1357 }
1358 pFunc++;
1359 }
1360
1361 /*
1362 * The GIP.
1363 */
1364 /** @todo R0 mapping? */
1365 if ( pszSymbol
1366 && g_pSUPGlobalInfoPage
1367 && g_pSUPGlobalInfoPageR0
1368 && !strcmp(pszSymbol, "g_SUPGlobalInfoPage"))
1369 {
1370 *pValue = (uintptr_t)g_pSUPGlobalInfoPageR0;
1371 return VINF_SUCCESS;
1372 }
1373
1374 /*
1375 * Despair.
1376 */
1377 c = g_pFunctions->u.Out.cFunctions;
1378 pFunc = &g_pFunctions->u.Out.aFunctions[0];
1379 while (c-- > 0)
1380 {
1381 AssertMsg2("%d: %s\n", g_pFunctions->u.Out.cFunctions - c, pFunc->szName);
1382 pFunc++;
1383 }
1384
1385 AssertMsg2("%s is importing %s which we couldn't find\n", pvUser, pszSymbol);
1386 AssertMsgFailed(("%s is importing %s which we couldn't find\n", pvUser, pszSymbol));
1387 if (g_u32FakeMode)
1388 {
1389 *pValue = 0xdeadbeef;
1390 return VINF_SUCCESS;
1391 }
1392 return VERR_SYMBOL_NOT_FOUND;
1393}
1394
1395
1396/** Argument package for supLoadModuleCalcSizeCB. */
1397typedef struct SUPLDRCALCSIZEARGS
1398{
1399 size_t cbStrings;
1400 uint32_t cSymbols;
1401 size_t cbImage;
1402} SUPLDRCALCSIZEARGS, *PSUPLDRCALCSIZEARGS;
1403
1404/**
1405 * Callback used to calculate the image size.
1406 * @return VINF_SUCCESS
1407 */
1408static DECLCALLBACK(int) supLoadModuleCalcSizeCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1409{
1410 PSUPLDRCALCSIZEARGS pArgs = (PSUPLDRCALCSIZEARGS)pvUser;
1411 if ( pszSymbol != NULL
1412 && *pszSymbol
1413 && Value <= pArgs->cbImage)
1414 {
1415 pArgs->cSymbols++;
1416 pArgs->cbStrings += strlen(pszSymbol) + 1;
1417 }
1418 return VINF_SUCCESS;
1419}
1420
1421
1422/** Argument package for supLoadModuleCreateTabsCB. */
1423typedef struct SUPLDRCREATETABSARGS
1424{
1425 size_t cbImage;
1426 PSUPLDRSYM pSym;
1427 char *pszBase;
1428 char *psz;
1429} SUPLDRCREATETABSARGS, *PSUPLDRCREATETABSARGS;
1430
1431/**
1432 * Callback used to calculate the image size.
1433 * @return VINF_SUCCESS
1434 */
1435static DECLCALLBACK(int) supLoadModuleCreateTabsCB(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol, RTUINTPTR Value, void *pvUser)
1436{
1437 PSUPLDRCREATETABSARGS pArgs = (PSUPLDRCREATETABSARGS)pvUser;
1438 if ( pszSymbol != NULL
1439 && *pszSymbol
1440 && Value <= pArgs->cbImage)
1441 {
1442 pArgs->pSym->offSymbol = (uint32_t)Value;
1443 pArgs->pSym->offName = pArgs->psz - pArgs->pszBase;
1444 pArgs->pSym++;
1445
1446 size_t cbCopy = strlen(pszSymbol) + 1;
1447 memcpy(pArgs->psz, pszSymbol, cbCopy);
1448 pArgs->psz += cbCopy;
1449 }
1450 return VINF_SUCCESS;
1451}
1452
1453
1454/**
1455 * Worker for SUPLoadModule().
1456 *
1457 * @returns VBox status code.
1458 * @param pszFilename Name of the VMMR0 image file
1459 */
1460static int supLoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase)
1461{
1462 /*
1463 * Validate input.
1464 */
1465 AssertPtrReturn(pszFilename, VERR_INVALID_PARAMETER);
1466 AssertPtrReturn(pszModule, VERR_INVALID_PARAMETER);
1467 AssertPtrReturn(ppvImageBase, VERR_INVALID_PARAMETER);
1468 AssertReturn(strlen(pszModule) < RT_SIZEOFMEMB(SUPLDROPEN, u.In.szName), VERR_FILENAME_TOO_LONG);
1469
1470 const bool fIsVMMR0 = !strcmp(pszModule, "VMMR0.r0");
1471 *ppvImageBase = NULL;
1472
1473 /*
1474 * Open image file and figure its size.
1475 */
1476 RTLDRMOD hLdrMod;
1477 int rc = RTLdrOpen(pszFilename, &hLdrMod);
1478 if (!RT_SUCCESS(rc))
1479 return rc;
1480
1481 SUPLDRCALCSIZEARGS CalcArgs;
1482 CalcArgs.cbStrings = 0;
1483 CalcArgs.cSymbols = 0;
1484 CalcArgs.cbImage = RTLdrSize(hLdrMod);
1485 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCalcSizeCB, &CalcArgs);
1486 if (RT_SUCCESS(rc))
1487 {
1488 const uint32_t offSymTab = RT_ALIGN_32(CalcArgs.cbImage, 8);
1489 const uint32_t offStrTab = offSymTab + CalcArgs.cSymbols * sizeof(SUPLDRSYM);
1490 const uint32_t cbImage = RT_ALIGN_32(offStrTab + CalcArgs.cbStrings, 8);
1491
1492 /*
1493 * Open the R0 image.
1494 */
1495 SUPLDROPEN OpenReq;
1496 OpenReq.Hdr.u32Cookie = g_u32Cookie;
1497 OpenReq.Hdr.u32SessionCookie = g_u32SessionCookie;
1498 OpenReq.Hdr.cbIn = SUP_IOCTL_LDR_OPEN_SIZE_IN;
1499 OpenReq.Hdr.cbOut = SUP_IOCTL_LDR_OPEN_SIZE_OUT;
1500 OpenReq.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1501 OpenReq.Hdr.rc = VERR_INTERNAL_ERROR;
1502 OpenReq.u.In.cbImage = cbImage;
1503 strcpy(OpenReq.u.In.szName, pszModule);
1504 if (!g_u32FakeMode)
1505 {
1506 rc = suplibOsIOCtl(SUP_IOCTL_LDR_OPEN, &OpenReq, SUP_IOCTL_LDR_OPEN_SIZE);
1507 if (RT_SUCCESS(rc))
1508 rc = OpenReq.Hdr.rc;
1509 }
1510 else
1511 {
1512 OpenReq.u.Out.fNeedsLoading = true;
1513 OpenReq.u.Out.pvImageBase = 0xef423420;
1514 }
1515 *ppvImageBase = (void *)OpenReq.u.Out.pvImageBase;
1516 if ( RT_SUCCESS(rc)
1517 && OpenReq.u.Out.fNeedsLoading)
1518 {
1519 /*
1520 * We need to load it.
1521 * Allocate memory for the image bits.
1522 */
1523 PSUPLDRLOAD pLoadReq = (PSUPLDRLOAD)RTMemTmpAlloc(SUP_IOCTL_LDR_LOAD_SIZE(cbImage));
1524 if (pLoadReq)
1525 {
1526 /*
1527 * Get the image bits.
1528 */
1529 rc = RTLdrGetBits(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase,
1530 supLoadModuleResolveImport, (void *)pszModule);
1531
1532 if (RT_SUCCESS(rc))
1533 {
1534 /*
1535 * Get the entry points.
1536 */
1537 RTUINTPTR VMMR0EntryInt = 0;
1538 RTUINTPTR VMMR0EntryFast = 0;
1539 RTUINTPTR VMMR0EntryEx = 0;
1540 RTUINTPTR ModuleInit = 0;
1541 RTUINTPTR ModuleTerm = 0;
1542 if (fIsVMMR0)
1543 {
1544 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryInt", &VMMR0EntryInt);
1545 if (RT_SUCCESS(rc))
1546 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryFast", &VMMR0EntryFast);
1547 if (RT_SUCCESS(rc))
1548 rc = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "VMMR0EntryEx", &VMMR0EntryEx);
1549 }
1550 if (RT_SUCCESS(rc))
1551 {
1552 int rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleInit", &ModuleInit);
1553 if (RT_FAILURE(rc2))
1554 ModuleInit = 0;
1555
1556 rc2 = RTLdrGetSymbolEx(hLdrMod, &pLoadReq->u.In.achImage[0], (uintptr_t)OpenReq.u.Out.pvImageBase, "ModuleTerm", &ModuleTerm);
1557 if (RT_FAILURE(rc2))
1558 ModuleTerm = 0;
1559 }
1560 if (RT_SUCCESS(rc))
1561 {
1562 /*
1563 * Create the symbol and string tables.
1564 */
1565 SUPLDRCREATETABSARGS CreateArgs;
1566 CreateArgs.cbImage = CalcArgs.cbImage;
1567 CreateArgs.pSym = (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab];
1568 CreateArgs.pszBase = (char *)&pLoadReq->u.In.achImage[offStrTab];
1569 CreateArgs.psz = CreateArgs.pszBase;
1570 rc = RTLdrEnumSymbols(hLdrMod, 0, NULL, 0, supLoadModuleCreateTabsCB, &CreateArgs);
1571 if (RT_SUCCESS(rc))
1572 {
1573 AssertRelease((size_t)(CreateArgs.psz - CreateArgs.pszBase) <= CalcArgs.cbStrings);
1574 AssertRelease((size_t)(CreateArgs.pSym - (PSUPLDRSYM)&pLoadReq->u.In.achImage[offSymTab]) <= CalcArgs.cSymbols);
1575
1576 /*
1577 * Upload the image.
1578 */
1579 pLoadReq->Hdr.u32Cookie = g_u32Cookie;
1580 pLoadReq->Hdr.u32SessionCookie = g_u32SessionCookie;
1581 pLoadReq->Hdr.cbIn = SUP_IOCTL_LDR_LOAD_SIZE_IN(cbImage);
1582 pLoadReq->Hdr.cbOut = SUP_IOCTL_LDR_LOAD_SIZE_OUT;
1583 pLoadReq->Hdr.fFlags = SUPREQHDR_FLAGS_MAGIC | SUPREQHDR_FLAGS_EXTRA_IN;
1584 pLoadReq->Hdr.rc = VERR_INTERNAL_ERROR;
1585
1586 pLoadReq->u.In.pfnModuleInit = (RTR0PTR)ModuleInit;
1587 pLoadReq->u.In.pfnModuleTerm = (RTR0PTR)ModuleTerm;
1588 if (fIsVMMR0)
1589 {
1590 pLoadReq->u.In.eEPType = SUPLDRLOADEP_VMMR0;
1591 pLoadReq->u.In.EP.VMMR0.pvVMMR0 = OpenReq.u.Out.pvImageBase;
1592 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryInt = (RTR0PTR)VMMR0EntryInt;
1593 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryFast= (RTR0PTR)VMMR0EntryFast;
1594 pLoadReq->u.In.EP.VMMR0.pvVMMR0EntryEx = (RTR0PTR)VMMR0EntryEx;
1595 }
1596 else
1597 pLoadReq->u.In.eEPType = SUPLDRLOADEP_NOTHING;
1598 pLoadReq->u.In.offStrTab = offStrTab;
1599 pLoadReq->u.In.cbStrTab = (uint32_t)CalcArgs.cbStrings;
1600 AssertRelease(pLoadReq->u.In.cbStrTab == CalcArgs.cbStrings);
1601 pLoadReq->u.In.offSymbols = offSymTab;
1602 pLoadReq->u.In.cSymbols = CalcArgs.cSymbols;
1603 pLoadReq->u.In.cbImage = cbImage;
1604 pLoadReq->u.In.pvImageBase = OpenReq.u.Out.pvImageBase;
1605 if (!g_u32FakeMode)
1606 {
1607 rc = suplibOsIOCtl(SUP_IOCTL_LDR_LOAD, pLoadReq, SUP_IOCTL_LDR_LOAD_SIZE(cbImage));
1608 if (RT_SUCCESS(rc))
1609 rc = pLoadReq->Hdr.rc;
1610 }
1611 else
1612 rc = VINF_SUCCESS;
1613 if ( RT_SUCCESS(rc)
1614 || rc == VERR_ALREADY_LOADED /* A competing process. */
1615 )
1616 {
1617 LogRel(("SUP: Loaded %s (%s) at %#p - ModuleInit at %RTptr and ModuleTerm at %RTptr\n", pszModule, pszFilename,
1618 OpenReq.u.Out.pvImageBase, ModuleInit, ModuleTerm));
1619 if (fIsVMMR0)
1620 {
1621 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1622 LogRel(("SUP: VMMR0EntryEx located at %RTptr, VMMR0EntryFast at %RTptr and VMMR0EntryInt at %RTptr\n",
1623 VMMR0EntryEx, VMMR0EntryFast, VMMR0EntryInt));
1624 }
1625#ifdef RT_OS_WINDOWS
1626 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1627#endif
1628
1629 RTMemTmpFree(pLoadReq);
1630 RTLdrClose(hLdrMod);
1631 return VINF_SUCCESS;
1632 }
1633 }
1634 }
1635 }
1636 RTMemTmpFree(pLoadReq);
1637 }
1638 else
1639 {
1640 AssertMsgFailed(("failed to allocated %d bytes for SUPLDRLOAD_IN structure!\n", SUP_IOCTL_LDR_LOAD_SIZE(cbImage)));
1641 rc = VERR_NO_TMP_MEMORY;
1642 }
1643 }
1644 else if (RT_SUCCESS(rc))
1645 {
1646 if (fIsVMMR0)
1647 g_pvVMMR0 = OpenReq.u.Out.pvImageBase;
1648 LogRel(("SUP: Opened %s (%s) at %#p.\n", pszModule, pszFilename, OpenReq.u.Out.pvImageBase));
1649#ifdef RT_OS_WINDOWS
1650 LogRel(("SUP: windbg> .reload /f %s=%#p\n", pszFilename, OpenReq.u.Out.pvImageBase));
1651#endif
1652 }
1653 }
1654 RTLdrClose(hLdrMod);
1655 return rc;
1656}
1657
1658
1659SUPR3DECL(int) SUPFreeModule(void *pvImageBase)
1660{
1661 /* fake */
1662 if (RT_UNLIKELY(g_u32FakeMode))
1663 {
1664#ifdef VBOX_WITH_IDT_PATCHING
1665 g_u8Interrupt = 3;
1666 RTMemExecFree(*(void **)&g_pfnCallVMMR0);
1667 g_pfnCallVMMR0 = NULL;
1668#endif
1669 g_pvVMMR0 = NIL_RTR0PTR;
1670 return VINF_SUCCESS;
1671 }
1672
1673#ifdef VBOX_WITH_IDT_PATCHING
1674 /*
1675 * There is one special module. When this is freed we'll
1676 * free the IDT entry that goes with it.
1677 *
1678 * Note that we don't keep count of VMMR0.r0 loads here, so the
1679 * first unload will free it.
1680 */
1681 if ( (RTR0PTR)pvImageBase == g_pvVMMR0
1682 && g_u8Interrupt != 3)
1683 {
1684 SUPIDTREMOVE Req;
1685 Req.Hdr.u32Cookie = g_u32Cookie;
1686 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1687 Req.Hdr.cbIn = SUP_IOCTL_IDT_REMOVE_SIZE_IN;
1688 Req.Hdr.cbOut = SUP_IOCTL_IDT_REMOVE_SIZE_OUT;
1689 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1690 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1691 int rc = suplibOsIOCtl(SUP_IOCTL_IDT_REMOVE, &Req, SUP_IOCTL_IDT_REMOVE_SIZE);
1692 if (RT_SUCCESS(rc))
1693 rc = Req.Hdr.rc;
1694 AssertRC(rc);
1695 g_u8Interrupt = 3;
1696 RTMemExecFree(*(void **)&g_pfnCallVMMR0);
1697 g_pfnCallVMMR0 = NULL;
1698 }
1699#endif /* VBOX_WITH_IDT_PATCHING */
1700
1701 /*
1702 * Free the requested module.
1703 */
1704 SUPLDRFREE Req;
1705 Req.Hdr.u32Cookie = g_u32Cookie;
1706 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1707 Req.Hdr.cbIn = SUP_IOCTL_LDR_FREE_SIZE_IN;
1708 Req.Hdr.cbOut = SUP_IOCTL_LDR_FREE_SIZE_OUT;
1709 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1710 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1711 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1712 int rc = suplibOsIOCtl(SUP_IOCTL_LDR_FREE, &Req, SUP_IOCTL_LDR_FREE_SIZE);
1713 if (RT_SUCCESS(rc))
1714 rc = Req.Hdr.rc;
1715 if ( RT_SUCCESS(rc)
1716 && (RTR0PTR)pvImageBase == g_pvVMMR0)
1717 g_pvVMMR0 = NIL_RTR0PTR;
1718 return rc;
1719}
1720
1721
1722SUPR3DECL(int) SUPGetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue)
1723{
1724 *ppvValue = NULL;
1725
1726 /* fake */
1727 if (RT_UNLIKELY(g_u32FakeMode))
1728 {
1729 *ppvValue = (void *)(uintptr_t)0xdeadf00d;
1730 return VINF_SUCCESS;
1731 }
1732
1733 /*
1734 * Do ioctl.
1735 */
1736 SUPLDRGETSYMBOL Req;
1737 Req.Hdr.u32Cookie = g_u32Cookie;
1738 Req.Hdr.u32SessionCookie = g_u32SessionCookie;
1739 Req.Hdr.cbIn = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_IN;
1740 Req.Hdr.cbOut = SUP_IOCTL_LDR_GET_SYMBOL_SIZE_OUT;
1741 Req.Hdr.fFlags = SUPREQHDR_FLAGS_DEFAULT;
1742 Req.Hdr.rc = VERR_INTERNAL_ERROR;
1743 Req.u.In.pvImageBase = (RTR0PTR)pvImageBase;
1744 size_t cchSymbol = strlen(pszSymbol);
1745 if (cchSymbol >= sizeof(Req.u.In.szSymbol))
1746 return VERR_SYMBOL_NOT_FOUND;
1747 memcpy(Req.u.In.szSymbol, pszSymbol, cchSymbol + 1);
1748 int rc = suplibOsIOCtl(SUP_IOCTL_LDR_GET_SYMBOL, &Req, SUP_IOCTL_LDR_GET_SYMBOL_SIZE);
1749 if (RT_SUCCESS(rc))
1750 rc = Req.Hdr.rc;
1751 if (RT_SUCCESS(rc))
1752 *ppvValue = (void *)Req.u.Out.pvSymbol;
1753 return rc;
1754}
1755
1756
1757SUPR3DECL(int) SUPLoadVMM(const char *pszFilename)
1758{
1759 void *pvImageBase;
1760 return SUPLoadModule(pszFilename, "VMMR0.r0", &pvImageBase);
1761}
1762
1763
1764SUPR3DECL(int) SUPUnloadVMM(void)
1765{
1766 return SUPFreeModule((void*)g_pvVMMR0);
1767}
1768
1769
1770SUPR3DECL(int) SUPGipGetPhys(PRTHCPHYS pHCPhys)
1771{
1772 if (g_pSUPGlobalInfoPage)
1773 {
1774 *pHCPhys = g_HCPhysSUPGlobalInfoPage;
1775 return VINF_SUCCESS;
1776 }
1777 *pHCPhys = NIL_RTHCPHYS;
1778 return VERR_WRONG_ORDER;
1779}
1780
Note: See TracBrowser for help on using the repository browser.

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