/* * \brief VirtualBox memory manager (MMR3) * \author Norman Feske * \date 2013-08-20 */ /* * Copyright (C) 2013-2017 Genode Labs GmbH * * This file is distributed under the terms of the GNU General Public License * version 2. */ /* Genode includes */ #include #include #include #include /* VirtualBox includes */ #include #include #include #include #include "MMInternal.h" #include #include #include #include #include /* libc memory allocator */ #include #include "util.h" #include "mm.h" #include "vmm.h" enum { VERBOSE_MM = false }; static struct { Sub_rm_connection * conn; Libc::Mem_alloc_impl * heap; } memory_regions [MM_TAG_HM + 1]; static Libc::Mem_alloc * heap_by_mmtag(MMTAG enmTag) { enum { REGION_SIZE = 4096 * 4096 }; static Genode::Lock memory_init_lock; Assert(enmTag < sizeof(memory_regions) / sizeof(memory_regions[0])); if (memory_regions[enmTag].conn) return memory_regions[enmTag].heap; Genode::Lock::Guard guard(memory_init_lock); if (memory_regions[enmTag].conn) return memory_regions[enmTag].heap; memory_regions[enmTag].conn = new Sub_rm_connection(genode_env(), REGION_SIZE); memory_regions[enmTag].heap = new Libc::Mem_alloc_impl(*memory_regions[enmTag].conn, genode_env().ram()); return memory_regions[enmTag].heap; } static Libc::Mem_alloc * heap_by_pointer(void * pv) { for (unsigned i = 0; i < sizeof(memory_regions) / sizeof(memory_regions[0]); i++) { if (!memory_regions[i].heap) continue; if (memory_regions[i].conn->contains(pv)) return memory_regions[i].heap; } return nullptr; } int MMR3Init(PVM) { return VINF_SUCCESS; } int MMR3Term(PVM) { return VINF_SUCCESS; } int MMR3InitUVM(PUVM) { return VINF_SUCCESS; } void MMR3TermUVM(PUVM) { } void *MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize) { return heap_by_mmtag(enmTag)->alloc(cbSize, Genode::log2(RTMEM_ALIGNMENT)); } /** * Return alignment to be used for allocations of given tag */ static unsigned align_by_mmtag(MMTAG enmTag) { switch (enmTag) { case MM_TAG_PGM: case MM_TAG_PDM_DEVICE: case MM_TAG_PDM_DEVICE_USER: case MM_TAG_VMM: case MM_TAG_CPUM_CTX: return 12; case MM_TAG_CPUM_CPUID: case MM_TAG_CPUM_MSRS: return Genode::log2(32); case MM_TAG_PGM_PHYS: return Genode::log2(16); default: return Genode::log2(RTMEM_ALIGNMENT); } } /** * Round allocation size for a given tag */ static size_t round_size_by_mmtag(MMTAG enmTag, size_t cb) { return Genode::align_addr(cb, align_by_mmtag(enmTag)); } void *MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize) { size_t const rounded_size = round_size_by_mmtag(enmTag, cbSize); return heap_by_mmtag(enmTag)->alloc(rounded_size, align_by_mmtag(enmTag)); } void *MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize) { void * const ret = MMR3HeapAlloc(pVM, enmTag, cbSize); if (ret) Genode::memset(ret, 0, cbSize); return ret; } void * MMR3HeapAllocZU(PUVM pUVM, MMTAG enmTag, size_t cbSize) { void * const ret = MMR3HeapAllocU(pUVM, enmTag, cbSize); if (ret) Genode::memset(ret, 0, cbSize); return ret; } void * MMR3UkHeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize, PRTR0PTR pR0Ptr) { if (pR0Ptr) *pR0Ptr = NIL_RTR0PTR; return MMR3HeapAllocZ(pVM, enmTag, cbSize); } int MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv) { *ppv = MMR3HeapAllocZ(pVM, enmTag, cbSize); return VINF_SUCCESS; } int MMR3HyperInitFinalize(PVM) { return VINF_SUCCESS; } int MMR3HyperSetGuard(PVM, void* ptr, size_t, bool) { return VINF_SUCCESS; } int MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv) { AssertRelease(align_by_mmtag(enmTag) >= (uAlignment ? Genode::log2(uAlignment) : 0)); unsigned const align_log2 = uAlignment ? Genode::log2(uAlignment) : align_by_mmtag(enmTag); size_t const rounded_size = round_size_by_mmtag(enmTag, cb); void *ret = heap_by_mmtag(enmTag)->alloc(rounded_size, align_log2); if (ret) Genode::memset(ret, 0, cb); *ppv = ret; return VINF_SUCCESS; } int MMR3HyperAllocOnceNoRelEx(PVM pVM, size_t cb, uint32_t uAlignment, MMTAG enmTag, uint32_t fFlags, void **ppv) { AssertRelease(align_by_mmtag(enmTag) >= (uAlignment ? Genode::log2(uAlignment) : 0)); return MMR3HyperAllocOnceNoRel(pVM, cb, uAlignment, enmTag, ppv); } int MMHyperAlloc(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv) { if (!(align_by_mmtag(enmTag) >= (uAlignment ? Genode::log2(uAlignment) : 0))) Genode::error(__func__, " ", (int)enmTag, " ", uAlignment, " ", (int)MM_TAG_PGM); AssertRelease(align_by_mmtag(enmTag) >= (uAlignment ? Genode::log2(uAlignment) : 0)); *ppv = MMR3HeapAllocZ(pVM, enmTag, cb); return VINF_SUCCESS; } int MMHyperFree(PVM pVM, void *pv) { MMR3HeapFree(pv); return VINF_SUCCESS; } int MMHyperDupMem(PVM pVM, const void *pvSrc, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv) { int rc = MMHyperAlloc(pVM, cb, uAlignment, enmTag, ppv); if (RT_SUCCESS(rc)) memcpy(*ppv, pvSrc, cb); return rc; } bool MMHyperIsInsideArea(PVM, RTGCPTR ptr) { Genode::log(__func__, " called"); return false; } void MMR3HeapFree(void *pv) { Libc::Mem_alloc *heap = heap_by_pointer(pv); Assert(heap); heap->free(pv); } int MMR3HyperMapHCPhys(PVM pVM, void *pvR3, RTR0PTR pvR0, RTHCPHYS HCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr) { static_assert(sizeof(*pGCPtr) == sizeof(HCPhys) , "pointer transformation bug"); *pGCPtr = (RTGCPTR)HCPhys; return VINF_SUCCESS; } int MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr) { if (VERBOSE_MM) Genode::log("MMR3HyperReserve: cb=", Genode::Hex(cb), ", " "pszDesc=", pszDesc); return VINF_SUCCESS; } int MMR3AdjustFixedReservation(PVM, int32_t, const char *pszDesc) { if (VERBOSE_MM) Genode::log(__func__, " called for '", pszDesc, "'"); return VINF_SUCCESS; } int MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb, const char *pszDesc, PRTRCPTR pRCPtr) { if (VERBOSE_MM) Genode::log("pszDesc=", pszDesc, " iRegion=", iRegion, " " "off=", Genode::Hex(off), " cb=", Genode::Hex(cb)); return VINF_SUCCESS; } VMMR3DECL(RTHCPHYS) MMR3HyperHCVirt2HCPhys(PVM pVM, void *pvR3) { return (RTHCPHYS)(uintptr_t)pvR3; } VMMDECL(RTHCPHYS) MMPage2Phys(PVM pVM, void *pvPage) { return (RTHCPHYS)(uintptr_t)pvPage; } VMMR3DECL(void *) MMR3PageAlloc(PVM pVM) { using Genode::Attached_ram_dataspace; Attached_ram_dataspace * ds = new Attached_ram_dataspace(genode_env().ram(), genode_env().rm(), 4096); return ds->local_addr(); } VMMR3DECL(void *) MMR3PageAllocLow(PVM pVM) { return MMR3PageAlloc(pVM); } int MMR3ReserveHandyPages(PVM pVM, uint32_t cHandyPages) { if (VERBOSE_MM) Genode::log(__func__, " called"); return VINF_SUCCESS; } VMMDECL(void *) MMHyperHeapOffsetToPtr(PVM pVM, uint32_t offHeap) { if (sizeof(void*) == 8) { uint64_t ptr = offHeap; return reinterpret_cast(ptr); } return reinterpret_cast(offHeap); } VMMDECL(uint32_t) MMHyperHeapPtrToOffset(PVM pVM, void *pv) { Genode::addr_t offset = reinterpret_cast(pv); Assert (reinterpret_cast(offset) == pv); return offset; }