mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-29 12:34:17 +01:00
coreinit: Fix memory mapping API
Fixes Unity based games freezing on boot
This commit is contained in:
parent
f2671f417f
commit
4b5014c16a
@ -8,4 +8,5 @@ namespace Espresso
|
|||||||
constexpr inline uint64 BUS_CLOCK = 248625000;
|
constexpr inline uint64 BUS_CLOCK = 248625000;
|
||||||
constexpr inline uint64 TIMER_CLOCK = BUS_CLOCK / 4;
|
constexpr inline uint64 TIMER_CLOCK = BUS_CLOCK / 4;
|
||||||
|
|
||||||
|
constexpr inline uint32 MEM_PAGE_SIZE = 0x20000;
|
||||||
};
|
};
|
@ -138,8 +138,6 @@ MMURange* memory_getMMURangeByAddress(MPTR address);
|
|||||||
|
|
||||||
bool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size);
|
bool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size);
|
||||||
|
|
||||||
#define MEMORY_PAGE_SIZE (0x20000)
|
|
||||||
|
|
||||||
#define MEMORY_CODELOW0_ADDR (0x00010000)
|
#define MEMORY_CODELOW0_ADDR (0x00010000)
|
||||||
#define MEMORY_CODELOW0_SIZE (0x000F0000) // ~1MB
|
#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_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
|
#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_ADDR (0xE8000000)
|
||||||
#define MEMORY_TILINGAPERTURE_AREA_SIZE (0x02000000) // 32MB
|
#define MEMORY_TILINGAPERTURE_AREA_SIZE (0x02000000) // 32MB
|
||||||
|
|
||||||
#define MEMORY_OVERLAY_AREA_OFFSET (0xA0000000)
|
#define MEMORY_OVERLAY_AREA_OFFSET (0xA0000000)
|
||||||
#define MEMORY_OVERLAY_AREA_SIZE (448*1024*1024) // 448MB (todo: verify if correct)
|
#define MEMORY_OVERLAY_AREA_SIZE (448*1024*1024) // 448MB (recycled background app memory)
|
||||||
|
|
||||||
#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_MEM1_AREA_ADDR (0xF4000000)
|
#define MEMORY_MEM1_AREA_ADDR (0xF4000000)
|
||||||
#define MEMORY_MEM1_AREA_SIZE (0x02000000) // 32MB
|
#define MEMORY_MEM1_AREA_SIZE (0x02000000) // 32MB
|
||||||
@ -191,7 +173,6 @@ bool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size);
|
|||||||
|
|
||||||
static uint16 CPU_swapEndianU16(uint16 v)
|
static uint16 CPU_swapEndianU16(uint16 v)
|
||||||
{
|
{
|
||||||
//return _byteswap_ushort(v);
|
|
||||||
return (v>>8)|(v<<8);
|
return (v>>8)|(v<<8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +366,7 @@ void coreinit_load()
|
|||||||
coreinit::InitializeMessageQueue();
|
coreinit::InitializeMessageQueue();
|
||||||
coreinit::InitializeIPC();
|
coreinit::InitializeIPC();
|
||||||
coreinit::InitializeIPCBuf();
|
coreinit::InitializeIPCBuf();
|
||||||
|
coreinit::InitializeMemoryMapping();
|
||||||
coreinit::InitializeCodeGen();
|
coreinit::InitializeCodeGen();
|
||||||
coreinit::InitializeCoroutine();
|
coreinit::InitializeCoroutine();
|
||||||
coreinit::InitializeOSScreen();
|
coreinit::InitializeOSScreen();
|
||||||
|
@ -4,24 +4,34 @@
|
|||||||
#define OS_MAP_READ_ONLY (1)
|
#define OS_MAP_READ_ONLY (1)
|
||||||
#define OS_MAP_READ_WRITE (2)
|
#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
|
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;
|
MPTR virtualAddress;
|
||||||
uint32 size;
|
uint32 size;
|
||||||
uint32 alignment;
|
uint32 alignment;
|
||||||
OSVirtMemory* next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OSVirtMemory* virtualMemoryList = nullptr;
|
std::vector<OSVirtMemoryEntry> s_allocatedVirtMemory;
|
||||||
|
|
||||||
MPTR _VirtualMemoryAlloc(uint32 size, uint32 alignment)
|
MPTR _OSAllocVirtAddr(uint32 size, uint32 alignment)
|
||||||
{
|
{
|
||||||
uint32 currentAddress = MEMORY_MAPABLE_VIRT_AREA_OFFSET;
|
std::lock_guard _l(s_memMappingMtx);
|
||||||
uint32 endAddress = MEMORY_MAPABLE_VIRT_AREA_OFFSET + MEMORY_MAPABLE_VIRT_AREA_SIZE;
|
uint32 currentAddress = VIRT_RANGE_ADDR;
|
||||||
|
uint32 endAddress = VIRT_RANGE_ADDR + VIRT_RANGE_SIZE;
|
||||||
uint32 pageSize = (uint32)MemMapper::GetPageSize();
|
uint32 pageSize = (uint32)MemMapper::GetPageSize();
|
||||||
|
pageSize = std::max<uint32>(pageSize, Espresso::MEM_PAGE_SIZE);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// calculated aligned start and end address for current region
|
// calculated aligned start and end address for current region
|
||||||
@ -30,95 +40,85 @@ namespace coreinit
|
|||||||
uint32 currentEndAddress = currentAddress + size;
|
uint32 currentEndAddress = currentAddress + size;
|
||||||
currentEndAddress = (currentEndAddress + pageSize - 1) & ~(pageSize - 1);
|
currentEndAddress = (currentEndAddress + pageSize - 1) & ~(pageSize - 1);
|
||||||
// check if out of available space
|
// check if out of available space
|
||||||
if (currentEndAddress >= endAddress)
|
if (currentEndAddress > endAddress)
|
||||||
{
|
{
|
||||||
debug_printf("coreinitVirtualMemory_alloc(): Unable to allocate memory\n");
|
cemuLog_log(LogType::APIErrors, "_OSAllocVirtAddr(): Unable to allocate memory\n");
|
||||||
debugBreakpoint();
|
|
||||||
return MPTR_NULL;
|
return MPTR_NULL;
|
||||||
}
|
}
|
||||||
// check for overlapping regions
|
// check for overlapping regions
|
||||||
OSVirtMemory* virtMemItr = virtualMemoryList;
|
|
||||||
bool emptySpaceFound = true;
|
bool emptySpaceFound = true;
|
||||||
while (virtMemItr)
|
for(auto& virtMemIt : s_allocatedVirtMemory)
|
||||||
{
|
{
|
||||||
// check for range collision
|
// check for range collision
|
||||||
if (currentAddress < (virtMemItr->virtualAddress + virtMemItr->size) && currentEndAddress > virtMemItr->virtualAddress)
|
if (currentAddress < (virtMemIt.virtualAddress + virtMemIt.size) && currentEndAddress > virtMemIt.virtualAddress)
|
||||||
{
|
{
|
||||||
// regions overlap
|
// regions overlap
|
||||||
// adjust current address and try again
|
// adjust current address and keep looking
|
||||||
currentAddress = virtMemItr->virtualAddress + virtMemItr->size;
|
currentAddress = virtMemIt.virtualAddress + virtMemIt.size;
|
||||||
emptySpaceFound = false;
|
emptySpaceFound = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// next
|
|
||||||
virtMemItr = virtMemItr->next;
|
|
||||||
}
|
}
|
||||||
if (emptySpaceFound)
|
if (emptySpaceFound)
|
||||||
{
|
{
|
||||||
// add entry
|
// add entry
|
||||||
OSVirtMemory* virtMemory = (OSVirtMemory*)malloc(sizeof(OSVirtMemory));
|
s_allocatedVirtMemory.emplace_back(currentAddress, currentEndAddress - currentAddress, alignment);
|
||||||
memset(virtMemory, 0x00, sizeof(OSVirtMemory));
|
|
||||||
virtMemory->virtualAddress = currentAddress;
|
|
||||||
virtMemory->size = currentEndAddress - currentAddress;
|
|
||||||
virtMemory->alignment = alignment;
|
|
||||||
virtMemory->next = virtualMemoryList;
|
|
||||||
virtualMemoryList = virtMemory;
|
|
||||||
return currentAddress;
|
return currentAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MPTR_NULL;
|
return MPTR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreinitExport_OSGetAvailPhysAddrRange(PPCInterpreter_t* hCPU)
|
bool _OSFreeVirtAddr(MPTR virtAddr)
|
||||||
{
|
{
|
||||||
// parameters:
|
std::lock_guard _l(s_memMappingMtx);
|
||||||
// r3 MPTR* areaStart
|
auto it = s_allocatedVirtMemory.begin();
|
||||||
// r4 uint32 areaSize
|
while (it != s_allocatedVirtMemory.end())
|
||||||
memory_writeU32(hCPU->gpr[3], MEMORY_MAPABLE_PHYS_AREA_OFFSET);
|
{
|
||||||
memory_writeU32(hCPU->gpr[4], MEMORY_MAPABLE_PHYS_AREA_SIZE);
|
if (it->virtualAddress == virtAddr)
|
||||||
|
{
|
||||||
osLib_returnFromFunction(hCPU, 0);
|
s_allocatedVirtMemory.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreinitExport_OSAllocVirtAddr(PPCInterpreter_t* hCPU)
|
void OSGetAvailPhysAddrRange(uint32be* physRangeStart, uint32be* physRangeSize)
|
||||||
{
|
{
|
||||||
// parameters:
|
*physRangeStart = PHYS_RANGE_ADDR;
|
||||||
// r3 MPTR address
|
*physRangeSize = PHYS_RANGE_SIZE;
|
||||||
// r4 uint32 size
|
|
||||||
// r5 uint32 align
|
|
||||||
|
|
||||||
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<void> address, uint32 size, uint32 align)
|
||||||
|
{
|
||||||
if (align == 0)
|
if (align == 0)
|
||||||
align = 1;
|
align = 1;
|
||||||
if (align != 0 && align != 1)
|
if (align != 0 && align != 1)
|
||||||
assert_dbg();
|
assert_dbg();
|
||||||
|
cemu_assert_debug(address == nullptr); // todo - support for allocation with fixed address
|
||||||
|
|
||||||
address = _VirtualMemoryAlloc(size, align);
|
address = _OSAllocVirtAddr(size, align);
|
||||||
debug_printf("coreinitExport_OSAllocVirtAddr(): Allocated virtual memory at 0x%08x\n", address);
|
debug_printf("OSAllocVirtAddr(): Allocated virtual memory at 0x%08x\n", address.GetMPTR());
|
||||||
osLib_returnFromFunction(hCPU, address);
|
return MEMPTR<void>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreinitExport_OSMapMemory(PPCInterpreter_t* hCPU)
|
uint32 OSFreeVirtAddr(MEMPTR<void> address)
|
||||||
{
|
{
|
||||||
// parameters:
|
bool r = _OSFreeVirtAddr(address.GetMPTR());
|
||||||
// r3 MPTR virtualAddress
|
if(!r)
|
||||||
// r4 MPTR physicalAddress
|
cemuLog_log(LogType::APIErrors, "OSFreeVirtAddr: Could not find allocation with address 0x{:08x}\n", address.GetMPTR());
|
||||||
// r5 uint32 size
|
return r ? 1 : 0;
|
||||||
// r6 uint32 mode
|
}
|
||||||
MPTR virtualAddress = hCPU->gpr[3];
|
|
||||||
MPTR physicalAddress = hCPU->gpr[4];
|
|
||||||
uint32 size = hCPU->gpr[5];
|
|
||||||
uint32 mode = hCPU->gpr[6];
|
|
||||||
|
|
||||||
if (virtualAddress < MEMORY_MAPABLE_VIRT_AREA_OFFSET || virtualAddress >= (MEMORY_MAPABLE_VIRT_AREA_OFFSET + MEMORY_MAPABLE_VIRT_AREA_SIZE))
|
uint32 OSMapMemory(MPTR virtualAddress, MPTR physicalAddress, uint32 size, uint32 mode)
|
||||||
cemu_assert_suspicious();
|
{
|
||||||
|
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);
|
uint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress);
|
||||||
|
|
||||||
@ -133,21 +133,14 @@ namespace coreinit
|
|||||||
if (!allocationResult)
|
if (!allocationResult)
|
||||||
{
|
{
|
||||||
cemuLog_log(LogType::Force, "OSMapMemory failed");
|
cemuLog_log(LogType::Force, "OSMapMemory failed");
|
||||||
osLib_returnFromFunction(hCPU, 0);
|
return 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
osLib_returnFromFunction(hCPU, 1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void coreinitExport_OSUnmapMemory(PPCInterpreter_t* hCPU)
|
uint32 OSUnmapMemory(MPTR virtualAddress, uint32 size)
|
||||||
{
|
{
|
||||||
// parameters:
|
if (virtualAddress < VIRT_RANGE_ADDR || virtualAddress >= (VIRT_RANGE_ADDR + VIRT_RANGE_SIZE))
|
||||||
// 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))
|
|
||||||
cemu_assert_suspicious();
|
cemu_assert_suspicious();
|
||||||
|
|
||||||
cemu_assert((size % MemMapper::GetPageSize()) == 0);
|
cemu_assert((size % MemMapper::GetPageSize()) == 0);
|
||||||
@ -155,14 +148,16 @@ namespace coreinit
|
|||||||
uint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress);
|
uint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress);
|
||||||
|
|
||||||
MemMapper::FreeMemory(virtualPtr, size, true);
|
MemMapper::FreeMemory(virtualPtr, size, true);
|
||||||
osLib_returnFromFunction(hCPU, 1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeMemoryMapping()
|
void InitializeMemoryMapping()
|
||||||
{
|
{
|
||||||
osLib_addFunction("coreinit", "OSGetAvailPhysAddrRange", coreinitExport_OSGetAvailPhysAddrRange);
|
s_allocatedVirtMemory.clear();
|
||||||
osLib_addFunction("coreinit", "OSAllocVirtAddr", coreinitExport_OSAllocVirtAddr);
|
cafeExportRegister("coreinit", OSGetAvailPhysAddrRange, LogType::CoreinitMemoryMapping);
|
||||||
osLib_addFunction("coreinit", "OSMapMemory", coreinitExport_OSMapMemory);
|
cafeExportRegister("coreinit", OSAllocVirtAddr, LogType::CoreinitMemoryMapping);
|
||||||
osLib_addFunction("coreinit", "OSUnmapMemory", coreinitExport_OSUnmapMemory);
|
cafeExportRegister("coreinit", OSFreeVirtAddr, LogType::CoreinitMemoryMapping);
|
||||||
|
cafeExportRegister("coreinit", OSMapMemory, LogType::CoreinitMemoryMapping);
|
||||||
|
cafeExportRegister("coreinit", OSUnmapMemory, LogType::CoreinitMemoryMapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ enum class LogType : sint32
|
|||||||
CoreinitMP = 16,
|
CoreinitMP = 16,
|
||||||
CoreinitThread = 17,
|
CoreinitThread = 17,
|
||||||
CoreinitLogging = 18, // OSReport, OSConsoleWrite etc.
|
CoreinitLogging = 18, // OSReport, OSConsoleWrite etc.
|
||||||
|
CoreinitMemoryMapping = 19, // OSGetAvailPhysAddrRange, OSAllocVirtAddr, OSMapMemory etc.
|
||||||
|
|
||||||
PPC_IPC = 20,
|
PPC_IPC = 20,
|
||||||
NN_AOC = 21,
|
NN_AOC = 21,
|
||||||
|
Loading…
Reference in New Issue
Block a user