VirtualBox

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

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

Increased the IOC version to 7.4 with the exporting of SUPR0ComponentQueryFactory and friends. Added release logging to darwin, windows and freebsd.

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