/** * Get the statistic record for a tag. * * @returns Pointer to a stat record. * @returns NULL on failure. * @param pHeap The heap. * @param enmTag The tag. */ static PMMHYPERSTAT mmHyperStat(PMMHYPERHEAP pHeap, MMTAG enmTag) { /* try look it up first. */ PMMHYPERSTAT pStat = (PMMHYPERSTAT)RTAvloGCPhysGet(&pHeap->HyperHeapStatTree, enmTag); if (!pStat) { /* try allocate a new one */ PMMHYPERCHUNK pChunk = mmHyperAllocChunk(pHeap, RT_ALIGN(sizeof(*pStat), MMHYPER_HEAP_ALIGN_MIN), MMHYPER_HEAP_ALIGN_MIN); if (!pChunk) return NULL; pStat = (PMMHYPERSTAT)(pChunk + 1); pChunk->offStat = (uintptr_t)pStat - (uintptr_t)pChunk; ASMMemZero32(pStat, sizeof(*pStat)); pStat->Core.Key = enmTag; RTAvloGCPhysInsert(&pHeap->HyperHeapStatTree, &pStat->Core); } if (!pStat->fRegistered) { # ifdef IN_RING3 mmR3HyperStatRegisterOne(pHeap->pVMR3, pStat); # else /** @todo schedule a R3 action. */ # endif } return pStat; }
/** * Allocates and maps one physically contiguous page. The allocated page is * zero'd out. * * @returns IPRT status code. * @param pMemObj Pointer to the ring-0 memory object. * @param ppVirt Where to store the virtual address of the * allocation. * @param pPhys Where to store the physical address of the * allocation. */ static int gimR0HvPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys) { AssertPtr(pMemObj); AssertPtr(ppVirt); AssertPtr(pHCPhys); int rc = RTR0MemObjAllocCont(pMemObj, PAGE_SIZE, false /* fExecutable */); if (RT_FAILURE(rc)) return rc; *ppVirt = RTR0MemObjAddress(*pMemObj); *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */); ASMMemZero32(*ppVirt, PAGE_SIZE); return VINF_SUCCESS; }
/** * Allocates memory in the Hypervisor (RC VMM) area. * The returned memory is of course zeroed. * * @returns VBox status code. * @param pVM The VM to operate on. * @param cb Number of bytes to allocate. * @param uAlignment Required memory alignment in bytes. * Values are 0,8,16,32,64 and PAGE_SIZE. * 0 -> default alignment, i.e. 8 bytes. * @param enmTag The statistics tag. * @param ppv Where to store the address to the allocated * memory. */ static int mmHyperAllocInternal(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv) { AssertMsg(cb >= 8, ("Hey! Do you really mean to allocate less than 8 bytes?! cb=%d\n", cb)); /* * Validate input and adjust it to reasonable values. */ if (!uAlignment || uAlignment < MMHYPER_HEAP_ALIGN_MIN) uAlignment = MMHYPER_HEAP_ALIGN_MIN; uint32_t cbAligned; switch (uAlignment) { case 8: case 16: case 32: case 64: cbAligned = RT_ALIGN_32(cb, MMHYPER_HEAP_ALIGN_MIN); if (!cbAligned || cbAligned < cb) { Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VERR_INVALID_PARAMETER\n", cb, uAlignment)); AssertMsgFailed(("Nice try.\n")); return VERR_INVALID_PARAMETER; } break; case PAGE_SIZE: AssertMsg(RT_ALIGN_32(cb, PAGE_SIZE) == cb, ("The size isn't page aligned. (cb=%#x)\n", cb)); cbAligned = RT_ALIGN_32(cb, PAGE_SIZE); if (!cbAligned) { Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VERR_INVALID_PARAMETER\n", cb, uAlignment)); AssertMsgFailed(("Nice try.\n")); return VERR_INVALID_PARAMETER; } break; default: Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VERR_INVALID_PARAMETER\n", cb, uAlignment)); AssertMsgFailed(("Invalid alignment %u\n", uAlignment)); return VERR_INVALID_PARAMETER; } /* * Get heap and statisticsStatistics. */ PMMHYPERHEAP pHeap = pVM->mm.s.CTX_SUFF(pHyperHeap); #ifdef VBOX_WITH_STATISTICS PMMHYPERSTAT pStat = mmHyperStat(pHeap, enmTag); if (!pStat) { Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VERR_MM_HYPER_NO_MEMORY\n", cb, uAlignment)); AssertMsgFailed(("Failed to allocate statistics!\n")); return VERR_MM_HYPER_NO_MEMORY; } #endif if (uAlignment < PAGE_SIZE) { /* * Allocate a chunk. */ PMMHYPERCHUNK pChunk = mmHyperAllocChunk(pHeap, cbAligned, uAlignment); if (pChunk) { #ifdef VBOX_WITH_STATISTICS const uint32_t cbChunk = pChunk->offNext ? pChunk->offNext : pHeap->CTX_SUFF(pbHeap) + pHeap->offPageAligned - (uint8_t *)pChunk; pStat->cbAllocated += (uint32_t)cbChunk; pStat->cbCurAllocated += (uint32_t)cbChunk; if (pStat->cbCurAllocated > pStat->cbMaxAllocated) pStat->cbMaxAllocated = pStat->cbCurAllocated; pStat->cAllocations++; pChunk->offStat = (uintptr_t)pStat - (uintptr_t)pChunk; #else pChunk->offStat = 0; #endif void *pv = pChunk + 1; *ppv = pv; ASMMemZero32(pv, cbAligned); Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VINF_SUCCESS and *ppv=%p\n", cb, uAlignment, pv)); return VINF_SUCCESS; } } else { /* * Allocate page aligned memory. */ void *pv = mmHyperAllocPages(pHeap, cbAligned); if (pv) { #ifdef VBOX_WITH_STATISTICS pStat->cbAllocated += cbAligned; pStat->cbCurAllocated += cbAligned; if (pStat->cbCurAllocated > pStat->cbMaxAllocated) pStat->cbMaxAllocated = pStat->cbCurAllocated; pStat->cAllocations++; #endif *ppv = pv; /* ASMMemZero32(pv, cbAligned); - not required since memory is alloc-only and SUPR3PageAlloc zeros it. */ Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VINF_SUCCESS and *ppv=%p\n", cb, uAlignment, ppv)); return VINF_SUCCESS; } } #ifdef VBOX_WITH_STATISTICS pStat->cAllocations++; pStat->cFailures++; #endif Log2(("MMHyperAlloc: cb=%#x uAlignment=%#x returns VERR_MM_HYPER_NO_MEMORY\n", cb, uAlignment)); AssertMsgFailed(("Failed to allocate %d bytes!\n", cb)); return VERR_MM_HYPER_NO_MEMORY; }