static std::string GX2PointerAsString(const void *pointer) { fmt::MemoryWriter format; format.write("{:08X}", memory_untranslate(pointer)); return format.str(); }
static BOOL spinTryLock(OSSpinLock *spinlock) { uint32_t owner, expected; auto thread = OSGetCurrentThread(); if (!thread) { return FALSE; } owner = memory_untranslate(thread); if (spinlock->owner.load(std::memory_order_relaxed) == owner) { ++spinlock->recursion; return TRUE; } expected = 0; if (spinlock->owner.compare_exchange_weak(expected, owner, std::memory_order_release, std::memory_order_relaxed)) { return TRUE; } else { return FALSE; } }
static int MEM_DynLoad_DefaultAlloc(int size, int alignment, be_val<uint32_t> *outPtr) { auto heap = MEMGetBaseHeapHandle(BaseHeapType::MEM2); auto memory = MEMAllocFromExpHeapEx(reinterpret_cast<ExpandedHeap*>(heap), size, alignment); *outPtr = memory_untranslate(memory); return 0; }
z_stream * getZStream(WZStream *in) { auto zstream = &gStreamMap[memory_untranslate(in)]; zstream->opaque = in; zstream->zalloc = &zlibAllocWrapper; zstream->zfree = &zlibFreeWrapper; return zstream; }
void MEMiDumpExpHeap(ExpandedHeap *heap) { gLog->debug("MEMiDumpExpHeap({:8x})", memory_untranslate(heap)); gLog->debug("Status Address Size Group"); for (auto block = heap->freeBlockList; block; block = block->next) { gLog->debug("FREE {:8x} {:8x} {:d}", block->addr, block->size, block->group); } for (auto block = heap->usedBlockList; block; block = block->next) { gLog->debug("USED {:8x} {:8x} {:d}", block->addr, block->size, block->group); } }
static CommonHeap * findHeapContainingBlock(MemoryList *list, void *block) { CommonHeap *heap = nullptr; uint32_t addr = memory_untranslate(block); while ((heap = reinterpret_cast<CommonHeap*>(MEMGetNextListObject(list, heap)))) { if (addr >= heap->dataStart && addr < heap->dataEnd) { auto child = findHeapContainingBlock(&heap->list, block); return child ? child : heap; } } return nullptr; }
void MEMFreeToExpHeap(ExpandedHeap *heap, uint8_t *address) { ScopedSpinLock lock(&heap->lock); auto base = memory_untranslate(address); if (!base) { return; } if (base < heap->bottom || base >= heap->top) { gLog->warn("FreeToExpHeap outside heap region; {:08x} not within {:08x}-{:08x}", base, heap->bottom, heap->top); return; } // Get the block header base = base - static_cast<uint32_t>(sizeof(ExpandedHeapBlock)); // Remove used blocked auto usedBlock = make_virtual_ptr<ExpandedHeapBlock>(base); auto addr = usedBlock->addr; auto size = usedBlock->size; eraseBlock(heap->usedBlockList, usedBlock); // Create free block auto freeBlock = make_virtual_ptr<ExpandedHeapBlock>(addr); freeBlock->addr = addr; freeBlock->size = size; insertBlock(heap->freeBlockList, freeBlock); // Merge with next free if contiguous auto nextFree = freeBlock->next; if (nextFree && nextFree->addr == freeBlock->addr + freeBlock->size) { freeBlock->size += nextFree->size; eraseBlock(heap->freeBlockList, nextFree); } // Merge with previous free if contiguous auto prevFree = freeBlock->prev; if (prevFree && freeBlock->addr == prevFree->addr + prevFree->size) { prevFree->size += freeBlock->size; eraseBlock(heap->freeBlockList, freeBlock); } }
static MemoryList * findListContainingBlock(void *block) { be_val<uint32_t> start, size, end; uint32_t addr = memory_untranslate(block); OSGetForegroundBucket(&start, &size); end = start + size; if (addr >= start && addr <= end) { return sForegroundMemlist; } else { OSGetMemBound(OSMemoryType::MEM1, &start, &size); end = start + size; if (addr >= start && addr <= end) { return sMEM1Memlist; } else { return sMEM2Memlist; } } }
static BOOL spinReleaseLock(OSSpinLock *spinlock) { uint32_t owner; auto thread = OSGetCurrentThread(); if (!thread) { return FALSE; } owner = memory_untranslate(OSGetCurrentThread()); if (spinlock->recursion > 0u) { --spinlock->recursion; return TRUE; } else if (spinlock->owner.load(std::memory_order_relaxed) == owner) { spinlock->owner = 0u; return TRUE; } return FALSE; }
ExpandedHeap * MEMCreateExpHeapEx(ExpandedHeap *heap, uint32_t size, uint16_t flags) { // Allocate memory auto base = memory_untranslate(heap); // Setup state heap->size = size; heap->bottom = base; heap->top = base + size; heap->mode = HeapMode::FirstFree; heap->group = 0; heap->usedBlockList = nullptr; heap->freeBlockList = make_virtual_ptr<ExpandedHeapBlock>(base + sizeof(ExpandedHeap)); heap->freeBlockList->addr = heap->freeBlockList.getAddress(); heap->freeBlockList->size = heap->size - sizeof(ExpandedHeap); heap->freeBlockList->next = nullptr; heap->freeBlockList->prev = nullptr; // Setup common header MEMiInitHeapHead(heap, HeapType::ExpandedHeap, heap->freeBlockList->addr, heap->freeBlockList->addr + heap->freeBlockList->size); return heap; }
void eraseZStream(WZStream *in) { gStreamMap.erase(memory_untranslate(in)); }
uint32_t MEMResizeForMBlockExpHeap(ExpandedHeap *heap, uint8_t *mblock, uint32_t size) { ScopedSpinLock lock(&heap->lock); // Get the block header auto address = memory_untranslate(mblock); auto base = address - static_cast<uint32_t>(sizeof(ExpandedHeapBlock)); auto block = make_virtual_ptr<ExpandedHeapBlock>(base); auto nextAddr = block->addr + block->size; auto freeBlock = findBlock(heap->freeBlockList, nextAddr); auto freeBlockSize = 0u; auto dataSize = (block->addr + block->size) - address; auto difSize = static_cast<int32_t>(size) - static_cast<int32_t>(dataSize); auto newSize = block->size + difSize; if (difSize == 0) { // No difference, return current size return size; } else if (difSize > 0) { if (!freeBlock) { // No free block to expand into, return fail return 0; } else if (freeBlock->size < static_cast<uint32_t>(difSize)) { // Free block is too small, return fail return 0; } else { if (freeBlock->size - difSize < minimumBlockSize) { // The free block will be smaller than minimum size, so just absorb it completely freeBlockSize = 0; newSize = freeBlock->size; } else { // Free block is large enough, we just reduce its size freeBlockSize = freeBlock->size - difSize; } } } else if (difSize < 0) { if (freeBlock) { // Increase size of free block freeBlockSize = freeBlock->size - difSize; } else if (difSize < minimumBlockSize) { // We can't fit a new free block in the gap, so return current size return block->size; } else { // Create a new free block in the gap freeBlockSize = -difSize; } } // Update free block if (freeBlockSize) { auto old = freeBlock; freeBlock = make_virtual_ptr<ExpandedHeapBlock>(block->addr + newSize); freeBlock->addr = block->addr + newSize; freeBlock->size = freeBlockSize; replaceBlock(heap->freeBlockList, old, freeBlock); } else { // We have totally consumed the free block eraseBlock(heap->freeBlockList, freeBlock); } // Resize block block->size = newSize; return size; }