diff --git a/.gitignore b/.gitignore index e915029..a3225cd 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ ################################################################################ /.vs +/source/boot/build/appboot.elf.map +/source/boot/build +/source/boot/appboot.elf +/source/boot/appboot.dol diff --git a/Makefile b/Makefile index abf1940..a76983e 100644 --- a/Makefile +++ b/Makefile @@ -100,11 +100,13 @@ export OUTPUT := $(CURDIR)/$(TARGET) #--------------------------------------------------------------------------------- $(BUILD): @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -s -C source/boot all @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @echo clean ... + @$(MAKE) --no-print-directory -s -C source/boot clean @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol #--------------------------------------------------------------------------------- @@ -139,6 +141,10 @@ $(OUTPUT).elf: $(OFILES) @echo $(notdir $<) $(bin2o) +%.bin.o : %.bin + @echo $(notdir $<) + $(bin2o) + -include $(DEPENDS) #--------------------------------------------------------------------------------- diff --git a/data/appboot.bin b/data/appboot.bin new file mode 100644 index 0000000..2b50077 Binary files /dev/null and b/data/appboot.bin differ diff --git a/source/appboot.c b/source/appboot.c new file mode 100644 index 0000000..d2d17b5 --- /dev/null +++ b/source/appboot.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +#include "fat.h" +#include "sys.h" +#include "wpad.h" + +extern void __exception_closeall(); + +//struct __argv arguments; +//char* m_argv[MAX_ARGV]; +//u8* m_Buffer = NULL; + +u8* appBuffer = NULL; +u32 appSize = 0; + +typedef void (*entrypoint)(); +u32 appEntry = 0; + +#include "appboot_bin.h" + +static void Jump(entrypoint EntryPoint) +{ + appEntry = (u32)EntryPoint; + + u32 level = IRQ_Disable(); + __IOS_ShutdownSubsystems(); + __exception_closeall(); + __lwp_thread_closeall(); + asm volatile ( + "lis %r3, appEntry@h\n" + "ori %r3, %r3, appEntry@l\n" + "lwz %r3, 0(%r3)\n" + "mtlr %r3\n" + "blr\n" + ); + IRQ_Restore(level); +} + +bool LoadApp(const char* path) +{ + appBuffer = (u8*)0x92000000; + + FILE* f = fopen(path, "rb"); + + if (f == NULL) + return false; + + fseek(f, 0, SEEK_END); + u32 size = ftell(f); + rewind(f); + + if (size > 0x1000000) + { + fclose(f); + return false; + } + + u32 ret = fread(appBuffer, 1, size, f); + DCFlushRange(appBuffer, (size + 31) & (~31)); + + fclose(f); + + return (ret == size); +} + +u8* GetApp(u32* size) +{ + *size = appSize; + return appBuffer; +} + +void LaunchApp(void) +{ + entrypoint entry; + + memcpy((u8*)0x93000000, appboot_bin, appboot_bin_size); + DCFlushRange((u8*)0x93000000, appboot_bin_size); + entry = (entrypoint)0x93000000; + + u32 dumdum = 0; + SYS_ResetSystem(SYS_SHUTDOWN, 0, 0); + _CPU_ISR_Disable(dumdum); + __exception_closeall(); + Jump(entry); + _CPU_ISR_Restore(dumdum); + + Sys_LoadMenu(); +} \ No newline at end of file diff --git a/source/appboot.h b/source/appboot.h new file mode 100644 index 0000000..b5808af --- /dev/null +++ b/source/appboot.h @@ -0,0 +1,8 @@ +#ifndef __APPBOOT_H__ +#define __APPBOOT_H__ + +bool LoadApp(const char* path); +u8* GetApp(u32* size); +void LaunchApp(void); + +#endif \ No newline at end of file diff --git a/source/boot/Makefile b/source/boot/Makefile new file mode 100644 index 0000000..61bee48 --- /dev/null +++ b/source/boot/Makefile @@ -0,0 +1,46 @@ + +PREFIX = $(DEVKITPPC)/bin/powerpc-eabi- + +AR = $(PREFIX)ar +AS = $(PREFIX)as +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +LD = $(PREFIX)ld +OBJCOPY = $(PREFIX)objcopy +RANLIB = $(PREFIX)ranlib +STRIP = $(PREFIX)strip + +MACHDEP = -mcpu=750 -meabi -mhard-float +CFLAGS = $(MACHDEP) -O0 -s -Werror -Wall -fdata-sections -ffunction-sections +LDFLAGS = $(MACHDEP) -n -nostartfiles -nostdlib -Wl,--gc-sections,-T,openstub.ld -L. +ASFLAGS = -D_LANGUAGE_ASSEMBLY -DHW_RVL + +TARGET_LINKED = patcher.elf +TARGET = ../../data/appboot.bin + +CFILES = main.c utils.c loaddol.c loadelf.c +OBJS = main.o utils.o loaddol.o loadelf.o + +DEPDIR = .deps + +LIBS = + +all: $(TARGET) + +%.o: %.s + @$(CC) $(CFLAGS) $(DEFINES) $(ASFLAGS) -c $< -o $@ + +%.o: %.S + @$(CC) $(CFLAGS) $(DEFINES) $(ASFLAGS) -c $< -o $@ + +%.o: %.c + @$(CC) $(CFLAGS) $(DEFINES) -c $< -o $@ + +$(TARGET_LINKED): $(OBJS) + @$(CC) -g -o $@ $(LDFLAGS) $(OBJS) $(LIBS) + +$(TARGET): $(TARGET_LINKED) + @$(OBJCOPY) -O binary -S $< $@ + +clean: + @-$(RM) -rf $(TARGET_LINKED) $(OBJS) $(DEPDIR) diff --git a/source/boot/loaddol.c b/source/boot/loaddol.c new file mode 100644 index 0000000..555621a --- /dev/null +++ b/source/boot/loaddol.c @@ -0,0 +1,32 @@ + +#include "loaddol.h" + +static void memcopy(void* address, void* buffer, u32 size) +{ + _memcpy(address, buffer, size); + sync_after_write(address, (size + 31) & (~31)); +} + +u32 LoadDol(void* buffer) +{ + u32 i; + struct dolhdr* dol = (struct dolhdr*)buffer; + + for (i = 0; i < 7; i++) + { + if (dol->sizeText[i] == 0) + continue; + + memcopy((void*)dol->addressText[i], buffer + dol->offsetText[i], dol->sizeText[i]); + } + + for (i = 0; i < 11; i++) + { + if (dol->sizeData[i] == 0) + continue; + + memcopy((void*)dol->addressData[i], buffer + dol->offsetData[i], dol->sizeData[i]); + } + + return dol->entrypoint; +} \ No newline at end of file diff --git a/source/boot/loaddol.h b/source/boot/loaddol.h new file mode 100644 index 0000000..4a12007 --- /dev/null +++ b/source/boot/loaddol.h @@ -0,0 +1,22 @@ +#ifndef __DOL_H__ +#define __DOL_H__ + +#include "utils.h" + +struct dolhdr +{ + u32 offsetText[7]; + u32 offsetData[11]; + u32 addressText[7]; + u32 addressData[11]; + u32 sizeText[7]; + u32 sizeData[11]; + u32 addressBSS; + u32 sizeBSS; + u32 entrypoint; +}; + + +u32 LoadDol(void* buffer); + +#endif \ No newline at end of file diff --git a/source/boot/loadelf.c b/source/boot/loadelf.c new file mode 100644 index 0000000..4ca0dbb --- /dev/null +++ b/source/boot/loadelf.c @@ -0,0 +1,52 @@ + +#include "loadelf.h" + +bool ExecIsElf(void* address) +{ + struct Elf32_Ehdr* ehdr = (struct Elf32_Ehdr*)address; + + if (*(u8*)address + 0 != 0x7F || *(u8*)address + 1 != 'E' || *(u8*)address + 2 != 'L' || *(u8*)address + 3 != 'F') + return false; + + if (ehdr->e_type != 2) // Executable + return false; + + if (ehdr->e_machine != 20) // PowerPC + return false; + + return true; +} + +u32 LoadElf(void* address) +{ + //u8* strtab = 0; + //u8* image; + int i; + + struct Elf32_Ehdr* ehdr = (struct Elf32_Ehdr*)address; + struct Elf32_Shdr* shdr = (struct Elf32_Shdr*)(address + ehdr->e_shoff + (ehdr->e_shstrndx * sizeof(struct Elf32_Shdr))); + + //if (shdr->sh_type == SHT_STRTAB) + // strtab = (u8*)(addr + shdr->sh_offset); + + for (i = 0; i < ehdr->e_shnum; i++) + { + shdr = (struct Elf32_Shdr*)(address + ehdr->e_shoff + (i * sizeof(struct Elf32_Shdr))); + + if (!(shdr->sh_flags & 0x02) || shdr->sh_addr == 0 || shdr->sh_size == 0) + continue; + + shdr->sh_addr &= 0x3FFFFFFF; + shdr->sh_addr |= 0x80000000; + + if (shdr->sh_type == 8) + _memset32((void*)shdr->sh_addr, 0, shdr->sh_size); + else + _memcpy((void*)shdr->sh_addr, (void*)(address + shdr->sh_offset), shdr->sh_size); + + sync_after_write((void*)shdr->sh_addr, (shdr->sh_size + 31) & (~31)); + + } + + return (ehdr->e_entry & 0x3FFFFFFF) | 0x80000000; +} \ No newline at end of file diff --git a/source/boot/loadelf.h b/source/boot/loadelf.h new file mode 100644 index 0000000..22e6ef1 --- /dev/null +++ b/source/boot/loadelf.h @@ -0,0 +1,55 @@ +#ifndef __ELF_H__ +#define __ELF_H__ + +#include "utils.h" + +#define EI_NIDENT 16 + +struct Elf32_Ehdr +{ + u8 e_ident[EI_NIDENT]; + u16 e_type; + u16 e_machine; + u32 e_version; + u32 e_entry; + u32 e_phoff; + u32 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; +}; + +struct Elf32_Shdr +{ + u32 sh_name; + u32 sh_type; + u32 sh_flags; + u32 sh_addr; + u32 sh_offset; + u32 sh_size; + u32 sh_link; + u32 sh_info; + u32 sh_addralign; + u32 sh_entsize; +}; + +struct Elf32_Phdr +{ + u32 p_type; + u32 p_offset; + u32 p_vaddr; + u32 p_paddr; + u32 p_filesz; + u32 p_memsz; + u32 p_flags; + u32 p_align; +}; + +bool ExecIsElf(void* address); +u32 LoadElf(void* address); + +#endif \ No newline at end of file diff --git a/source/boot/main.c b/source/boot/main.c new file mode 100644 index 0000000..689fcd4 --- /dev/null +++ b/source/boot/main.c @@ -0,0 +1,21 @@ + +#include "loaddol.h" +#include "loadelf.h" + +typedef void (*entrypoint)(); + +void _main(void) +{ + void* buffer = (void*)0x92000000; + entrypoint entry; + + if (ExecIsElf(buffer)) + entry = (entrypoint)LoadElf(buffer); + else + entry = (entrypoint)LoadDol(buffer); + + if (!entry) + return; + + entry(); +} \ No newline at end of file diff --git a/source/boot/openstub.ld b/source/boot/openstub.ld new file mode 100644 index 0000000..165168b --- /dev/null +++ b/source/boot/openstub.ld @@ -0,0 +1,15 @@ +/* + TinyLoad - a simple region free (original) game launcher in 4k + +# This code is licensed to you under the terms of the GNU GPL, version 2; +# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +*/ + +OUTPUT_FORMAT("elf32-powerpc") +OUTPUT_ARCH(powerpc:common) + +ENTRY(_main) + +SECTIONS { + . = 0x93000000; +} \ No newline at end of file diff --git a/source/boot/utils.c b/source/boot/utils.c new file mode 100644 index 0000000..05d3540 --- /dev/null +++ b/source/boot/utils.c @@ -0,0 +1,77 @@ +#include "utils.h" + +void sync_before_read(void *ptr, u32 len) +{ + u32 a, b; + + a = (u32)ptr & ~0x1f; + b = ((u32)ptr + len + 0x1f) & ~0x1f; + + for ( ; a < b; a += 32) + asm("dcbi 0,%0" : : "b"(a) : "memory"); + + asm("sync ; isync"); +} + +void sync_after_write(const void *ptr, u32 len) +{ + u32 a, b; + + a = (u32)ptr & ~0x1f; + b = ((u32)ptr + len + 0x1f) & ~0x1f; + + for ( ; a < b; a += 32) + asm("dcbf 0,%0" : : "b"(a)); + + asm("sync ; isync"); +} + +void _memcpy(void *ptr, const void *src, u32 size) +{ + char *ptr2 = ptr; + u32 bsize = size; + const char* src2 = src; + while(size--) *ptr2++ = *src2++; + + sync_after_write(ptr, bsize); +} + +void _memset32(u32 *address, u32 data, u32 length) +{ + while(length--) + *address++ = data; +} + +int _memcmp(const void *s1, const void *s2, size_t n) +{ + unsigned char *us1 = (unsigned char *) s1; + unsigned char *us2 = (unsigned char *) s2; + while(n-- != 0) + { + if (*us1 != *us2) + return (*us1 < *us2) ? -1 : +1; + us1++; + us2++; + } + return 0; +} + +size_t strnlen(const char *s, size_t count) +{ + const char *sc; + + for(sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +inline void write32(u32 dest, u32 value) +{ + *(u32*)dest = value; + sync_after_write((void*)dest, 0x20); +} + +inline u32 read32(u32 src) +{ + return *(u32*)src; +} \ No newline at end of file diff --git a/source/boot/utils.h b/source/boot/utils.h new file mode 100644 index 0000000..96070ee --- /dev/null +++ b/source/boot/utils.h @@ -0,0 +1,46 @@ +#ifndef __UTILS_H__ +#define __UTILS_H__ + +typedef unsigned char u8; +typedef unsigned char uint8_t; +typedef unsigned short u16; +typedef unsigned short uint16_t; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef int bool; +typedef unsigned int sec_t; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; +typedef volatile unsigned long long vu64; + +typedef volatile signed char vs8; +typedef volatile signed short vs16; +typedef volatile signed int vs32; +typedef volatile signed long long vs64; + +typedef s32 size_t; +typedef u32 u_int32_t; + +#define NULL ((void*)0) +#define true 1 +#define false 0 +#define IsWiiU ((*(u32*)0xcd8005A0 >> 16 ) == 0xCAFE) + +void sync_before_read(void* ptr, u32 len); +void sync_after_write(const void* ptr, u32 len); +void _memcpy(void *ptr, const void *src, u32 size); +void _memset32(unsigned int *addr, unsigned int data, unsigned int count); +int _memcmp(const void *s1, const void *s2, size_t n); +size_t strnlen(const char *s, size_t count); +void write32(u32 value, u32 dest); +u32 read32(u32 src); + +#endif \ No newline at end of file diff --git a/source/wad-manager.c b/source/wad-manager.c index f3f768a..44f67ac 100644 --- a/source/wad-manager.c +++ b/source/wad-manager.c @@ -30,6 +30,7 @@ int ReadConfigFile (char *configFilePath); int GetIntParam (char *inputStr); int GetStartupPath (char *startupPath, char *inputStr); int GetStringParam (char *outParam, char *inputStr, int maxChars); +int LaunchApp(const char* path, bool external); // Default password Up-Down-Left-Right-Up-Down //#define PASSWORD "UDLRUD" @@ -215,7 +216,7 @@ int ReadConfigFile (char *configFilePath) fdev = &fdevList[2]; ret = Fat_Mount(fdev); snprintf(path, sizeof(path), "%s%s", fdev->mount, configFilePath); - snprintf(path, sizeof(path), "%s%s", fdev->mount, configFilePath); + //snprintf(path, sizeof(path), "%s%s", fdev->mount, configFilePath); } if (ret < 0) @@ -237,7 +238,7 @@ int ReadConfigFile (char *configFilePath) { if (fgets (tmpStr, MAX_FILE_PATH_LEN, fptr) == NULL) done = 1; - else if (isalpha(tmpStr[0])) + else if (isalpha((int)tmpStr[0])) { // Get the password if (strncmp (tmpStr, "Password", 8) == 0) @@ -378,14 +379,14 @@ int GetIntParam (char *inputStr) i++; // Get to the first alpha numeric character - while ((isdigit(inputStr [i]) == 0) && (i < len)) + while ((isdigit((int)inputStr[i]) == 0) && (i < len)) { i++; } // Get the string param int outCount = 0; - while ((isdigit(inputStr [i])) && (i < len) && (outCount < 40)) + while ((isdigit((int)inputStr[i])) && (i < len) && (outCount < 40)) { outParam [outCount++] = inputStr [i++]; } @@ -409,14 +410,14 @@ int GetStringParam (char *outParam, char *inputStr, int maxChars) i++; // Get to the first alpha character - while ((isalpha(inputStr [i]) == 0) && (i < len)) + while ((isalpha((int)inputStr[i]) == 0) && (i < len)) { i++; } // Get the string param int outCount = 0; - while ((isalnum(inputStr [i])) && (i < len) && (outCount < maxChars)) + while ((isalnum((int)inputStr[i])) && (i < len) && (outCount < maxChars)) { outParam [outCount++] = inputStr [i++]; }