VirtualBox

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

Last change on this file since 2919 was 1890, checked in by vboxsync, 18 years ago

Attempt to fix ALSA on Linux kernels <= 2.6.17: use mmap not memalign for allocating pages. Use madvise or mprotect to separater VM area structs inside the kernel. Most SUP* functions work on cPages now (not cBytes anymore). The free functions take a cPages parameter which is used for munmap on Linux.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 34.1 KB
Line 
1/* $Id: MMHyper.cpp 1890 2007-04-03 16:04:19Z 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, cb >> PAGE_SHIFT);
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