diff --git a/src/Cafe/HW/Espresso/Const.h b/src/Cafe/HW/Espresso/Const.h index 88a1a9de..06959bb0 100644 --- a/src/Cafe/HW/Espresso/Const.h +++ b/src/Cafe/HW/Espresso/Const.h @@ -8,4 +8,5 @@ namespace Espresso constexpr inline uint64 BUS_CLOCK = 248625000; constexpr inline uint64 TIMER_CLOCK = BUS_CLOCK / 4; + constexpr inline uint32 MEM_PAGE_SIZE = 0x20000; }; \ No newline at end of file diff --git a/src/Cafe/HW/MMU/MMU.h b/src/Cafe/HW/MMU/MMU.h index 0e27d81a..63272440 100644 --- a/src/Cafe/HW/MMU/MMU.h +++ b/src/Cafe/HW/MMU/MMU.h @@ -138,8 +138,6 @@ MMURange* memory_getMMURangeByAddress(MPTR address); bool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size); -#define MEMORY_PAGE_SIZE (0x20000) - #define MEMORY_CODELOW0_ADDR (0x00010000) #define MEMORY_CODELOW0_SIZE (0x000F0000) // ~1MB @@ -158,27 +156,11 @@ bool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size); #define MEMORY_FGBUCKET_AREA_ADDR (0xE0000000) // actual offset is 0xE0000000 according to PPC kernel #define MEMORY_FGBUCKET_AREA_SIZE (0x04000000) // 64MB split up into multiple subareas, size is verified with value from PPC kernel -// move these to rpl loader -#define MEMORY_SDA_SIZE (0x10000) -#define MEMORY_SDA2_SIZE (0x10000) - -//#define MEMORY_SYSTEM_AREA_ADDR (0x90000000) -//#define MEMORY_SYSTEM_AREA_SIZE (0x02000000) // 32MB of memory area that can't be allocated by the game directly - this is emulator specific. - -//#define MEMORY_SYSTEM_AREA_ADDR (0x7C000000) -//#define MEMORY_SYSTEM_AREA_SIZE (0x02000000) // 32MB of memory area that can't be allocated by the game directly - this is emulator specific. -// moved the sys area below 0x80000000. Turns out that some games treat stack/os-object pointers as signed and run into issues if the highest bit is set (e.g. Monster Hunter Frontier G) - #define MEMORY_TILINGAPERTURE_AREA_ADDR (0xE8000000) #define MEMORY_TILINGAPERTURE_AREA_SIZE (0x02000000) // 32MB #define MEMORY_OVERLAY_AREA_OFFSET (0xA0000000) -#define MEMORY_OVERLAY_AREA_SIZE (448*1024*1024) // 448MB (todo: verify if correct) - -#define MEMORY_MAPABLE_PHYS_AREA_OFFSET (0x80000000) // todo: verify offset -#define MEMORY_MAPABLE_PHYS_AREA_SIZE (32*1024*1024) // todo: verify size -#define MEMORY_MAPABLE_VIRT_AREA_OFFSET (0x70000000) // todo: verify offset -#define MEMORY_MAPABLE_VIRT_AREA_SIZE (32*1024*1024) // todo: verify size +#define MEMORY_OVERLAY_AREA_SIZE (448*1024*1024) // 448MB (recycled background app memory) #define MEMORY_MEM1_AREA_ADDR (0xF4000000) #define MEMORY_MEM1_AREA_SIZE (0x02000000) // 32MB @@ -191,7 +173,6 @@ bool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size); static uint16 CPU_swapEndianU16(uint16 v) { - //return _byteswap_ushort(v); return (v>>8)|(v<<8); } diff --git a/src/Cafe/OS/libs/coreinit/coreinit.cpp b/src/Cafe/OS/libs/coreinit/coreinit.cpp index af6e78ea..e882baf8 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit.cpp @@ -366,10 +366,11 @@ void coreinit_load() coreinit::InitializeMessageQueue(); coreinit::InitializeIPC(); coreinit::InitializeIPCBuf(); + coreinit::InitializeMemoryMapping(); coreinit::InitializeCodeGen(); coreinit::InitializeCoroutine(); coreinit::InitializeOSScreen(); - + // legacy mem stuff coreinit::expheap_load(); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp index fe7f4d0b..d32a105c 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp @@ -4,24 +4,34 @@ #define OS_MAP_READ_ONLY (1) #define OS_MAP_READ_WRITE (2) +#define VIRT_RANGE_ADDR (0xA0000000) // todo: Process specific. For the main ram pid this overlaps with the overlay arena? +#define VIRT_RANGE_SIZE (0x40000000) + +#define PHYS_RANGE_ADDR (0x10000000) // todo: Process specific +#define PHYS_RANGE_SIZE (0x40000000) + namespace coreinit { + std::mutex s_memMappingMtx; - struct OSVirtMemory + struct OSVirtMemoryEntry { + OSVirtMemoryEntry(MPTR virtualAddress, uint32 size, uint32 alignment) : virtualAddress(virtualAddress), size(size), alignment(alignment) {}; + MPTR virtualAddress; uint32 size; uint32 alignment; - OSVirtMemory* next; }; - OSVirtMemory* virtualMemoryList = nullptr; + std::vector s_allocatedVirtMemory; - MPTR _VirtualMemoryAlloc(uint32 size, uint32 alignment) + MPTR _OSAllocVirtAddr(uint32 size, uint32 alignment) { - uint32 currentAddress = MEMORY_MAPABLE_VIRT_AREA_OFFSET; - uint32 endAddress = MEMORY_MAPABLE_VIRT_AREA_OFFSET + MEMORY_MAPABLE_VIRT_AREA_SIZE; + std::lock_guard _l(s_memMappingMtx); + uint32 currentAddress = VIRT_RANGE_ADDR; + uint32 endAddress = VIRT_RANGE_ADDR + VIRT_RANGE_SIZE; uint32 pageSize = (uint32)MemMapper::GetPageSize(); + pageSize = std::max(pageSize, Espresso::MEM_PAGE_SIZE); while (true) { // calculated aligned start and end address for current region @@ -30,95 +40,85 @@ namespace coreinit uint32 currentEndAddress = currentAddress + size; currentEndAddress = (currentEndAddress + pageSize - 1) & ~(pageSize - 1); // check if out of available space - if (currentEndAddress >= endAddress) + if (currentEndAddress > endAddress) { - debug_printf("coreinitVirtualMemory_alloc(): Unable to allocate memory\n"); - debugBreakpoint(); + cemuLog_log(LogType::APIErrors, "_OSAllocVirtAddr(): Unable to allocate memory\n"); return MPTR_NULL; } // check for overlapping regions - OSVirtMemory* virtMemItr = virtualMemoryList; bool emptySpaceFound = true; - while (virtMemItr) + for(auto& virtMemIt : s_allocatedVirtMemory) { // check for range collision - if (currentAddress < (virtMemItr->virtualAddress + virtMemItr->size) && currentEndAddress > virtMemItr->virtualAddress) + if (currentAddress < (virtMemIt.virtualAddress + virtMemIt.size) && currentEndAddress > virtMemIt.virtualAddress) { // regions overlap - // adjust current address and try again - currentAddress = virtMemItr->virtualAddress + virtMemItr->size; + // adjust current address and keep looking + currentAddress = virtMemIt.virtualAddress + virtMemIt.size; emptySpaceFound = false; break; } - // next - virtMemItr = virtMemItr->next; } if (emptySpaceFound) { // add entry - OSVirtMemory* virtMemory = (OSVirtMemory*)malloc(sizeof(OSVirtMemory)); - memset(virtMemory, 0x00, sizeof(OSVirtMemory)); - virtMemory->virtualAddress = currentAddress; - virtMemory->size = currentEndAddress - currentAddress; - virtMemory->alignment = alignment; - virtMemory->next = virtualMemoryList; - virtualMemoryList = virtMemory; + s_allocatedVirtMemory.emplace_back(currentAddress, currentEndAddress - currentAddress, alignment); return currentAddress; } } return MPTR_NULL; } - void coreinitExport_OSGetAvailPhysAddrRange(PPCInterpreter_t* hCPU) + bool _OSFreeVirtAddr(MPTR virtAddr) { - // parameters: - // r3 MPTR* areaStart - // r4 uint32 areaSize - memory_writeU32(hCPU->gpr[3], MEMORY_MAPABLE_PHYS_AREA_OFFSET); - memory_writeU32(hCPU->gpr[4], MEMORY_MAPABLE_PHYS_AREA_SIZE); - - osLib_returnFromFunction(hCPU, 0); + std::lock_guard _l(s_memMappingMtx); + auto it = s_allocatedVirtMemory.begin(); + while (it != s_allocatedVirtMemory.end()) + { + if (it->virtualAddress == virtAddr) + { + s_allocatedVirtMemory.erase(it); + return true; + } + ++it; + } + return false; } - void coreinitExport_OSAllocVirtAddr(PPCInterpreter_t* hCPU) + void OSGetAvailPhysAddrRange(uint32be* physRangeStart, uint32be* physRangeSize) { - // parameters: - // r3 MPTR address - // r4 uint32 size - // r5 uint32 align + *physRangeStart = PHYS_RANGE_ADDR; + *physRangeSize = PHYS_RANGE_SIZE; + } - uint32 address = hCPU->gpr[3]; - uint32 size = hCPU->gpr[4]; - uint32 align = hCPU->gpr[5]; - if (address != MPTR_NULL) - { - debug_printf("coreinitExport_OSAllocVirtAddr(): Unsupported address != NULL\n"); - debugBreakpoint(); - } + void* OSAllocVirtAddr(MEMPTR address, uint32 size, uint32 align) + { if (align == 0) align = 1; if (align != 0 && align != 1) assert_dbg(); + cemu_assert_debug(address == nullptr); // todo - support for allocation with fixed address - address = _VirtualMemoryAlloc(size, align); - debug_printf("coreinitExport_OSAllocVirtAddr(): Allocated virtual memory at 0x%08x\n", address); - osLib_returnFromFunction(hCPU, address); + address = _OSAllocVirtAddr(size, align); + debug_printf("OSAllocVirtAddr(): Allocated virtual memory at 0x%08x\n", address.GetMPTR()); + return MEMPTR(address); } - void coreinitExport_OSMapMemory(PPCInterpreter_t* hCPU) + uint32 OSFreeVirtAddr(MEMPTR address) { - // parameters: - // r3 MPTR virtualAddress - // r4 MPTR physicalAddress - // r5 uint32 size - // r6 uint32 mode - MPTR virtualAddress = hCPU->gpr[3]; - MPTR physicalAddress = hCPU->gpr[4]; - uint32 size = hCPU->gpr[5]; - uint32 mode = hCPU->gpr[6]; + bool r = _OSFreeVirtAddr(address.GetMPTR()); + if(!r) + cemuLog_log(LogType::APIErrors, "OSFreeVirtAddr: Could not find allocation with address 0x{:08x}\n", address.GetMPTR()); + return r ? 1 : 0; + } - if (virtualAddress < MEMORY_MAPABLE_VIRT_AREA_OFFSET || virtualAddress >= (MEMORY_MAPABLE_VIRT_AREA_OFFSET + MEMORY_MAPABLE_VIRT_AREA_SIZE)) - cemu_assert_suspicious(); + uint32 OSMapMemory(MPTR virtualAddress, MPTR physicalAddress, uint32 size, uint32 mode) + { + if (virtualAddress < VIRT_RANGE_ADDR || virtualAddress >= (VIRT_RANGE_ADDR + VIRT_RANGE_SIZE)) + { + cemuLog_log(LogType::APIErrors, "OSMapMemory: Virtual address out of bounds\n"); + return 0; + } uint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress); @@ -133,21 +133,14 @@ namespace coreinit if (!allocationResult) { cemuLog_log(LogType::Force, "OSMapMemory failed"); - osLib_returnFromFunction(hCPU, 0); - return; + return 0; } - osLib_returnFromFunction(hCPU, 1); + return 1; } - void coreinitExport_OSUnmapMemory(PPCInterpreter_t* hCPU) + uint32 OSUnmapMemory(MPTR virtualAddress, uint32 size) { - // parameters: - // r3 MPTR virtualAddress - // r4 uint32 size - MPTR virtualAddress = hCPU->gpr[3]; - uint32 size = hCPU->gpr[4]; - - if (virtualAddress < MEMORY_MAPABLE_VIRT_AREA_OFFSET || virtualAddress >= (MEMORY_MAPABLE_VIRT_AREA_OFFSET + MEMORY_MAPABLE_VIRT_AREA_SIZE)) + if (virtualAddress < VIRT_RANGE_ADDR || virtualAddress >= (VIRT_RANGE_ADDR + VIRT_RANGE_SIZE)) cemu_assert_suspicious(); cemu_assert((size % MemMapper::GetPageSize()) == 0); @@ -155,14 +148,16 @@ namespace coreinit uint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress); MemMapper::FreeMemory(virtualPtr, size, true); - osLib_returnFromFunction(hCPU, 1); + return 1; } void InitializeMemoryMapping() { - osLib_addFunction("coreinit", "OSGetAvailPhysAddrRange", coreinitExport_OSGetAvailPhysAddrRange); - osLib_addFunction("coreinit", "OSAllocVirtAddr", coreinitExport_OSAllocVirtAddr); - osLib_addFunction("coreinit", "OSMapMemory", coreinitExport_OSMapMemory); - osLib_addFunction("coreinit", "OSUnmapMemory", coreinitExport_OSUnmapMemory); + s_allocatedVirtMemory.clear(); + cafeExportRegister("coreinit", OSGetAvailPhysAddrRange, LogType::CoreinitMemoryMapping); + cafeExportRegister("coreinit", OSAllocVirtAddr, LogType::CoreinitMemoryMapping); + cafeExportRegister("coreinit", OSFreeVirtAddr, LogType::CoreinitMemoryMapping); + cafeExportRegister("coreinit", OSMapMemory, LogType::CoreinitMemoryMapping); + cafeExportRegister("coreinit", OSUnmapMemory, LogType::CoreinitMemoryMapping); } } \ No newline at end of file diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index 20dba9bd..67de6a6a 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -23,6 +23,7 @@ enum class LogType : sint32 CoreinitMP = 16, CoreinitThread = 17, CoreinitLogging = 18, // OSReport, OSConsoleWrite etc. + CoreinitMemoryMapping = 19, // OSGetAvailPhysAddrRange, OSAllocVirtAddr, OSMapMemory etc. PPC_IPC = 20, NN_AOC = 21,