-fixed screen corruption when loading homebrew launcher by properly clearing the screen

-modified IOSU exploit to load from high MEM1 to not run into existing memory and crash
-updated homebrew launcher loader to follow dimoks latest commit and be ready for 1.4 .rpx loading
This commit is contained in:
FIX94 2016-11-12 22:16:06 +01:00
parent 2562624f20
commit 791b2944a7
18 changed files with 737 additions and 195 deletions

View File

@ -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

View File

@ -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

View File

@ -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));

View File

@ -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);

View File

@ -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));
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,75 @@
#ifndef __KERNEL_DEFS_H_
#define __KERNEL_DEFS_H_
#include <stdint.h>
#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_

View File

@ -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

View File

@ -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.");

View File

@ -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_

60
zip/LICENSE Normal file
View File

@ -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.

BIN
zip/zip.exe Normal file

Binary file not shown.