VirtualBox

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

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

SUPLib: Build fix.

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

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