VirtualBox

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

Last change on this file since 50653 was 50113, checked in by vboxsync, 10 years ago

Because of the CPUID leaves we'll need the heap to always be mapped into ring-0 in the VBOX_WITH_2X_4GB_ADDR_SPACE case (mac).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 50.4 KB
Line 
1/* $Id: MMHyper.cpp 50113 2014-01-20 11:57:31Z vboxsync $ */
2/** @file
3 * MM - Memory Manager - Hypervisor Memory Area.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_MM_HYPER
23#include <VBox/vmm/pgm.h>
24#include <VBox/vmm/mm.h>
25#include <VBox/vmm/hm.h>
26#include <VBox/vmm/dbgf.h>
27#include "MMInternal.h"
28#include <VBox/vmm/vm.h>
29#include <VBox/err.h>
30#include <VBox/param.h>
31#include <VBox/log.h>
32#include "internal/pgm.h"
33#include <iprt/alloc.h>
34#include <iprt/assert.h>
35#include <iprt/string.h>
36
37
38/*******************************************************************************
39* Internal Functions *
40*******************************************************************************/
41static DECLCALLBACK(bool) mmR3HyperRelocateCallback(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode,
42 void *pvUser);
43static int mmR3HyperMap(PVM pVM, const size_t cb, const char *pszDesc, PRTGCPTR pGCPtr, PMMLOOKUPHYPER *ppLookup);
44static int mmR3HyperHeapCreate(PVM pVM, const size_t cb, PMMHYPERHEAP *ppHeap, PRTR0PTR pR0PtrHeap);
45static int mmR3HyperHeapMap(PVM pVM, PMMHYPERHEAP pHeap, PRTGCPTR ppHeapGC);
46static DECLCALLBACK(void) mmR3HyperInfoHma(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
47
48
49/**
50 * Determin the default heap size.
51 *
52 * @returns The heap size in bytes.
53 * @param pVM Pointer to the VM.
54 */
55static uint32_t mmR3HyperComputeHeapSize(PVM pVM)
56{
57 /*
58 * Gather parameters.
59 */
60 bool fCanUseLargerHeap;
61 int rc = CFGMR3QueryBoolDef(CFGMR3GetChild(CFGMR3GetRoot(pVM), "MM"), "CanUseLargerHeap", &fCanUseLargerHeap, false);
62 AssertStmt(RT_SUCCESS(rc), fCanUseLargerHeap = false);
63
64 uint64_t cbRam;
65 rc = CFGMR3QueryU64(CFGMR3GetRoot(pVM), "RamSize", &cbRam);
66 AssertStmt(RT_SUCCESS(rc), cbRam = _1G);
67
68 /*
69 * We need to keep saved state compatibility if raw-mode is an option,
70 * so lets filter out that case first.
71 */
72 if ( !fCanUseLargerHeap
73 && !HMIsEnabled(pVM)
74 && cbRam < 16*_1G64)
75 return 1280 * _1K;
76
77 /*
78 * Calculate the heap size.
79 */
80 uint32_t cbHeap = _1M;
81
82 /* The newer chipset may have more devices attached, putting additional
83 pressure on the heap. */
84 if (fCanUseLargerHeap)
85 cbHeap += _1M;
86
87 /* More CPUs means some extra memory usage. */
88 if (pVM->cCpus > 1)
89 cbHeap += pVM->cCpus * _64K;
90
91 /* Lots of memory means extra memory consumption as well (pool). */
92 if (cbRam > 16*_1G64)
93 cbHeap += _2M; /** @todo figure out extactly how much */
94
95 return RT_ALIGN(cbHeap, _256K);
96}
97
98
99/**
100 * Initializes the hypervisor related MM stuff without
101 * calling down to PGM.
102 *
103 * PGM is not initialized at this point, PGM relies on
104 * the heap to initialize.
105 *
106 * @returns VBox status.
107 */
108int mmR3HyperInit(PVM pVM)
109{
110 LogFlow(("mmR3HyperInit:\n"));
111
112 /*
113 * Decide Hypervisor mapping in the guest context
114 * And setup various hypervisor area and heap parameters.
115 */
116 pVM->mm.s.pvHyperAreaGC = (RTGCPTR)MM_HYPER_AREA_ADDRESS;
117 pVM->mm.s.cbHyperArea = MM_HYPER_AREA_MAX_SIZE;
118 AssertRelease(RT_ALIGN_T(pVM->mm.s.pvHyperAreaGC, 1 << X86_PD_SHIFT, RTGCPTR) == pVM->mm.s.pvHyperAreaGC);
119 Assert(pVM->mm.s.pvHyperAreaGC < 0xff000000);
120
121 /** @todo @bugref{1865}, @bugref{3202}: Change the cbHyperHeap default
122 * depending on whether VT-x/AMD-V is enabled or not! Don't waste
123 * precious kernel space on heap for the PATM.
124 */
125 PCFGMNODE pMM = CFGMR3GetChild(CFGMR3GetRoot(pVM), "MM");
126 uint32_t cbHyperHeap;
127 int rc = CFGMR3QueryU32Def(pMM, "cbHyperHeap", &cbHyperHeap, mmR3HyperComputeHeapSize(pVM));
128 AssertLogRelRCReturn(rc, rc);
129
130 cbHyperHeap = RT_ALIGN_32(cbHyperHeap, PAGE_SIZE);
131 LogRel(("MM: cbHyperHeap=%#x (%u)\n", cbHyperHeap, cbHyperHeap));
132
133 /*
134 * Allocate the hypervisor heap.
135 *
136 * (This must be done before we start adding memory to the
137 * hypervisor static area because lookup records are allocated from it.)
138 */
139 rc = mmR3HyperHeapCreate(pVM, cbHyperHeap, &pVM->mm.s.pHyperHeapR3, &pVM->mm.s.pHyperHeapR0);
140 if (RT_SUCCESS(rc))
141 {
142 /*
143 * Make a small head fence to fend of accidental sequential access.
144 */
145 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
146
147 /*
148 * Map the VM structure into the hypervisor space.
149 */
150 AssertRelease(pVM->cbSelf == RT_UOFFSETOF(VM, aCpus[pVM->cCpus]));
151 RTGCPTR GCPtr;
152 rc = MMR3HyperMapPages(pVM, pVM, pVM->pVMR0, RT_ALIGN_Z(pVM->cbSelf, PAGE_SIZE) >> PAGE_SHIFT, pVM->paVMPagesR3, "VM",
153 &GCPtr);
154 if (RT_SUCCESS(rc))
155 {
156 pVM->pVMRC = (RTRCPTR)GCPtr;
157 for (VMCPUID i = 0; i < pVM->cCpus; i++)
158 pVM->aCpus[i].pVMRC = pVM->pVMRC;
159
160 /* Reserve a page for fencing. */
161 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
162
163 /*
164 * Map the heap into the hypervisor space.
165 */
166 rc = mmR3HyperHeapMap(pVM, pVM->mm.s.pHyperHeapR3, &GCPtr);
167 if (RT_SUCCESS(rc))
168 {
169 pVM->mm.s.pHyperHeapRC = (RTRCPTR)GCPtr;
170 Assert(pVM->mm.s.pHyperHeapRC == GCPtr);
171
172 /*
173 * Register info handlers.
174 */
175 DBGFR3InfoRegisterInternal(pVM, "hma", "Show the layout of the Hypervisor Memory Area.", mmR3HyperInfoHma);
176
177 LogFlow(("mmR3HyperInit: returns VINF_SUCCESS\n"));
178 return VINF_SUCCESS;
179 }
180 /* Caller will do proper cleanup. */
181 }
182 }
183
184 LogFlow(("mmR3HyperInit: returns %Rrc\n", rc));
185 return rc;
186}
187
188
189/**
190 * Cleans up the hypervisor heap.
191 *
192 * @returns VBox status.
193 */
194int mmR3HyperTerm(PVM pVM)
195{
196 if (pVM->mm.s.pHyperHeapR3)
197 PDMR3CritSectDelete(&pVM->mm.s.pHyperHeapR3->Lock);
198
199 return VINF_SUCCESS;
200}
201
202
203/**
204 * Finalizes the HMA mapping.
205 *
206 * This is called later during init, most (all) HMA allocations should be done
207 * by the time this function is called.
208 *
209 * @returns VBox status.
210 */
211VMMR3DECL(int) MMR3HyperInitFinalize(PVM pVM)
212{
213 LogFlow(("MMR3HyperInitFinalize:\n"));
214
215 /*
216 * Initialize the hyper heap critical section.
217 */
218 int rc = PDMR3CritSectInit(pVM, &pVM->mm.s.pHyperHeapR3->Lock, RT_SRC_POS, "MM-HYPER");
219 AssertRC(rc);
220
221 /*
222 * Adjust and create the HMA mapping.
223 */
224 while ((RTINT)pVM->mm.s.offHyperNextStatic + 64*_1K < (RTINT)pVM->mm.s.cbHyperArea - _4M)
225 pVM->mm.s.cbHyperArea -= _4M;
226 rc = PGMR3MapPT(pVM, pVM->mm.s.pvHyperAreaGC, pVM->mm.s.cbHyperArea, 0 /*fFlags*/,
227 mmR3HyperRelocateCallback, NULL, "Hypervisor Memory Area");
228 if (RT_FAILURE(rc))
229 return rc;
230 pVM->mm.s.fPGMInitialized = true;
231
232 /*
233 * Do all the delayed mappings.
234 */
235 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uintptr_t)pVM->mm.s.pHyperHeapR3 + pVM->mm.s.offLookupHyper);
236 for (;;)
237 {
238 RTGCPTR GCPtr = pVM->mm.s.pvHyperAreaGC + pLookup->off;
239 uint32_t cPages = pLookup->cb >> PAGE_SHIFT;
240 switch (pLookup->enmType)
241 {
242 case MMLOOKUPHYPERTYPE_LOCKED:
243 {
244 PCRTHCPHYS paHCPhysPages = pLookup->u.Locked.paHCPhysPages;
245 for (uint32_t i = 0; i < cPages; i++)
246 {
247 rc = PGMMap(pVM, GCPtr + (i << PAGE_SHIFT), paHCPhysPages[i], PAGE_SIZE, 0);
248 AssertRCReturn(rc, rc);
249 }
250 break;
251 }
252
253 case MMLOOKUPHYPERTYPE_HCPHYS:
254 rc = PGMMap(pVM, GCPtr, pLookup->u.HCPhys.HCPhys, pLookup->cb, 0);
255 break;
256
257 case MMLOOKUPHYPERTYPE_GCPHYS:
258 {
259 const RTGCPHYS GCPhys = pLookup->u.GCPhys.GCPhys;
260 const uint32_t cb = pLookup->cb;
261 for (uint32_t off = 0; off < cb; off += PAGE_SIZE)
262 {
263 RTHCPHYS HCPhys;
264 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys + off, &HCPhys);
265 if (RT_FAILURE(rc))
266 break;
267 rc = PGMMap(pVM, GCPtr + off, HCPhys, PAGE_SIZE, 0);
268 if (RT_FAILURE(rc))
269 break;
270 }
271 break;
272 }
273
274 case MMLOOKUPHYPERTYPE_MMIO2:
275 {
276 const RTGCPHYS offEnd = pLookup->u.MMIO2.off + pLookup->cb;
277 for (RTGCPHYS offCur = pLookup->u.MMIO2.off; offCur < offEnd; offCur += PAGE_SIZE)
278 {
279 RTHCPHYS HCPhys;
280 rc = PGMR3PhysMMIO2GetHCPhys(pVM, pLookup->u.MMIO2.pDevIns, pLookup->u.MMIO2.iRegion, offCur, &HCPhys);
281 if (RT_FAILURE(rc))
282 break;
283 rc = PGMMap(pVM, GCPtr + (offCur - pLookup->u.MMIO2.off), HCPhys, PAGE_SIZE, 0);
284 if (RT_FAILURE(rc))
285 break;
286 }
287 break;
288 }
289
290 case MMLOOKUPHYPERTYPE_DYNAMIC:
291 /* do nothing here since these are either fences or managed by someone else using PGM. */
292 break;
293
294 default:
295 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
296 break;
297 }
298
299 if (RT_FAILURE(rc))
300 {
301 AssertMsgFailed(("rc=%Rrc cb=%d off=%#RX32 enmType=%d pszDesc=%s\n",
302 rc, pLookup->cb, pLookup->off, pLookup->enmType, pLookup->pszDesc));
303 return rc;
304 }
305
306 /* next */
307 if (pLookup->offNext == (int32_t)NIL_OFFSET)
308 break;
309 pLookup = (PMMLOOKUPHYPER)((uintptr_t)pLookup + pLookup->offNext);
310 }
311
312 LogFlow(("MMR3HyperInitFinalize: returns VINF_SUCCESS\n"));
313 return VINF_SUCCESS;
314}
315
316
317/**
318 * Callback function which will be called when PGM is trying to find a new
319 * location for the mapping.
320 *
321 * The callback is called in two modes, 1) the check mode and 2) the relocate mode.
322 * In 1) the callback should say if it objects to a suggested new location. If it
323 * accepts the new location, it is called again for doing it's relocation.
324 *
325 *
326 * @returns true if the location is ok.
327 * @returns false if another location should be found.
328 * @param pVM Pointer to the VM.
329 * @param GCPtrOld The old virtual address.
330 * @param GCPtrNew The new virtual address.
331 * @param enmMode Used to indicate the callback mode.
332 * @param pvUser User argument. Ignored.
333 * @remark The return value is no a failure indicator, it's an acceptance
334 * indicator. Relocation can not fail!
335 */
336static DECLCALLBACK(bool) mmR3HyperRelocateCallback(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew,
337 PGMRELOCATECALL enmMode, void *pvUser)
338{
339 NOREF(pvUser);
340 switch (enmMode)
341 {
342 /*
343 * Verify location - all locations are good for us.
344 */
345 case PGMRELOCATECALL_SUGGEST:
346 return true;
347
348 /*
349 * Execute the relocation.
350 */
351 case PGMRELOCATECALL_RELOCATE:
352 {
353 /*
354 * Accepted!
355 */
356 AssertMsg(GCPtrOld == pVM->mm.s.pvHyperAreaGC,
357 ("GCPtrOld=%RGv pVM->mm.s.pvHyperAreaGC=%RGv\n", GCPtrOld, pVM->mm.s.pvHyperAreaGC));
358 Log(("Relocating the hypervisor from %RGv to %RGv\n", GCPtrOld, GCPtrNew));
359
360 /*
361 * Relocate the VM structure and ourselves.
362 */
363 RTGCINTPTR offDelta = GCPtrNew - GCPtrOld;
364 pVM->pVMRC += offDelta;
365 for (VMCPUID i = 0; i < pVM->cCpus; i++)
366 pVM->aCpus[i].pVMRC = pVM->pVMRC;
367
368 pVM->mm.s.pvHyperAreaGC += offDelta;
369 Assert(pVM->mm.s.pvHyperAreaGC < _4G);
370 pVM->mm.s.pHyperHeapRC += offDelta;
371 pVM->mm.s.pHyperHeapR3->pbHeapRC += offDelta;
372 pVM->mm.s.pHyperHeapR3->pVMRC = pVM->pVMRC;
373
374 /*
375 * Relocate the rest.
376 */
377 VMR3Relocate(pVM, offDelta);
378 return true;
379 }
380
381 default:
382 AssertMsgFailed(("Invalid relocation mode %d\n", enmMode));
383 }
384
385 return false;
386}
387
388/**
389 * Service a VMMCALLRING3_MMHYPER_LOCK call.
390 *
391 * @returns VBox status code.
392 * @param pVM Pointer to the VM.
393 */
394VMMR3DECL(int) MMR3LockCall(PVM pVM)
395{
396 PMMHYPERHEAP pHeap = pVM->mm.s.CTX_SUFF(pHyperHeap);
397
398 int rc = PDMR3CritSectEnterEx(&pHeap->Lock, true /* fHostCall */);
399 AssertRC(rc);
400 return rc;
401}
402
403/**
404 * Maps contiguous HC physical memory into the hypervisor region in the GC.
405 *
406 * @return VBox status code.
407 *
408 * @param pVM Pointer to the VM.
409 * @param pvR3 Ring-3 address of the memory. Must be page aligned!
410 * @param pvR0 Optional ring-0 address of the memory.
411 * @param HCPhys Host context physical address of the memory to be
412 * mapped. Must be page aligned!
413 * @param cb Size of the memory. Will be rounded up to nearest page.
414 * @param pszDesc Description.
415 * @param pGCPtr Where to store the GC address.
416 */
417VMMR3DECL(int) MMR3HyperMapHCPhys(PVM pVM, void *pvR3, RTR0PTR pvR0, RTHCPHYS HCPhys, size_t cb,
418 const char *pszDesc, PRTGCPTR pGCPtr)
419{
420 LogFlow(("MMR3HyperMapHCPhys: pvR3=%p pvR0=%p HCPhys=%RHp cb=%d pszDesc=%p:{%s} pGCPtr=%p\n",
421 pvR3, pvR0, HCPhys, (int)cb, pszDesc, pszDesc, pGCPtr));
422
423 /*
424 * Validate input.
425 */
426 AssertReturn(RT_ALIGN_P(pvR3, PAGE_SIZE) == pvR3, VERR_INVALID_PARAMETER);
427 AssertReturn(RT_ALIGN_T(pvR0, PAGE_SIZE, RTR0PTR) == pvR0, VERR_INVALID_PARAMETER);
428 AssertReturn(RT_ALIGN_T(HCPhys, PAGE_SIZE, RTHCPHYS) == HCPhys, VERR_INVALID_PARAMETER);
429 AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
430
431 /*
432 * Add the memory to the hypervisor area.
433 */
434 uint32_t cbAligned = RT_ALIGN_32(cb, PAGE_SIZE);
435 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
436 RTGCPTR GCPtr;
437 PMMLOOKUPHYPER pLookup;
438 int rc = mmR3HyperMap(pVM, cbAligned, pszDesc, &GCPtr, &pLookup);
439 if (RT_SUCCESS(rc))
440 {
441 pLookup->enmType = MMLOOKUPHYPERTYPE_HCPHYS;
442 pLookup->u.HCPhys.pvR3 = pvR3;
443 pLookup->u.HCPhys.pvR0 = pvR0;
444 pLookup->u.HCPhys.HCPhys = HCPhys;
445
446 /*
447 * Update the page table.
448 */
449 if (pVM->mm.s.fPGMInitialized)
450 rc = PGMMap(pVM, GCPtr, HCPhys, cbAligned, 0);
451 if (RT_SUCCESS(rc))
452 *pGCPtr = GCPtr;
453 }
454 return rc;
455}
456
457
458/**
459 * Maps contiguous GC physical memory into the hypervisor region in the GC.
460 *
461 * @return VBox status code.
462 *
463 * @param pVM Pointer to the VM.
464 * @param GCPhys Guest context physical address of the memory to be mapped. Must be page aligned!
465 * @param cb Size of the memory. Will be rounded up to nearest page.
466 * @param pszDesc Mapping description.
467 * @param pGCPtr Where to store the GC address.
468 */
469VMMR3DECL(int) MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr)
470{
471 LogFlow(("MMR3HyperMapGCPhys: GCPhys=%RGp cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", GCPhys, (int)cb, pszDesc, pszDesc, pGCPtr));
472
473 /*
474 * Validate input.
475 */
476 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
477 AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
478
479 /*
480 * Add the memory to the hypervisor area.
481 */
482 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
483 RTGCPTR GCPtr;
484 PMMLOOKUPHYPER pLookup;
485 int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
486 if (RT_SUCCESS(rc))
487 {
488 pLookup->enmType = MMLOOKUPHYPERTYPE_GCPHYS;
489 pLookup->u.GCPhys.GCPhys = GCPhys;
490
491 /*
492 * Update the page table.
493 */
494 for (unsigned off = 0; off < cb; off += PAGE_SIZE)
495 {
496 RTHCPHYS HCPhys;
497 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys + off, &HCPhys);
498 AssertRC(rc);
499 if (RT_FAILURE(rc))
500 {
501 AssertMsgFailed(("rc=%Rrc GCPhys=%RGp off=%#x %s\n", rc, GCPhys, off, pszDesc));
502 break;
503 }
504 if (pVM->mm.s.fPGMInitialized)
505 {
506 rc = PGMMap(pVM, GCPtr + off, HCPhys, PAGE_SIZE, 0);
507 AssertRC(rc);
508 if (RT_FAILURE(rc))
509 {
510 AssertMsgFailed(("rc=%Rrc GCPhys=%RGp off=%#x %s\n", rc, GCPhys, off, pszDesc));
511 break;
512 }
513 }
514 }
515
516 if (RT_SUCCESS(rc) && pGCPtr)
517 *pGCPtr = GCPtr;
518 }
519 return rc;
520}
521
522
523/**
524 * Maps a portion of an MMIO2 region into the hypervisor region.
525 *
526 * Callers of this API must never deregister the MMIO2 region before the
527 * VM is powered off. If this becomes a requirement MMR3HyperUnmapMMIO2
528 * API will be needed to perform cleanups.
529 *
530 * @return VBox status code.
531 *
532 * @param pVM Pointer to the VM.
533 * @param pDevIns The device owning the MMIO2 memory.
534 * @param iRegion The region.
535 * @param off The offset into the region. Will be rounded down to closest page boundary.
536 * @param cb The number of bytes to map. Will be rounded up to the closest page boundary.
537 * @param pszDesc Mapping description.
538 * @param pRCPtr Where to store the RC address.
539 */
540VMMR3DECL(int) MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
541 const char *pszDesc, PRTRCPTR pRCPtr)
542{
543 LogFlow(("MMR3HyperMapMMIO2: pDevIns=%p iRegion=%#x off=%RGp cb=%RGp pszDesc=%p:{%s} pRCPtr=%p\n",
544 pDevIns, iRegion, off, cb, pszDesc, pszDesc, pRCPtr));
545 int rc;
546
547 /*
548 * Validate input.
549 */
550 AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
551 AssertReturn(off + cb > off, VERR_INVALID_PARAMETER);
552 uint32_t const offPage = off & PAGE_OFFSET_MASK;
553 off &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
554 cb += offPage;
555 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
556 const RTGCPHYS offEnd = off + cb;
557 AssertReturn(offEnd > off, VERR_INVALID_PARAMETER);
558 for (RTGCPHYS offCur = off; offCur < offEnd; offCur += PAGE_SIZE)
559 {
560 RTHCPHYS HCPhys;
561 rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iRegion, offCur, &HCPhys);
562 AssertMsgRCReturn(rc, ("rc=%Rrc - iRegion=%d off=%RGp\n", rc, iRegion, off), rc);
563 }
564
565 /*
566 * Add the memory to the hypervisor area.
567 */
568 RTGCPTR GCPtr;
569 PMMLOOKUPHYPER pLookup;
570 rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
571 if (RT_SUCCESS(rc))
572 {
573 pLookup->enmType = MMLOOKUPHYPERTYPE_MMIO2;
574 pLookup->u.MMIO2.pDevIns = pDevIns;
575 pLookup->u.MMIO2.iRegion = iRegion;
576 pLookup->u.MMIO2.off = off;
577
578 /*
579 * Update the page table.
580 */
581 if (pVM->mm.s.fPGMInitialized)
582 {
583 for (RTGCPHYS offCur = off; offCur < offEnd; offCur += PAGE_SIZE)
584 {
585 RTHCPHYS HCPhys;
586 rc = PGMR3PhysMMIO2GetHCPhys(pVM, pDevIns, iRegion, offCur, &HCPhys);
587 AssertRCReturn(rc, rc);
588 rc = PGMMap(pVM, GCPtr + (offCur - off), HCPhys, PAGE_SIZE, 0);
589 if (RT_FAILURE(rc))
590 {
591 AssertMsgFailed(("rc=%Rrc offCur=%RGp %s\n", rc, offCur, pszDesc));
592 break;
593 }
594 }
595 }
596
597 if (RT_SUCCESS(rc))
598 {
599 GCPtr |= offPage;
600 *pRCPtr = GCPtr;
601 AssertLogRelReturn(*pRCPtr == GCPtr, VERR_INTERNAL_ERROR);
602 }
603 }
604 return rc;
605}
606
607
608/**
609 * Maps locked R3 virtual memory into the hypervisor region in the GC.
610 *
611 * @return VBox status code.
612 *
613 * @param pVM Pointer to the VM.
614 * @param pvR3 The ring-3 address of the memory, must be page aligned.
615 * @param pvR0 The ring-0 address of the memory, must be page aligned. (optional)
616 * @param cPages The number of pages.
617 * @param paPages The page descriptors.
618 * @param pszDesc Mapping description.
619 * @param pGCPtr Where to store the GC address corresponding to pvR3.
620 */
621VMMR3DECL(int) MMR3HyperMapPages(PVM pVM, void *pvR3, RTR0PTR pvR0, size_t cPages, PCSUPPAGE paPages,
622 const char *pszDesc, PRTGCPTR pGCPtr)
623{
624 LogFlow(("MMR3HyperMapPages: pvR3=%p pvR0=%p cPages=%zu paPages=%p pszDesc=%p:{%s} pGCPtr=%p\n",
625 pvR3, pvR0, cPages, paPages, pszDesc, pszDesc, pGCPtr));
626
627 /*
628 * Validate input.
629 */
630 AssertPtrReturn(pvR3, VERR_INVALID_POINTER);
631 AssertPtrReturn(paPages, VERR_INVALID_POINTER);
632 AssertReturn(cPages > 0, VERR_PAGE_COUNT_OUT_OF_RANGE);
633 AssertReturn(cPages <= VBOX_MAX_ALLOC_PAGE_COUNT, VERR_PAGE_COUNT_OUT_OF_RANGE);
634 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
635 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
636 AssertPtrReturn(pGCPtr, VERR_INVALID_PARAMETER);
637
638 /*
639 * Add the memory to the hypervisor area.
640 */
641 RTGCPTR GCPtr;
642 PMMLOOKUPHYPER pLookup;
643 int rc = mmR3HyperMap(pVM, cPages << PAGE_SHIFT, pszDesc, &GCPtr, &pLookup);
644 if (RT_SUCCESS(rc))
645 {
646 /*
647 * Copy the physical page addresses and tell PGM about them.
648 */
649 PRTHCPHYS paHCPhysPages = (PRTHCPHYS)MMR3HeapAlloc(pVM, MM_TAG_MM, sizeof(RTHCPHYS) * cPages);
650 if (paHCPhysPages)
651 {
652 for (size_t i = 0; i < cPages; i++)
653 {
654 AssertReleaseMsgReturn( paPages[i].Phys != 0
655 && paPages[i].Phys != NIL_RTHCPHYS
656 && !(paPages[i].Phys & PAGE_OFFSET_MASK),
657 ("i=%#zx Phys=%RHp %s\n", i, paPages[i].Phys, pszDesc),
658 VERR_INTERNAL_ERROR);
659 paHCPhysPages[i] = paPages[i].Phys;
660 }
661
662 if (pVM->mm.s.fPGMInitialized)
663 {
664 for (size_t i = 0; i < cPages; i++)
665 {
666 rc = PGMMap(pVM, GCPtr + (i << PAGE_SHIFT), paHCPhysPages[i], PAGE_SIZE, 0);
667 AssertRCBreak(rc);
668 }
669 }
670 if (RT_SUCCESS(rc))
671 {
672 pLookup->enmType = MMLOOKUPHYPERTYPE_LOCKED;
673 pLookup->u.Locked.pvR3 = pvR3;
674 pLookup->u.Locked.pvR0 = pvR0;
675 pLookup->u.Locked.paHCPhysPages = paHCPhysPages;
676
677 /* done. */
678 *pGCPtr = GCPtr;
679 return rc;
680 }
681 /* Don't care about failure clean, we're screwed if this fails anyway. */
682 }
683 }
684
685 return rc;
686}
687
688
689/**
690 * Reserves a hypervisor memory area.
691 * Most frequent usage is fence pages and dynamically mappings like the guest PD and PDPT.
692 *
693 * @return VBox status code.
694 *
695 * @param pVM Pointer to the VM.
696 * @param cb Size of the memory. Will be rounded up to nearest page.
697 * @param pszDesc Mapping description.
698 * @param pGCPtr Where to store the assigned GC address. Optional.
699 */
700VMMR3DECL(int) MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr)
701{
702 LogFlow(("MMR3HyperMapHCRam: cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", (int)cb, pszDesc, pszDesc, pGCPtr));
703
704 /*
705 * Validate input.
706 */
707 if ( cb <= 0
708 || !pszDesc
709 || !*pszDesc)
710 {
711 AssertMsgFailed(("Invalid parameter\n"));
712 return VERR_INVALID_PARAMETER;
713 }
714
715 /*
716 * Add the memory to the hypervisor area.
717 */
718 RTGCPTR GCPtr;
719 PMMLOOKUPHYPER pLookup;
720 int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
721 if (RT_SUCCESS(rc))
722 {
723 pLookup->enmType = MMLOOKUPHYPERTYPE_DYNAMIC;
724 if (pGCPtr)
725 *pGCPtr = GCPtr;
726 return VINF_SUCCESS;
727 }
728 return rc;
729}
730
731
732/**
733 * Adds memory to the hypervisor memory arena.
734 *
735 * @return VBox status code.
736 * @param pVM Pointer to the VM.
737 * @param cb Size of the memory. Will be rounded up to nearest page.
738 * @param pszDesc The description of the memory.
739 * @param pGCPtr Where to store the GC address.
740 * @param ppLookup Where to store the pointer to the lookup record.
741 * @remark We assume the threading structure of VBox imposes natural
742 * serialization of most functions, this one included.
743 */
744static int mmR3HyperMap(PVM pVM, const size_t cb, const char *pszDesc, PRTGCPTR pGCPtr, PMMLOOKUPHYPER *ppLookup)
745{
746 /*
747 * Validate input.
748 */
749 const uint32_t cbAligned = RT_ALIGN_32(cb, PAGE_SIZE);
750 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
751 if (pVM->mm.s.offHyperNextStatic + cbAligned >= pVM->mm.s.cbHyperArea) /* don't use the last page, it's a fence. */
752 {
753 AssertMsgFailed(("Out of static mapping space in the HMA! offHyperAreaGC=%x cbAligned=%x cbHyperArea=%x\n",
754 pVM->mm.s.offHyperNextStatic, cbAligned, pVM->mm.s.cbHyperArea));
755 return VERR_NO_MEMORY;
756 }
757
758 /*
759 * Allocate lookup record.
760 */
761 PMMLOOKUPHYPER pLookup;
762 int rc = MMHyperAlloc(pVM, sizeof(*pLookup), 1, MM_TAG_MM, (void **)&pLookup);
763 if (RT_SUCCESS(rc))
764 {
765 /*
766 * Initialize it and insert it.
767 */
768 pLookup->offNext = pVM->mm.s.offLookupHyper;
769 pLookup->cb = cbAligned;
770 pLookup->off = pVM->mm.s.offHyperNextStatic;
771 pVM->mm.s.offLookupHyper = (uint8_t *)pLookup - (uint8_t *)pVM->mm.s.pHyperHeapR3;
772 if (pLookup->offNext != (int32_t)NIL_OFFSET)
773 pLookup->offNext -= pVM->mm.s.offLookupHyper;
774 pLookup->enmType = MMLOOKUPHYPERTYPE_INVALID;
775 memset(&pLookup->u, 0xff, sizeof(pLookup->u));
776 pLookup->pszDesc = pszDesc;
777
778 /* Mapping. */
779 *pGCPtr = pVM->mm.s.pvHyperAreaGC + pVM->mm.s.offHyperNextStatic;
780 pVM->mm.s.offHyperNextStatic += cbAligned;
781
782 /* Return pointer. */
783 *ppLookup = pLookup;
784 }
785
786 AssertRC(rc);
787 LogFlow(("mmR3HyperMap: returns %Rrc *pGCPtr=%RGv\n", rc, *pGCPtr));
788 return rc;
789}
790
791
792/**
793 * Allocates a new heap.
794 *
795 * @returns VBox status code.
796 * @param pVM Pointer to the VM.
797 * @param cb The size of the new heap.
798 * @param ppHeap Where to store the heap pointer on successful return.
799 * @param pR0PtrHeap Where to store the ring-0 address of the heap on
800 * success.
801 */
802static int mmR3HyperHeapCreate(PVM pVM, const size_t cb, PMMHYPERHEAP *ppHeap, PRTR0PTR pR0PtrHeap)
803{
804 /*
805 * Allocate the hypervisor heap.
806 */
807 const uint32_t cbAligned = RT_ALIGN_32(cb, PAGE_SIZE);
808 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
809 uint32_t const cPages = cbAligned >> PAGE_SHIFT;
810 PSUPPAGE paPages = (PSUPPAGE)MMR3HeapAlloc(pVM, MM_TAG_MM, cPages * sizeof(paPages[0]));
811 if (!paPages)
812 return VERR_NO_MEMORY;
813 void *pv;
814 RTR0PTR pvR0 = NIL_RTR0PTR;
815 int rc = SUPR3PageAllocEx(cPages,
816 0 /*fFlags*/,
817 &pv,
818#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
819 &pvR0,
820#else
821 NULL,
822#endif
823 paPages);
824 if (RT_SUCCESS(rc))
825 {
826#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
827 pvR0 = (uintptr_t)pv;
828#endif
829 memset(pv, 0, cbAligned);
830
831 /*
832 * Initialize the heap and first free chunk.
833 */
834 PMMHYPERHEAP pHeap = (PMMHYPERHEAP)pv;
835 pHeap->u32Magic = MMHYPERHEAP_MAGIC;
836 pHeap->pbHeapR3 = (uint8_t *)pHeap + MMYPERHEAP_HDR_SIZE;
837 pHeap->pbHeapR0 = pvR0 != NIL_RTR0PTR ? pvR0 + MMYPERHEAP_HDR_SIZE : NIL_RTR0PTR;
838 //pHeap->pbHeapRC = 0; // set by mmR3HyperHeapMap()
839 pHeap->pVMR3 = pVM;
840 pHeap->pVMR0 = pVM->pVMR0;
841 pHeap->pVMRC = pVM->pVMRC;
842 pHeap->cbHeap = cbAligned - MMYPERHEAP_HDR_SIZE;
843 pHeap->cbFree = pHeap->cbHeap - sizeof(MMHYPERCHUNK);
844 //pHeap->offFreeHead = 0;
845 //pHeap->offFreeTail = 0;
846 pHeap->offPageAligned = pHeap->cbHeap;
847 //pHeap->HyperHeapStatTree = 0;
848 pHeap->paPages = paPages;
849
850 PMMHYPERCHUNKFREE pFree = (PMMHYPERCHUNKFREE)pHeap->pbHeapR3;
851 pFree->cb = pHeap->cbFree;
852 //pFree->core.offNext = 0;
853 MMHYPERCHUNK_SET_TYPE(&pFree->core, MMHYPERCHUNK_FLAGS_FREE);
854 pFree->core.offHeap = -(int32_t)MMYPERHEAP_HDR_SIZE;
855 //pFree->offNext = 0;
856 //pFree->offPrev = 0;
857
858 STAMR3Register(pVM, &pHeap->cbHeap, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, "/MM/HyperHeap/cbHeap", STAMUNIT_BYTES, "The heap size.");
859 STAMR3Register(pVM, &pHeap->cbFree, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, "/MM/HyperHeap/cbFree", STAMUNIT_BYTES, "The free space.");
860
861 *ppHeap = pHeap;
862 *pR0PtrHeap = pvR0;
863 return VINF_SUCCESS;
864 }
865 AssertMsgFailed(("SUPR3PageAllocEx(%d,,,,) -> %Rrc\n", cbAligned >> PAGE_SHIFT, rc));
866
867 *ppHeap = NULL;
868 return rc;
869}
870
871/**
872 * Allocates a new heap.
873 */
874static int mmR3HyperHeapMap(PVM pVM, PMMHYPERHEAP pHeap, PRTGCPTR ppHeapGC)
875{
876 Assert(RT_ALIGN_Z(pHeap->cbHeap + MMYPERHEAP_HDR_SIZE, PAGE_SIZE) == pHeap->cbHeap + MMYPERHEAP_HDR_SIZE);
877 Assert(pHeap->paPages);
878 int rc = MMR3HyperMapPages(pVM,
879 pHeap,
880 pHeap->pbHeapR0 != NIL_RTR0PTR ? pHeap->pbHeapR0 - MMYPERHEAP_HDR_SIZE : NIL_RTR0PTR,
881 (pHeap->cbHeap + MMYPERHEAP_HDR_SIZE) >> PAGE_SHIFT,
882 pHeap->paPages,
883 "Heap", ppHeapGC);
884 if (RT_SUCCESS(rc))
885 {
886 pHeap->pVMRC = pVM->pVMRC;
887 pHeap->pbHeapRC = *ppHeapGC + MMYPERHEAP_HDR_SIZE;
888 /* Reserve a page for fencing. */
889 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
890
891 /* We won't need these any more. */
892 MMR3HeapFree(pHeap->paPages);
893 pHeap->paPages = NULL;
894 }
895 return rc;
896}
897
898
899/**
900 * Allocates memory in the Hypervisor (GC VMM) area which never will
901 * be freed and doesn't have any offset based relation to other heap blocks.
902 *
903 * The latter means that two blocks allocated by this API will not have the
904 * same relative position to each other in GC and HC. In short, never use
905 * this API for allocating nodes for an offset based AVL tree!
906 *
907 * The returned memory is of course zeroed.
908 *
909 * @returns VBox status code.
910 * @param pVM Pointer to the VM.
911 * @param cb Number of bytes to allocate.
912 * @param uAlignment Required memory alignment in bytes.
913 * Values are 0,8,16,32 and PAGE_SIZE.
914 * 0 -> default alignment, i.e. 8 bytes.
915 * @param enmTag The statistics tag.
916 * @param ppv Where to store the address to the allocated
917 * memory.
918 * @remark This is assumed not to be used at times when serialization is required.
919 */
920VMMR3DECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv)
921{
922 return MMR3HyperAllocOnceNoRelEx(pVM, cb, uAlignment, enmTag, 0/*fFlags*/, ppv);
923}
924
925
926/**
927 * Allocates memory in the Hypervisor (GC VMM) area which never will
928 * be freed and doesn't have any offset based relation to other heap blocks.
929 *
930 * The latter means that two blocks allocated by this API will not have the
931 * same relative position to each other in GC and HC. In short, never use
932 * this API for allocating nodes for an offset based AVL tree!
933 *
934 * The returned memory is of course zeroed.
935 *
936 * @returns VBox status code.
937 * @param pVM Pointer to the VM.
938 * @param cb Number of bytes to allocate.
939 * @param uAlignment Required memory alignment in bytes.
940 * Values are 0,8,16,32 and PAGE_SIZE.
941 * 0 -> default alignment, i.e. 8 bytes.
942 * @param enmTag The statistics tag.
943 * @param fFlags Flags, see MMHYPER_AONR_FLAGS_KERNEL_MAPPING.
944 * @param ppv Where to store the address to the allocated memory.
945 * @remark This is assumed not to be used at times when serialization is required.
946 */
947VMMR3DECL(int) MMR3HyperAllocOnceNoRelEx(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, uint32_t fFlags, void **ppv)
948{
949 AssertMsg(cb >= 8, ("Hey! Do you really mean to allocate less than 8 bytes?! cb=%d\n", cb));
950 Assert(!(fFlags & ~(MMHYPER_AONR_FLAGS_KERNEL_MAPPING)));
951
952 /*
953 * Choose between allocating a new chunk of HMA memory
954 * and the heap. We will only do BIG allocations from HMA and
955 * only at creation time.
956 */
957 if ( ( cb < _64K
958 && ( uAlignment != PAGE_SIZE
959 || cb < 48*_1K)
960 && !(fFlags & MMHYPER_AONR_FLAGS_KERNEL_MAPPING)
961 )
962 || VMR3GetState(pVM) != VMSTATE_CREATING
963 )
964 {
965 Assert(!(fFlags & MMHYPER_AONR_FLAGS_KERNEL_MAPPING));
966 int rc = MMHyperAlloc(pVM, cb, uAlignment, enmTag, ppv);
967 if ( rc != VERR_MM_HYPER_NO_MEMORY
968 || cb <= 8*_1K)
969 {
970 Log2(("MMR3HyperAllocOnceNoRel: cb=%#zx uAlignment=%#x returns %Rrc and *ppv=%p\n",
971 cb, uAlignment, rc, *ppv));
972 return rc;
973 }
974 }
975
976#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
977 /*
978 * Set MMHYPER_AONR_FLAGS_KERNEL_MAPPING if we're in going to execute in ring-0.
979 */
980 if (HMIsEnabled(pVM))
981 fFlags |= MMHYPER_AONR_FLAGS_KERNEL_MAPPING;
982#endif
983
984 /*
985 * Validate alignment.
986 */
987 switch (uAlignment)
988 {
989 case 0:
990 case 8:
991 case 16:
992 case 32:
993 case PAGE_SIZE:
994 break;
995 default:
996 AssertMsgFailed(("Invalid alignment %u\n", uAlignment));
997 return VERR_INVALID_PARAMETER;
998 }
999
1000 /*
1001 * Allocate the pages and map them into HMA space.
1002 */
1003 uint32_t const cbAligned = RT_ALIGN_32(cb, PAGE_SIZE);
1004 AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
1005 uint32_t const cPages = cbAligned >> PAGE_SHIFT;
1006 PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(paPages[0]));
1007 if (!paPages)
1008 return VERR_NO_TMP_MEMORY;
1009 void *pvPages;
1010 RTR0PTR pvR0 = NIL_RTR0PTR;
1011 int rc = SUPR3PageAllocEx(cPages,
1012 0 /*fFlags*/,
1013 &pvPages,
1014 fFlags & MMHYPER_AONR_FLAGS_KERNEL_MAPPING ? &pvR0 : NULL,
1015 paPages);
1016 if (RT_SUCCESS(rc))
1017 {
1018 if (!(fFlags & MMHYPER_AONR_FLAGS_KERNEL_MAPPING))
1019#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
1020 pvR0 = NIL_RTR0PTR;
1021#else
1022 pvR0 = (RTR0PTR)pvPages;
1023#endif
1024
1025 memset(pvPages, 0, cbAligned);
1026
1027 RTGCPTR GCPtr;
1028 rc = MMR3HyperMapPages(pVM,
1029 pvPages,
1030 pvR0,
1031 cPages,
1032 paPages,
1033 MMR3HeapAPrintf(pVM, MM_TAG_MM, "alloc once (%s)", mmGetTagName(enmTag)),
1034 &GCPtr);
1035 if (RT_SUCCESS(rc))
1036 {
1037 *ppv = pvPages;
1038 Log2(("MMR3HyperAllocOnceNoRel: cbAligned=%#x uAlignment=%#x returns VINF_SUCCESS and *ppv=%p\n",
1039 cbAligned, uAlignment, *ppv));
1040 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
1041 return rc;
1042 }
1043 AssertMsgFailed(("Failed to allocate %zd bytes! %Rrc\n", cbAligned, rc));
1044 SUPR3PageFreeEx(pvPages, cPages);
1045
1046
1047 /*
1048 * HACK ALERT! Try allocate it off the heap so that we don't freak
1049 * out during vga/vmmdev mmio2 allocation with certain ram sizes.
1050 */
1051 /** @todo make a proper fix for this so we will never end up in this kind of situation! */
1052 Log(("MMR3HyperAllocOnceNoRel: MMR3HyperMapHCRam failed with rc=%Rrc, try MMHyperAlloc(,%#x,,) instead\n", rc, cb));
1053 int rc2 = MMHyperAlloc(pVM, cb, uAlignment, enmTag, ppv);
1054 if (RT_SUCCESS(rc2))
1055 {
1056 Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns %Rrc and *ppv=%p\n",
1057 cb, uAlignment, rc, *ppv));
1058 return rc;
1059 }
1060 }
1061 else
1062 AssertMsgFailed(("Failed to allocate %zd bytes! %Rrc\n", cbAligned, rc));
1063
1064 if (rc == VERR_NO_MEMORY)
1065 rc = VERR_MM_HYPER_NO_MEMORY;
1066 LogRel(("MMR3HyperAllocOnceNoRel: cb=%#zx uAlignment=%#x returns %Rrc\n", cb, uAlignment, rc));
1067 return rc;
1068}
1069
1070
1071/**
1072 * Lookus up a ring-3 pointer to HMA.
1073 *
1074 * @returns The lookup record on success, NULL on failure.
1075 * @param pVM Pointer to the VM.
1076 * @param pvR3 The ring-3 address to look up.
1077 */
1078DECLINLINE(PMMLOOKUPHYPER) mmR3HyperLookupR3(PVM pVM, void *pvR3)
1079{
1080 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uint8_t *)pVM->mm.s.pHyperHeapR3 + pVM->mm.s.offLookupHyper);
1081 for (;;)
1082 {
1083 switch (pLookup->enmType)
1084 {
1085 case MMLOOKUPHYPERTYPE_LOCKED:
1086 {
1087 unsigned off = (uint8_t *)pvR3 - (uint8_t *)pLookup->u.Locked.pvR3;
1088 if (off < pLookup->cb)
1089 return pLookup;
1090 break;
1091 }
1092
1093 case MMLOOKUPHYPERTYPE_HCPHYS:
1094 {
1095 unsigned off = (uint8_t *)pvR3 - (uint8_t *)pLookup->u.HCPhys.pvR3;
1096 if (off < pLookup->cb)
1097 return pLookup;
1098 break;
1099 }
1100
1101 case MMLOOKUPHYPERTYPE_GCPHYS:
1102 case MMLOOKUPHYPERTYPE_MMIO2:
1103 case MMLOOKUPHYPERTYPE_DYNAMIC:
1104 /** @todo ? */
1105 break;
1106
1107 default:
1108 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
1109 return NULL;
1110 }
1111
1112 /* next */
1113 if ((unsigned)pLookup->offNext == NIL_OFFSET)
1114 return NULL;
1115 pLookup = (PMMLOOKUPHYPER)((uint8_t *)pLookup + pLookup->offNext);
1116 }
1117}
1118
1119
1120/**
1121 * Set / unset guard status on one or more hyper heap pages.
1122 *
1123 * @returns VBox status code (first failure).
1124 * @param pVM Pointer to the VM.
1125 * @param pvStart The hyper heap page address. Must be page
1126 * aligned.
1127 * @param cb The number of bytes. Must be page aligned.
1128 * @param fSet Whether to set or unset guard page status.
1129 */
1130VMMR3DECL(int) MMR3HyperSetGuard(PVM pVM, void *pvStart, size_t cb, bool fSet)
1131{
1132 /*
1133 * Validate input.
1134 */
1135 AssertReturn(!((uintptr_t)pvStart & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
1136 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1137 AssertReturn(cb <= UINT32_MAX, VERR_INVALID_PARAMETER);
1138 PMMLOOKUPHYPER pLookup = mmR3HyperLookupR3(pVM, pvStart);
1139 AssertReturn(pLookup, VERR_INVALID_PARAMETER);
1140 AssertReturn(pLookup->enmType == MMLOOKUPHYPERTYPE_LOCKED, VERR_INVALID_PARAMETER);
1141
1142 /*
1143 * Get down to business.
1144 * Note! We quietly ignore errors from the support library since the
1145 * protection stuff isn't possible to implement on all platforms.
1146 */
1147 uint8_t *pbR3 = (uint8_t *)pLookup->u.Locked.pvR3;
1148 RTR0PTR R0Ptr = pLookup->u.Locked.pvR0 != (uintptr_t)pLookup->u.Locked.pvR3
1149 ? pLookup->u.Locked.pvR0
1150 : NIL_RTR0PTR;
1151 uint32_t off = (uint32_t)((uint8_t *)pvStart - pbR3);
1152 int rc;
1153 if (fSet)
1154 {
1155 rc = PGMMapSetPage(pVM, MMHyperR3ToRC(pVM, pvStart), cb, 0);
1156 SUPR3PageProtect(pbR3, R0Ptr, off, (uint32_t)cb, RTMEM_PROT_NONE);
1157 }
1158 else
1159 {
1160 rc = PGMMapSetPage(pVM, MMHyperR3ToRC(pVM, pvStart), cb, X86_PTE_P | X86_PTE_A | X86_PTE_D | X86_PTE_RW);
1161 SUPR3PageProtect(pbR3, R0Ptr, off, (uint32_t)cb, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
1162 }
1163 return rc;
1164}
1165
1166
1167/**
1168 * Convert hypervisor HC virtual address to HC physical address.
1169 *
1170 * @returns HC physical address.
1171 * @param pVM Pointer to the VM
1172 * @param pvR3 Host context virtual address.
1173 */
1174VMMR3DECL(RTHCPHYS) MMR3HyperHCVirt2HCPhys(PVM pVM, void *pvR3)
1175{
1176 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uint8_t *)pVM->mm.s.pHyperHeapR3 + pVM->mm.s.offLookupHyper);
1177 for (;;)
1178 {
1179 switch (pLookup->enmType)
1180 {
1181 case MMLOOKUPHYPERTYPE_LOCKED:
1182 {
1183 unsigned off = (uint8_t *)pvR3 - (uint8_t *)pLookup->u.Locked.pvR3;
1184 if (off < pLookup->cb)
1185 return pLookup->u.Locked.paHCPhysPages[off >> PAGE_SHIFT] | (off & PAGE_OFFSET_MASK);
1186 break;
1187 }
1188
1189 case MMLOOKUPHYPERTYPE_HCPHYS:
1190 {
1191 unsigned off = (uint8_t *)pvR3 - (uint8_t *)pLookup->u.HCPhys.pvR3;
1192 if (off < pLookup->cb)
1193 return pLookup->u.HCPhys.HCPhys + off;
1194 break;
1195 }
1196
1197 case MMLOOKUPHYPERTYPE_GCPHYS:
1198 case MMLOOKUPHYPERTYPE_MMIO2:
1199 case MMLOOKUPHYPERTYPE_DYNAMIC:
1200 /* can (or don't want to) convert these kind of records. */
1201 break;
1202
1203 default:
1204 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
1205 break;
1206 }
1207
1208 /* next */
1209 if ((unsigned)pLookup->offNext == NIL_OFFSET)
1210 break;
1211 pLookup = (PMMLOOKUPHYPER)((uint8_t *)pLookup + pLookup->offNext);
1212 }
1213
1214 AssertMsgFailed(("pvR3=%p is not inside the hypervisor memory area!\n", pvR3));
1215 return NIL_RTHCPHYS;
1216}
1217
1218
1219/**
1220 * Implements the hcphys-not-found return case of MMR3HyperQueryInfoFromHCPhys.
1221 *
1222 * @returns VINF_SUCCESS, VINF_BUFFER_OVERFLOW.
1223 * @param pVM Pointer to the VM.
1224 * @param HCPhys The host physical address to look for.
1225 * @param pLookup The HMA lookup entry corresponding to HCPhys.
1226 * @param pszWhat Where to return the description.
1227 * @param cbWhat Size of the return buffer.
1228 * @param pcbAlloc Where to return the size of whatever it is.
1229 */
1230static int mmR3HyperQueryInfoFromHCPhysFound(PVM pVM, RTHCPHYS HCPhys, PMMLOOKUPHYPER pLookup,
1231 char *pszWhat, size_t cbWhat, uint32_t *pcbAlloc)
1232{
1233 NOREF(pVM); NOREF(HCPhys);
1234 *pcbAlloc = pLookup->cb;
1235 int rc = RTStrCopy(pszWhat, cbWhat, pLookup->pszDesc);
1236 return rc == VERR_BUFFER_OVERFLOW ? VINF_BUFFER_OVERFLOW : rc;
1237}
1238
1239
1240/**
1241 * Scans the HMA for the physical page and reports back a description if found.
1242 *
1243 * @returns VINF_SUCCESS, VINF_BUFFER_OVERFLOW, VERR_NOT_FOUND.
1244 * @param pVM Pointer to the VM.
1245 * @param HCPhys The host physical address to look for.
1246 * @param pszWhat Where to return the description.
1247 * @param cbWhat Size of the return buffer.
1248 * @param pcbAlloc Where to return the size of whatever it is.
1249 */
1250VMMR3_INT_DECL(int) MMR3HyperQueryInfoFromHCPhys(PVM pVM, RTHCPHYS HCPhys, char *pszWhat, size_t cbWhat, uint32_t *pcbAlloc)
1251{
1252 RTHCPHYS HCPhysPage = HCPhys & ~(RTHCPHYS)PAGE_OFFSET_MASK;
1253 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uint8_t *)pVM->mm.s.pHyperHeapR3 + pVM->mm.s.offLookupHyper);
1254 for (;;)
1255 {
1256 switch (pLookup->enmType)
1257 {
1258 case MMLOOKUPHYPERTYPE_LOCKED:
1259 {
1260 uint32_t i = pLookup->cb >> PAGE_SHIFT;
1261 while (i-- > 0)
1262 if (pLookup->u.Locked.paHCPhysPages[i] == HCPhysPage)
1263 return mmR3HyperQueryInfoFromHCPhysFound(pVM, HCPhys, pLookup, pszWhat, cbWhat, pcbAlloc);
1264 break;
1265 }
1266
1267 case MMLOOKUPHYPERTYPE_HCPHYS:
1268 {
1269 if (pLookup->u.HCPhys.HCPhys - HCPhysPage < pLookup->cb)
1270 return mmR3HyperQueryInfoFromHCPhysFound(pVM, HCPhys, pLookup, pszWhat, cbWhat, pcbAlloc);
1271 break;
1272 }
1273
1274 case MMLOOKUPHYPERTYPE_MMIO2:
1275 case MMLOOKUPHYPERTYPE_GCPHYS:
1276 case MMLOOKUPHYPERTYPE_DYNAMIC:
1277 {
1278 /* brute force. */
1279 uint32_t i = pLookup->cb >> PAGE_SHIFT;
1280 while (i-- > 0)
1281 {
1282 RTGCPTR GCPtr = pLookup->off + pVM->mm.s.pvHyperAreaGC;
1283 RTHCPHYS HCPhysCur;
1284 int rc = PGMMapGetPage(pVM, GCPtr, NULL, &HCPhysCur);
1285 if (RT_SUCCESS(rc) && HCPhysCur == HCPhysPage)
1286 return mmR3HyperQueryInfoFromHCPhysFound(pVM, HCPhys, pLookup, pszWhat, cbWhat, pcbAlloc);
1287 }
1288 break;
1289 }
1290 default:
1291 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
1292 break;
1293 }
1294
1295 /* next */
1296 if ((unsigned)pLookup->offNext == NIL_OFFSET)
1297 break;
1298 pLookup = (PMMLOOKUPHYPER)((uint8_t *)pLookup + pLookup->offNext);
1299 }
1300 return VERR_NOT_FOUND;
1301}
1302
1303
1304#if 0 /* unused, not implemented */
1305/**
1306 * Convert hypervisor HC physical address to HC virtual address.
1307 *
1308 * @returns HC virtual address.
1309 * @param pVM Pointer to the VM
1310 * @param HCPhys Host context physical address.
1311 */
1312VMMR3DECL(void *) MMR3HyperHCPhys2HCVirt(PVM pVM, RTHCPHYS HCPhys)
1313{
1314 void *pv;
1315 int rc = MMR3HyperHCPhys2HCVirtEx(pVM, HCPhys, &pv);
1316 if (RT_SUCCESS(rc))
1317 return pv;
1318 AssertMsgFailed(("Invalid address HCPhys=%x rc=%d\n", HCPhys, rc));
1319 return NULL;
1320}
1321
1322
1323/**
1324 * Convert hypervisor HC physical address to HC virtual address.
1325 *
1326 * @returns VBox status.
1327 * @param pVM Pointer to the VM
1328 * @param HCPhys Host context physical address.
1329 * @param ppv Where to store the HC virtual address.
1330 */
1331VMMR3DECL(int) MMR3HyperHCPhys2HCVirtEx(PVM pVM, RTHCPHYS HCPhys, void **ppv)
1332{
1333 /*
1334 * Linear search.
1335 */
1336 /** @todo implement when actually used. */
1337 return VERR_INVALID_POINTER;
1338}
1339#endif /* unused, not implemented */
1340
1341
1342/**
1343 * Read hypervisor memory from GC virtual address.
1344 *
1345 * @returns VBox status.
1346 * @param pVM Pointer to the VM.
1347 * @param pvDst Destination address (HC of course).
1348 * @param GCPtr GC virtual address.
1349 * @param cb Number of bytes to read.
1350 *
1351 * @remarks For DBGF only.
1352 */
1353VMMR3DECL(int) MMR3HyperReadGCVirt(PVM pVM, void *pvDst, RTGCPTR GCPtr, size_t cb)
1354{
1355 if (GCPtr - pVM->mm.s.pvHyperAreaGC >= pVM->mm.s.cbHyperArea)
1356 return VERR_INVALID_POINTER;
1357 return PGMR3MapRead(pVM, pvDst, GCPtr, cb);
1358}
1359
1360
1361/**
1362 * Info handler for 'hma', it dumps the list of lookup records for the hypervisor memory area.
1363 *
1364 * @param pVM Pointer to the VM.
1365 * @param pHlp Callback functions for doing output.
1366 * @param pszArgs Argument string. Optional and specific to the handler.
1367 */
1368static DECLCALLBACK(void) mmR3HyperInfoHma(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1369{
1370 NOREF(pszArgs);
1371
1372 pHlp->pfnPrintf(pHlp, "Hypervisor Memory Area (HMA) Layout: Base %RGv, 0x%08x bytes\n",
1373 pVM->mm.s.pvHyperAreaGC, pVM->mm.s.cbHyperArea);
1374
1375 PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uint8_t *)pVM->mm.s.pHyperHeapR3 + pVM->mm.s.offLookupHyper);
1376 for (;;)
1377 {
1378 switch (pLookup->enmType)
1379 {
1380 case MMLOOKUPHYPERTYPE_LOCKED:
1381 pHlp->pfnPrintf(pHlp, "%RGv-%RGv %RHv %RHv LOCKED %-*s %s\n",
1382 pLookup->off + pVM->mm.s.pvHyperAreaGC,
1383 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
1384 pLookup->u.Locked.pvR3,
1385 pLookup->u.Locked.pvR0,
1386 sizeof(RTHCPTR) * 2, "",
1387 pLookup->pszDesc);
1388 break;
1389
1390 case MMLOOKUPHYPERTYPE_HCPHYS:
1391 pHlp->pfnPrintf(pHlp, "%RGv-%RGv %RHv %RHv HCPHYS %RHp %s\n",
1392 pLookup->off + pVM->mm.s.pvHyperAreaGC,
1393 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
1394 pLookup->u.HCPhys.pvR3,
1395 pLookup->u.HCPhys.pvR0,
1396 pLookup->u.HCPhys.HCPhys,
1397 pLookup->pszDesc);
1398 break;
1399
1400 case MMLOOKUPHYPERTYPE_GCPHYS:
1401 pHlp->pfnPrintf(pHlp, "%RGv-%RGv %*s GCPHYS %RGp%*s %s\n",
1402 pLookup->off + pVM->mm.s.pvHyperAreaGC,
1403 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
1404 sizeof(RTHCPTR) * 2 * 2 + 1, "",
1405 pLookup->u.GCPhys.GCPhys, RT_ABS((int)(sizeof(RTHCPHYS) - sizeof(RTGCPHYS))) * 2, "",
1406 pLookup->pszDesc);
1407 break;
1408
1409 case MMLOOKUPHYPERTYPE_MMIO2:
1410 pHlp->pfnPrintf(pHlp, "%RGv-%RGv %*s MMIO2 %RGp%*s %s\n",
1411 pLookup->off + pVM->mm.s.pvHyperAreaGC,
1412 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
1413 sizeof(RTHCPTR) * 2 * 2 + 1, "",
1414 pLookup->u.MMIO2.off, RT_ABS((int)(sizeof(RTHCPHYS) - sizeof(RTGCPHYS))) * 2, "",
1415 pLookup->pszDesc);
1416 break;
1417
1418 case MMLOOKUPHYPERTYPE_DYNAMIC:
1419 pHlp->pfnPrintf(pHlp, "%RGv-%RGv %*s DYNAMIC %*s %s\n",
1420 pLookup->off + pVM->mm.s.pvHyperAreaGC,
1421 pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
1422 sizeof(RTHCPTR) * 2 * 2 + 1, "",
1423 sizeof(RTHCPTR) * 2, "",
1424 pLookup->pszDesc);
1425 break;
1426
1427 default:
1428 AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
1429 break;
1430 }
1431
1432 /* next */
1433 if ((unsigned)pLookup->offNext == NIL_OFFSET)
1434 break;
1435 pLookup = (PMMLOOKUPHYPER)((uint8_t *)pLookup + pLookup->offNext);
1436 }
1437}
1438
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use