On error return to system menu instead of crashing.
This commit is contained in:
parent
234c180659
commit
f4e393a885
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
12
src/entry.c
12
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);
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
|
81
src/utils.c
81
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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue