- Added external app booter + code

- Added app load/launch code

Notes:
- Will add support for arguments later
This commit is contained in:
0verjoY 2022-07-18 18:42:59 +02:00
parent 167993c279
commit 0ed791842f
15 changed files with 484 additions and 6 deletions

4
.gitignore vendored
View File

@ -3,3 +3,7 @@
################################################################################
/.vs
/source/boot/build/appboot.elf.map
/source/boot/build
/source/boot/appboot.elf
/source/boot/appboot.dol

View File

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

BIN
data/appboot.bin Normal file

Binary file not shown.

93
source/appboot.c Normal file
View File

@ -0,0 +1,93 @@
#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ogc/machine/processor.h>
#include <ogc/lwp_threads.h>
#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();
}

8
source/appboot.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __APPBOOT_H__
#define __APPBOOT_H__
bool LoadApp(const char* path);
u8* GetApp(u32* size);
void LaunchApp(void);
#endif

46
source/boot/Makefile Normal file
View File

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

32
source/boot/loaddol.c Normal file
View File

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

22
source/boot/loaddol.h Normal file
View File

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

52
source/boot/loadelf.c Normal file
View File

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

55
source/boot/loadelf.h Normal file
View File

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

21
source/boot/main.c Normal file
View File

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

15
source/boot/openstub.ld Normal file
View File

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

77
source/boot/utils.c Normal file
View File

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

46
source/boot/utils.h Normal file
View File

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

View File

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