VirtualBox

source: vbox/trunk/src/VBox/VMM/MMHyper.cpp@ 1875

Last change on this file since 1875 was 1480, checked in by vboxsync, 18 years ago

No longer require contiguous memory for the VM structure.
Did long overdue IOCtl cleanup wrt R3/R0 pointers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.1 KB
Line 
1/* $Id: MMHyper.cpp 1480 2007-03-14 18:27:47Z vboxsync $ */
2/** @file
3 * MM - Memory Monitor(/Manager) - Hypervisor Memory Area.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23
24
25/*******************************************************************************
26* Header Files *
27*******************************************************************************/
28#define LOG_GROUP LOG_GROUP_MM_HYPER
29#include <VBox/pgm.h>
30#include <VBox/mm.h>
31#include <VBox/dbgf.h>
32#include "MMInternal.h"
33#include <VBox/vm.h>
34#include <VBox/err.h>
35#include <VBox/param.h>
36#include <VBox/log.h>
37#include <iprt/alloc.h>
38#include <iprt/assert.h>
39#include <iprt/string.h>
40
41
42/*******************************************************************************
43* Internal Functions *
44*******************************************************************************/
45static DECLCALLBACK(bool) mmR3HyperRelocateCallback(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser);
46static int mmR3HyperMap(PVM pVM, const size_t cb, const char *pszDesc, PRTGCPTR pGCPtr, PMMLOOKUPHYPER *ppLookup);
47static int mmR3HyperHeapCreate(PVM pVM, const size_t cb, PMMHYPERHEAP *ppHeap);
48static int mmR3HyperHeapMap(PVM pVM, PMMHYPERHEAP pHeap, PRTGCPTR ppHeapGC);
49static DECLCALLBACK(void) mmR3HyperInfoHma(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
50
51
52/**
53 * Initializes the hypvervisor related MM stuff without
54 * calling down to PGM.
55 *
56 * PGM is not initialized at this point, PGM relies on
57 * the heap to initialize.
58 *
59 * @returns VBox status.
60 */
61int mmr3HyperInit(PVM pVM)
62{
63 LogFlow(("mmr3HyperInit:\n"));
64
65 /*
66 * Decide Hypervisor mapping in the guest context
67 * And setup various hypervisor area and heap parameters.
68 */
69 pVM->mm.s.pvHyperAreaGC = (RTGCPTR)MM_HYPER_AREA_ADDRESS;
70 pVM->mm.s.cbHyperArea = MM_HYPER_AREA_MAX_SIZE;
71 AssertRelease(RT_ALIGN_T(pVM->mm.s.pvHyperAreaGC, 1 << X86_PD_SHIFT, RTGCPTR) == pVM->mm.s.pvHyperAreaGC);
72 Assert(pVM->mm.s.pvHyperAreaGC < 0xff000000);
73
74 uint32_t cbHyperHeap;
75 int rc = CFGMR3QueryU32(CFGMR3GetChild(CFGMR3GetRoot(pVM), "MM"), "cbHyperHeap", &cbHyperHeap);
76 if (rc == VERR_CFGM_NO_PARENT || rc == VERR_CFGM_VALUE_NOT_FOUND)
77 cbHyperHeap = 1280*_1K;
78 else if (VBOX_FAILURE(rc))
79 {
80 LogRel(("MM/cbHyperHeap query -> %Vrc\n", rc));
81 AssertRCReturn(rc, rc);
82 }
83 cbHyperHeap = RT_ALIGN_32(cbHyperHeap, PAGE_SIZE);
84
85 /*
86 * Allocate the hypervisor heap.
87 *
88 * (This must be done before we start adding memory to the
89 * hypervisor static area because lookup records are allocated from it.)
90 */
91 rc = mmR3HyperHeapCreate(pVM, cbHyperHeap, &pVM->mm.s.pHyperHeapHC);
92 if (VBOX_SUCCESS(rc))
93 {
94 /*
95 * Make a small head fence to fend of accidental sequential access.
96 */
97 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
98
99 /*
100 * Map the VM structure into the hypervisor space.
101 */
102 rc = MMR3HyperMapPages(pVM, pVM, pVM->pVMR0, RT_ALIGN_Z(sizeof(VM), PAGE_SIZE) >> PAGE_SHIFT, pVM->paVMPagesR3, "VM", &pVM->pVMGC);
103 if (VBOX_SUCCESS(rc))
104 {
105 /* Reserve a page for fencing. */
106 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
107
108 /*
109 * Map the heap into the hypervisor space.
110 */
111 rc = mmR3HyperHeapMap(pVM, pVM->mm.s.pHyperHeapHC, &pVM->mm.s.pHyperHeapGC);
112 if (VBOX_SUCCESS(rc))
113 {
114 /*
115 * Register info handlers.
116 */
117 DBGFR3InfoRegisterInternal(pVM, "hma", "Show the layout of the Hypervisor Memory Area.", mmR3HyperInfoHma);
118
119 LogFlow(("mmr3HyperInit: returns VINF_SUCCESS\n"));
120 return VINF_SUCCESS;
121 }
122 /* Caller will do proper cleanup. */
123 }
124 }
125
126 LogFlow(("mmr3HyperInit: returns %Vrc\n", rc));
127 return rc;
128}
129
130
131/**
132 * Finalizes the HMA mapping.
133 *
134 * This is called later during init, most (all) HMA allocations should be done
135 * by the time this function is called.
136 *
137 * @returns VBox status.
138 */
139MMR3DECL(int) MMR3HyperInitFinalize(PVM pVM)
140{
141 LogFlow(("MMR3HyperInitFinalize:\n"));
142
143 /*
144 * Adjust and create the HMA mapping.
145 */
146 while ((RTINT)pVM->mm.s.offHyperNextStatic + 64*_1K < (RTINT)pVM->mm.s.cbHyperArea - _4M)
147 pVM->mm.s.cbHyperArea -= _4M;
148 int rc = PGMR3MapPT(pVM, pVM->mm.s.pvHyperAreaGC, pVM->mm.s.cbHyperArea,
149 mmR3HyperRelocateCallback, NULL, "Hypervisor Memory Area");
150 if (VBOX_FAILURE(rc))
151 return rc;
152 pVM->mm.s.fPGMInitialized = true;
153
154 /*
155 * Do all the delayed mappings.
156 */
157 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uintptr_t)pVM->mm.s.pHyperHeapHC + pVM->mm.s.offLookupHyper);
158 for (;;)
159 {
160 RTGCPTR GCPtr = pVM->mm.s.pvHyperAreaGC + pLookup->off;
161 unsigned cPages = pLookup->cb >> PAGE_SHIFT;
162 switch (pLookup->enmType)
163 {
164 case MMLOOKUPHYPERTYPE_LOCKED:
165 rc = mmr3MapLocked(pVM, pLookup->u.Locked.pLockedMem, GCPtr, 0, cPages, 0);
166 break;
167
168 case MMLOOKUPHYPERTYPE_HCPHYS:
169 rc = PGMMap(pVM, GCPtr, pLookup->u.HCPhys.HCPhys, pLookup->cb, 0);
170 break;
171
172 case MMLOOKUPHYPERTYPE_GCPHYS:
173 {
174 const RTGCPHYS GCPhys = pLookup->u.GCPhys.GCPhys;
175 const size_t cb = pLookup->cb;
176 for (unsigned off = 0; off < cb; off += PAGE_SIZE)
177 {
178 RTHCPHYS HCPhys;
179 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys + off, &HCPhys);
180 if (VBOX_FAILURE(rc))
181 break;
182 rc = PGMMap(pVM, GCPtr + off, HCPhys, PAGE_SIZE, 0);
183 if (VBOX_FAILURE(rc))
184 break;
185 }
186 break;
187 }
188
189 case MMLOOKUPHYPERTYPE_DYNAMIC:
190 /* do nothing here since these are either fences or managed by someone else using PGM. */
191 break;
192
193 default:
194 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
195 break;
196 }
197
198 if (VBOX_FAILURE(rc))
199 {
200 AssertMsgFailed(("rc=%Vrc cb=%d GCPtr=%VGv enmType=%d pszDesc=%s\n",
201 rc, pLookup->cb, pLookup->enmType, pLookup->pszDesc));
202 return rc;
203 }
204
205 /* next */
206 if (pLookup->offNext == (int32_t)NIL_OFFSET)
207 break;
208 pLookup = (PMMLOOKUPHYPER)((uintptr_t)pLookup + pLookup->offNext);
209 }
210
211 LogFlow(("MMR3HyperInitFinalize: returns VINF_SUCCESS\n"));
212 return VINF_SUCCESS;
213}
214
215
216/**
217 * Callback function which will be called when PGM is trying to find
218 * a new location for the mapping.
219 *
220 * The callback is called in two modes, 1) the check mode and 2) the relocate mode.
221 * In 1) the callback should say if it objects to a suggested new location. If it
222 * accepts the new location, it is called again for doing it's relocation.
223 *
224 *
225 * @returns true if the location is ok.
226 * @returns false if another location should be found.
227 * @param pVM The VM handle.
228 * @param GCPtrOld The old virtual address.
229 * @param GCPtrNew The new virtual address.
230 * @param enmMode Used to indicate the callback mode.
231 * @param pvUser User argument. Ignored.
232 * @remark The return value is no a failure indicator, it's an acceptance
233 * indicator. Relocation can not fail!
234 */
235static DECLCALLBACK(bool) mmR3HyperRelocateCallback(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)
236{
237 switch (enmMode)
238 {
239 /*
240 * Verify location - all locations are good for us.
241 */
242 case PGMRELOCATECALL_SUGGEST:
243 return true;
244
245 /*
246 * Execute the relocation.
247 */
248 case PGMRELOCATECALL_RELOCATE:
249 {
250 /*
251 * Accepted!
252 */
253 AssertMsg(GCPtrOld == pVM->mm.s.pvHyperAreaGC, ("GCPtrOld=%#x pVM->mm.s.pvHyperAreaGC=%#x\n", GCPtrOld, pVM->mm.s.pvHyperAreaGC));
254 Log(("Relocating the hypervisor from %#x to %#x\n", GCPtrOld, GCPtrNew));
255
256 /* relocate our selves and the VM structure. */
257 RTGCINTPTR offDelta = GCPtrNew - GCPtrOld;
258 pVM->pVMGC += offDelta;
259 pVM->mm.s.pvHyperAreaGC += offDelta;
260 pVM->mm.s.pHyperHeapGC += offDelta;
261 pVM->mm.s.pHyperHeapHC->pbHeapGC += offDelta;
262 pVM->mm.s.pHyperHeapHC->pVMGC += pVM->pVMGC;
263
264 /* relocate the rest. */
265 VMR3Relocate(pVM, offDelta);
266 return true;
267 }
268
269 default:
270 AssertMsgFailed(("Invalid relocation mode %d\n", enmMode));
271 }
272
273 return false;
274}
275
276
277/**
278 * Maps contiguous HC physical memory into the hypervisor region in the GC.
279 *
280 * @return VBox status code.
281 *
282 * @param pVM VM handle.
283 * @param pvHC Host context address of the memory. Must be page aligned!
284 * @param HCPhys Host context physical address of the memory to be mapped. Must be page aligned!
285 * @param cb Size of the memory. Will be rounded up to nearest page.
286 * @param pszDesc Description.
287 * @param pGCPtr Where to store the GC address.
288 */
289MMR3DECL(int) MMR3HyperMapHCPhys(PVM pVM, void *pvHC, RTHCPHYS HCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr)
290{
291 LogFlow(("MMR3HyperMapHCPhys: pvHc=%p HCPhys=%VHp cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", pvHC, HCPhys, (int)cb, pszDesc, pszDesc, pGCPtr));
292
293 /*
294 * Validate input.
295 */
296 AssertReturn(RT_ALIGN_P(pvHC, PAGE_SIZE) == pvHC, VERR_INVALID_PARAMETER);
297 AssertReturn(RT_ALIGN_T(HCPhys, PAGE_SIZE, RTHCPHYS) == HCPhys, VERR_INVALID_PARAMETER);
298 AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
299
300 /*
301 * Add the memory to the hypervisor area.
302 */
303 uint32_t cbAligned = RT_ALIGN_32(cb, PAGE_SIZE);
304 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
305 RTGCPTR GCPtr;
306 PMMLOOKUPHYPER pLookup;
307 int rc = mmR3HyperMap(pVM, cbAligned, pszDesc, &GCPtr, &pLookup);
308 if (VBOX_SUCCESS(rc))
309 {
310 pLookup->enmType = MMLOOKUPHYPERTYPE_HCPHYS;
311 pLookup->u.HCPhys.pvHC = pvHC;
312 pLookup->u.HCPhys.HCPhys = HCPhys;
313
314 /*
315 * Update the page table.
316 */
317 if (pVM->mm.s.fPGMInitialized)
318 rc = PGMMap(pVM, GCPtr, HCPhys, cbAligned, 0);
319 if (VBOX_SUCCESS(rc))
320 *pGCPtr = GCPtr;
321 }
322 return rc;
323}
324
325
326/**
327 * Maps contiguous GC physical memory into the hypervisor region in the GC.
328 *
329 * @return VBox status code.
330 *
331 * @param pVM VM handle.
332 * @param GCPhys Guest context physical address of the memory to be mapped. Must be page aligned!
333 * @param cb Size of the memory. Will be rounded up to nearest page.
334 * @param pszDesc Mapping description.
335 * @param pGCPtr Where to store the GC address.
336 */
337MMR3DECL(int) MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr)
338{
339 LogFlow(("MMR3HyperMapGCPhys: GCPhys=%VGp cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", GCPhys, (int)cb, pszDesc, pszDesc, pGCPtr));
340
341 /*
342 * Validate input.
343 */
344 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
345 AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
346
347 /*
348 * Add the memory to the hypervisor area.
349 */
350 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
351 RTGCPTR GCPtr;
352 PMMLOOKUPHYPER pLookup;
353 int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
354 if (VBOX_SUCCESS(rc))
355 {
356 pLookup->enmType = MMLOOKUPHYPERTYPE_GCPHYS;
357 pLookup->u.GCPhys.GCPhys = GCPhys;
358
359 /*
360 * Update the page table.
361 */
362 for (unsigned off = 0; off < cb; off += PAGE_SIZE)
363 {
364 RTHCPHYS HCPhys;
365 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys + off, &HCPhys);
366 AssertRC(rc);
367 if (VBOX_FAILURE(rc))
368 {
369 AssertMsgFailed(("rc=%Vrc GCPhys=%VGv off=%#x %s\n", rc, GCPhys, off, pszDesc));
370 break;
371 }
372 if (pVM->mm.s.fPGMInitialized)
373 {
374 rc = PGMMap(pVM, GCPtr + off, HCPhys, PAGE_SIZE, 0);
375 AssertRC(rc);
376 if (VBOX_FAILURE(rc))
377 {
378 AssertMsgFailed(("rc=%Vrc GCPhys=%VGv off=%#x %s\n", rc, GCPhys, off, pszDesc));
379 break;
380 }
381 }
382 }
383
384 if (VBOX_SUCCESS(rc) && pGCPtr)
385 *pGCPtr = GCPtr;
386 }
387 return rc;
388}
389
390
391/**
392 * Locks and Maps HC virtual memory into the hypervisor region in the GC.
393 *
394 * @return VBox status code.
395 *
396 * @param pVM VM handle.
397 * @param pvHC Host context address of the memory (may be not page aligned).
398 * @param cb Size of the memory. Will be rounded up to nearest page.
399 * @param fFree Set this if MM is responsible for freeing the memory using SUPPageFree.
400 * @param pszDesc Mapping description.
401 * @param pGCPtr Where to store the GC address corresponding to pvHC.
402 */
403MMR3DECL(int) MMR3HyperMapHCRam(PVM pVM, void *pvHC, size_t cb, bool fFree, const char *pszDesc, PRTGCPTR pGCPtr)
404{
405 LogFlow(("MMR3HyperMapHCRam: pvHc=%p cb=%d fFree=%d pszDesc=%p:{%s} pGCPtr=%p\n", pvHC, (int)cb, fFree, pszDesc, pszDesc, pGCPtr));
406
407 /*
408 * Validate input.
409 */
410 if ( !pvHC
411 || cb <= 0
412 || !pszDesc
413 || !*pszDesc)
414 {
415 AssertMsgFailed(("Invalid parameter\n"));
416 return VERR_INVALID_PARAMETER;
417 }
418
419 /*
420 * Page align address and size.
421 */
422 void *pvHCPage = (void *)((uintptr_t)pvHC & PAGE_BASE_HC_MASK);
423 cb += (uintptr_t)pvHC & PAGE_OFFSET_MASK;
424 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
425
426 /*
427 * Add the memory to the hypervisor area.
428 */
429 RTGCPTR GCPtr;
430 PMMLOOKUPHYPER pLookup;
431 int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
432 if (VBOX_SUCCESS(rc))
433 {
434 /*
435 * Lock the heap memory and tell PGM about the locked pages.
436 */
437 PMMLOCKEDMEM pLockedMem;
438 rc = mmr3LockMem(pVM, pvHCPage, cb, fFree ? MM_LOCKED_TYPE_HYPER : MM_LOCKED_TYPE_HYPER_NOFREE, &pLockedMem, false /* fSilentFailure */);
439 if (VBOX_SUCCESS(rc))
440 {
441 /* map the stuff into guest address space. */
442 if (pVM->mm.s.fPGMInitialized)
443 rc = mmr3MapLocked(pVM, pLockedMem, GCPtr, 0, ~(size_t)0, 0);
444 if (VBOX_SUCCESS(rc))
445 {
446 pLookup->enmType = MMLOOKUPHYPERTYPE_LOCKED;
447 pLookup->u.Locked.pvHC = pvHC;
448 pLookup->u.Locked.pvR0 = NIL_RTR0PTR;
449 pLookup->u.Locked.pLockedMem = pLockedMem;
450
451 /* done. */
452 GCPtr |= (uintptr_t)pvHC & PAGE_OFFSET_MASK;
453 *pGCPtr = GCPtr;
454 return rc;
455 }
456 /* Don't care about failure clean, we're screwed if this fails anyway. */
457 }
458 }
459
460 return rc;
461}
462
463
464/**
465 * Maps locked R3 virtual memory into the hypervisor region in the GC.
466 *
467 * @return VBox status code.
468 *
469 * @param pVM VM handle.
470 * @param pvR3 The ring-3 address of the memory, must be page aligned.
471 * @param pvR0 The ring-0 address of the memory, must be page aligned. (optional)
472 * @param cPages The number of pages.
473 * @param paPages The page descriptors.
474 * @param pszDesc Mapping description.
475 * @param pGCPtr Where to store the GC address corresponding to pvHC.
476 */
477MMR3DECL(int) MMR3HyperMapPages(PVM pVM, void *pvR3, RTR0PTR pvR0, size_t cPages, PCSUPPAGE paPages, const char *pszDesc, PRTGCPTR pGCPtr)
478{
479 LogFlow(("MMR3HyperMapPages: pvR3=%p pvR0=%p cPages=%zu paPages=%p pszDesc=%p:{%s} pGCPtr=%p\n",
480 pvR3, pvR0, cPages, paPages, pszDesc, pszDesc, pGCPtr));
481
482 /*
483 * Validate input.
484 */
485 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
486 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
487 AssertReturn(cPages > 0, VERR_INVALID_PARAMETER);
488 AssertReturn(cPages < 1024, VERR_INVALID_PARAMETER);
489 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
490 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
491 AssertPtrReturn(pGCPtr, VERR_INVALID_PARAMETER);
492
493 /*
494 * Add the memory to the hypervisor area.
495 */
496 RTGCPTR GCPtr;
497 PMMLOOKUPHYPER pLookup;
498 int rc = mmR3HyperMap(pVM, cPages << PAGE_SHIFT, pszDesc, &GCPtr, &pLookup);
499 if (VBOX_SUCCESS(rc))
500 {
501 /*
502 * Create a locked memory record and tell PGM about this.
503 */
504 PMMLOCKEDMEM pLockedMem = (PMMLOCKEDMEM)MMR3HeapAlloc(pVM, MM_TAG_MM, RT_OFFSETOF(MMLOCKEDMEM, aPhysPages[cPages]));
505 if (pLockedMem)
506 {
507 pLockedMem->pv = pvR3;
508 pLockedMem->cb = cPages << PAGE_SHIFT;
509 pLockedMem->eType = MM_LOCKED_TYPE_HYPER_PAGES;
510 memset(&pLockedMem->u, 0, sizeof(pLockedMem->u));
511 for (size_t i = 0; i < cPages; i++)
512 {
513 AssertReleaseReturn(paPages[i].Phys != 0 && paPages[i].Phys != NIL_RTHCPHYS && !(paPages[i].Phys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR);
514 pLockedMem->aPhysPages[i].Phys = paPages[i].Phys;
515 pLockedMem->aPhysPages[i].uReserved = (RTHCUINTPTR)pLockedMem;
516 }
517
518 /* map the stuff into guest address space. */
519 if (pVM->mm.s.fPGMInitialized)
520 rc = mmr3MapLocked(pVM, pLockedMem, GCPtr, 0, ~(size_t)0, 0);
521 if (VBOX_SUCCESS(rc))
522 {
523 pLookup->enmType = MMLOOKUPHYPERTYPE_LOCKED;
524 pLookup->u.Locked.pvHC = pvR3;
525 pLookup->u.Locked.pvR0 = pvR0;
526 pLookup->u.Locked.pLockedMem = pLockedMem;
527
528 /* done. */
529 *pGCPtr = GCPtr;
530 return rc;
531 }
532 /* Don't care about failure clean, we're screwed if this fails anyway. */
533 }
534 }
535
536 return rc;
537}
538
539
540/**
541 * Reserves a hypervisor memory area.
542 * Most frequent usage is fence pages and dynamically mappings like the guest PD and PDPTR.
543 *
544 * @return VBox status code.
545 *
546 * @param pVM VM handle.
547 * @param cb Size of the memory. Will be rounded up to nearest page.
548 * @param pszDesc Mapping description.
549 * @param pGCPtr Where to store the assigned GC address. Optional.
550 */
551MMR3DECL(int) MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr)
552{
553 LogFlow(("MMR3HyperMapHCRam: cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", (int)cb, pszDesc, pszDesc, pGCPtr));
554
555 /*
556 * Validate input.
557 */
558 if ( cb <= 0
559 || !pszDesc
560 || !*pszDesc)
561 {
562 AssertMsgFailed(("Invalid parameter\n"));
563 return VERR_INVALID_PARAMETER;
564 }
565
566 /*
567 * Add the memory to the hypervisor area.
568 */
569 RTGCPTR GCPtr;
570 PMMLOOKUPHYPER pLookup;
571 int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
572 if (VBOX_SUCCESS(rc))
573 {
574 pLookup->enmType = MMLOOKUPHYPERTYPE_DYNAMIC;
575 if (pGCPtr)
576 *pGCPtr = GCPtr;
577 return VINF_SUCCESS;
578 }
579 return rc;
580}
581
582
583/**
584 * Adds memory to the hypervisor memory arena.
585 *
586 * @return VBox status code.
587 * @param pVM The VM handle.
588 * @param cb Size of the memory. Will be rounded up to neares page.
589 * @param pszDesc The description of the memory.
590 * @param pGCPtr Where to store the GC address.
591 * @param ppLookup Where to store the pointer to the lookup record.
592 * @remark We assume the threading structure of VBox imposes natural
593 * serialization of most functions, this one included.
594 */
595static int mmR3HyperMap(PVM pVM, const size_t cb, const char *pszDesc, PRTGCPTR pGCPtr, PMMLOOKUPHYPER *ppLookup)
596{
597 /*
598 * Validate input.
599 */
600 const uint32_t cbAligned = RT_ALIGN(cb, PAGE_SIZE);
601 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
602 if (pVM->mm.s.offHyperNextStatic + cbAligned >= pVM->mm.s.cbHyperArea) /* don't use the last page, it's a fence. */
603 {
604 AssertMsgFailed(("Out of static mapping space in the HMA! offHyperAreaGC=%x cbAligned=%x\n",
605 pVM->mm.s.offHyperNextStatic, cbAligned));
606 return VERR_NO_MEMORY;
607 }
608
609 /*
610 * Allocate lookup record.
611 */
612 PMMLOOKUPHYPER pLookup;
613 int rc = MMHyperAlloc(pVM, sizeof(*pLookup), 1, MM_TAG_MM, (void **)&pLookup);
614 if (VBOX_SUCCESS(rc))
615 {
616 /*
617 * Initialize it and insert it.
618 */
619 pLookup->offNext = pVM->mm.s.offLookupHyper;
620 pLookup->cb = cbAligned;
621 pLookup->off = pVM->mm.s.offHyperNextStatic;
622 pVM->mm.s.offLookupHyper = (char *)pLookup - (char *)pVM->mm.s.pHyperHeapHC;
623 if (pLookup->offNext != (int32_t)NIL_OFFSET)
624 pLookup->offNext -= pVM->mm.s.offLookupHyper;
625 pLookup->enmType = MMLOOKUPHYPERTYPE_INVALID;
626 memset(&pLookup->u, 0xff, sizeof(pLookup->u));
627 pLookup->pszDesc = pszDesc;
628
629 /* Mapping. */
630 *pGCPtr = pVM->mm.s.pvHyperAreaGC + pVM->mm.s.offHyperNextStatic;
631 pVM->mm.s.offHyperNextStatic += cbAligned;
632
633 /* Return pointer. */
634 *ppLookup = pLookup;
635 }
636
637 AssertRC(rc);
638 LogFlow(("mmR3HyperMap: returns %Vrc *pGCPtr=%VGv\n", rc, *pGCPtr));
639 return rc;
640}
641
642
643/**
644 * Allocates a new heap.
645 *
646 * @returns VBox status code.
647 * @param pVM The VM handle.
648 * @param cb The size of the new heap.
649 * @param ppHeap Where to store the heap pointer on successful return.
650 */
651static int mmR3HyperHeapCreate(PVM pVM, const size_t cb, PMMHYPERHEAP *ppHeap)
652{
653 /*
654 * Allocate the hypervisor heap.
655 */
656 const uint32_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
657 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
658 void *pv;
659 int rc = SUPPageAlloc(cbAligned >> PAGE_SHIFT, &pv);
660 if (VBOX_SUCCESS(rc))
661 {
662 /*
663 * Initialize the heap and first free chunk.
664 */
665 PMMHYPERHEAP pHeap = (PMMHYPERHEAP)pv;
666 pHeap->u32Magic = MMHYPERHEAP_MAGIC;
667 pHeap->pVMHC = pVM;
668 pHeap->pVMGC = pVM->pVMGC;
669 pHeap->pbHeapHC = (uint8_t *)pHeap + MMYPERHEAP_HDR_SIZE;
670 //pHeap->pbHeapGC = 0; // set by mmR3HyperHeapMap()
671 pHeap->cbHeap = cbAligned - MMYPERHEAP_HDR_SIZE;
672 pHeap->cbFree = pHeap->cbHeap - sizeof(MMHYPERCHUNK);
673 //pHeap->offFreeHead = 0;
674 //pHeap->offFreeTail = 0;
675 pHeap->offPageAligned = pHeap->cbHeap;
676 //pHeap->HyperHeapStatTree = 0;
677
678 PMMHYPERCHUNKFREE pFree = (PMMHYPERCHUNKFREE)pHeap->pbHeapHC;
679 pFree->cb = pHeap->cbFree;
680 //pFree->core.offNext = 0;
681 MMHYPERCHUNK_SET_TYPE(&pFree->core, MMHYPERCHUNK_FLAGS_FREE);
682 pFree->core.offHeap = -(int32_t)MMYPERHEAP_HDR_SIZE;
683 //pFree->offNext = 0;
684 //pFree->offPrev = 0;
685
686 STAMR3Register(pVM, &pHeap->cbHeap, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, "/MM/HyperHeap/cbHeap", STAMUNIT_BYTES, "The heap size.");
687 STAMR3Register(pVM, &pHeap->cbFree, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, "/MM/HyperHeap/cbFree", STAMUNIT_BYTES, "The free space.");
688
689 *ppHeap = pHeap;
690 return VINF_SUCCESS;
691 }
692 AssertMsgFailed(("SUPPageAlloc(%d,) -> %Vrc\n", cbAligned >> PAGE_SHIFT, rc));
693
694 *ppHeap = NULL;
695 return rc;
696}
697
698
699/**
700 * Allocates a new heap.
701 */
702static int mmR3HyperHeapMap(PVM pVM, PMMHYPERHEAP pHeap, PRTGCPTR ppHeapGC)
703{
704 int rc = MMR3HyperMapHCRam(pVM, pHeap, pHeap->cbHeap + MMYPERHEAP_HDR_SIZE, true, "Heap", ppHeapGC);
705 if (VBOX_SUCCESS(rc))
706 {
707 pHeap->pVMGC = pVM->pVMGC;
708 pHeap->pbHeapGC = *ppHeapGC + MMYPERHEAP_HDR_SIZE;
709 /* Reserve a page for fencing. */
710 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
711 }
712 return rc;
713}
714
715
716#if 0
717/**
718 * Destroys a heap.
719 */
720static int mmR3HyperHeapDestroy(PVM pVM, PMMHYPERHEAP pHeap)
721{
722 /* all this is dealt with when unlocking and freeing locked memory. */
723}
724#endif
725
726
727/**
728 * Allocates memory in the Hypervisor (GC VMM) area which never will
729 * be freed and doesn't have any offset based relation to other heap blocks.
730 *
731 * The latter means that two blocks allocated by this API will not have the
732 * same relative position to each other in GC and HC. In short, never use
733 * this API for allocating nodes for an offset based AVL tree!
734 *
735 * The returned memory is of course zeroed.
736 *
737 * @returns VBox status code.
738 * @param pVM The VM to operate on.
739 * @param cb Number of bytes to allocate.
740 * @param uAlignment Required memory alignment in bytes.
741 * Values are 0,8,16,32 and PAGE_SIZE.
742 * 0 -> default alignment, i.e. 8 bytes.
743 * @param enmTag The statistics tag.
744 * @param ppv Where to store the address to the allocated
745 * memory.
746 * @remark This is assumed not to be used at times when serialization is required.
747 */
748MMDECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv)
749{
750 AssertMsg(cb >= 8, ("Hey! Do you really mean to allocate less than 8 bytes?! cb=%d\n", cb));
751 AssertMsg(cb <= _4M, ("Allocating more than 4MB!? (cb=%#x) HMA limit might need adjusting if you allocate more.\n", cb));
752
753 /*
754 * Choose between allocating a new chunk of HMA memory
755 * and the heap. We will only do BIG allocations from HMA.
756 */
757 if ( cb < _64K
758 && ( uAlignment != PAGE_SIZE
759 || cb < 48*_1K))
760 {
761 int rc = MMHyperAlloc(pVM, cb, uAlignment, enmTag, ppv);
762 if ( rc != VERR_MM_HYPER_NO_MEMORY
763 || cb <= 8*_1K)
764 {
765 Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns %Rrc and *ppv=%p\n",
766 cb, uAlignment, rc, *ppv));
767 return rc;
768 }
769 }
770
771 /*
772 * Validate alignment.
773 */
774 switch (uAlignment)
775 {
776 case 0:
777 case 8:
778 case 16:
779 case 32:
780 case PAGE_SIZE:
781 break;
782 default:
783 AssertMsgFailed(("Invalid alignment %u\n", uAlignment));
784 return VERR_INVALID_PARAMETER;
785 }
786
787 /*
788 * Allocate the pages and the HMA space.
789 */
790 cb = RT_ALIGN(cb, PAGE_SIZE);
791 void *pvPages;
792 int rc = SUPPageAlloc(cb >> PAGE_SHIFT, &pvPages);
793 if (VBOX_SUCCESS(rc))
794 {
795 RTGCPTR GCPtr;
796 rc = MMR3HyperMapHCRam(pVM, pvPages, cb, true, mmR3GetTagName(enmTag), &GCPtr);
797 if (VBOX_SUCCESS(rc))
798 {
799 *ppv = pvPages;
800 Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns VINF_SUCCESS and *ppv=%p\n",
801 cb, uAlignment, *ppv));
802 return rc;
803 }
804 SUPPageFree(pvPages);
805 }
806 if (rc == VERR_NO_MEMORY)
807 rc = VERR_MM_HYPER_NO_MEMORY;
808 Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns %Rrc\n", cb, uAlignment, rc));
809 AssertMsgFailed(("Failed to allocate %d bytes!\n", cb));
810 return rc;
811}
812
813
814/**
815 * Convert hypervisor HC virtual address to HC physical address.
816 *
817 * @returns HC physical address.
818 * @param pVM VM Handle
819 * @param pvHC Host context physical address.
820 */
821MMR3DECL(RTHCPHYS) MMR3HyperHCVirt2HCPhys(PVM pVM, void *pvHC)
822{
823 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((char*)pVM->mm.s.pHyperHeapHC + pVM->mm.s.offLookupHyper);
824 for (;;)
825 {
826 switch (pLookup->enmType)
827 {
828 case MMLOOKUPHYPERTYPE_LOCKED:
829 {
830 unsigned off = (char *)pvHC - (char *)pLookup->u.Locked.pvHC;
831 if (off < pLookup->cb)
832 return (pLookup->u.Locked.pLockedMem->aPhysPages[off >> PAGE_SHIFT].Phys & X86_PTE_PAE_PG_MASK) | (off & PAGE_OFFSET_MASK);
833 break;
834 }
835
836 case MMLOOKUPHYPERTYPE_HCPHYS:
837 {
838 unsigned off = (char *)pvHC - (char *)pLookup->u.HCPhys.pvHC;
839 if (off < pLookup->cb)
840 return pLookup->u.HCPhys.HCPhys + off;
841 break;
842 }
843
844 case MMLOOKUPHYPERTYPE_GCPHYS:
845 case MMLOOKUPHYPERTYPE_DYNAMIC:
846 /* can convert these kind of records. */
847 break;
848
849 default:
850 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
851 break;
852 }
853
854 /* next */
855 if ((unsigned)pLookup->offNext == NIL_OFFSET)
856 break;
857 pLookup = (PMMLOOKUPHYPER)((char *)pLookup + pLookup->offNext);
858 }
859
860 AssertMsgFailed(("pvHC=%p is not inside the hypervisor memory area!\n", pvHC));
861 return NIL_RTHCPHYS;
862}
863
864
865#if 0 /* unused, not implemented */
866/**
867 * Convert hypervisor HC physical address to HC virtual address.
868 *
869 * @returns HC virtual address.
870 * @param pVM VM Handle
871 * @param HCPhys Host context physical address.
872 */
873MMR3DECL(void *) MMR3HyperHCPhys2HCVirt(PVM pVM, RTHCPHYS HCPhys)
874{
875 void *pv;
876 int rc = MMR3HyperHCPhys2HCVirtEx(pVM, HCPhys, &pv);
877 if (VBOX_SUCCESS(rc))
878 return pv;
879 AssertMsgFailed(("Invalid address HCPhys=%x rc=%d\n", HCPhys, rc));
880 return NULL;
881}
882
883
884/**
885 * Convert hypervisor HC physical address to HC virtual address.
886 *
887 * @returns VBox status.
888 * @param pVM VM Handle
889 * @param HCPhys Host context physical address.
890 * @param ppv Where to store the HC virtual address.
891 */
892MMR3DECL(int) MMR3HyperHCPhys2HCVirtEx(PVM pVM, RTHCPHYS HCPhys, void **ppv)
893{
894 /*
895 * Linear search.
896 */
897 /** @todo implement when actually used. */
898 return VERR_INVALID_POINTER;
899}
900#endif /* unused, not implemented */
901
902
903/**
904 * Read hypervisor memory from GC virtual address.
905 *
906 * @returns VBox status.
907 * @param pVM VM handle.
908 * @param pvDst Destination address (HC of course).
909 * @param GCPtr GC virtual address.
910 * @param cb Number of bytes to read.
911 */
912MMR3DECL(int) MMR3HyperReadGCVirt(PVM pVM, void *pvDst, RTGCPTR GCPtr, size_t cb)
913{
914 if (GCPtr - pVM->mm.s.pvHyperAreaGC >= pVM->mm.s.cbHyperArea)
915 return VERR_INVALID_PARAMETER;
916 return PGMR3MapRead(pVM, pvDst, GCPtr, cb);
917}
918
919
920/**
921 * Info handler for 'hma', it dumps the list of lookup records for the hypervisor memory area.
922 *
923 * @param pVM The VM handle.
924 * @param pHlp Callback functions for doing output.
925 * @param pszArgs Argument string. Optional and specific to the handler.
926 */
927static DECLCALLBACK(void) mmR3HyperInfoHma(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
928{
929 pHlp->pfnPrintf(pHlp, "Hypervisor Memory Area (HMA) Layout: Base %VGv, 0x%08x bytes\n",
930 pVM->mm.s.pvHyperAreaGC, pVM->mm.s.cbHyperArea);
931
932 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((char*)pVM->mm.s.pHyperHeapHC + pVM->mm.s.offLookupHyper);
933 for (;;)
934 {
935 switch (pLookup->enmType)
936 {
937 case MMLOOKUPHYPERTYPE_LOCKED:
938 pHlp->pfnPrintf(pHlp, "%VGv-%VGv %VHv LOCKED %-*s %s\n",
939 pLookup->off + pVM->mm.s.pvHyperAreaGC,
940 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
941 pLookup->u.Locked.pvHC,
942 sizeof(RTHCPTR) * 2,
943 pLookup->u.Locked.pLockedMem->eType == MM_LOCKED_TYPE_HYPER_NOFREE ? "nofree"
944 : pLookup->u.Locked.pLockedMem->eType == MM_LOCKED_TYPE_HYPER ? "autofree"
945 : pLookup->u.Locked.pLockedMem->eType == MM_LOCKED_TYPE_HYPER_PAGES ? "pages"
946 : pLookup->u.Locked.pLockedMem->eType == MM_LOCKED_TYPE_PHYS ? "gstphys"
947 : "??",
948 pLookup->pszDesc);
949 break;
950
951 case MMLOOKUPHYPERTYPE_HCPHYS:
952 pHlp->pfnPrintf(pHlp, "%VGv-%VGv %VHv HCPHYS %VHp %s\n",
953 pLookup->off + pVM->mm.s.pvHyperAreaGC,
954 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
955 pLookup->u.HCPhys.pvHC, pLookup->u.HCPhys.HCPhys,
956 pLookup->pszDesc);
957 break;
958
959 case MMLOOKUPHYPERTYPE_GCPHYS:
960 pHlp->pfnPrintf(pHlp, "%VGv-%VGv %*s GCPHYS %VGp%*s %s\n",
961 pLookup->off + pVM->mm.s.pvHyperAreaGC,
962 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
963 sizeof(RTHCPTR) * 2, "",
964 pLookup->u.GCPhys.GCPhys, RT_ABS(sizeof(RTHCPHYS) - sizeof(RTGCPHYS)) * 2, "",
965 pLookup->pszDesc);
966 break;
967
968 case MMLOOKUPHYPERTYPE_DYNAMIC:
969 pHlp->pfnPrintf(pHlp, "%VGv-%VGv %*s DYNAMIC %*s %s\n",
970 pLookup->off + pVM->mm.s.pvHyperAreaGC,
971 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
972 sizeof(RTHCPTR) * 2, "",
973 sizeof(RTHCPTR) * 2, "",
974 pLookup->pszDesc);
975 break;
976
977 default:
978 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
979 break;
980 }
981
982 /* next */
983 if ((unsigned)pLookup->offNext == NIL_OFFSET)
984 break;
985 pLookup = (PMMLOOKUPHYPER)((char *)pLookup + pLookup->offNext);
986 }
987}
988
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