VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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