VirtualBox

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

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

ATTENTION: Driver version change (backwards compatible). Need more RTMp* stuff.

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

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