VirtualBox

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

Last change on this file since 10603 was 10257, checked in by vboxsync, 17 years ago

space

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