diff --git a/loader/Makefile b/loader/Makefile index 52a6332..6721d6f 100644 --- a/loader/Makefile +++ b/loader/Makefile @@ -37,6 +37,8 @@ SOURCES := src/common \ src/libelf \ src/menu/content \ src/menu \ + src/mymemory \ + src/mykernel \ src/myutils \ src/patcher \ src/plugin \ diff --git a/loader/src/Application.cpp b/loader/src/Application.cpp index 1eb0c0d..cfe9f6a 100644 --- a/loader/src/Application.cpp +++ b/loader/src/Application.cpp @@ -26,6 +26,7 @@ #include #include "settings/CSettings.h" #include "myutils/TcpReceiver.h" +#include "mymemory/memory_mapping.h" Application *Application::applicationInstance = NULL; bool Application::exitApplication = false; @@ -185,6 +186,11 @@ void Application::executeThread(void) { exitApplication = true; } + if(controller[i]->data.buttons_d & VPAD_BUTTON_MINUS) { + exitCode = APPLICATION_CLOSE_APPLY_MEMORY; + exitApplication = true; + } + if(controller[i]->data.buttons_d & VPAD_BUTTON_HOME) { exitCode = APPLICATION_CLOSE_MIIMAKER; exitApplication = true; diff --git a/loader/src/Application.h b/loader/src/Application.h index cd3dc0b..5848898 100644 --- a/loader/src/Application.h +++ b/loader/src/Application.h @@ -24,6 +24,7 @@ #include #define APPLICATION_CLOSE_APPLY 1 +#define APPLICATION_CLOSE_APPLY_MEMORY 3 #define APPLICATION_CLOSE_MIIMAKER 2 class Application : public CThread { diff --git a/loader/src/main.cpp b/loader/src/main.cpp index 41906c5..ca6d6f4 100644 --- a/loader/src/main.cpp +++ b/loader/src/main.cpp @@ -30,14 +30,17 @@ #include #include #include + #include +#include + +#include "mymemory/memory_mapping.h" #include "common/retain_vars.h" #include "common/common.h" #include "plugin/PluginLoader.h" #include "plugin/PluginInformation.h" - #include #include #include @@ -56,16 +59,15 @@ #include "settings/CSettings.h" static void ApplyPatchesAndCallHookStartingApp(); -void CallHook(wups_loader_hook_type_t hook_type); static void RestorePatches(); s32 isInMiiMakerHBL(); -/* Entry point */ extern "C" int Menu_Main(int argc, char **argv) { if(gAppStatus == 2) { //"No, we don't want to patch stuff again."); return EXIT_RELAUNCH_ON_LOAD; } + InitOSFunctionPointers(); InitSocketFunctionPointers(); //For logging InitSysFunctionPointers(); @@ -80,14 +82,21 @@ extern "C" int Menu_Main(int argc, char **argv) { log_init(); DEBUG_FUNCTION_LINE("We have %d kb for plugins.\n",(PLUGIN_LOCATION_END_ADDRESS-getApplicationEndAddr())/1024); + setup_os_exceptions(); DEBUG_FUNCTION_LINE("Wii U Plugin System Loader %s\n",APP_VERSION); - - //setup_os_exceptions(); - Init(); + + init_kernel_syscalls(); + wups_init_kernel_syscalls(); + gGameTitleID = OSGetTitleID(); + if(MemoryMapping::isMemoryMapped()) { + DEBUG_FUNCTION_LINE("Mapping was already done.\n"); + MemoryMapping::readTestValuesFromMemory(); + } + s32 result = 0; //Reset everything when were going back to the Mii Maker @@ -95,7 +104,6 @@ extern "C" int Menu_Main(int argc, char **argv) { CallHook(WUPS_LOADER_HOOK_DEINIT_PLUGIN); // Restore patches as the patched functions could change. RestorePatches(); - PluginLoader * pluginLoader = PluginLoader::getInstance(); std::vector pluginList = pluginLoader->getPluginInformation("sd:/wiiu/plugins/"); pluginLoader->loadAndLinkPlugins(pluginList); @@ -109,6 +117,8 @@ extern "C" int Menu_Main(int argc, char **argv) { DEBUG_FUNCTION_LINE("Start main application\n"); result = Application::instance()->exec(); DEBUG_FUNCTION_LINE("Main application stopped result: %d\n",result); + + DEBUG_FUNCTION_LINE("Application::destroyInstance\n"); Application::destroyInstance(); DEBUG_FUNCTION_LINE("Release memory\n"); @@ -117,28 +127,38 @@ extern "C" int Menu_Main(int argc, char **argv) { PluginLoader::destroyInstance(); } + if(result == APPLICATION_CLOSE_APPLY_MEMORY){ + if(!MemoryMapping::isMemoryMapped()) { + MemoryMapping::setupMemoryMapping(); + } + } + + if(!isInMiiMakerHBL()) { - //CallHook(WUPS_LOADER_HOOK_STARTING_APPLICATION); DEBUG_FUNCTION_LINE("Apply patches.\n"); ApplyPatchesAndCallHookStartingApp(); return EXIT_RELAUNCH_ON_LOAD; } - if(result == APPLICATION_CLOSE_APPLY) { + + if(result == APPLICATION_CLOSE_APPLY || result == APPLICATION_CLOSE_APPLY_MEMORY) { CallHook(WUPS_LOADER_HOOK_INIT_FS); CallHook(WUPS_LOADER_HOOK_INIT_OVERLAY); CallHook(WUPS_LOADER_HOOK_INIT_PLUGIN); DEBUG_FUNCTION_LINE("Loading the system menu.\n"); DeInit(); - init_kernel_syscalls(); SYSLaunchMenu(); return EXIT_RELAUNCH_ON_LOAD; } - DEBUG_FUNCTION_LINE("Going back to the Homebrew Launcher\n"); + DEBUG_FUNCTION_LINE("Let's go to back to the Homebrew Launcher\n"); + DEBUG_FUNCTION_LINE("Restoring the patched functions\n"); RestorePatches(); + DEBUG_FUNCTION_LINE("Calling the plugin deinit hook\n"); CallHook(WUPS_LOADER_HOOK_DEINIT_PLUGIN); + DEBUG_FUNCTION_LINE("Unmounting SD/USB devices\n"); DeInit(); + DEBUG_FUNCTION_LINE("Bye bye!\n"); return EXIT_SUCCESS; } diff --git a/loader/src/mykernel/kernel_defs.h b/loader/src/mykernel/kernel_defs.h new file mode 100644 index 0000000..276310e --- /dev/null +++ b/loader/src/mykernel/kernel_defs.h @@ -0,0 +1,33 @@ +#ifndef __WUPS_KERNEL_DEFS_H_ +#define __WUPS_KERNEL_DEFS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _sr_table_t +{ + u32 value[16]; + u32 sdr1; +} sr_table_t; + +typedef struct _bat_t +{ + u32 h; + u32 l; +} bat_t; + +typedef struct _bat_table_t +{ + bat_t bat[8]; +} bat_table_t; + + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_DEFS_H_ diff --git a/loader/src/mykernel/kernel_utils.c b/loader/src/mykernel/kernel_utils.c new file mode 100644 index 0000000..0a7411a --- /dev/null +++ b/loader/src/mykernel/kernel_utils.c @@ -0,0 +1,181 @@ +#include +#include +#include "kernel_defs.h" +#include + +static void KernelReadSRs(sr_table_t * table) { + u32 i = 0; + + // calculate PT_size ((end-start)*8/4096)*4 or (end-start)/128 + // Minimum page table size is 64Kbytes. + + asm volatile("eieio; isync"); + + asm volatile("mfspr %0, 25" : "=r" (table->sdr1)); + + asm volatile("mfsr %0, 0" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 1" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 2" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 3" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 4" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 5" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 6" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 7" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 8" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 9" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 10" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 11" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 12" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 13" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 14" : "=r" (table->value[i])); + i++; + asm volatile("mfsr %0, 15" : "=r" (table->value[i])); + i++; + + asm volatile("eieio; isync"); +} + +static void KernelWriteSRs(sr_table_t * table) { + u32 i = 0; + + + asm volatile("eieio; isync"); + + // Writing didn't work for all at once so we only write number 8. + // TODO: fix this and change it if required. + + /*asm volatile("mtsr 0, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 1, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 2, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 3, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 4, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 5, %0" : : "r" (table->value[i])); i++;*/ + //asm volatile("mtsr 6, %0" : : "r" (table->value[6])); i++; + /*asm volatile("mtsr 7, %0" : : "r" (table->value[i])); i++;*/ + asm volatile("mtsr 8, %0" : : "r" (table->value[8])); i++; + /*asm volatile("mtsr 9, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 10, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 11, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 12, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 13, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 14, %0" : : "r" (table->value[i])); i++; + asm volatile("mtsr 15, %0" : : "r" (table->value[i])); i++;*/ + + + asm volatile("isync"); +} + +void KernelReadPTE(u32* dest, u32 size) { + u32 msr = 0; + u32 oldmsr = 0; + //TODO: Calculate from SDR1 + u32 addr_base = 0xFFE20000; + asm volatile("mfmsr %0" : "=r" (msr)); + oldmsr = msr; + msr &= ~0x10; + for(int i = 0;iaddr_KernSyscallTbl1 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x0A * 4)), (unsigned int)KernelWriteWitoutDAT); + + // Override all writes to SR8 with nops. + SC0x0A_KernelWriteWitoutDAT(0xFFF1D754,0x60000000); + SC0x0A_KernelWriteWitoutDAT(0xFFF1D64C,0x60000000); + SC0x0A_KernelWriteWitoutDAT(0xFFE00638,0x60000000); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x36 * 4)), (unsigned int)KernelReadSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x36 * 4)), (unsigned int)KernelReadSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x36 * 4)), (unsigned int)KernelReadSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x36 * 4)), (unsigned int)KernelReadSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x36 * 4)), (unsigned int)KernelReadSRs); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x37 * 4)), (unsigned int)KernelReadPTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x37 * 4)), (unsigned int)KernelReadPTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x37 * 4)), (unsigned int)KernelReadPTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x37 * 4)), (unsigned int)KernelReadPTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x37 * 4)), (unsigned int)KernelReadPTE); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x09 * 4)), (unsigned int)KernelWritePTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x09 * 4)), (unsigned int)KernelWritePTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x09 * 4)), (unsigned int)KernelWritePTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x09 * 4)), (unsigned int)KernelWritePTE); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x09 * 4)), (unsigned int)KernelWritePTE); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x0A * 4)), (unsigned int)KernelWriteSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x0A * 4)), (unsigned int)KernelWriteSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x0A * 4)), (unsigned int)KernelWriteSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x0A * 4)), (unsigned int)KernelWriteSRs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x0A * 4)), (unsigned int)KernelWriteSRs); +} diff --git a/loader/src/mykernel/kernel_utils.h b/loader/src/mykernel/kernel_utils.h new file mode 100644 index 0000000..3f42838 --- /dev/null +++ b/loader/src/mykernel/kernel_utils.h @@ -0,0 +1,14 @@ +#ifndef __WUPS_KERNEL_UTILS_H_ +#define __WUPS_KERNEL_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void wups_init_kernel_syscalls(); + +#ifdef __cplusplus +} +#endif + +#endif // __WUPS_KERNEL_UTILS_H_ diff --git a/loader/src/mykernel/syscalls.h b/loader/src/mykernel/syscalls.h new file mode 100644 index 0000000..247bcce --- /dev/null +++ b/loader/src/mykernel/syscalls.h @@ -0,0 +1,20 @@ +#ifndef __WUPS_SYSCALLS_H_ +#define __WUPS_SYSCALLS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "kernel_defs.h" + +void SC0x0A_KernelWriteSRs(sr_table_t * table); +void SC0x36_KernelReadSRs(sr_table_t * table); +void SC0x37_KernelReadPTE(u32* dest, u32 size); +void SC0x09_KernelWritePTE(u32* addr,u32 size); +void KernelTest(); + +#ifdef __cplusplus +} +#endif + +#endif // __WUPS_SYSCALLS_H_ diff --git a/loader/src/mykernel/syscalls_asm.s b/loader/src/mykernel/syscalls_asm.s new file mode 100644 index 0000000..10292e7 --- /dev/null +++ b/loader/src/mykernel/syscalls_asm.s @@ -0,0 +1,30 @@ +.globl SC0x36_KernelReadSRs +SC0x36_KernelReadSRs: + li r0, 0x3600 + sc + blr + + .globl SC0x0A_KernelWriteSRs +SC0x0A_KernelWriteSRs: + li r0, 0x0A00 + sc + blr + + .globl SC0x0A_KernelWriteWitoutDAT +SC0x0A_KernelWriteWitoutDAT: + li r0, 0x0A00 + sc + blr + + .globl SC0x37_KernelReadPTE +SC0x37_KernelReadPTE: + li r0, 0x3700 + sc + blr + + .globl SC0x09_KernelWritePTE +SC0x09_KernelWritePTE: + li r0, 0x0900 + sc + blr + diff --git a/loader/src/mymemory/memory_mapping.cpp b/loader/src/mymemory/memory_mapping.cpp new file mode 100644 index 0000000..2cea7f9 --- /dev/null +++ b/loader/src/mymemory/memory_mapping.cpp @@ -0,0 +1,637 @@ +#include "memory_mapping.h" +#include "mykernel/syscalls.h" +#include "common/retain_vars.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void runOnAllCores(CThread::Callback callback, void *callbackArg, s32 iAttr = 0, s32 iPriority = 16, s32 iStackSize = 0x8000) { + int aff[] = {CThread::eAttributeAffCore2,CThread::eAttributeAffCore1,CThread::eAttributeAffCore0}; + + for(u32 i = 0; i <(sizeof(aff)/sizeof(aff[0])); i++) { + CThread * thread = CThread::create(callback, callbackArg, iAttr | aff[i],iPriority,iStackSize); + thread->resumeThread(); + delete thread; + } +} + +void writeSegmentRegister(CThread *thread, void *arg) { + sr_table_t * table = (sr_table_t *) arg; + u16 core = OSGetThreadAffinity(OSGetCurrentThread()); + DEBUG_FUNCTION_LINE("Writing segment register to core %d\n",core); + + DCFlushRange(table,sizeof(sr_table_t)); + SC0x0A_KernelWriteSRs(table); +} + +void readAndPrintSegmentRegister(CThread *thread, void *arg) { + u16 core = OSGetThreadAffinity(OSGetCurrentThread()); + DEBUG_FUNCTION_LINE("Reading segment register and page table from core %d\n",core); + sr_table_t srTable; + memset(&srTable,0,sizeof(srTable)); + + SC0x36_KernelReadSRs(&srTable); + DCFlushRange(&srTable,sizeof(srTable)); + + for(int i = 0; i < 16; i++) { + DEBUG_FUNCTION_LINE("[%d] SR[%d]=%08X\n",core,i,srTable.value[i]); + } + + u32 pageTable[0x8000]; + + memset(pageTable,0,sizeof(pageTable)); + DEBUG_FUNCTION_LINE("Reading pageTable now.\n"); + SC0x37_KernelReadPTE(pageTable,sizeof(pageTable)); + DCFlushRange(pageTable,sizeof(pageTable)); + + DEBUG_FUNCTION_LINE("Reading pageTable done\n"); + + MemoryMapping::printPageTableTranslation(srTable,pageTable); + + DEBUG_FUNCTION_LINE("-----------------------------\n"); +} + +bool MemoryMapping::isMemoryMapped() { + sr_table_t srTable; + memset(&srTable,0,sizeof(srTable)); + + SC0x36_KernelReadSRs(&srTable); + if((srTable.value[MEMORY_START_BASE >> 28] & 0x00FFFFFF) == SEGMENT_UNIQUE_ID) { + return true; + } + return false; +} + +u32 MemoryMapping::getHeapAddress() { + return MEMORY_START_PLUGIN_HEAP; +} + +u32 MemoryMapping::getHeapSize() { + const memory_values_t * mem_vals = mem_mapping[2].physical_addresses; + u32 ea_size = 0; + for(u32 j = 0;; j++) { + u32 pa_start_address = mem_vals[j].start_address; + u32 pa_end_address = mem_vals[j].end_address; + if(pa_end_address == 0 && pa_start_address == 0) { + break; + } + ea_size += pa_end_address - pa_start_address; + } + return ea_size; +} + +void MemoryMapping::searchEmptyMemoryRegions() { + DEBUG_FUNCTION_LINE("Searching for empty memory.\n"); + + for(int i = 0;; i++) { + if(mem_mapping[i].physical_addresses == NULL) { + break; + } + u32 ea_start_address = mem_mapping[i].effective_start_address; + + const memory_values_t * mem_vals = mem_mapping[i].physical_addresses; + + u32 ea_size = 0; + for(u32 j = 0;; j++) { + u32 pa_start_address = mem_vals[j].start_address; + u32 pa_end_address = mem_vals[j].end_address; + if(pa_end_address == 0 && pa_start_address == 0) { + break; + } + ea_size += pa_end_address - pa_start_address; + } + + u32* flush_start = (u32*)ea_start_address; + u32 flush_size = ea_size; + + DEBUG_FUNCTION_LINE("Flushing %08X (%d kB) at %08X.\n",flush_size,flush_size/1024, flush_start); + DCFlushRange(flush_start,flush_size); + + DEBUG_FUNCTION_LINE("Searching in memory region %d. 0x%08X - 0x%08X. Size 0x%08X (%d KBytes).\n",i+1,ea_start_address,ea_start_address+ea_size,ea_size,ea_size/1024); + bool success = true; + u32 * memory_ptr = (u32*) ea_start_address; + bool inFailRange = false; + u32 startFailing = 0; + u32 startGood = ea_start_address; + for(u32 j=0; j < ea_size/4; j++) { + if(memory_ptr[j] != 0) { + success = false; + if(!success && !inFailRange) { + if((((u32)&memory_ptr[j])-(u32)startGood)/1024 > 512) { + u32 start_addr = startGood & 0xFFFE0000; + if(start_addr != startGood) { + start_addr += 0x20000; + } + u32 end_addr = ((u32)&memory_ptr[j]) - MEMORY_START_BASE; + end_addr = (end_addr & 0xFFFE0000); + DEBUG_FUNCTION_LINE("+ Free between 0x%08X and 0x%08X size: %u kB\n",start_addr - MEMORY_START_BASE,end_addr,(((u32)end_addr)-((u32)startGood - MEMORY_START_BASE))/1024); + } + startFailing = (u32)&memory_ptr[j]; + inFailRange = true; + startGood = 0; + j = ((j & 0xFFFF8000) + 0x00008000)-1; + } + //break; + } else { + if(inFailRange) { + //DEBUG_FUNCTION_LINE("- Error between 0x%08X and 0x%08X size: %u kB\n",startFailing,&memory_ptr[j],(((u32)&memory_ptr[j])-(u32)startFailing)/1024); + startFailing = 0; + startGood = (u32) &memory_ptr[j]; + inFailRange = false; + } + } + } + if(startGood != 0 && (startGood != ea_start_address + ea_size)) { + DEBUG_FUNCTION_LINE("+ Good between 0x%08X and 0x%08X size: %u kB\n",startGood - MEMORY_START_BASE,((u32)(ea_start_address + ea_size) - (u32)MEMORY_START_BASE),((u32)(ea_start_address + ea_size) - (u32)startGood)/1024); + } else if(inFailRange) { + DEBUG_FUNCTION_LINE("- Used between 0x%08X and 0x%08X size: %u kB\n",startFailing,ea_start_address + ea_size,((u32)(ea_start_address + ea_size) - (u32)startFailing)/1024); + } + if(success) { + DEBUG_FUNCTION_LINE("Test %d was successful!\n",i+1); + } + + } + DEBUG_FUNCTION_LINE("All tests done.\n"); +} + +void MemoryMapping::writeTestValuesToMemory() { + //don't smash the stack. + u32 chunk_size = 0x1000; + u32 testBuffer[chunk_size]; + + for(int i = 0;; i++) { + if(mem_mapping[i].physical_addresses == NULL) { + break; + } + u32 cur_ea_start_address = mem_mapping[i].effective_start_address; + + DEBUG_FUNCTION_LINE("Preparing memory test for region %d. Region start at effective address %08X.\n",i+1,cur_ea_start_address); + + const memory_values_t * mem_vals = mem_mapping[i].physical_addresses; + u32 counter = 0; + for(u32 j = 0;; j++) { + u32 pa_start_address = mem_vals[j].start_address; + u32 pa_end_address = mem_vals[j].end_address; + if(pa_end_address == 0 && pa_start_address == 0) { + break; + } + u32 pa_size = pa_end_address - pa_start_address; + DEBUG_FUNCTION_LINE("Writing region %d of mapping %d. From %08X to %08X Size: %d KBytes...\n",j+1,i+1,pa_start_address,pa_end_address,pa_size/1024); + for(u32 k=0; k<=pa_size/4; k++) { + if(k > 0 && (k % chunk_size) == 0) { + DCFlushRange(&testBuffer,sizeof(testBuffer)); + DCInvalidateRange(&testBuffer,sizeof(testBuffer)); + u32 destination = pa_start_address + ((k*4) - sizeof(testBuffer)); + SC0x25_KernelCopyData(destination,(u32)OSEffectiveToPhysical(testBuffer),sizeof(testBuffer)); + //DEBUG_FUNCTION_LINE("Copy testBuffer into %08X\n",destination); + } + if(k != pa_size/4) { + testBuffer[k % chunk_size] = counter++; + } + //DEBUG_FUNCTION_LINE("testBuffer[%d] = %d\n",i % chunk_size,i); + } + u32* flush_start = (u32*)cur_ea_start_address; + u32 flush_size = pa_size; + + cur_ea_start_address += pa_size; + + DEBUG_FUNCTION_LINE("Flushing %08X (%d kB) at %08X to map memory.\n",flush_size,flush_size/1024, flush_start); + DCFlushRange(flush_start,flush_size); + } + + DEBUG_FUNCTION_LINE("Done writing region %d\n",i+1); + } +} + +void MemoryMapping::readTestValuesFromMemory() { + DEBUG_FUNCTION_LINE("Testing reading the written values.\n"); + + for(int i = 0;; i++) { + if(mem_mapping[i].physical_addresses == NULL) { + break; + } + u32 ea_start_address = mem_mapping[i].effective_start_address; + + const memory_values_t * mem_vals = mem_mapping[i].physical_addresses; + //u32 counter = 0; + u32 ea_size = 0; + for(u32 j = 0;; j++) { + u32 pa_start_address = mem_vals[j].start_address; + u32 pa_end_address = mem_vals[j].end_address; + if(pa_end_address == 0 && pa_start_address == 0) { + break; + } + ea_size += pa_end_address - pa_start_address; + } + + u32* flush_start = (u32*)ea_start_address; + u32 flush_size = ea_size; + + DEBUG_FUNCTION_LINE("Flushing %08X (%d kB) at %08X to map memory.\n",flush_size,flush_size/1024, flush_start); + DCFlushRange(flush_start,flush_size); + + DEBUG_FUNCTION_LINE("Testing memory region %d. 0x%08X - 0x%08X. Size 0x%08X (%d KBytes).\n",i+1,ea_start_address,ea_start_address+ea_size,ea_size,ea_size/1024); + bool success = true; + u32 * memory_ptr = (u32*) ea_start_address; + bool inFailRange = false; + u32 startFailing = 0; + u32 startGood = ea_start_address; + for(u32 j=0; j < ea_size/4; j++) { + if(memory_ptr[j] != j) { + success = false; + if(!success && !inFailRange) { + DEBUG_FUNCTION_LINE("+ Good between 0x%08X and 0x%08X size: %u kB\n",startGood,&memory_ptr[j],(((u32)&memory_ptr[j])-(u32)startGood)/1024); + startFailing = (u32)&memory_ptr[j]; + inFailRange = true; + startGood = 0; + j = ((j & 0xFFFF8000) + 0x00008000)-1; + } + //break; + } else { + if(inFailRange) { + DEBUG_FUNCTION_LINE("- Error between 0x%08X and 0x%08X size: %u kB\n",startFailing,&memory_ptr[j],(((u32)&memory_ptr[j])-(u32)startFailing)/1024); + startFailing = 0; + startGood = (u32) &memory_ptr[j]; + inFailRange = false; + } + } + } + if(startGood != 0 && (startGood != ea_start_address + ea_size)) { + DEBUG_FUNCTION_LINE("+ Good between 0x%08X and 0x%08X size: %u kB\n",startGood,ea_start_address + ea_size,((u32)(ea_start_address + ea_size) - (u32)startGood)/1024); + } else if(inFailRange) { + DEBUG_FUNCTION_LINE("- Error between 0x%08X and 0x%08X size: %u kB\n",startFailing,ea_start_address + ea_size,((u32)(ea_start_address + ea_size) - (u32)startFailing)/1024); + } + if(success) { + DEBUG_FUNCTION_LINE("Test %d was successful!\n",i+1); + } + + } + DEBUG_FUNCTION_LINE("All tests done.\n"); +} + +void MemoryMapping::memoryMappingForRegions(const memory_mapping_t * memory_mapping, sr_table_t SRTable, u32 * translation_table) { + for(int i = 0; /* waiting for a break */; i++) { + DEBUG_FUNCTION_LINE("In loop %d\n",i); + if(memory_mapping[i].physical_addresses == NULL) { + DEBUG_FUNCTION_LINE("break %d\n",i); + break; + } + u32 cur_ea_start_address = memory_mapping[i].effective_start_address; + + DEBUG_FUNCTION_LINE("Mapping area %d. effective address %08X...\n",i+1,cur_ea_start_address); + const memory_values_t * mem_vals = memory_mapping[i].physical_addresses; + + for(u32 j = 0;; j++) { + DEBUG_FUNCTION_LINE("In inner loop %d\n",j); + u32 pa_start_address = mem_vals[j].start_address; + u32 pa_end_address = mem_vals[j].end_address; + if(pa_end_address == 0 && pa_start_address == 0) { + DEBUG_FUNCTION_LINE("inner break %d\n",j); + // Break if entry was empty. + break; + } + u32 pa_size = pa_end_address - pa_start_address; + DEBUG_FUNCTION_LINE("Adding page table entry %d for mapping area %d. %08X-%08X => %08X-%08X...\n",j+1,i+1,cur_ea_start_address,memory_mapping[i].effective_start_address+pa_size,pa_start_address,pa_end_address); + if(!mapMemory(pa_start_address,pa_end_address,cur_ea_start_address,SRTable,translation_table)) { + log_print("error =(\n"); + DEBUG_FUNCTION_LINE("Failed to map memory.\n"); + //OSFatal("Failed to map memory."); + return; + break; + } + cur_ea_start_address += pa_size; + log_print("done\n"); + } + } +} + +void MemoryMapping::setupMemoryMapping() { + //runOnAllCores(readAndPrintSegmentRegister,NULL,0,16,0x20000); + + sr_table_t srTableCpy; + u32 pageTableCpy[0x8000]; + + SC0x36_KernelReadSRs(&srTableCpy); + SC0x37_KernelReadPTE(pageTableCpy,sizeof(pageTableCpy)); + + DCFlushRange(&srTableCpy,sizeof(srTableCpy)); + DCFlushRange(pageTableCpy,sizeof(pageTableCpy)); + + for(int i = 0; i < 16; i++) { + DEBUG_FUNCTION_LINE("SR[%d]=%08X\n",i,srTableCpy.value[i]); + } + + printPageTableTranslation(srTableCpy,pageTableCpy); + + // According to + // http://wiiubrew.org/wiki/Cafe_OS#Virtual_Memory_Map 0x80000000 + // is currently unmapped. + // This is nice because it leads to SR[8] which also seems to be unused (was set to 0x30FFFFFF) + // The content of the segment was chosen randomly. + u32 segment_index = MEMORY_START_BASE >> 28; + u32 segment_content = 0x20000000 | SEGMENT_UNIQUE_ID; + + DEBUG_FUNCTION_LINE("Setting SR[%d] to %08X\n",segment_index,segment_content); + srTableCpy.value[segment_index] = segment_content; + DCFlushRange(&srTableCpy,sizeof(srTableCpy)); + + DEBUG_FUNCTION_LINE("Writing segment registers...\n",segment_index,segment_content); + // Writing the segment registers to ALL cores. + runOnAllCores(writeSegmentRegister,&srTableCpy); + + memoryMappingForRegions(mem_mapping,srTableCpy,pageTableCpy); + + //printPageTableTranslation(srTableCpy,pageTableCpy); + + DEBUG_FUNCTION_LINE("Writing PageTable... "); + DCFlushRange(pageTableCpy,sizeof(pageTableCpy)); + SC0x09_KernelWritePTE(pageTableCpy,sizeof(pageTableCpy)); + DCFlushRange(pageTableCpy,sizeof(pageTableCpy)); + log_print("done\n"); + + //printPageTableTranslation(srTableCpy,pageTableCpy); + + runOnAllCores(readAndPrintSegmentRegister,NULL,0,16,0x80000); + + searchEmptyMemoryRegions(); + + writeTestValuesToMemory(); + readTestValuesFromMemory(); +} + +void MemoryMapping::printPageTableTranslation(sr_table_t srTable, u32 * translation_table) { + u32 SDR1 = srTable.sdr1; + //u32 pagemask = SDR1 & 0x1FF; + //u32 hashmask = (pagemask << 10) | 0x3FF; + uint32_t pagetbl = SDR1 & 0xFFFF0000; + + u32 pageIndexShift = 32 - 15; + u32 pageIndexMask = (1 << (28 - pageIndexShift)) - 1; + //u32 byteOffsetMask = (1 << pageIndexShift) - 1; + //u32 apiShift = 22 - pageIndexShift; + + //FSUtils::saveBufferToFile("sd:/table.bin", pteTable,sizeof(pteTable)); + + pageInformation current; + memset(¤t,0,sizeof(current)); + + std::vector pageInfos; + + DEBUG_FUNCTION_LINE("Page table (%08X):\n",pagetbl); + + for(u32 segment = 0; segment < 16 ; segment++) { + u32 sr = srTable.value[segment]; + if(sr >> 31) { + DEBUG_FUNCTION_LINE("Direct access not supported\n"); + } else { + u32 ks = (sr >> 30) & 1; + u32 kp = (sr >> 29) & 1; + u32 nx = (sr >> 28) & 1; + u32 vsid = sr & 0xFFFFFF; + + DEBUG_FUNCTION_LINE("ks %08X kp %08X nx %08X vsid %08X\n",ks,kp,nx,vsid); + u32 pageSize = 1 << pageIndexShift; + for(u32 addr = segment * 0x10000000; addr < (segment + 1) * 0x10000000; addr += pageSize) { + uint32_t pageIndex = (addr >> pageIndexShift) & pageIndexMask; + uint32_t primaryHash = (vsid & 0x7FFFF) ^ pageIndex; + + uint32_t pageTable = SDR1 & 0xFFFF0000; + uint32_t pageMask = SDR1 & 0x1FF; + uint32_t maskedHash = primaryHash & ((pageMask << 10) | 0x3FF); + uint32_t api = (addr >> 22) & 0x3F; + + uint32_t pteaddr = pageTable | (maskedHash << 6); + + //DEBUG_FUNCTION_LINE("pteAddr %08X\n",pteAddr); + + bool found = false; + for (int j = 0; j < 8; j++, pteaddr += 8) { + uint32_t PTEH = 0; + uint32_t PTEL = 0; + + u32 pteh_index = (pteaddr-pagetbl) / 4; + u32 ptel_index = pteh_index + 1; + //DEBUG_FUNCTION_LINE("pteh_index %08X\n",pteh_index); + //DEBUG_FUNCTION_LINE("ptel_index %08X\n",ptel_index); + + PTEH = translation_table[pteh_index]; + PTEL = translation_table[ptel_index]; + + //if(!readPTE(pteaddr,&PTEH)) continue; + //if(!readPTE(pteaddr+4,&PTEL)) continue; + + //Check validity + + if (!(PTEH >> 31)) { + //printf("PTE is not valid \n"); + continue; + } + //DEBUG_FUNCTION_LINE("in\n"); + // the H bit indicated if the PTE was found using the second hash. + if (((PTEH >> 6) & 1)) { + //DEBUG_FUNCTION_LINE("Secondary hash is used\n",((PTEH >> 6) & 1)); + continue; + } + + // Check if the VSID matches, otherwise this is a PTE for another SR + // This is the place where collision could happen. + // Hopefully no collision happen and only the PTEs of the SR will match. + if (((PTEH >> 7) & 0xFFFFFF) != vsid) { + //DEBUG_FUNCTION_LINE("VSID mismatch\n"); + continue; + } + + // Check the API (Abbreviated Page Index) + if ((PTEH & 0x3F) != api) { + //DEBUG_FUNCTION_LINE("API mismatch\n"); + continue; + } + + uint32_t pp = PTEL & 3; + uint32_t phys = PTEL & 0xFFFFF000; + + //DEBUG_FUNCTION_LINE("%08X: %08X %08X \n",pteaddr-pagetbl,PTEH,PTEL); + //DEBUG_FUNCTION_LINE("current.phys == phys - current.size ( %08X %08X)\n",current.phys, phys - current.size); + + if( current.ks == ks && + current.kp == kp && + current.nx == nx && + current.pp == pp && + current.phys == phys - current.size + ) { + current.size += pageSize; + //DEBUG_FUNCTION_LINE("New size of %08X is %08X\n",current.addr,current.size); + } else { + if(current.addr != 0 && current.size != 0) { + /*DEBUG_FUNCTION_LINE("Saving old block from %08X\n",current.addr); + DEBUG_FUNCTION_LINE("ks %08X new %08X\n",current.ks,ks); + DEBUG_FUNCTION_LINE("kp %08X new %08X\n",current.kp,kp); + DEBUG_FUNCTION_LINE("nx %08X new %08X\n",current.nx,nx); + DEBUG_FUNCTION_LINE("pp %08X new %08X\n",current.pp,pp);*/ + pageInfos.push_back(current); + memset(¤t,0,sizeof(current)); + } + //DEBUG_FUNCTION_LINE("Found new block at %08X\n",addr); + current.addr = addr; + current.size = pageSize; + current.kp = kp; + current.ks = ks; + current.nx = nx; + current.pp = pp; + current.phys = phys; + } + found = true; + break; + + } + if(!found) { + if(current.addr != 0 && current.size != 0) { + pageInfos.push_back(current); + memset(¤t,0,sizeof(current)); + } + } + } + } + } + + const char *access1[] = {"read/write", "read/write", "read/write", "read only"}; + const char *access2[] = {"no access", "read only", "read/write", "read only"}; + + for(std::vector::iterator it = pageInfos.begin(); it != pageInfos.end(); ++it) { + pageInformation cur = *it; + // TODO: print if it's executable + DEBUG_FUNCTION_LINE("%08X %08X -> %08X %08X. user access %s. supervisor access %s. %s\n",cur.addr,cur.addr+cur.size,cur.phys,cur.phys+cur.size,cur.kp ? access2[cur.pp] : access1[cur.pp], + cur.ks ? access2[cur.pp] : access1[cur.pp],cur.nx? " not executable " : " executable"); + } +} + + +bool MemoryMapping::mapMemory(uint32_t pa_start_address,uint32_t pa_end_address,uint32_t ea_start_address, sr_table_t SRTable, u32 * translation_table) { + // Based on code from dimok. Thanks! + + u32 pageIndexShift = 32 - 15; + u32 pageIndexMask = (1 << (28 - pageIndexShift)) - 1; + //u32 byteOffsetMask = (1 << pageIndexShift) - 1; + //u32 apiShift = 22 - pageIndexShift; + + // Information on page 5. + // https://www.nxp.com/docs/en/application-note/AN2794.pdf + uint32_t HTABORG = SRTable.sdr1 >> 16; + uint32_t HTABMASK = SRTable.sdr1 & 0x1FF; + + // Iterate to all possible pages. Each page is 1<<(pageIndexShift) big. + + uint32_t pageSize = 1<<(pageIndexShift); + for(u32 i = 0; i < pa_end_address - pa_start_address; i += pageSize) { + // Calculate the current effective address. + uint32_t ea_addr = ea_start_address + i; + // Calculate the segement. + uint32_t segment = SRTable.value[ea_addr >> 28]; + + // Unique ID from the segment which is the input for the hash function. + // Change it to prevent collisions. + uint32_t VSID = segment & 0x00FFFFFF; + uint32_t V = 1; + + //Indicated if second hash is used. + uint32_t H = 0; + + // Abbreviated Page Index + + // Real page number + uint32_t RPN = (pa_start_address + i) >> 12; + uint32_t RC = 3; + uint32_t WIMG = 0x02; + uint32_t PP = 0x02; + + uint32_t page_index = (ea_addr >> pageIndexShift) & pageIndexMask; + uint32_t API = (ea_addr >> 22) & 0x3F; + + uint32_t PTEH = (V << 31) | (VSID << 7) | (H << 6) | API; + uint32_t PTEL = (RPN << 12) | (RC << 7) | (WIMG << 3) | PP; + + + //unsigned long long virtual_address = ((unsigned long long)VSID << 28UL) | (page_index << pageIndexShift) | (ea_addr & 0xFFF); + + uint32_t primary_hash = (VSID & 0x7FFFF); + + uint32_t hashvalue1 = primary_hash ^ page_index; + + // hashvalue 2 is the complement of the first hash. + uint32_t hashvalue2 = ~hashvalue1; + + //uint32_t pageMask = SRTable.sdr1 & 0x1FF; + + // calculate the address of the PTE groups. + // PTEs are saved in a group of 8 PTEs + // When PTEGaddr1 is full (all 8 PTEs set), PTEGaddr2 is used. + // Then H in PTEH needs to be set to 1. + uint32_t PTEGaddr1 = (HTABORG << 16) | (((hashvalue1 >> 10) & HTABMASK) << 16) | ((hashvalue1 & 0x3FF) << 6); + uint32_t PTEGaddr2 = (HTABORG << 16) | (((hashvalue2 >> 10) & HTABMASK) << 16) | ((hashvalue2 & 0x3FF) << 6); + + //offset of the group inside the PTE Table. + uint32_t PTEGoffset = PTEGaddr1 - (HTABORG << 16); + + bool setSuccessfully = false; + PTEGoffset += 7*8; + // Lets iterate through the PTE group where out PTE should be saved. + for(int j = 7; j>0; PTEGoffset -= 8) { + int index = (PTEGoffset/4); + + uint32_t pteh = translation_table[index]; + // Check if it's already taken. The first bit indicates if the PTE-slot inside + // this group is already taken. + if ((pteh == 0)) { + // If we found a free slot, set the PTEH and PTEL value. + DEBUG_FUNCTION_LINE("Used slot %d. PTEGaddr1 %08X addr %08X\n",j+1,PTEGaddr1 - (HTABORG << 16),PTEGoffset); + translation_table[index] = PTEH; + translation_table[index+1] = PTEL; + setSuccessfully = true; + break; + } else { + //printf("PTEGoffset %08X was taken\n",PTEGoffset); + } + j--; + } + // Check if we already found a slot. + if(!setSuccessfully) { + DEBUG_FUNCTION_LINE("-------------- Using second slot -----------------------\n"); + // We still have a chance to find a slot in the PTEGaddr2 using the complement of the hash. + // We need to set the H flag in PTEH and use PTEGaddr2. + // (Not well tested) + H = 1; + PTEH = (V << 31) | (VSID << 7) | (H << 6) | API; + PTEGoffset = PTEGaddr2 - (HTABORG << 16); + PTEGoffset += 7*8; + // Same as before. + for(int j = 7; j>0; PTEGoffset -= 8) { + int index = (PTEGoffset/4); + uint32_t pteh = translation_table[index]; + //Check if it's already taken. + if ((pteh == 0)) { + translation_table[index] = PTEH; + translation_table[index+1] = PTEL; + setSuccessfully = true; + break; + } else { + //printf("PTEGoffset %08X was taken\n",PTEGoffset); + } + j--; + } + + if(!setSuccessfully) { + // Fail if we couldn't find a free slot. + DEBUG_FUNCTION_LINE("-------------- No more free PTE -----------------------\n"); + return false; + } + } + } + return true; +} + diff --git a/loader/src/mymemory/memory_mapping.h b/loader/src/mymemory/memory_mapping.h new file mode 100644 index 0000000..51385a8 --- /dev/null +++ b/loader/src/mymemory/memory_mapping.h @@ -0,0 +1,128 @@ +#ifndef __WUPS_MEMORY_MAPPING_H_ +#define __WUPS_MEMORY_MAPPING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "mykernel/kernel_defs.h" + +typedef struct pageInformation_ { + uint32_t addr; + uint32_t size; + uint32_t ks; + uint32_t kp; + uint32_t nx; + uint32_t pp; + uint32_t phys; +} pageInformation; + +typedef struct _memory_values_t { + unsigned int start_address; + unsigned int end_address; +} memory_values_t; + +typedef struct _memory_mapping_t { + unsigned int effective_start_address; + const memory_values_t* physical_addresses; +} memory_mapping_t; + + +#define SEGMENT_UNIQUE_ID 0x00AABBCC // Unique ID. Chosen arbitrary. + +#define MEMORY_START_BASE 0x80000000 // At most: 128MB for plugins heap. +#define MEMORY_START_PLUGIN_HEAP MEMORY_START_BASE + 0x08000000 // At most: 128MB for plugins heap. +#define MEMORY_START_PLUGIN_SPACE MEMORY_START_BASE + 0x00800000 // At most: 120MB for plugins. +#define MEMORY_START_PLUGIN_LOADER MEMORY_START_BASE + 0x00000000 // At most: 8MB for the plugin loader. + +const memory_values_t mem_vals_loader[] = { + {0x28000000 + 0x06620000 , 0x28000000 + 0x06E20000}, // 8MB 0x80000000 0x80800000 -> 0x2E700000 0x2EF00000 + {0,0} +}; + +const memory_values_t mem_vals_plugins[] = { + {0x28000000 + 0x06E20000 , 0x28000000 + 0x07E20000}, // 16MB 0x80800000 0x81800000 -> 0x2EF00000 0x2FF00000 + {0,0} +}; + +// Values needs to be aligned to 0x20000 and size needs to be a multiple of 0x20000 +const memory_values_t mem_vals_heap[] = { + // 5.5.2 EUR + {0x28000000 + 0x000E0000, 0x28000000 + 0x00160000}, // size: 512 kB + {0x28000000 + 0x003C0000, 0x28000000 + 0x004C0000}, // size: 1024 kB + {0x28000000 + 0x00900000, 0x28000000 + 0x00B00000}, // size: 2048 kB + {0x28000000 + 0x00E40000, 0x28000000 + 0x00EC0000}, // size: 512 kB + {0x28000000 + 0x00EE0000, 0x28000000 + 0x00F60000}, // size: 512 kB + {0x28000000 + 0x00FA0000, 0x28000000 + 0x01020000}, // size: 512 kB + {0x28000000 + 0x01040000, 0x28000000 + 0x013C0000}, // size: 3584 kB + {0x28000000 + 0x02060000, 0x28000000 + 0x021A0000}, // size: 1280 kB + {0x28000000 + 0x02BC0000, 0x28000000 + 0x02CA0000}, // size: 896 kB + {0x28000000 + 0x04B60000, 0x28000000 + 0x04B80000}, // size: 128 kB + {0x28000000 + 0x053C0000, 0x28000000 + 0x05880000}, // size: 4864 kB + {0x28000000 + 0x058E0000, 0x28000000 + 0x06000000}, // size: 7296 kB + {0x28000000 + 0x07E20000, 0x28000000 + 0x07F80000}, // size: 1408 kB + {0x28000000 + 0x080E0000, 0x28000000 + 0x08180000}, // size: 640 kB + {0x28000000 + 0x083C0000, 0x28000000 + 0x084C0000}, // size: 1024 kB + {0x28000000 + 0x086E0000, 0x28000000 + 0x08760000}, // size: 512 kB + {0x28000000 + 0x08C20000, 0x28000000 + 0x08F20000}, // size: 3072 kB + {0x28000000 + 0x09000000, 0x28000000 + 0x09E20000}, // size: 14464 kB + + // Not usable on 5.5.2 + // + // Used in notifications {0x28000000 + 0x01720000, 0x28000000 + 0x018A0000}, // size: 1536 kB + // {0x28000000 + 0x03820000, 0x28000000 + 0x038C0000}, // size: 640 kB + // {0x28000000 + 0x03920000, 0x28000000 + 0x039A0000}, // size: 512 kB + // Used in notifications {0x28000000 + 0x04B80000, 0x28000000 + 0x051E0000}, // size: 6528 kB + // {0x28000000 + 0x08F20000, 0x28000000 + 0x09000000}, // size: 896 kB + + // Porting to other/newer firmware: + // Map this to check for free regions. + // Use MemoryMapper::testFreeMemory() to see regions with are 0x00000000; + // Then map the promising regions, and do the write/read check. + // Writing numbers into the area, open the home menu and all background apps an check if anything was + // overridden. + // {0x28000000 + 0x00000000, 0x28000000 + 0x0A000000}, // + + {0,0} +}; + +const memory_mapping_t mem_mapping[] = { + {MEMORY_START_PLUGIN_LOADER, mem_vals_loader}, + {MEMORY_START_PLUGIN_SPACE, mem_vals_plugins}, + {MEMORY_START_PLUGIN_HEAP, mem_vals_heap}, + {0,NULL} +}; + +class MemoryMapping { + +public: + static bool isMemoryMapped(); + + static void setupMemoryMapping(); + + static void printPageTableTranslation(sr_table_t srTable, u32 * translation_table); + + static void writeTestValuesToMemory(); + + static void readTestValuesFromMemory(); + + static void searchEmptyMemoryRegions(); + + static u32 getHeapAddress(); + + static u32 getHeapSize(); + +private: + + static void memoryMappingForRegions(const memory_mapping_t * memory_mapping, sr_table_t SRTable, u32 * translation_table); + + static bool mapMemory(u32 pa_start_address,u32 pa_end_address,u32 ea_start_address, sr_table_t SRTable, u32 * translation_table); +}; + + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_DEFS_H_ diff --git a/loader/src/patcher/hooks_patcher.cpp b/loader/src/patcher/hooks_patcher.cpp index 4fcdff0..15bb357 100644 --- a/loader/src/patcher/hooks_patcher.cpp +++ b/loader/src/patcher/hooks_patcher.cpp @@ -1,10 +1,12 @@ #include #include +#include #include "common/retain_vars.h" #include "hooks_patcher.h" #include "myutils/overlay_helper.h" #include "main.h" #include "utils.h" +#include "mymemory/memory_mapping.h" DECL(void, __PPCExit, void) { // Only continue if we are in the "right" application. @@ -54,12 +56,32 @@ DECL(void, GX2WaitForVsync, void) { real_GX2WaitForVsync(); } +u8 vpadPressCooldown = 0xFF; +DECL(int, VPADRead, int chan, VPADData *buffer, u32 buffer_size, s32 *error) { + int result = real_VPADRead(chan, buffer, buffer_size, error); + + if(result > 0 && (buffer[0].btns_h == (VPAD_BUTTON_PLUS | VPAD_BUTTON_R | VPAD_BUTTON_L)) && vpadPressCooldown == 0 && OSIsHomeButtonMenuEnabled()) { + if(MemoryMapping::isMemoryMapped()) { + MemoryMapping::readTestValuesFromMemory(); + }else{ + DEBUG_FUNCTION_LINE("Memory was not mapped. To test the memory please exit the plugin loader by pressing MINUS\n"); + } + vpadPressCooldown = 0x3C; + } + if(vpadPressCooldown > 0) { + vpadPressCooldown--; + } + return result; +} + + hooks_magic_t method_hooks_hooks[] __attribute__((section(".data"))) = { MAKE_MAGIC(__PPCExit, LIB_CORE_INIT, STATIC_FUNCTION), MAKE_MAGIC(ProcUIProcessMessages, LIB_PROC_UI, DYNAMIC_FUNCTION), MAKE_MAGIC(GX2SetTVBuffer, LIB_GX2, STATIC_FUNCTION), MAKE_MAGIC(GX2SetDRCBuffer, LIB_GX2, STATIC_FUNCTION), MAKE_MAGIC(GX2WaitForVsync, LIB_GX2, STATIC_FUNCTION), + MAKE_MAGIC(VPADRead, LIB_VPAD, STATIC_FUNCTION), };