diff --git a/src/elf_loading.c b/src/elf_loading.c index b8875aa..eabeb83 100644 --- a/src/elf_loading.c +++ b/src/elf_loading.c @@ -9,12 +9,14 @@ static int32_t LoadFileToMem(private_data_t *private_data, const char *filepath, int32_t iFd = -1; void *pClient = private_data->MEMAllocFromDefaultHeapEx(FS_CLIENT_SIZE, 4); if(!pClient) { + ExitFailure(private_data, "Failed to allocate pClient."); return 0; } void *pCmd = private_data->MEMAllocFromDefaultHeapEx(FS_CMD_BLOCK_SIZE, 4); if(!pCmd) { private_data->MEMFreeToDefaultHeap(pClient); + ExitFailure(private_data, "Failed to allocate pCmd."); return 0; } @@ -29,18 +31,21 @@ static int32_t LoadFileToMem(private_data_t *private_data, const char *filepath, int32_t status = private_data->FSGetMountSource(pClient, pCmd, 0, tempPath, -1); if (status != 0) { - OSFatal("FSGetMountSource failed. Please insert a FAT32 formatted sd card."); + ExitFailure(private_data, "FSGetMountSource failed. Please insert a FAT32 formatted sd card."); + return 0; } status = private_data->FSMount(pClient, pCmd, tempPath, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); if(status != 0) { - OSFatal("SD mount failed. Please insert a FAT32 formatted sd card."); + ExitFailure(private_data, "SD mount failed. Please insert a FAT32 formatted sd card."); + return 0; } status = private_data->FSOpenFile(pClient, pCmd, filepath, "r", &iFd, -1); if(status != 0) { char buf[0x255]; - __os_snprintf(buf,0x254,"FSOpenFile failed. File missing %s",filepath); - OSFatal(buf); + __os_snprintf(buf,0x254,"FSOpenFile failed. File missing %s",filepath); + ExitFailure(private_data, buf); + return 0; } FSStat stat; @@ -50,10 +55,12 @@ static int32_t LoadFileToMem(private_data_t *private_data, const char *filepath, private_data->FSGetStatFile(pClient, pCmd, iFd, &stat, -1); - if(stat.size > 0) + if(stat.size > 0) { pBuffer = private_data->MEMAllocFromDefaultHeapEx((stat.size + 0x3F) & ~0x3F, 0x40); - else - OSFatal("ELF file empty."); + } else { + ExitFailure(private_data, "ELF file empty."); + return 0; + } uint32_t done = 0; @@ -66,6 +73,7 @@ static int32_t LoadFileToMem(private_data_t *private_data, const char *filepath, } if(done != stat.size) { + ExitFailure(private_data, "Loaded file size was not as expected"); private_data->MEMFreeToDefaultHeap(pBuffer); } else { *fileOut = (uint8_t*)pBuffer; @@ -92,10 +100,12 @@ static uint32_t load_elf_image_to_mem (private_data_t *private_data, uint8_t *el ehdr = (Elf32_Ehdr *) elfstart; if(ehdr->e_phoff == 0 || ehdr->e_phnum == 0) { + ExitFailure(private_data, "e_phoff or e_phnum were NULL"); return 0; } if(ehdr->e_phentsize != sizeof(Elf32_Phdr)) { + ExitFailure(private_data, "wrong e_phentsize"); return 0; } @@ -141,24 +151,25 @@ static uint32_t load_elf_image_to_mem (private_data_t *private_data, uint8_t *el return ehdr->e_entry; } -uint32_t LoadAndCopyFile(const char *filepath) { - private_data_t private_data; - - loadFunctionPointers(&private_data); - +uint32_t LoadAndCopyFile(const char *filepath, private_data_t * private_data) { unsigned char *pElfBuffer = NULL; unsigned int uiElfSize = 0; - LoadFileToMem(&private_data, filepath, &pElfBuffer, &uiElfSize); + if(!LoadFileToMem(private_data, filepath, &pElfBuffer, &uiElfSize)){ + // Error messages are set inside the function + return 0; + } if(!pElfBuffer) { - OSFatal("Failed to load homebrew_launcher.elf"); + ExitFailure(private_data, "Failed to load homebrew_launcher.elf"); + return 0; } - unsigned int newEntry = load_elf_image_to_mem(&private_data, pElfBuffer); + unsigned int newEntry = load_elf_image_to_mem(private_data, pElfBuffer); if(newEntry == 0) { - OSFatal("failed to load .elf"); + // Error messages are set inside the function + return 0; } - private_data.MEMFreeToDefaultHeap(pElfBuffer); + private_data->MEMFreeToDefaultHeap(pElfBuffer); return newEntry; } diff --git a/src/elf_loading.h b/src/elf_loading.h index 46a3ae1..397bc7e 100644 --- a/src/elf_loading.h +++ b/src/elf_loading.h @@ -6,8 +6,9 @@ #ifdef __cplusplus extern "C" { #endif +#include "structs.h" -uint32_t LoadAndCopyFile(const char *filepath); +uint32_t LoadAndCopyFile(const char *filepath, private_data_t * private_data); #ifdef __cplusplus } diff --git a/src/entry.c b/src/entry.c index 284569d..de46499 100644 --- a/src/entry.c +++ b/src/entry.c @@ -9,7 +9,17 @@ int _start(int argc, char **argv) { setup_memory(); - uint32_t newEntry = LoadAndCopyFile(CAFE_OS_SD_PATH WIIU_PATH "/payload.elf"); + private_data_t private_data; + loadFunctionPointers(&private_data); + + uint32_t newEntry = LoadAndCopyFile(CAFE_OS_SD_PATH WIIU_PATH "/payload.elf", &private_data); + if(newEntry == 0) { + // When loading the payload failed, wait 1 second to display the error and return back to System Menu. + revertMainHook(&private_data); + private_data.OSSleepTicks(SECS_TO_TICKS(1)); + private_data._SYSLaunchTitleWithStdArgsInNoSplash(private_data.sysmenuTitleID, 0); + return ( (int (*)(int, char **))(*(unsigned int*)ADDRESS_OSTitle_main_entry_ptr) )(argc, argv); + } return ((int (*)(int, char **))newEntry)(argc, argv); } diff --git a/src/kernel_patches.S b/src/kernel_patches.S index 04193d8..37a5c61 100644 --- a/src/kernel_patches.S +++ b/src/kernel_patches.S @@ -9,3 +9,31 @@ SC_0x36_SETBATS: li r0, 0x3600 sc blr + +.global SCKernelCopyData +SCKernelCopyData: + // Disable data address translation + mfmsr %r6 + li %r7, 0x10 + andc %r6, %r6, %r7 + mtmsr %r6 + + // Copy data + addi %r3, %r3, -1 + addi %r4, %r4, -1 + mtctr %r5 +SCKernelCopyData_loop: + lbzu %r5, 1(%r4) + stbu %r5, 1(%r3) + bdnz SCKernelCopyData_loop + + // Enable data address translation + ori %r6, %r6, 0x10 + mtmsr %r6 +blr + +.global SC_0x25_KernelCopyData +SC_0x25_KernelCopyData: + li %r0, 0x2500 + sc +blr \ No newline at end of file diff --git a/src/memory_setup.c b/src/memory_setup.c index 03d3005..a5ce628 100644 --- a/src/memory_setup.c +++ b/src/memory_setup.c @@ -100,7 +100,7 @@ void setup_memory() { int ret = OSCreateThread(thread, thread_callback, 0, (void*)0, (unsigned int)stack+0x4000, 0x4000, 0, 0x8 + (1 << i)); if (ret == 0) { - OSFatal("Failed to create thread. Exit and re-enter browser."); + OSFatal("Failed to create thread."); } // Schedule it for execution diff --git a/src/structs.h b/src/structs.h index d85f607..39475a8 100644 --- a/src/structs.h +++ b/src/structs.h @@ -8,6 +8,11 @@ extern "C" { #endif +#include + +#define BUS_SPEED 248625000 +#define SECS_TO_TICKS(sec) (((unsigned long long)(sec)) * (BUS_SPEED/4)) + typedef struct _private_data_t { EXPORT_DECL(void *, MEMAllocFromDefaultHeapEx,int size, int align); EXPORT_DECL(void, MEMFreeToDefaultHeap,void *ptr); @@ -33,7 +38,22 @@ typedef struct _private_data_t { EXPORT_DECL(int, FSReadFile, void *pClient, void *pCmd, void *buffer, int size, int count, int fd, int flag, int errHandling); EXPORT_DECL(int, FSCloseFile, void *pClient, void *pCmd, int fd, int errHandling); + EXPORT_DECL(unsigned int, OSScreenPutFontEx, unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); + + EXPORT_DECL(void, OSScreenInit, void); + EXPORT_DECL(void, OSForceFullRelaunch, void); + EXPORT_DECL(unsigned int, OSScreenGetBufferSizeEx, unsigned int bufferNum); + EXPORT_DECL(unsigned int, OSScreenSetBufferEx, unsigned int bufferNum, void * addr); + EXPORT_DECL(unsigned int, OSScreenClearBufferEx, unsigned int bufferNum, unsigned int temp); + EXPORT_DECL(unsigned int, OSScreenFlipBuffersEx, unsigned int bufferNum); + EXPORT_DECL(unsigned int, OSSleepTicks, uint64_t ticks); + EXPORT_DECL(int, SYSRelaunchTitle, int argc, char** argv); + EXPORT_DECL(void, SYSLaunchMenu, void); + EXPORT_DECL(void, _SYSLaunchMiiStudio, void); + EXPORT_DECL(int, _SYSLaunchTitleWithStdArgsInNoSplash, unsigned long long tid, void *ptr); + EXPORT_DECL(unsigned long long, _SYSGetSystemApplicationTitleId, int sysApp); + uint64_t sysmenuTitleID; } private_data_t; #ifdef __cplusplus diff --git a/src/utils.c b/src/utils.c index e62447c..92dae69 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,5 +1,69 @@ #include "utils.h" +extern void SCKernelCopyData(unsigned int addr, unsigned int src, unsigned int len); +extern void SC_0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); + +static void KernelWriteU32(uint32_t addr, uint32_t value, private_data_t * pdata) { + pdata->ICInvalidateRange(&value, 4); + pdata->DCFlushRange(&value, 4); + + uint32_t dst = (uint32_t) pdata->OSEffectiveToPhysical((void *)addr); + uint32_t src = (uint32_t) pdata->OSEffectiveToPhysical((void *)&value); + + SC_0x25_KernelCopyData(dst, src, 4); + + pdata->DCFlushRange((void *)addr, 4); + pdata->ICInvalidateRange((void *)addr, 4); +} + +void revertMainHook(private_data_t * private_data) { + kern_write((void*)(KERN_SYSCALL_TBL_1 + (0x25 * 4)), (unsigned int)SCKernelCopyData); + kern_write((void*)(KERN_SYSCALL_TBL_2 + (0x25 * 4)), (unsigned int)SCKernelCopyData); + kern_write((void*)(KERN_SYSCALL_TBL_3 + (0x25 * 4)), (unsigned int)SCKernelCopyData); + kern_write((void*)(KERN_SYSCALL_TBL_4 + (0x25 * 4)), (unsigned int)SCKernelCopyData); + kern_write((void*)(KERN_SYSCALL_TBL_5 + (0x25 * 4)), (unsigned int)SCKernelCopyData); + + unsigned int repl_addr = ADDRESS_main_entry_hook; + unsigned int bufferU32 = 0x4E800421; + KernelWriteU32(repl_addr,bufferU32,private_data); +} + +void PrepareScreen(private_data_t *private_data) { + // Prepare screen + int screen_buf0_size = 0; + int screen_buf1_size = 0; + unsigned int screen_color = 0; // (r << 24) | (g << 16) | (b << 8) | a; + + // Init screen and screen buffers + private_data->OSScreenInit(); + screen_buf0_size = private_data->OSScreenGetBufferSizeEx(0); + screen_buf1_size = private_data->OSScreenGetBufferSizeEx(1); + private_data->OSScreenSetBufferEx(0, (void *)0xF4000000); + private_data->OSScreenSetBufferEx(1, (void *)0xF4000000 + screen_buf0_size); + + // Clear screens + private_data->OSScreenClearBufferEx(0, screen_color); + private_data->OSScreenClearBufferEx(1, screen_color); + + // Flush the cache + private_data->DCFlushRange((void *)0xF4000000, screen_buf0_size); + private_data->DCFlushRange((void *)0xF4000000 + screen_buf0_size, screen_buf1_size); + + // Flip buffers + private_data->OSScreenFlipBuffersEx(0); + private_data->OSScreenFlipBuffersEx(1); +} + +void ExitFailure(private_data_t *private_data, const char *failure) { + PrepareScreen(private_data); + private_data->OSScreenClearBufferEx(1,0); + private_data->OSScreenPutFontEx(1, 0, 0, failure); + private_data->OSScreenFlipBuffersEx(1); + private_data->OSScreenClearBufferEx(1,0); + private_data->OSScreenPutFontEx(1, 0, 0, failure); + private_data->OSScreenFlipBuffersEx(1); +} + void loadFunctionPointers(private_data_t * private_data) { unsigned int coreinit_handle; @@ -32,9 +96,26 @@ void loadFunctionPointers(private_data_t * private_data) { OS_FIND_EXPORT(coreinit_handle, "FSReadFile", private_data->FSReadFile); OS_FIND_EXPORT(coreinit_handle, "FSCloseFile", private_data->FSCloseFile); + OS_FIND_EXPORT(coreinit_handle, "OSSleepTicks", private_data->OSSleepTicks); + OS_FIND_EXPORT(coreinit_handle, "OSScreenPutFontEx", private_data->OSScreenPutFontEx); + + OS_FIND_EXPORT(coreinit_handle, "OSScreenInit", private_data->OSScreenInit); + OS_FIND_EXPORT(coreinit_handle, "OSScreenGetBufferSizeEx", private_data->OSScreenGetBufferSizeEx); + OS_FIND_EXPORT(coreinit_handle, "OSScreenSetBufferEx", private_data->OSScreenSetBufferEx); + OS_FIND_EXPORT(coreinit_handle, "OSScreenClearBufferEx", private_data->OSScreenClearBufferEx); + OS_FIND_EXPORT(coreinit_handle, "OSScreenFlipBuffersEx", private_data->OSScreenFlipBuffersEx); + OS_FIND_EXPORT(coreinit_handle, "OSForceFullRelaunch", private_data->OSForceFullRelaunch); + + unsigned int sysapp_handle; OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); OS_FIND_EXPORT(sysapp_handle, "SYSRelaunchTitle", private_data->SYSRelaunchTitle); + OS_FIND_EXPORT(sysapp_handle, "SYSLaunchMenu", private_data->SYSLaunchMenu); + OS_FIND_EXPORT(sysapp_handle, "_SYSLaunchMiiStudio", private_data->_SYSLaunchMiiStudio); + OS_FIND_EXPORT(sysapp_handle, "_SYSGetSystemApplicationTitleId", private_data->_SYSGetSystemApplicationTitleId); + OS_FIND_EXPORT(sysapp_handle, "_SYSLaunchTitleWithStdArgsInNoSplash", private_data->_SYSLaunchTitleWithStdArgsInNoSplash); + + private_data->sysmenuTitleID = private_data->_SYSGetSystemApplicationTitleId(0); } /* Read a 32-bit word with kernel permissions */ diff --git a/src/utils.h b/src/utils.h index 9ddd166..81005c5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -8,8 +8,14 @@ extern "C" { #endif +void revertMainHook(); + void loadFunctionPointers(private_data_t * private_data); +void PrepareScreen(private_data_t *private_data); + +void ExitFailure(private_data_t *private_data, const char *failure); + /* Read a 32-bit word with kernel permissions */ uint32_t __attribute__ ((noinline)) kern_read(const void *addr);