diff --git a/installer/Makefile b/installer/Makefile index a5d3343..491ec3f 100644 --- a/installer/Makefile +++ b/installer/Makefile @@ -16,7 +16,7 @@ sd_loader_elf := ../sd_loader/sd_loader.elf CFLAGS += -DUSE_SD_LOADER ASFLAGS += -DUSE_SD_LOADER -all: clean setup main532 main550 main500 main410 main400 main310 main300 +all: clean setup main532 main550 main500 main410 main400 sd_loader.h: $(sd_loader_elf) xxd -i $< | sed "s/unsigned/static const unsigned/g;s/loader/loader/g;s/build_//g" > $@ diff --git a/installer/launcher.c b/installer/launcher.c index 8a6e398..a86b468 100644 --- a/installer/launcher.c +++ b/installer/launcher.c @@ -23,6 +23,14 @@ #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader #define KERN_SYSCALL_TBL_4 0xFFEA9CE0 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEAA0E0 // works with browser (previously KERN_SYSCALL_TBL) + + #define address_LiWaitIopComplete 0x0100FFA4 + #define address_LiWaitIopCompleteWithInterrupts 0x0100FE90 + #define address_LiWaitOneChunk 0x010007EC + #define address_PrepareTitle_hook 0xFFF18558 + #define address_sgIsLoadingBuffer 0xEFE19D00 + #define address_gDynloadInitialized 0xEFE13C3C + #elif ( (VER == 500) || (VER == 510) ) #define ADDRESS_OSTitle_main_entry_ptr 0x1005CB00 #define ADDRESS_main_entry_hook 0x0101C15C @@ -32,6 +40,14 @@ #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader #define KERN_SYSCALL_TBL_4 0xFFEA9120 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEA9520 // works with browser (previously KERN_SYSCALL_TBL) + + #define address_LiWaitIopComplete 0x0100FBC4 + #define address_LiWaitIopCompleteWithInterrupts 0x0100FAB0 + #define address_LiWaitOneChunk 0x010007EC + #define address_PrepareTitle_hook 0xFFF18534 + #define address_sgIsLoadingBuffer 0xEFE19D00 + #define address_gDynloadInitialized 0xEFE13C3C + #elif (VER == 550) #define ADDRESS_OSTitle_main_entry_ptr 0x1005E040 #define ADDRESS_main_entry_hook 0x0101c56c @@ -41,6 +57,13 @@ #define KERN_SYSCALL_TBL_3 0xFFE85470 // works with loader #define KERN_SYSCALL_TBL_4 0xFFEAAA60 // works with home menu #define KERN_SYSCALL_TBL_5 0xFFEAAE60 // works with browser (previously KERN_SYSCALL_TBL) + + #define address_LiWaitIopComplete 0x01010180 + #define address_LiWaitIopCompleteWithInterrupts 0x0101006C + #define address_LiWaitOneChunk 0x0100080C + #define address_PrepareTitle_hook 0xFFF184E4 + #define address_sgIsLoadingBuffer 0xEFE19E80 + #define address_gDynloadInitialized 0xEFE13DBC #elif (VER == 410) #define ADDRESS_OSTitle_main_entry_ptr 0x1005A8C0 #define ADDRESS_main_entry_hook 0x0101BD4C @@ -50,6 +73,13 @@ #define KERN_SYSCALL_TBL_3 0xFFE85C90 #define KERN_SYSCALL_TBL_4 0xFFE85490 #define KERN_SYSCALL_TBL_5 0xFFE85890 // works with browser + + #define address_LiWaitIopComplete 0x0100F78C + #define address_LiWaitIopCompleteWithInterrupts 0x0100F678 + #define address_LiWaitOneChunk 0x010007F8 + #define address_PrepareTitle_hook 0xFFF166DC + #define address_sgIsLoadingBuffer 0xEFE19CC0 + #define address_gDynloadInitialized 0xEFE13BFC #elif (VER == 400) #define ADDRESS_OSTitle_main_entry_ptr 0x1005A600 #define ADDRESS_main_entry_hook 0x0101BD4C @@ -59,6 +89,13 @@ #define KERN_SYSCALL_TBL_3 0xFFE85C90 #define KERN_SYSCALL_TBL_4 0xFFE85490 #define KERN_SYSCALL_TBL_5 0xFFE85890 // works with browser + + #define address_LiWaitIopComplete 0x0100F78C + #define address_LiWaitIopCompleteWithInterrupts 0x0100F678 + #define address_LiWaitOneChunk 0x010007F8 + #define address_PrepareTitle_hook 0xFFF15E70 + #define address_sgIsLoadingBuffer 0xEFE19CC0 + #define address_gDynloadInitialized 0xEFE13BFC #elif ( (VER == 300) || (VER == 310) ) #define ADDRESS_OSTitle_main_entry_ptr 0x1005BBC0 #define ADDRESS_main_entry_hook 0x0101894C // used OSDynLoad_Acquire 0x01022CBC from libwiiu to calculate @@ -496,6 +533,15 @@ static void InstallPatches(private_data_t *private_data) osSpecificFunctions.addr_KernSyscallTbl3 = KERN_SYSCALL_TBL_3; osSpecificFunctions.addr_KernSyscallTbl4 = KERN_SYSCALL_TBL_4; osSpecificFunctions.addr_KernSyscallTbl5 = KERN_SYSCALL_TBL_5; + + osSpecificFunctions.LiWaitIopComplete = (int (*)(int, int *)) address_LiWaitIopComplete; + osSpecificFunctions.LiWaitIopCompleteWithInterrupts = (int (*)(int, int *)) address_LiWaitIopCompleteWithInterrupts; + osSpecificFunctions.addr_LiWaitOneChunk = address_LiWaitOneChunk; + osSpecificFunctions.addr_PrepareTitle_hook = address_PrepareTitle_hook; + osSpecificFunctions.addr_sgIsLoadingBuffer = address_sgIsLoadingBuffer; + osSpecificFunctions.addr_gDynloadInitialized = address_gDynloadInitialized; + osSpecificFunctions.orig_LiWaitOneChunkInstr = *(unsigned int*)address_LiWaitOneChunk; + //! pointer to main entry point of a title osSpecificFunctions.addr_OSTitle_main_entry = ADDRESS_OSTitle_main_entry_ptr; diff --git a/sd_loader/src/entry.c b/sd_loader/src/entry.c index 3fa523d..8f62750 100644 --- a/sd_loader/src/entry.c +++ b/sd_loader/src/entry.c @@ -3,13 +3,11 @@ #include "../../src/common/common.h" #include "../../src/common/fs_defs.h" #include "../../src/common/os_defs.h" - -#define CODE_RW_BASE_OFFSET 0 -#define DATA_RW_BASE_OFFSET 0 +#include "kernel_defs.h" +#include "loader_defs.h" #define EXPORT_DECL(res, func, ...) res (* func)(__VA_ARGS__); - -#define OS_FIND_EXPORT(handle, funcName, func) OSDynLoad_FindExport(handle, 0, funcName, &func) +#define OS_FIND_EXPORT(handle, funcName, func) OSDynLoad_FindExport(handle, 0, funcName, &func) typedef struct _private_data_t { @@ -19,10 +17,8 @@ typedef struct _private_data_t EXPORT_DECL(void*, memcpy, void *p1, const void *p2, unsigned int s); EXPORT_DECL(void*, memset, void *p1, int val, unsigned int s); EXPORT_DECL(void, OSFatal, const char* msg); - EXPORT_DECL(void, DCFlushRange, const void *addr, u32 length); - EXPORT_DECL(void, ICInvalidateRange, const void *addr, u32 length); - EXPORT_DECL(int, __os_snprintf, char* s, int n, const char * format, ...); - EXPORT_DECL(void, exit, void); + EXPORT_DECL(unsigned int, OSEffectiveToPhysical, const void*); + EXPORT_DECL(void, exit, int); EXPORT_DECL(int, FSInit, void); EXPORT_DECL(int, FSAddClientEx, void *pClient, int unk_zero_param, int errHandling); @@ -39,6 +35,333 @@ typedef struct _private_data_t EXPORT_DECL(int, SYSRelaunchTitle, int argc, char** argv); } private_data_t; +static void (*DCFlushRange)(void *addr, unsigned int size); +static void (*DCInvalidateRange)(void *addr, unsigned int size); +static void (*ICInvalidateRange)(void *addr, unsigned int size); +static unsigned int hook_LiWaitOneChunk; +static unsigned int addrphys_LiWaitOneChunk; + +extern void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); +extern void my_PrepareTitle_hook(void); + +/* Write a 32-bit word with kernel permissions */ +static void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) +{ + asm volatile ( + "li 3,1\n" + "li 4,0\n" + "mr 5,%1\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%0\n" + "mr %1,1\n" + "li 0,0x3500\n" + "sc\n" + "nop\n" + "mr 1,%1\n" + : + : "r"(addr), "r"(value) + : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); +} + +static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len) +{ + /* + * Setup a DBAT access with cache inhibited to write through and read directly from memory + */ + unsigned int dbatu0, dbatl0, dbatu1, dbatl1; + // save the original DBAT value + asm volatile("mfdbatu %0, 0" : "=r" (dbatu0)); + asm volatile("mfdbatl %0, 0" : "=r" (dbatl0)); + asm volatile("mfdbatu %0, 1" : "=r" (dbatu1)); + asm volatile("mfdbatl %0, 1" : "=r" (dbatl1)); + + unsigned int target_dbatu0 = 0; + unsigned int target_dbatl0 = 0; + unsigned int target_dbatu1 = 0; + unsigned int target_dbatl1 = 0; + + unsigned int *dst_p = (unsigned int*)addr; + unsigned int *src_p = (unsigned int*)src; + + // we only need DBAT modification for addresses out of our own DBAT range + // as our own DBAT is available everywhere for user and supervisor + // since our own DBAT is on DBAT5 position we don't collide here + if(addr < 0x00800000 || addr >= 0x01000000) + { + target_dbatu0 = (addr & 0x00F00000) | 0xC0000000 | 0x1F; + target_dbatl0 = (addr & 0xFFF00000) | 0x32; + asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0)); + dst_p = (unsigned int*)((addr & 0xFFFFFF) | 0xC0000000); + } + if(src < 0x00800000 || src >= 0x01000000) + { + target_dbatu1 = (src & 0x00F00000) | 0xB0000000 | 0x1F; + target_dbatl1 = (src & 0xFFF00000) | 0x32; + + asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1)); + src_p = (unsigned int*)((src & 0xFFFFFF) | 0xB0000000); + } + + asm volatile("eieio; isync"); + + unsigned int i; + for(i = 0; i < len; i += 4) + { + // if we are on the edge to next chunk + if((target_dbatu0 != 0) && (((unsigned int)dst_p & 0x00F00000) != (target_dbatu0 & 0x00F00000))) + { + target_dbatu0 = ((addr + i) & 0x00F00000) | 0xC0000000 | 0x1F; + target_dbatl0 = ((addr + i) & 0xFFF00000) | 0x32; + dst_p = (unsigned int*)(((addr + i) & 0xFFFFFF) | 0xC0000000); + + asm volatile("eieio; isync"); + asm volatile("mtdbatu 0, %0" : : "r" (target_dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (target_dbatl0)); + asm volatile("eieio; isync"); + } + if((target_dbatu1 != 0) && (((unsigned int)src_p & 0x00F00000) != (target_dbatu1 & 0x00F00000))) + { + target_dbatu1 = ((src + i) & 0x00F00000) | 0xB0000000 | 0x1F; + target_dbatl1 = ((src + i) & 0xFFF00000) | 0x32; + src_p = (unsigned int*)(((src + i) & 0xFFFFFF) | 0xB0000000); + + asm volatile("eieio; isync"); + asm volatile("mtdbatu 1, %0" : : "r" (target_dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (target_dbatl1)); + asm volatile("eieio; isync"); + } + + *dst_p = *src_p; + + ++dst_p; + ++src_p; + } + + /* + * Restore original DBAT value + */ + asm volatile("eieio; isync"); + asm volatile("mtdbatu 0, %0" : : "r" (dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (dbatl0)); + asm volatile("mtdbatu 1, %0" : : "r" (dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (dbatl1)); + asm volatile("eieio; isync"); +} + +// This function is called every time after LiBounceOneChunk. +// It waits for the asynchronous call of LiLoadAsync for the IOSU to fill data to the RPX/RPL address +// and return the still remaining bytes to load. +// We override it and replace the loaded date from LiLoadAsync with our data and our remaining bytes to load. +static int LiWaitOneChunk(unsigned int * iRemainingBytes, const char *filename, int fileType) +{ + unsigned int result; + register int core_id; + int remaining_bytes = 0; + + int sgFileOffset; + int sgBufferNumber; + int *sgBounceError; + int *sgGotBytes; + int *sgTotalBytes; + int *sgIsLoadingBuffer; + int *sgFinishedLoadingBuffer; + + // get the current core + asm volatile("mfspr %0, 0x3EF" : "=r" (core_id)); + + // get the offset of per core global variable for dynload initialized (just a simple address + (core_id * 4)) + unsigned int gDynloadInitialized = *(volatile unsigned int*)(OS_SPECIFICS->addr_gDynloadInitialized + (core_id << 2)); + + // Comment (Dimok): + // time measurement at this position for logger -> we don't need it right now except maybe for debugging + //unsigned long long systemTime1 = Loader_GetSystemTime(); + + if(OS_FIRMWARE == 550) + { + // pointer to global variables of the loader + loader_globals_550_t *loader_globals = (loader_globals_550_t*)(0xEFE19E80); + + sgBufferNumber = loader_globals->sgBufferNumber; + sgFileOffset = loader_globals->sgFileOffset; + sgBounceError = &loader_globals->sgBounceError; + sgGotBytes = &loader_globals->sgGotBytes; + sgTotalBytes = &loader_globals->sgTotalBytes; + sgFinishedLoadingBuffer = &loader_globals->sgFinishedLoadingBuffer; + // not available on 5.5.x + sgIsLoadingBuffer = NULL; + } + else + { + // pointer to global variables of the loader + loader_globals_t *loader_globals = (loader_globals_t*)(OS_SPECIFICS->addr_sgIsLoadingBuffer); + + sgBufferNumber = loader_globals->sgBufferNumber; + sgFileOffset = loader_globals->sgFileOffset; + sgBounceError = &loader_globals->sgBounceError; + sgGotBytes = &loader_globals->sgGotBytes; + sgIsLoadingBuffer = &loader_globals->sgIsLoadingBuffer; + // not available on < 5.5.x + sgTotalBytes = NULL; + sgFinishedLoadingBuffer = NULL; + } + + // the data loading was started in LiBounceOneChunk() and here it waits for IOSU to finish copy the data + if(gDynloadInitialized != 0) { + result = OS_SPECIFICS->LiWaitIopCompleteWithInterrupts(0x2160EC0, &remaining_bytes); + + } + else { + result = OS_SPECIFICS->LiWaitIopComplete(0x2160EC0, &remaining_bytes); + } + + // Comment (Dimok): + // time measurement at this position for logger -> we don't need it right now except maybe for debugging + //unsigned long long systemTime2 = Loader_GetSystemTime(); + + //------------------------------------------------------------------------------------------------------------------ + // Start of our function intrusion: + // After IOSU is done writing the data into the 0xF6000000/0xF6400000 address, + // we overwrite it with our data before setting the global flag for IsLoadingBuffer to 0 + // Do this only if we are in the game that was launched by our method + s_mem_area *mem_area = MEM_AREA_TABLE; + if((ELF_DATA_ADDR == mem_area->address) && (fileType == 0)) + { + unsigned int load_address = (sgBufferNumber == 1) ? 0xF6000000 : (0xF6000000 + 0x00400000); + unsigned int load_addressPhys = (sgBufferNumber == 1) ? 0x1B000000 : (0x1B000000 + 0x00400000); // virtual 0xF6000000 and 0xF6400000 + + remaining_bytes = ELF_DATA_SIZE - sgFileOffset; + if (remaining_bytes > 0x400000) + // truncate size + remaining_bytes = 0x400000; + + DCFlushRange((void*)load_address, remaining_bytes); + + u32 rpxBlockPos = 0; + u32 done = 0; + u32 mapOffset = 0; + + while((done < (u32)sgFileOffset) && mem_area) + { + if((done + mem_area->size) > (u32)sgFileOffset) + { + mapOffset = sgFileOffset - done; + done = sgFileOffset; + } + else + { + done += mem_area->size; + mem_area = mem_area->next; + } + } + + while((done < ELF_DATA_SIZE) && (rpxBlockPos < 0x400000) && mem_area) + { + u32 address = mem_area->address + mapOffset; + u32 blockSize = ELF_DATA_SIZE - done; + + if(blockSize > (0x400000 - rpxBlockPos)) + { + blockSize = 0x400000 - rpxBlockPos; + } + if((mapOffset + blockSize) >= mem_area->size) + { + blockSize = mem_area->size - mapOffset; + mem_area = mem_area->next; + mapOffset = 0; + } + + SC0x25_KernelCopyData(load_addressPhys + rpxBlockPos, address, blockSize); + done += blockSize; + rpxBlockPos += blockSize; + mapOffset += blockSize; + } + + DCInvalidateRange((void*)load_address, remaining_bytes); + + if((u32)(sgFileOffset + remaining_bytes) == ELF_DATA_SIZE) + { + ELF_DATA_ADDR = 0xDEADC0DE; + ELF_DATA_SIZE = 0; + MAIN_ENTRY_ADDR = 0xC001C0DE; + } + // set result to 0 -> "everything OK" + result = 0; + } + + // end of our little intrusion into this function + //------------------------------------------------------------------------------------------------------------------ + + // set the result to the global bounce error variable + if(sgBounceError) { + *sgBounceError = result; + } + + // disable global flag that buffer is still loaded by IOSU + if(sgFinishedLoadingBuffer) + { + unsigned int zeroBitCount = 0; + asm volatile("cntlzw %0, %0" : "=r" (zeroBitCount) : "r"(*sgFinishedLoadingBuffer)); + *sgFinishedLoadingBuffer = zeroBitCount >> 5; + } + else if(sgIsLoadingBuffer) + { + *sgIsLoadingBuffer = 0; + } + + // check result for errors + if(result == 0) + { + // the remaining size is set globally and in stack variable only + // if a pointer was passed to this function + if(iRemainingBytes) { + if(sgGotBytes) { + *sgGotBytes = remaining_bytes; + } + + *iRemainingBytes = remaining_bytes; + + // on 5.5.x a new variable for total loaded bytes was added + if(sgTotalBytes) { + *sgTotalBytes += remaining_bytes; + } + } + // Comment (Dimok): + // calculate time difference and print it on logging how long the wait for asynchronous data load took + // something like (systemTime2 - systemTime1) * constant / bus speed, did not look deeper into it as we don't need that crap + } + else { + // Comment (Dimok): + // a lot of error handling here. depending on error code sometimes calls Loader_Panic() -> we don't make errors so we can skip that part ;-P + } + return result; +} + +void my_PrepareTitle(CosAppXmlInfo *xmlKernelInfo) +{ + if(ELF_DATA_ADDR == MEM_AREA_TABLE->address) + { + xmlKernelInfo->max_size = RPX_MAX_SIZE; + xmlKernelInfo->max_codesize = RPX_MAX_CODE_SIZE; + //! setup our hook to LiWaitOneChunk for RPX loading + hook_LiWaitOneChunk = ((u32)LiWaitOneChunk) | 0x48000002; + KernelCopyData(addrphys_LiWaitOneChunk, (u32) &hook_LiWaitOneChunk, 4); + asm volatile("icbi 0, %0" : : "r" (OS_SPECIFICS->addr_LiWaitOneChunk & ~31)); + } + else if((MAIN_ENTRY_ADDR == 0xC001C0DE) && (*(u32*)xmlKernelInfo->rpx_name == 0x66666c5f)) // ffl_ + { + //! restore original LiWaitOneChunk instruction as our RPX is done + MAIN_ENTRY_ADDR = 0xDEADC0DE; + KernelCopyData(addrphys_LiWaitOneChunk, (u32)&OS_SPECIFICS->orig_LiWaitOneChunkInstr, 4); + asm volatile("icbi 0, %0" : : "r" (OS_SPECIFICS->addr_LiWaitOneChunk & ~31)); + } +} + static int LoadFileToMem(private_data_t *private_data, const char *filepath, unsigned char **fileOut, unsigned int * sizeOut) { int iFd = -1; @@ -66,19 +389,15 @@ static int LoadFileToMem(private_data_t *private_data, const char *filepath, uns int status = private_data->FSGetMountSource(pClient, pCmd, 0, tempPath, -1); if (status != 0) { private_data->OSFatal("FSGetMountSource failed."); - break; } status = private_data->FSMount(pClient, pCmd, tempPath, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); if(status != 0) { private_data->OSFatal("SD mount failed."); - break; } status = private_data->FSOpenFile(pClient, pCmd, filepath, "r", &iFd, -1); - if(status != 0) - { - private_data->FSUnmount(pClient, pCmd, mountPath, -1); - break; + if(status != 0) { + private_data->OSFatal("FSOpenFile failed."); } FSStat stat; @@ -90,9 +409,8 @@ static int LoadFileToMem(private_data_t *private_data, const char *filepath, uns if(stat.size > 0) pBuffer = private_data->MEMAllocFromDefaultHeapEx((stat.size + 0x3F) & ~0x3F, 0x40); - - if(!pBuffer) - private_data->OSFatal("Not enough memory for ELF file."); + else + private_data->OSFatal("ELF file empty."); unsigned int done = 0; @@ -150,25 +468,19 @@ static unsigned int load_elf_image (private_data_t *private_data, unsigned char continue; if(phdrs[i].p_filesz > phdrs[i].p_memsz) - return 0; + continue; if(!phdrs[i].p_filesz) continue; unsigned int p_paddr = phdrs[i].p_paddr; - - // use correct offset address for executables and data access - if(phdrs[i].p_flags & PF_X) - p_paddr += CODE_RW_BASE_OFFSET; - else - p_paddr += DATA_RW_BASE_OFFSET; - image = (unsigned char *) (elfstart + phdrs[i].p_offset); - private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz); - private_data->DCFlushRange((void*)p_paddr, phdrs[i].p_filesz); + + private_data->memcpy ((void *) p_paddr, image, phdrs[i].p_filesz); + DCFlushRange((void*)p_paddr, phdrs[i].p_filesz); if(phdrs[i].p_flags & PF_X) - private_data->ICInvalidateRange ((void *) phdrs[i].p_paddr, phdrs[i].p_memsz); + ICInvalidateRange ((void *) p_paddr, phdrs[i].p_memsz); } //! clear BSS @@ -179,15 +491,31 @@ static unsigned int load_elf_image (private_data_t *private_data, unsigned char if(section_name[0] == '.' && section_name[1] == 'b' && section_name[2] == 's' && section_name[3] == 's') { private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size); - private_data->DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size); + DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size); } else if(section_name[0] == '.' && section_name[1] == 's' && section_name[2] == 'b' && section_name[3] == 's' && section_name[4] == 's') { private_data->memset((void*)shdr[i].sh_addr, 0, shdr[i].sh_size); - private_data->DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size); + DCFlushRange((void*)shdr[i].sh_addr, shdr[i].sh_size); } } + //! setup hooks + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x25 * 4)), (unsigned int)KernelCopyData); + + //! store physical address for later use + addrphys_LiWaitOneChunk = private_data->OSEffectiveToPhysical((void*)OS_SPECIFICS->addr_LiWaitOneChunk); + + u32 addr_my_PrepareTitle_hook = ((u32)my_PrepareTitle_hook) | 0x48000003; + DCFlushRange(&addr_my_PrepareTitle_hook, 4); + + //! create our copy syscall + SC0x25_KernelCopyData(OS_SPECIFICS->addr_PrepareTitle_hook, private_data->OSEffectiveToPhysical(&addr_my_PrepareTitle_hook), 4); + return ehdr->e_entry; } @@ -213,9 +541,10 @@ static void loadFunctionPointers(private_data_t * private_data) OS_FIND_EXPORT(coreinit_handle, "memcpy", private_data->memcpy); OS_FIND_EXPORT(coreinit_handle, "memset", private_data->memset); OS_FIND_EXPORT(coreinit_handle, "OSFatal", private_data->OSFatal); - OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", private_data->DCFlushRange); - OS_FIND_EXPORT(coreinit_handle, "ICInvalidateRange", private_data->ICInvalidateRange); - OS_FIND_EXPORT(coreinit_handle, "__os_snprintf", private_data->__os_snprintf); + OS_FIND_EXPORT(coreinit_handle, "DCFlushRange", DCFlushRange); + OS_FIND_EXPORT(coreinit_handle, "DCInvalidateRange", DCInvalidateRange); + OS_FIND_EXPORT(coreinit_handle, "ICInvalidateRange", ICInvalidateRange); + OS_FIND_EXPORT(coreinit_handle, "OSEffectiveToPhysical", private_data->OSEffectiveToPhysical); OS_FIND_EXPORT(coreinit_handle, "exit", private_data->exit); OS_FIND_EXPORT(coreinit_handle, "FSInit", private_data->FSInit); @@ -237,8 +566,10 @@ static void loadFunctionPointers(private_data_t * private_data) int _start(int argc, char **argv) { + private_data_t private_data; + + if(MAIN_ENTRY_ADDR != 0xC001C0DE) { - private_data_t private_data; loadFunctionPointers(&private_data); while(1) @@ -252,6 +583,7 @@ int _start(int argc, char **argv) private_data.memcpy(pElfBuffer, (unsigned char*)ELF_DATA_ADDR, ELF_DATA_SIZE); MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); private_data.MEMFreeToDefaultHeap(pElfBuffer); + } ELF_DATA_ADDR = 0xDEADC0DE; ELF_DATA_SIZE = 0; @@ -259,30 +591,38 @@ int _start(int argc, char **argv) if(MAIN_ENTRY_ADDR == 0xDEADC0DE || MAIN_ENTRY_ADDR == 0) { - unsigned char *pElfBuffer = NULL; - unsigned int uiElfSize = 0; - - LoadFileToMem(&private_data, CAFE_OS_SD_PATH WIIU_PATH "/apps/homebrew_launcher/homebrew_launcher.elf", &pElfBuffer, &uiElfSize); - - if(!pElfBuffer) + if(HBL_CHANNEL) { - private_data.OSFatal("Could not load file " WIIU_PATH "/apps/homebrew_launcher/homebrew_launcher.elf"); + break; } else { - MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); - private_data.MEMFreeToDefaultHeap(pElfBuffer); + unsigned char *pElfBuffer = NULL; + unsigned int uiElfSize = 0; - if(MAIN_ENTRY_ADDR == 0) + LoadFileToMem(&private_data, CAFE_OS_SD_PATH WIIU_PATH "/apps/homebrew_launcher/homebrew_launcher.elf", &pElfBuffer, &uiElfSize); + + if(!pElfBuffer) { - private_data.OSFatal("Failed to load ELF " WIIU_PATH "/apps/homebrew_launcher/homebrew_launcher.elf"); + private_data.OSFatal("Failed to load homebrew_launcher.elf"); + } + else + { + MAIN_ENTRY_ADDR = load_elf_image(&private_data, pElfBuffer); + if(MAIN_ENTRY_ADDR == 0) + { + private_data.OSFatal("Failed to load homebrew_launcher.elf"); + } + else + { + private_data.MEMFreeToDefaultHeap(pElfBuffer); + } } } } else { int returnVal = ((int (*)(int, char **))MAIN_ENTRY_ADDR)(argc, argv); - //! exit to miimaker and restart application on re-enter of another application if(returnVal == (int)EXIT_RELAUNCH_ON_LOAD) { @@ -293,12 +633,20 @@ int _start(int argc, char **argv) { MAIN_ENTRY_ADDR = 0xDEADC0DE; private_data.SYSRelaunchTitle(0, 0); - private_data.exit(); + private_data.exit(0); break; } } } } - return ( (int (*)(int, char **))(*(unsigned int*)OS_SPECIFICS->addr_OSTitle_main_entry) )(argc, argv); + int ret = ( (int (*)(int, char **))(*(unsigned int*)OS_SPECIFICS->addr_OSTitle_main_entry) )(argc, argv); + + //! if an application returns and was an RPX launch then launch HBL again + if(MAIN_ENTRY_ADDR == 0xC001C0DE) + { + private_data.SYSRelaunchTitle(0, 0); + private_data.exit(0); + } + return ret; } diff --git a/sd_loader/src/kernel_defs.h b/sd_loader/src/kernel_defs.h new file mode 100644 index 0000000..a1cce49 --- /dev/null +++ b/sd_loader/src/kernel_defs.h @@ -0,0 +1,75 @@ +#ifndef __KERNEL_DEFS_H_ +#define __KERNEL_DEFS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// original structure in the kernel that is originally 0x1270 long +typedef struct +{ + uint32_t version_cos_xml; // version tag from cos.xml + uint64_t os_version; // os_version from app.xml + uint64_t title_id; // title_id tag from app.xml + uint32_t app_type; // app_type tag from app.xml + uint32_t cmdFlags; // unknown tag as it is always 0 (might be cmdFlags from cos.xml but i am not sure) + char rpx_name[0x1000]; // rpx name from cos.xml + uint32_t unknown2; // 0x050B8304 in mii maker and system menu (looks a bit like permissions complex that got masked!?) + uint32_t unknown3[63]; // those were all zeros, but its probably connected with unknown2 + uint32_t max_size; // max_size in cos.xml which defines the maximum amount of memory reserved for the app + uint32_t avail_size; // avail_size or codegen_size in cos.xml (seems to mostly be 0?) + uint32_t codegen_size; // codegen_size or avail_size in cos.xml (seems to mostly be 0?) + uint32_t codegen_core; // codegen_core in cos.xml (seems to mostly be 1?) + uint32_t max_codesize; // max_codesize in cos.xml + uint32_t overlay_arena; // overlay_arena in cos.xml + uint32_t unknown4[59]; // all zeros it seems + uint32_t default_stack0_size; // not sure because always 0 but very likely + uint32_t default_stack1_size; // not sure because always 0 but very likely + uint32_t default_stack2_size; // not sure because always 0 but very likely + uint32_t default_redzone0_size; // not sure because always 0 but very likely + uint32_t default_redzone1_size; // not sure because always 0 but very likely + uint32_t default_redzone2_size; // not sure because always 0 but very likely + uint32_t exception_stack0_size; // from cos.xml, 0x1000 on mii maker + uint32_t exception_stack1_size; // from cos.xml, 0x1000 on mii maker + uint32_t exception_stack2_size; // from cos.xml, 0x1000 on mii maker + uint32_t sdk_version; // from app.xml, 20909 (0x51AD) on mii maker + uint32_t title_version; // from app.xml, 0x32 on mii maker + /* + // --------------------------------------------------------------------------------------------------------------------------------------------- + // the next part might be changing from title to title?! I don't think its important but nice to know maybe.... + // --------------------------------------------------------------------------------------------------------------------------------------------- + char mlc[4]; // string "mlc" on mii maker and sysmenu + uint32_t unknown5[7]; // all zeros on mii maker and sysmenu + uint32_t unknown6_one; // 0x01 on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + char ACP[4]; // string "ACP" on mii maker and sysmenu + uint32_t unknown7[15]; // all zeros on mii maker and sysmenu + uint32_t unknown8_5; // 0x05 on mii maker and sysmenu + uint32_t unknown9_zero; // 0x00 on mii maker and sysmenu + uint32_t unknown10_ptr; // 0xFF23DD0C pointer on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + char UVD[4]; // string "UVD" on mii maker and sysmenu + uint32_t unknown11[15]; // all zeros on mii maker and sysmenu + uint32_t unknown12_5; // 0x05 on mii maker and sysmenu + uint32_t unknown13_zero; // 0x00 on mii maker and sysmenu + uint32_t unknown14_ptr; // 0xFF23EFC8 pointer on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + char SND[4]; // string "SND" on mii maker and sysmenu + uint32_t unknown15[15]; // all zeros on mii maker and sysmenu + uint32_t unknown16_5; // 0x05 on mii maker and sysmenu + uint32_t unknown17_zero; // 0x00 on mii maker and sysmenu + uint32_t unknown18_ptr; // 0xFF23F014 pointer on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + uint32_t unknown19; // 0x02 on miimaker, 0x0F on system menu + */ + // after that only zeros follow +} __attribute__((packed)) CosAppXmlInfo; + + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_DEFS_H_ diff --git a/sd_loader/src/kernel_hooks.S b/sd_loader/src/kernel_hooks.S index 7f70ebb..0d7f11f 100644 --- a/sd_loader/src/kernel_hooks.S +++ b/sd_loader/src/kernel_hooks.S @@ -27,3 +27,43 @@ SaveAndResetDataBATs_And_SRs_hook: mtsr 7, r5 # jump back to the position in kernel after our patch (from LR) bctr + +.extern my_PrepareTitle + .globl my_PrepareTitle_hook +my_PrepareTitle_hook: + # store all registers on stack to avoid issues with the call to C functions + stwu r1, -0x90(r1) + # registers for our own usage + # just store everything + stmw r3, 0x10(r1) + + # save the LR from where we came + mflr r31 + + # the cos.xml/app.xml structure is at the location 0x68 of r11 + # there are actually many places that can be hooked for it + # e.g. 0xFFF16130 and r27 points to this structure + addi r3, r11, 0x68 + + bl my_PrepareTitle + + # setup LR to jump back to kernel code + mtlr r31 + + # restore all original values of registers from stack + lmw r3, 0x10(r1) + + # restore the stack + addi r1, r1, 0x90 + + # restore original instruction that we replaced in the kernel + clrlwi r7, r12, 0 + + # jump back + blr + + .globl SC0x25_KernelCopyData +SC0x25_KernelCopyData: + li r0, 0x2500 + sc + blr diff --git a/sd_loader/src/link.ld b/sd_loader/src/link.ld index f57f59b..1d82ead 100644 --- a/sd_loader/src/link.ld +++ b/sd_loader/src/link.ld @@ -13,10 +13,11 @@ SECTIONS { .data : { *(.rodata*); *(.data*); + *(.bss*); } /DISCARD/ : { *(*); } } -ASSERT((SIZEOF(.text) + SIZEOF(.data)) < 0x1000, "Memory overlapping with main elf."); +ASSERT((SIZEOF(.text) + SIZEOF(.data)) < 0x1300, "Memory overlapping with main elf."); diff --git a/sd_loader/src/loader_defs.h b/sd_loader/src/loader_defs.h new file mode 100644 index 0000000..b71514f --- /dev/null +++ b/sd_loader/src/loader_defs.h @@ -0,0 +1,38 @@ +#ifndef __LOADER_DEFS_H_ +#define __LOADER_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// struct holding the globals of the loader (there are actually more but we don't need others) +typedef struct _loader_globals_t +{ + int sgIsLoadingBuffer; + int sgFileType; + int sgProcId; + int sgGotBytes; + int sgFileOffset; + int sgBufferNumber; + int sgBounceError; + char sgLoadName[0x1000]; +} __attribute__((packed)) loader_globals_t; + +typedef struct _loader_globals_550_t +{ + int sgFinishedLoadingBuffer; + int sgFileType; + int sgProcId; + int sgGotBytes; + int sgTotalBytes; + int sgFileOffset; + int sgBufferNumber; + int sgBounceError; + char sgLoadName[0x1000]; +} __attribute__((packed)) loader_globals_550_t; + +#ifdef __cplusplus +} +#endif + +#endif // __LOADER_DEFS_H_ diff --git a/src/common/common.h b/src/common/common.h index 3f2aafa..71beaae 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -7,7 +7,7 @@ extern "C" { #include "os_defs.h" -#define HBL_VERSION "v1.3" +#define HBL_VERSION "v1.4" #define CAFE_OS_SD_PATH "/vol/external01" #define SD_PATH "sd:" @@ -19,11 +19,16 @@ extern "C" { #define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00)) #define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04)) +#define HBL_CHANNEL (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x08)) +#define RPX_MAX_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x0C)) +#define RPX_MAX_CODE_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x10)) #define MAIN_ENTRY_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00)) #define OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04)) #define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500)) +#define MEM_AREA_TABLE ((s_mem_area*)(MEM_BASE + 0x1600)) + #ifndef EXIT_SUCCESS #define EXIT_SUCCESS 0 #endif diff --git a/src/common/os_defs.h b/src/common/os_defs.h index 48a4c8f..b92c527 100644 --- a/src/common/os_defs.h +++ b/src/common/os_defs.h @@ -16,8 +16,23 @@ typedef struct _OsSpecifics unsigned int addr_KernSyscallTbl3; unsigned int addr_KernSyscallTbl4; unsigned int addr_KernSyscallTbl5; + + int (*LiWaitIopComplete)(int, int *); + int (*LiWaitIopCompleteWithInterrupts)(int, int *); + unsigned int addr_LiWaitOneChunk; + unsigned int addr_PrepareTitle_hook; + unsigned int addr_sgIsLoadingBuffer; + unsigned int addr_gDynloadInitialized; + unsigned int orig_LiWaitOneChunkInstr; } OsSpecifics; +typedef struct _s_mem_area +{ + unsigned int address; + unsigned int size; + struct _s_mem_area* next; +} s_mem_area; + #ifdef __cplusplus } #endif diff --git a/src/menu/HomebrewLaunchWindow.cpp b/src/menu/HomebrewLaunchWindow.cpp index 9642824..c81bfc1 100644 --- a/src/menu/HomebrewLaunchWindow.cpp +++ b/src/menu/HomebrewLaunchWindow.cpp @@ -167,10 +167,6 @@ void HomebrewLaunchWindow::OnFileLoadFinish(GuiElement *element, const std::stri if(result > 0) { - u32 ApplicationMemoryEnd = getApplicationEndAddr(); - - ELF_DATA_ADDR = ApplicationMemoryEnd; - ELF_DATA_SIZE = result; Application::instance()->quit(EXIT_SUCCESS); } } @@ -181,9 +177,7 @@ void HomebrewLaunchWindow::OnLoadButtonClick(GuiButton *button, const GuiControl backBtn.setState(GuiElement::STATE_DISABLED); loadBtn.setState(GuiElement::STATE_DISABLED); - u32 ApplicationMemoryEnd = getApplicationEndAddr(); - - HomebrewLoader * loader = HomebrewLoader::loadToMemoryAsync(homebrewLaunchPath, (unsigned char*)ApplicationMemoryEnd); + HomebrewLoader * loader = HomebrewLoader::loadToMemoryAsync(homebrewLaunchPath); loader->setEffect(EFFECT_FADE, 15, 255); loader->effectFinished.connect(this, &HomebrewLaunchWindow::OnOpenEffectFinish); loader->asyncLoadFinished.connect(this, &HomebrewLaunchWindow::OnFileLoadFinish); diff --git a/src/menu/HomebrewLoader.cpp b/src/menu/HomebrewLoader.cpp index 9aa3043..e6b1359 100644 --- a/src/menu/HomebrewLoader.cpp +++ b/src/menu/HomebrewLoader.cpp @@ -3,13 +3,14 @@ #include #include "HomebrewLoader.h" +#include "HomebrewMemory.h" #include "fs/CFile.hpp" #include "utils/logger.h" #include "utils/StringTools.h" -HomebrewLoader * HomebrewLoader::loadToMemoryAsync(const std::string & file, unsigned char *address) +HomebrewLoader * HomebrewLoader::loadToMemoryAsync(const std::string & file) { - HomebrewLoader * loader = new HomebrewLoader(file, address); + HomebrewLoader * loader = new HomebrewLoader(file); loader->resumeThread(); return loader; } @@ -29,13 +30,25 @@ int HomebrewLoader::loadToMemory() CFile file(filepath, CFile::ReadOnly); if(!file.isOpen()) + { + progressWindow.setTitle(strfmt("Failed to open file %s", FullpathToFilename(filepath.c_str()))); + sleep(1); return FILE_OPEN_FAILURE; + } u32 bytesRead = 0; u32 fileSize = file.size(); progressWindow.setTitle(strfmt("Loading file %s", FullpathToFilename(filepath.c_str()))); + unsigned char *buffer = (unsigned char*) memalign(0x40, (fileSize + 0x3F) & ~0x3F); + if(!buffer) + { + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } + // Copy rpl in memory while(bytesRead < fileSize) { @@ -45,13 +58,7 @@ int HomebrewLoader::loadToMemory() if(blockSize > (fileSize - bytesRead)) blockSize = fileSize - bytesRead; - if((u32)(loadAddress + bytesRead + blockSize) > 0x01000000) - { - log_printf("File ist too big\n"); - return NOT_ENOUGH_MEMORY; - } - - int ret = file.read(loadAddress + bytesRead, blockSize); + int ret = file.read(buffer + bytesRead, blockSize); if(ret <= 0) { log_printf("Failure on reading file %s\n", filepath.c_str()); @@ -65,9 +72,25 @@ int HomebrewLoader::loadToMemory() if(bytesRead != fileSize) { + free(buffer); log_printf("File loading not finished for file %s, finished %i of %i bytes\n", filepath.c_str(), bytesRead, fileSize); + progressWindow.setTitle("File read failure"); + sleep(1); return FILE_READ_ERROR; } + HomebrewInitMemory(); + + int ret = HomebrewCopyMemory(buffer, bytesRead); + + free(buffer); + + if(ret < 0) + { + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } + return fileSize; } diff --git a/src/menu/HomebrewLoader.h b/src/menu/HomebrewLoader.h index 87c7a67..dfe048b 100644 --- a/src/menu/HomebrewLoader.h +++ b/src/menu/HomebrewLoader.h @@ -22,15 +22,14 @@ public: }; - static HomebrewLoader * loadToMemoryAsync(const std::string & filepath, unsigned char *address); + static HomebrewLoader * loadToMemoryAsync(const std::string & filepath); sigslot::signal3 asyncLoadFinished; private: - HomebrewLoader(const std::string & file, unsigned char *address) + HomebrewLoader(const std::string & file) : GuiFrame(0, 0) , CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff) , filepath(file) - , loadAddress(address) , progressWindow("Loading file...") { append(&progressWindow); @@ -45,7 +44,6 @@ private: static void loadCallback(CThread *thread, void *arg); const std::string filepath; - unsigned char *loadAddress; ProgressWindow progressWindow; }; diff --git a/src/menu/HomebrewMemory.cpp b/src/menu/HomebrewMemory.cpp new file mode 100644 index 0000000..7e6f429 --- /dev/null +++ b/src/menu/HomebrewMemory.cpp @@ -0,0 +1,84 @@ +#include +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "system/memory_area_table.h" +#include "utils/utils.h" +#include "utils/logger.h" + +static s_mem_area *mem_map = 0; +static u32 mapPosition = 0; + +void HomebrewInitMemory(void) +{ + memoryInitAreaTable(); + + mem_map = MEM_AREA_TABLE; + mapPosition = 0; + + ELF_DATA_ADDR = 0; + ELF_DATA_SIZE = 0; + RPX_MAX_SIZE = 0x40000000; + RPX_MAX_CODE_SIZE = 0x03000000; +} + +int HomebrewCopyMemory(u8 *address, u32 bytes) +{ + if(ELF_DATA_SIZE == 0) + { + // check if we load an RPX or an ELF + if(*(u16*)&address[7] != 0xCAFE) + { + // assume ELF + ELF_DATA_ADDR = getApplicationEndAddr(); + } + else + { + // RPX + ELF_DATA_ADDR = MEM_AREA_TABLE->address; + } + } + + //! if we load an ELF file + if(ELF_DATA_ADDR < 0x01000000) + { + u32 targetAddress = ELF_DATA_ADDR + ELF_DATA_SIZE; + if((targetAddress + bytes) > 0x01000000) + return -1; + + memcpy((void*)(targetAddress + ELF_DATA_SIZE), address, bytes); + ELF_DATA_SIZE += bytes; + } + else + { + DCFlushRange(address, bytes); + + u32 done = 0; + u32 addressPhysical = (u32)OSEffectiveToPhysical(address); + + while((done < bytes) && mem_map) + { + if(mapPosition >= mem_map->size) + { + mem_map = mem_map->next; + if(!mem_map) + return -1; + + mapPosition = 0; + } + + u32 blockSize = bytes - done; + if((mapPosition + blockSize) > mem_map->size) + { + blockSize = mem_map->size - mapPosition; + } + + SC0x25_KernelCopyData(mem_map->address + mapPosition, (addressPhysical + done), blockSize); + + mapPosition += blockSize; + done += blockSize; + } + + ELF_DATA_SIZE += done; + } + return bytes; +} diff --git a/src/menu/HomebrewMemory.h b/src/menu/HomebrewMemory.h new file mode 100644 index 0000000..2d14ffb --- /dev/null +++ b/src/menu/HomebrewMemory.h @@ -0,0 +1,7 @@ +#ifndef HOMEBREW_MEMORY_H_ +#define HOMEBREW_MEMORY_H_ + +void HomebrewInitMemory(void); +int HomebrewCopyMemory(u8 *address, u32 bytes); + +#endif diff --git a/src/menu/HomebrewWindow.cpp b/src/menu/HomebrewWindow.cpp index 0560b0c..0d59caa 100644 --- a/src/menu/HomebrewWindow.cpp +++ b/src/menu/HomebrewWindow.cpp @@ -52,7 +52,7 @@ HomebrewWindow::HomebrewWindow(int w, int h) currentLeftPosition = 0; listOffset = 0; - DirList dirList("sd:/wiiu/apps", ".elf", DirList::Files | DirList::CheckSubfolders, 1); + DirList dirList("sd:/wiiu/apps", ".elf,.rpx", DirList::Files | DirList::CheckSubfolders, 1); dirList.SortList(); @@ -314,8 +314,6 @@ void HomebrewWindow::OnCloseTcpReceiverFinish(GuiElement *element) void HomebrewWindow::OnTcpReceiveStart(GuiElement *element, u32 ip) { - setState(STATE_DISABLED); - element->setEffect(EFFECT_FADE, 15, 255); element->effectFinished.connect(this, &HomebrewWindow::OnOpenEffectFinish); append(element); @@ -329,10 +327,7 @@ void HomebrewWindow::OnTcpReceiveFinish(GuiElement *element, u32 ip, int result) if(result > 0) { - u32 ApplicationMemoryEnd = getApplicationEndAddr(); - - ELF_DATA_ADDR = ApplicationMemoryEnd; - ELF_DATA_SIZE = result; + log_printf("Launching homebrew, loaded to address %08X size %08X\n", ELF_DATA_ADDR, ELF_DATA_SIZE); Application::instance()->quit(EXIT_SUCCESS); } } diff --git a/src/menu/TcpReceiver.cpp b/src/menu/TcpReceiver.cpp index 528d2f6..c7a6341 100644 --- a/src/menu/TcpReceiver.cpp +++ b/src/menu/TcpReceiver.cpp @@ -4,6 +4,7 @@ #include #include "TcpReceiver.h" +#include "HomebrewMemory.h" #include "dynamic_libs/os_functions.h" #include "dynamic_libs/socket_functions.h" #include "fs/CFile.hpp" @@ -15,7 +16,6 @@ TcpReceiver::TcpReceiver(int port) : GuiFrame(0, 0) , CThread(CThread::eAttributeAffCore0 | CThread::eAttributePinnedAff) , exitRequested(false) - , loadAddress(0) , serverPort(port) , serverSocket(-1) , progressWindow("Receiving file...") @@ -23,10 +23,6 @@ TcpReceiver::TcpReceiver(int port) width = progressWindow.getWidth(); height = progressWindow.getHeight(); append(&progressWindow); - - u32 ApplicationMemoryEnd = getApplicationEndAddr(); - - loadAddress = (unsigned char*)ApplicationMemoryEnd; resumeThread(); } @@ -116,32 +112,30 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) log_printf("transfer start\n"); - std::string strBuffer; - strBuffer.resize(0x1000); + unsigned char* loadAddress = (unsigned char*)memalign(0x40, fileSize); + if(!loadAddress) + { + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } // Copy rpl in memory while(bytesRead < fileSize) { progressWindow.setProgress(100.0f * (f32)bytesRead / (f32)fileSize); - u32 blockSize = strBuffer.size(); + u32 blockSize = 0x1000; if(blockSize > (fileSize - bytesRead)) blockSize = fileSize - bytesRead; - if((u32)(loadAddress + bytesRead + blockSize) > 0x01000000) - { - log_printf("File ist too big\n"); - return NOT_ENOUGH_MEMORY; - } - - int ret = recv(clientSocket, &strBuffer[0], blockSize, 0); + int ret = recv(clientSocket, loadAddress + bytesRead, blockSize, 0); if(ret <= 0) { log_printf("Failure on reading file\n"); break; } - memcpy(loadAddress + bytesRead, &strBuffer[0], ret); bytesRead += ret; } @@ -149,13 +143,20 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) if(bytesRead != fileSize) { + free(loadAddress); log_printf("File loading not finished, %i of %i bytes received\n", bytesRead, fileSize); + progressWindow.setTitle("Receive incomplete"); + sleep(1); return FILE_READ_ERROR; } + int res = -1; + // Do we need to unzip this thing? if (haxx[4] > 0 || haxx[5] > 4) { + unsigned char* inflatedData = NULL; + // We need to unzip... if (loadAddress[0] == 'P' && loadAddress[1] == 'K' && loadAddress[2] == 0x03 && loadAddress[3] == 0x04) { @@ -163,8 +164,14 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) //! mhmm this is incorrect, it has to parse the zip // Section is compressed, inflate - std::string inflatedData; - inflatedData.resize(fileSizeUnc); + inflatedData = (unsigned char*)malloc(fileSizeUnc); + if(!inflatedData) + { + free(loadAddress); + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } int ret = 0; z_stream s; @@ -176,7 +183,13 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) ret = inflateInit(&s); if (ret != Z_OK) + { + free(loadAddress); + free(inflatedData); + progressWindow.setTitle("Uncompress failure"); + sleep(1); return FILE_READ_ERROR; + } s.avail_in = fileSize; s.next_in = (Bytef *)(&loadAddress[0]); @@ -186,34 +199,62 @@ int TcpReceiver::loadToMemory(s32 clientSocket, u32 ipAddress) ret = inflate(&s, Z_FINISH); if (ret != Z_OK && ret != Z_STREAM_END) + { + free(loadAddress); + free(inflatedData); + progressWindow.setTitle("Uncompress failure"); + sleep(1); return FILE_READ_ERROR; + } inflateEnd(&s); - - if(fileSizeUnc > (0x01000000 - (u32)loadAddress)) - return FILE_READ_ERROR; - - memcpy(loadAddress, &inflatedData[0], fileSizeUnc); fileSize = fileSizeUnc; } else { // Section is compressed, inflate - std::string inflatedData; - inflatedData.resize(fileSizeUnc); + inflatedData = (unsigned char*)malloc(fileSizeUnc); + if(!inflatedData) + { + free(loadAddress); + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } uLongf f = fileSizeUnc; int result = uncompress((Bytef*)&inflatedData[0], &f, (Bytef*)loadAddress, fileSize); if(result != Z_OK) { log_printf("uncompress failed %i\n", result); + progressWindow.setTitle("Uncompress failure"); + sleep(1); return FILE_READ_ERROR; } fileSizeUnc = f; - memcpy(loadAddress, &inflatedData[0], fileSizeUnc); fileSize = fileSizeUnc; } + + free(loadAddress); + + HomebrewInitMemory(); + res = HomebrewCopyMemory(inflatedData, fileSize); + free(inflatedData); } + else + { + HomebrewInitMemory(); + res = HomebrewCopyMemory(loadAddress, fileSize); + free(loadAddress); + } + + if(res < 0) + { + progressWindow.setTitle("Not enough memory"); + sleep(1); + return NOT_ENOUGH_MEMORY; + } + return fileSize; } diff --git a/src/menu/TcpReceiver.h b/src/menu/TcpReceiver.h index cf572d6..5510e14 100644 --- a/src/menu/TcpReceiver.h +++ b/src/menu/TcpReceiver.h @@ -33,7 +33,6 @@ private: int loadToMemory(s32 clientSocket, u32 ipAddress); bool exitRequested; - unsigned char *loadAddress; s32 serverPort; s32 serverSocket; ProgressWindow progressWindow; diff --git a/src/system/memory_area_table.c b/src/system/memory_area_table.c new file mode 100644 index 0000000..cc37fc3 --- /dev/null +++ b/src/system/memory_area_table.c @@ -0,0 +1,400 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include +#include "common/common.h" +#include "utils/utils.h" +#include "memory_area_table.h" + +typedef struct _memory_values_t +{ + unsigned int start_address; + unsigned int end_address; +} memory_values_t; + +static const memory_values_t mem_vals_400[] = +{ + { 0x2E573BFC, 0x2FF8F83C }, // 26735 kB + { 0x2D86D318, 0x2DFFFFFC }, // 7755 kB + { 0x2CE59830, 0x2D3794D8 }, // 5247 kB + { 0x2D3795AC, 0x2D854300 }, // 4971 kB + { 0x28FEC800, 0x293B29D0 }, // 3864 kB + { 0x29BC200C, 0x29D79B94 }, // 1758 kB + { 0x2A517A68, 0x2A6794B8 }, // 1414 kB + { 0x288C1D80, 0x28A69FA0 }, // 1696 kB + + { 0, 0 } +}; + +static const memory_values_t mem_vals_410[] = +{ +// { 0x28041760, 0x28049D0C } // 33 kB +// { 0x280608F4, 0x2806C97C } // 48 kB +// { 0x280953C8, 0x280A1324 } // 47 kB +// { 0x280A1358, 0x280AD388 } // 48 kB +// { 0x280C9040, 0x280D0ABC } // 30 kB +// { 0x280D0AD8, 0x28113FBC } // 269 kB +// { 0x2812575C, 0x2817A53C } // 339 kB +// { 0x2817A6A0, 0x281BA53C } // 255 kB +// { 0x281D571C, 0x2820253C } // 179 kB +// { 0x28234D00, 0x2824B33C } // 89 kB +// { 0x2824E300, 0x2828D7BC } // 253 kB +// { 0x282A8DF0, 0x282B63FC } // 53 kB +// { 0x282BC524, 0x282C62FC } // 39 kB +// { 0x2835A988, 0x28366804 } // 47 kB +// { 0x2836E05C, 0x28378DBC } // 43 kB +// { 0x283A735C, 0x284D2A64 } // 1197 kB (1 MB) +// { 0x284D76B0, 0x285021FC } // 170 kB +// { 0x285766A4, 0x28583E4C } // 53 kB +// { 0x28590E5C, 0x2859B248 } // 40 kB +// { 0x2859B288, 0x285AE06C } // 75 kB +// { 0x285B7108, 0x285C0A7C } // 38 kB +// { 0x285C38A0, 0x285D089C } // 52 kB +// { 0x285D0A84, 0x285DC63C } // 46 kB +// { 0x285E0A84, 0x285F089C } // 63 kB +// { 0x285F7FD0, 0x286037D8 } // 46 kB +// { 0x2860E3E4, 0x28621B00 } // 77 kB +// { 0x286287B0, 0x28638BC0 } // 65 kB +// { 0x2863F4A0, 0x2864DE00 } // 58 kB +// { 0x2864F1FC, 0x28656EE0 } // 31 kB +// { 0x2865AF44, 0x286635A0 } // 33 kB +// { 0x2866F774, 0x2867C680 } // 51 kB +// { 0x2867FAC0, 0x286A2CA0 } // 140 kB +// { 0x286B3540, 0x286C1900 } // 56 kB +// { 0x286C64A4, 0x286DDB80 } // 93 kB +// { 0x286E640C, 0x286F1DC0 } // 46 kB +// { 0x286F3884, 0x2870D3C0 } // 102 kB +// { 0x28710824, 0x28719D80 } // 37 kB +// { 0x2872A674, 0x2873B180 } // 66 kB +// { 0x287402F0, 0x28758780 } // 97 kB +// { 0x287652F0, 0x28771C00 } // 50 kB +// { 0x287F878C, 0x2880A680 } // 71 kB +// { 0x2880F4AC, 0x2881E6E0 } // 60 kB +// { 0x28821488, 0x28829A40 } // 33 kB +// { 0x2882A5D0, 0x288385BC } // 55 kB +// { 0x288385D8, 0x28854780 } // 112 kB +// { 0x28857984, 0x28864F80 } // 53 kB +// { 0x28870AC0, 0x2887CAC0 } // 48 kB +// { 0x2887CAC8, 0x28888CC8 } // 48 kB +// { 0x28888CD0, 0x28894ED0 } // 48 kB +// { 0x28894ED8, 0x288BE0DC } // 164 kB +// { 0x288C1C70, 0x28AD9ED4 } // 2144 kB (2 MB) +// { 0x28AD9F04, 0x28B66100 } // 560 kB +// { 0x28B748A8, 0x28B952E0 } // 130 kB +// { 0x28B9AB58, 0x28BA2480 } // 30 kB +// { 0x28BA3D00, 0x28BC21C0 } // 121 kB +// { 0x28BC2F08, 0x28BD9860 } // 90 kB +// { 0x28BED09C, 0x28BFDD00 } // 67 kB +// { 0x28C068F0, 0x28C2E220 } // 158 kB +// { 0x28CC4C6C, 0x28CF6834 } // 198 kB +// { 0x28D3DD64, 0x28D4BF8C } // 56 kB +// { 0x28D83C4C, 0x28DD0284 } // 305 kB +// { 0x28DDDED4, 0x28E84294 } // 664 kB +// { 0x28E99C7C, 0x28F382A4 } // 633 kB +// { 0x28F45EF4, 0x28FEC2B4 } // 664 kB +// { 0x28FEC800, 0x293B2A18 } // 3864 kB (3 MB) +// { 0x293E187C, 0x293EC7FC } // 43 kB +// { 0x295C7240, 0x295D523C } // 56 kB +// { 0x295DA8DC, 0x295E323C } // 34 kB +// { 0x295ED6C0, 0x295F6FDC } // 38 kB +// { 0x29606340, 0x2960FC5C } // 38 kB +// { 0x2964F040, 0x29657C3C } // 35 kB +// { 0x296E0EBC, 0x296EBDBC } // 43 kB +// { 0x2998DFB4, 0x2999DEE4 } // 63 kB +// { 0x2999E6A8, 0x299BE9C4 } // 128 kB +// { 0x29B8DF40, 0x29BA09DC } // 74 kB +// { 0x29BC200C, 0x29D79B94 } // 1758 kB (1 MB) +// { 0x29DA9694, 0x29DB1694 } // 32 kB +// { 0x2A3D7558, 0x2A427558 } // 320 kB +// { 0x2A42769C, 0x2A47769C } // 320 kB +// { 0x2A4777E0, 0x2A4C77E0 } // 320 kB +// { 0x2A4C7924, 0x2A517924 } // 320 kB +// { 0x2A517A68, 0x2A6794B8 } // 1414 kB (1 MB) +// { 0x2AD17528, 0x2AD4EA24 } // 221 kB +// { 0x2B038C4C, 0x2B1794C8 } // 1282 kB (1 MB) +// { 0x2BBA990C, 0x2BBB983C } // 63 kB +// { 0x2BBBA160, 0x2BC82164 } // 800 kB +// { 0x2BD0000C, 0x2BD71638 } // 453 kB +// { 0x2BD7170C, 0x2BD83B0C } // 73 kB +// { 0x2BDBA000, 0x2BDCA028 } // 64 kB +// { 0x2BDCE000, 0x2BDDE028 } // 64 kB +// { 0x2BDE2E34, 0x2BDF2D64 } // 63 kB +// { 0x2BDF35E8, 0x2BE031BC } // 62 kB +// { 0x2BE052A4, 0x2BE151D4 } // 63 kB +// { 0x2BE174AC, 0x2BE27244 } // 63 kB +// { 0x2BE3AC80, 0x2BE48C80 } // 56 kB +// { 0x2BE49EDC, 0x2BE56C7C } // 51 kB +// { 0x2BE82F70, 0x2BE92E9C } // 63 kB +// { 0x2BE9ADBC, 0x2BEA8DBC } // 56 kB +// { 0x2BEAAB7C, 0x2BEB6DBC } // 48 kB +// { 0x2BEC0F3C, 0x2BECEF3C } // 56 kB +// { 0x2BED45DC, 0x2BEDCF3C } // 34 kB +// { 0x2BEE73C0, 0x2BEF0CDC } // 38 kB +// { 0x2BF00040, 0x2BF0995C } // 38 kB +// { 0x2BF48D40, 0x2BF5193C } // 35 kB +// { 0x2BFDABBC, 0x2BFE5ABC } // 43 kB +// { 0x2C03DA40, 0x2C045D7C } // 32 kB +// { 0x2C179450, 0x2C18937C } // 63 kB +// { 0x2C1DC940, 0x2C1EA93C } // 56 kB +// { 0x2C1EABDC, 0x2C1F893C } // 55 kB +// { 0x2C239A80, 0x2C243D3C } // 40 kB +// { 0x2CE10224, 0x2CE3683C } // 153 kB +// { 0x2CE374F4, 0x2CE473A4 } // 63 kB +// { 0x2CE49830, 0x2D3794D8 } // 5311 kB (5 MB) +// { 0x2D3795AC, 0x2D854300 } // 4971 kB (4 MB) +// { 0x2D8546B0, 0x2D8602C4 } // 47 kB +// { 0x2D86D318, 0x2DFFFFFC } // 7755 kB (7 MB) +// { 0x2E2DCD60, 0x2E2E4D7C } // 32 kB +// { 0x2E33F160, 0x2E365AFC } // 154 kB +// { 0x2E37AC40, 0x2E39BB3C } // 131 kB +// { 0x2E3A6EF0, 0x2E3CA2FC } // 141 kB +// { 0x2E3D9EE0, 0x2E400B3C } // 155 kB +// { 0x2E43A8F0, 0x2E442BBC } // 32 kB +// { 0x2E46EC90, 0x2E48E27C } // 125 kB +// { 0x2E497F90, 0x2E4A147C } // 37 kB +// { 0x2E4A5B40, 0x2E4C67BC } // 131 kB +// { 0x2E4FBEF0, 0x2E52697C } // 170 kB +// { 0x2E550750, 0x2E57333C } // 138 kB +// { 0x2E573F3C, 0x2FF8F07C } // 226732 kB (26 MB) +// { 0x31000000, 0x31E1FFFC } // 614464 kB (14 MB) +// { 0x320A5D80, 0x320AEA3C } // 35 kB +// { 0x320E8670, 0x3210017C } // 94 kB +// { 0x3212609C, 0x3213187C } // 45 kB +// { 0x3219DF08, 0x321B72BC } // 100 kB +// { 0x3300ED34, 0x3301AD3C } // 48 kB +// { 0x33041760, 0x33049D0C } // 33 kB +// { 0x330608F8, 0x3306C97C } // 48 kB +// { 0x33089D80, 0x33095284 } // 45 kB +// { 0x33095470, 0x330A1324 } // 47 kB +// { 0x330A1358, 0x330ADC10 } // 50 kB +// { 0x330C9040, 0x330D0ABC } // 30 kB +// { 0x330D0AD8, 0x3311F9CC } // 315 kB +// { 0x3312575C, 0x3320A63C } // 915 kB +// { 0x33234D00, 0x3324B33C } // 89 kB +// { 0x3324E300, 0x3328D7BC } // 253 kB +// { 0x3329D134, 0x332CA324 } // 180 kB +// { 0x3332B200, 0x33340C88 } // 86 kB +// { 0x3335A440, 0x335021FC } // 1695 kB (1 MB) +// { 0x3350A778, 0x3391680C } // 4144 kB (4 MB) +// { 0x3391A444, 0x3392A25C } // 63 kB +// { 0x3392A444, 0x33939EB4 } // 62 kB +// { 0x3393A444, 0x3394A25C } // 63 kB +// { 0x339587C0, 0x33976C80 } // 121 kB +// { 0x339779C8, 0x3398E320 } // 90 kB +// { 0x3399AE74, 0x339A7D80 } // 51 kB +// { 0x339AB1C0, 0x339CE3A0 } // 140 kB +// { 0x339CEB28, 0x339DEC38 } // 64 kB +// { 0x339DEC40, 0x339ED000 } // 56 kB +// { 0x339F1BA4, 0x33A09280 } // 93 kB +// { 0x33A0C6E4, 0x33A15C40 } // 37 kB +// { 0x33A15D64, 0x33EBFFFC } // 4776 kB (4 MB) +// { 0x33F01380, 0x33F21FFC } // 131 kB +// { 0x33F44820, 0x33F6B1BC } // 154 kB +// { 0x33F80300, 0x33FA11FC } // 131 kB +// { 0x33FA4D3C, 0x33FEDAFC } // 291 kB +// { 0x33FFFFD4, 0x38FFFFFC } // 81920 kB (80 MB) + {0, 0} +}; + +static const memory_values_t mem_vals_500[] = +{ + { 0x2E605CBC, 0x2FF849BC }, // size 26733828 (26107 kB) (25 MB) + { 0x2CAE7878, 0x2D207DB4 }, // size 7472448 (7297 kB) (7 MB) + { 0x2D3B966C, 0x2D8943C0 }, // size 5090648 (4971 kB) (4 MB) + { 0x2D8AD3D8, 0x2DFFFFFC }, // size 7679016 (7499 kB) (7 MB) + // TODO: Check which of those areas are usable +// { 0x283A73DC, 0x284D2AE4 } // size 1226508 (1197 kB) (1 MB) +// { 0x29030800, 0x293F69FC } // size 3957248 (3864 kB) (3 MB) +// { 0x2970200C, 0x298B9C54 } // size 1801292 (1759 kB) (1 MB) +// { 0x2A057B68, 0x2A1B9578 } // size 1448468 (1414 kB) (1 MB) + +// { 0x29030800, 0x293F69FC } // size 3957248 (3864 kB) (3 MB) +// { 0x2970200C, 0x298B9C54 } // size 1801292 (1759 kB) (1 MB) +// { 0x2A057B68, 0x2A1B9578 } // size 1448468 (1414 kB) (1 MB) +// { 0x288EEC30, 0x28B06E94 } // size 2196072 (2144 kB) (2 MB) +// { 0x283A73DC, 0x284D2AE4 } // size 1226508 (1197 kB) (1 MB) +// { 0x3335A4C0, 0x335021FC } // size 1736000 (1695 kB) (1 MB) +// { 0x3350C1D4, 0x339182CC } // size 4243708 (4144 kB) (4 MB) +// { 0x33A14094, 0x33EBFFFC } // size 4898668 (4783 kB) (4 MB) +// { 0x33FFFFD4, 0x38FFFFFC } // size 83886124 (81920 kB) (80 MB) + {0, 0} +}; + +static const memory_values_t mem_vals_532[] = +{ + // TODO: Check which of those areas are usable +// {0x28000000 + 0x000DCC9C, 0x28000000 + 0x00174F80}, // 608 kB +// {0x28000000 + 0x00180B60, 0x28000000 + 0x001C0A00}, // 255 kB +// {0x28000000 + 0x001ECE9C, 0x28000000 + 0x00208CC0}, // 111 kB +// {0x28000000 + 0x00234180, 0x28000000 + 0x0024B444}, // 92 kB +// {0x28000000 + 0x0024D8C0, 0x28000000 + 0x0028D884}, // 255 kB +// {0x28000000 + 0x003A745C, 0x28000000 + 0x004D2B68}, // 1197 kB +// {0x28000000 + 0x004D77B0, 0x28000000 + 0x00502200}, // 170 kB +// {0x28000000 + 0x005B3A88, 0x28000000 + 0x005C6870}, // 75 kB +// {0x28000000 + 0x0061F3E4, 0x28000000 + 0x00632B04}, // 77 kB +// {0x28000000 + 0x00639790, 0x28000000 + 0x00649BC4}, // 65 kB +// {0x28000000 + 0x00691490, 0x28000000 + 0x006B3CA4}, // 138 kB +// {0x28000000 + 0x006D7BCC, 0x28000000 + 0x006EEB84}, // 91 kB +// {0x28000000 + 0x00704E44, 0x28000000 + 0x0071E3C4}, // 101 kB +// {0x28000000 + 0x0073B684, 0x28000000 + 0x0074C184}, // 66 kB +// {0x28000000 + 0x00751354, 0x28000000 + 0x00769784}, // 97 kB +// {0x28000000 + 0x008627DC, 0x28000000 + 0x00872904}, // 64 kB +// {0x28000000 + 0x008C1E98, 0x28000000 + 0x008EB0A0}, // 164 kB +// {0x28000000 + 0x008EEC30, 0x28000000 + 0x00B06E98}, // 2144 kB +// {0x28000000 + 0x00B06EC4, 0x28000000 + 0x00B930C4}, // 560 kB +// {0x28000000 + 0x00BA1868, 0x28000000 + 0x00BC22A4}, // 130 kB +// {0x28000000 + 0x00BC48F8, 0x28000000 + 0x00BDEC84}, // 104 kB +// {0x28000000 + 0x00BE3DC0, 0x28000000 + 0x00C02284}, // 121 kB +// {0x28000000 + 0x00C02FC8, 0x28000000 + 0x00C19924}, // 90 kB +// {0x28000000 + 0x00C2D35C, 0x28000000 + 0x00C3DDC4}, // 66 kB +// {0x28000000 + 0x00C48654, 0x28000000 + 0x00C6E2E4}, // 151 kB +// {0x28000000 + 0x00D04E04, 0x28000000 + 0x00D36938}, // 198 kB +// {0x28000000 + 0x00DC88AC, 0x28000000 + 0x00E14288}, // 302 kB +// {0x28000000 + 0x00E21ED4, 0x28000000 + 0x00EC8298}, // 664 kB +// {0x28000000 + 0x00EDDC7C, 0x28000000 + 0x00F7C2A8}, // 633 kB +// {0x28000000 + 0x00F89EF4, 0x28000000 + 0x010302B8}, // 664 kB +// {0x28000000 + 0x01030800, 0x28000000 + 0x013F69A0}, // 3864 kB +// {0x28000000 + 0x016CE000, 0x28000000 + 0x016E0AA0}, // 74 kB +// {0x28000000 + 0x0170200C, 0x28000000 + 0x018B9C58}, // 1759 kB +// {0x28000000 + 0x01F17658, 0x28000000 + 0x01F6765C}, // 320 kB +// {0x28000000 + 0x01F6779C, 0x28000000 + 0x01FB77A0}, // 320 kB +// {0x28000000 + 0x01FB78E0, 0x28000000 + 0x020078E4}, // 320 kB +// {0x28000000 + 0x02007A24, 0x28000000 + 0x02057A28}, // 320 kB +// {0x28000000 + 0x02057B68, 0x28000000 + 0x021B957C}, // 1414 kB +// {0x28000000 + 0x02891528, 0x28000000 + 0x028C8A28}, // 221 kB +// {0x28000000 + 0x02BBCC4C, 0x28000000 + 0x02CB958C}, // 1010 kB +// {0x28000000 + 0x0378D45C, 0x28000000 + 0x03855464}, // 800 kB +// {0x28000000 + 0x0387800C, 0x28000000 + 0x03944938}, // 818 kB +// {0x28000000 + 0x03944A08, 0x28000000 + 0x03956E0C}, // 73 kB +// {0x28000000 + 0x04A944A4, 0x28000000 + 0x04ABAAC0}, // 153 kB +// {0x28000000 + 0x04ADE370, 0x28000000 + 0x0520EAB8}, // 7361 kB // ok +// {0x28000000 + 0x053B966C, 0x28000000 + 0x058943C4}, // 4971 kB // ok +// {0x28000000 + 0x058AD3D8, 0x28000000 + 0x06000000}, // 7499 kB +// {0x28000000 + 0x0638D320, 0x28000000 + 0x063B0280}, // 139 kB +// {0x28000000 + 0x063C39E0, 0x28000000 + 0x063E62C0}, // 138 kB +// {0x28000000 + 0x063F52A0, 0x28000000 + 0x06414A80}, // 125 kB +// {0x28000000 + 0x06422810, 0x28000000 + 0x0644B2C0}, // 162 kB +// {0x28000000 + 0x064E48D0, 0x28000000 + 0x06503EC0}, // 125 kB +// {0x28000000 + 0x0650E360, 0x28000000 + 0x06537080}, // 163 kB +// {0x28000000 + 0x0653A460, 0x28000000 + 0x0655C300}, // 135 kB +// {0x28000000 + 0x0658AA40, 0x28000000 + 0x065BC4C0}, // 198 kB // ok +// {0x28000000 + 0x065E51A0, 0x28000000 + 0x06608E80}, // 143 kB // ok +// {0x28000000 + 0x06609ABC, 0x28000000 + 0x07F82C00}, // 26084 kB // ok + +// {0x30000000 + 0x000DCC9C, 0x30000000 + 0x00180A00}, // 655 kB +// {0x30000000 + 0x00180B60, 0x30000000 + 0x001C0A00}, // 255 kB +// {0x30000000 + 0x001F5EF0, 0x30000000 + 0x00208CC0}, // 75 kB +// {0x30000000 + 0x00234180, 0x30000000 + 0x0024B444}, // 92 kB +// {0x30000000 + 0x0024D8C0, 0x30000000 + 0x0028D884}, // 255 kB +// {0x30000000 + 0x003A745C, 0x30000000 + 0x004D2B68}, // 1197 kB +// {0x30000000 + 0x006D3334, 0x30000000 + 0x00772204}, // 635 kB +// {0x30000000 + 0x00789C60, 0x30000000 + 0x007C6000}, // 240 kB +// {0x30000000 + 0x00800000, 0x30000000 + 0x01E20000}, // 22876 kB // ok + { 0x2E609ABC, 0x2FF82C00 }, // 26084 kB + { 0x29030800, 0x293F69A0 }, // 3864 kB + { 0x288EEC30, 0x28B06E98 }, // 2144 kB + { 0x2D3B966C, 0x2D8943C4 }, // 4971 kB + { 0x2CAE0370, 0x2D20EAB8 }, // 7361 kB + { 0x2D8AD3D8, 0x2E000000 }, // 7499 kB + + {0, 0} +}; // total : 66mB + 25mB + +static const memory_values_t mem_vals_540[] = +{ + { 0x2E609EFC, 0x2FF82000 }, // 26083 kB + { 0x29030800, 0x293F6000 }, // 3864 kB + { 0x288EEC30, 0x28B06800 }, // 2144 kB + { 0x2D3B966C, 0x2D894000 }, // 4971 kB + { 0x2CB56370, 0x2D1EF000 }, // 6756 kB + { 0x2D8AD3D8, 0x2E000000 }, // 7499 kB + { 0x2970200C, 0x298B9800 }, // 1759 kB + { 0x2A057B68, 0x2A1B9000 }, // 1414 kB + { 0x2ABBCC4C, 0x2ACB9000 }, // 1010 kB + {0, 0} +}; + +s_mem_area * memoryGetAreaTable(void) +{ + return MEM_AREA_TABLE; +} + +static inline void memoryAddArea(int start, int end, int cur_index) +{ + // Create and copy new memory area + s_mem_area * mem_area = memoryGetAreaTable(); + mem_area[cur_index].address = start; + mem_area[cur_index].size = end - start; + mem_area[cur_index].next = 0; + + // Fill pointer to this area in the previous area + if (cur_index > 0) + { + mem_area[cur_index - 1].next = &mem_area[cur_index]; + } +} + +/* Create memory areas arrays */ +void memoryInitAreaTable() +{ + u32 ApplicationMemoryEnd = getApplicationEndAddr(); + if(ApplicationMemoryEnd >= 0x01000000) + ApplicationMemoryEnd = 0x00800000; + + // This one seems to be available on every firmware and therefore its our code area but also our main RPX area behind our code + // 22876 kB - our application // ok + if(OS_FIRMWARE <= 400) { + memoryAddArea(ApplicationMemoryEnd + 0x4B000000, 0x4B000000 + 0x01E20000, 0); + } + else { + memoryAddArea(ApplicationMemoryEnd + 0x30000000, 0x30000000 + 0x01E20000, 0); + } + + const memory_values_t * mem_vals = NULL; + + switch(OS_FIRMWARE) + { + case 400: { + mem_vals = mem_vals_400; + break; + } + case 500: { + mem_vals = mem_vals_500; + break; + } + case 532: { + mem_vals = mem_vals_532; + break; + } + case 540: + case 550: { + mem_vals = mem_vals_540; + break; + } + default: + return; // no known values + } + + // Fill entries + int i = 0; + while (mem_vals[i].start_address) + { + memoryAddArea(mem_vals[i].start_address, mem_vals[i].end_address, i + 1); + i++; + } +} diff --git a/src/system/memory_area_table.h b/src/system/memory_area_table.h new file mode 100644 index 0000000..70d7f2f --- /dev/null +++ b/src/system/memory_area_table.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef _MEMORY_AREA_TABLE_H_ +#define _MEMORY_AREA_TABLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common/common.h" + +void memoryInitAreaTable(); +s_mem_area * memoryGetAreaTable(void); + + +#ifdef __cplusplus +} +#endif + +#endif // _MEMORY_AREA_TABLE_H_ diff --git a/src/utils/utils.S b/src/utils/utils.S index b210f76..fbf1400 100644 --- a/src/utils/utils.S +++ b/src/utils/utils.S @@ -3,3 +3,9 @@ getApplicationEndAddr: lis r3, __CODE_END@h ori r3, r3, __CODE_END@l blr + + .globl SC0x25_KernelCopyData +SC0x25_KernelCopyData: + li r0, 0x2500 + sc + blr diff --git a/src/utils/utils.h b/src/utils/utils.h index 676a9d9..c3634a1 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -41,6 +41,7 @@ extern "C" { #define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) unsigned int getApplicationEndAddr(void); +void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); #ifdef __cplusplus }