From 3b150d408de95669f79defac7fcb954506d46617 Mon Sep 17 00:00:00 2001 From: Cuyler36 Date: Wed, 15 Mar 2023 16:46:43 -0400 Subject: [PATCH] Get osreport.c linked --- common.py | 8 +- config/analysis_overrides.yml | 2 +- config/disasm_overrides.yml | 5 +- config/dol_slices.yml | 13 +- configure.py | 62 +++++++-- include/JSystem/JSystem.h | 1 + include/MSL_C/printf.h | 6 +- include/dolphin/os.h | 18 ++- include/dolphin/os/OSCache.h | 24 ++-- include/dolphin/os/OSException.h | 9 ++ include/dolphin/os/OSExi.h | 72 ++++++++++ include/dolphin/os/OSInterrupt.h | 126 ++++++++++++++++- include/dolphin/os/OSRtc.h | 112 ++++++++++++++- include/libforest/osreport.h | 40 ++++-- include/types.h | 12 ++ src/dolphin/os/OSRtc.c | 230 +++++++++++++++++++++++++++++++ src/libforest/osreport.c | 62 ++++----- tools/frank.py | 215 +++++++++++++++++++++++++++++ tools/franklite.py | 52 +++++++ 19 files changed, 976 insertions(+), 93 deletions(-) create mode 100644 include/dolphin/os/OSException.h create mode 100644 include/dolphin/os/OSExi.h create mode 100644 src/dolphin/os/OSRtc.c create mode 100644 tools/frank.py create mode 100644 tools/franklite.py diff --git a/common.py b/common.py index e643c97c..a0d180af 100644 --- a/common.py +++ b/common.py @@ -203,14 +203,20 @@ FORCEFILESGEN = f"{PYTHON} {PPCDIS}/forcefilesgen.py" TOOLS = "tools" CODEWARRIOR = os.path.join(TOOLS, "1.3.2") SDK_CW = os.path.join(TOOLS, "1.2.5") +HOTFIX_CW = os.path.join(TOOLS, "1.2.5e") CC = os.path.join(CODEWARRIOR, "mwcceppc.exe") OCC = os.path.join(SDK_CW, "mwcceppc.exe") +PROFILE = os.path.join(HOTFIX_CW, "mwcceppc.exe") LD = os.path.join(CODEWARRIOR, "mwldeppc.exe") if platform != "win32": CC = f"wibo {CC}" OCC = f"wibo {OCC}" LD = f"wibo {LD}" +# Frank +FRANKLITE = "tools/franklite.py" +FRANK = "tools/frank.py" + # DevkitPPC DEVKITPPC = os.environ.get("DEVKITPPC") AS = os.path.join(DEVKITPPC, "bin", "powerpc-eabi-as") @@ -306,7 +312,7 @@ CPLFLAGS =[ "-O0" ] BASE_DOL_CFLAGS = CFLAGS + [ - "-inline all", + "-inline on", "-sdata 8", f"-sdata2 {DOL_SDATA2_SIZE}" ] diff --git a/config/analysis_overrides.yml b/config/analysis_overrides.yml index bd513ddd..3c43cf5e 100644 --- a/config/analysis_overrides.yml +++ b/config/analysis_overrides.yml @@ -352,7 +352,7 @@ forced_types: 0x80078fcc: ENTRY 0x8007ac24: ENTRY 0x8007ac34: ENTRY - 0x8007db20: ENTRY +# 0x8007db20: ENTRY 0x8007db3c: ENTRY 0x8009ae2c: ENTRY 0x8009ae34: ENTRY diff --git a/config/disasm_overrides.yml b/config/disasm_overrides.yml index 933e8dbd..78dd3143 100644 --- a/config/disasm_overrides.yml +++ b/config/disasm_overrides.yml @@ -1 +1,4 @@ -trim_ctors: true \ No newline at end of file +trim_ctors: true + +symbol_aligns: + 0x80207458: 8 # align RunQueue to 0x001251d8 diff --git a/config/dol_slices.yml b/config/dol_slices.yml index ca0e8ff6..3d982a67 100644 --- a/config/dol_slices.yml +++ b/config/dol_slices.yml @@ -16,11 +16,11 @@ jaudio_NES/dummyprobe.c: #jaudio_NES/verysimple.c: # .text: [0x80008400, 0x80008480] # .sdata: [0x80217b80, 0x80217b88] -#libforest/osreport.c: //see why it doesn't match -# .text: [0x8005a654, 0x8005a92c] -# .data: [0x800dc6d8, 0x800dc738] -# .bss: [0x80206f08, 0x80206f20] -# .sbss: [0x80218618, 0x80218628] +libforest/osreport.c: + .text: [0x8005a654, 0x8005a92c] + .data: [0x800dc6d8, 0x800dc738] + .bss: [0x80206f08, 0x80206f20] + .sbss: [0x80218618, 0x80218628] #libforest/fault.c: # .text: [0x8005a92c, 0x8005adac] # .data: [0x800dc738, 0x800dc7c8] @@ -146,6 +146,9 @@ dolphin/os/OSEnableInterrupts.c: .text: [0x8007ac38, 0x8007ac4c] dolphin/os/OSRestoreInterrupts.c: .text: [0x8007ac4c, 0x8007ac70] +dolphin/os/OSRtc.c: + .text: [0x8007d050, 0x8007db20] + .bss: [0x80207400, 0x80207458] MSL_C/rand.c: .text: [0x8009f46c, 0x8009f494] .sdata: [0x80218260, 0x80218268] diff --git a/configure.py b/configure.py index b7597ea1..634c7c56 100644 --- a/configure.py +++ b/configure.py @@ -82,6 +82,8 @@ n.variable("elf2dol", c.ELF2DOL) n.variable("elf2rel", c.ELF2REL) n.variable("codewarrior", c.CODEWARRIOR) n.variable("cc", c.CC) +n.variable("franklite", c.FRANKLITE) +n.variable("frank", c.FRANK) n.variable("occ", c.OCC) n.variable("align16", c.ALIGN16) n.variable("ld", c.LD) @@ -109,6 +111,7 @@ n.newline() # Windows can't use && without this statement ALLOW_CHAIN = "cmd /c " if os.name == "nt" else "" +mwcc_cmd = ALLOW_CHAIN + f"$cpp -M $in -MF $out.d $cppflags && $cc $cflags -c $in -o $out" n.rule( "relextern", @@ -204,11 +207,30 @@ n.rule( n.rule( "cc", - command = ALLOW_CHAIN + f"$cpp -M $in -MF $out.d $cppflags && $cc $cflags -c $in -o $out", + command = mwcc_cmd, description = "CC $in", deps = "gcc", depfile = "$out.d" ) + +n.rule( + "franklite", + command = f"{mwcc_cmd} && $python $franklite $basefile $basefile", + description = "FRANKLITE $out", + deps = "gcc", + depfile = "$basefile.d" +) + +n.rule( + "frank", + command = f"{mwcc_cmd} " + + f"&& {c.PROFILE} $cflags -c $in -o $out.profile " + + f"&& $python $frank $out $out.profile $out ", + description = "FRANK $out", + deps = "gcc", + depfile = "$out.d" +) + n.rule( "ccs", command = ALLOW_CHAIN + f"$cpp -M $in -MF $out.d $cppflags && $cc $cflags -S $in -o $out", @@ -609,15 +631,19 @@ class CSource(Source): if path.startswith("src/dolphin/"): self.cflags = c.SDK_FLAGS self.cc = c.OCC + self.frank = True elif path.startswith("src/JSystem/"): self.cflags = c.JSYSTEM_CFLAGS self.cc = c.CC + self.frank = False elif path.startswith("src/jaudio_NES"): self.cc = c.CC self.cflags = c.DOL_CPPFLAGS + self.frank = False else: self.cflags = ctx.cflags self.cc = c.CC + self.frank = False self.iconv_path = f"$builddir/iconv/{path}" # Find generated includes @@ -645,16 +671,30 @@ class CSource(Source): #) #print(self.i_path) - n.build( - self.o_path, - rule = "cc", - inputs = self.iconv_path, - implicit = [inc.path for inc in self.gen_includes], - variables = { - "cc" : self.cc, - "cflags" : self.cflags - } - ) + if self.frank == True: + #print(f"python3 franklite.py {self.o_path} {self.o_path}") + n.build( + self.o_path, + rule = "frank", + inputs = self.iconv_path, + implicit = [inc.path for inc in self.gen_includes], + variables = { + "cc" : self.cc, + "cflags" : self.cflags, + #"basefile" : self.o_path + } + ) + else: + n.build( + self.o_path, + rule = "cc", + inputs = self.iconv_path, + implicit = [inc.path for inc in self.gen_includes], + variables = { + "cc" : self.cc, + "cflags" : self.cflags + } + ) # Optional manual debug target n.build( self.s_path, diff --git a/include/JSystem/JSystem.h b/include/JSystem/JSystem.h index 7a998953..cfea0d3d 100644 --- a/include/JSystem/JSystem.h +++ b/include/JSystem/JSystem.h @@ -2,6 +2,7 @@ #define JSYSTEM_H #include "dolphin/os.h" +#include "libforest/osreport.h" #include "JSystem/JKernel/JKRAram.h" //#include "JSystem/JUtility/JUTException.h" diff --git a/include/MSL_C/printf.h b/include/MSL_C/printf.h index 5b421ff5..13d5a41b 100644 --- a/include/MSL_C/printf.h +++ b/include/MSL_C/printf.h @@ -5,7 +5,7 @@ #include "va_args.h" -void vprintf(const char*, va_list); -void print(const char*, ...); +extern void vprintf(const char*, va_list); +extern void printf(const char*, ...); -#endif \ No newline at end of file +#endif diff --git a/include/dolphin/os.h b/include/dolphin/os.h index ced9df20..a73bf03a 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -3,8 +3,11 @@ #include "types.h" #include "dolphin/os/OSContext.h" +#include "dolphin/os/OSInterrupt.h" #include "dolphin/os/OSMessage.h" +#include "libforest/osreport.h" /* OSReport funcs */ #include "va_args.h" + #ifdef __cplusplus extern "C" { #endif @@ -15,8 +18,8 @@ extern void __OSFPRInit(); extern void __OSCacheInit(); void OSPanic(const char *file, int line, const char *message, ...); -void OSReport(const char*, ...); -void OSVReport(const char* format, va_list list); +void OSVReport(const char* fmt, va_list list); +void OSReport(const char* fmt, ...); extern void __OSPSInit(); extern void __OSCacheInit(); @@ -24,6 +27,15 @@ extern void __OSCacheInit(); #define OSErrorLine(line, ...) \ OSPanic(__FILE__, line, __VA_ARGS__) +#ifdef DOLPHIN_DEBUG +#define DOLPHIN_ASSERTLINE(assertion, line) \ + (void) ((assertion) || (OSErrorLine(line, "Failed assertion " #assertion), 0)) +#define DOLPHIN_ASSERT(assertion) \ + (void) ((assertion) || (OSPanic(__FILE__, __LINE__, "Failed assertion " #assertion), 0)) +#else +#define DOLPHIN_ASSERTLINE(assertion, line) +#define DOLPHIN_ASSERT(assertion) +#endif void OSResetSystem(u32, u32, u32); // goes in reset, but eh void OSInit(void); @@ -33,6 +45,6 @@ typedef void (*OSExceptionHandler)(u8, OSContext*); OSExceptionHandler __OSSetExceptionHandler(u8, OSExceptionHandler); #ifdef __cplusplus -}; +} #endif #endif diff --git a/include/dolphin/os/OSCache.h b/include/dolphin/os/OSCache.h index a5fa78a9..dc777120 100644 --- a/include/dolphin/os/OSCache.h +++ b/include/dolphin/os/OSCache.h @@ -5,18 +5,18 @@ extern "C" { #endif -asm void DCEnable(void); -asm void DCInvalidateRange(void*, u32); -asm void DCFlushRange(void*, u32); -asm void DCStoreRange(void*, u32); -asm void DCFlushRangeNoSync(void*, u32); -asm void DCStoreRangeNoSync(void*, u32); -asm void DCZeroRange(void*, u32); -asm void DCTouchRange(void*, u32 len); -asm void ICInvalidateRange(void*, u32); -asm void ICFlashInvalidate(void); -asm void ICEnable(void); -asm void LCDisable(void); +void DCEnable(void); +void DCInvalidateRange(void*, u32); +void DCFlushRange(void*, u32); +void DCStoreRange(void*, u32); +void DCFlushRangeNoSync(void*, u32); +void DCStoreRangeNoSync(void*, u32); +void DCZeroRange(void*, u32); +void DCTouchRange(void*, u32 len); +void ICInvalidateRange(void*, u32); +void ICFlashInvalidate(void); +void ICEnable(void); +void LCDisable(void); //void L2GlobalInvalidate(void); diff --git a/include/dolphin/os/OSException.h b/include/dolphin/os/OSException.h new file mode 100644 index 00000000..a6ad8a2d --- /dev/null +++ b/include/dolphin/os/OSException.h @@ -0,0 +1,9 @@ +#ifndef DOLPHIN_OSEXCEPTION_H +#define DOLPHIN_OSEXCEPTION_H + +typedef enum OSException { + OS_EXCEPTION_FLOATING_POINT = 7, + OS_EXCEPTION_COUNT = 15, +} OSException; + +#endif diff --git a/include/dolphin/os/OSExi.h b/include/dolphin/os/OSExi.h new file mode 100644 index 00000000..b11ede2d --- /dev/null +++ b/include/dolphin/os/OSExi.h @@ -0,0 +1,72 @@ +#ifndef DOLPHIN_OSEXI_H +#define DOLPHIN_OSEXI_H + +#include "dolphin/os/OSContext.h" +#include "dolphin/os/OSInterrupt.h" +#include "types.h" + +typedef enum { + EXI_STATE_DMA_ACCESS = (1 << 0), + EXI_STATE_IMM_ACCESS = (1 << 1), + EXI_STATE_SELECTED = (1 << 2), + EXI_STATE_ATTACHED = (1 << 3), + EXI_STATE_LOCKED = (1 << 4), + EXI_STATE_BUSY = EXI_STATE_DMA_ACCESS | EXI_STATE_IMM_ACCESS +} EXIState; + +typedef enum { + EXI_CHAN_0, + EXI_CHAN_1, + EXI_CHAN_2, + EXI_MAX_CHAN +} EXIChannel; + +typedef enum { + EXI_READ, + EXI_WRITE, + EXI_TYPE_2, + EXI_MAX_TYPE +} EXIType; + +typedef void (*EXICallback)(EXIChannel, OSContext*); + +typedef struct EXIControl { + EXICallback exiCallback; + EXICallback tcCallback; + EXICallback extCallback; + vu32 state; + int immLen; + u8* immBuf; + u32 dev; + u32 id; + s32 idTime; + int items; + struct { + u32 dev; + EXICallback callback; + } queue[3]; +} EXIControl; + +#define EXI_REG_MAX 5 +extern vu32 __EXIRegs[EXI_MAX_CHAN][EXI_REG_MAX] AT_ADDRESS(0xCC006800); + +void SetExiInterruptMask(EXIChannel, volatile EXIControl*); +BOOL EXIImm(EXIChannel, void* buf, s32 len, u32 type, EXICallback); +BOOL EXIImmEx(EXIChannel, void* buf, s32 len, u32 mode); +BOOL EXIDma(EXIChannel, void* buf, s32 len, u32 type, EXICallback); +BOOL EXISync(EXIChannel); +u32 EXIClearInterrupts(EXIChannel, BOOL exi, BOOL tc, BOOL ext); +EXICallback EXISetExiCallback(EXIChannel, EXICallback exiCallback); +BOOL EXIProbe(EXIChannel); +s32 EXIProbeEx(EXIChannel); +BOOL EXIAttach(EXIChannel, EXICallback); +BOOL EXIDetach(EXIChannel); +BOOL EXISelect(EXIChannel, u32 dev, u32 freq); +BOOL EXIDeselect(EXIChannel); +void EXIInit(void); +BOOL EXILock(EXIChannel, u32 dev, EXICallback unlockedCallback); +BOOL EXIUnlock(EXIChannel); +u32 EXIGetState(EXIChannel); +s32 EXIGetID(EXIChannel, u32 dev, u32* id); + +#endif diff --git a/include/dolphin/os/OSInterrupt.h b/include/dolphin/os/OSInterrupt.h index d9c3011a..e149c15a 100644 --- a/include/dolphin/os/OSInterrupt.h +++ b/include/dolphin/os/OSInterrupt.h @@ -1,13 +1,127 @@ -#ifndef OS_INTERRUPT_H -#define OS_INTERRUPT_H +#ifndef DOLPHIN_OSINTERRUPT_H +#define DOLPHIN_OSINTERRUPT_H + +#include "dolphin/os/OSContext.h" +#include "dolphin/os/OSException.h" #include "types.h" +typedef s16 __OSInterrupt; +typedef u32 OSInterruptMask; -BOOL OSDisableInterrupts(void); -BOOL OSEnableInterrupts(void); -BOOL OSRestoreInterrupts(BOOL status); +typedef enum OSInterruptType { + OS_INTR_MEM_0, + OS_INTR_MEM_1, + OS_INTR_MEM_2, + OS_INTR_MEM_3, + OS_INTR_MEM_ADDRESS, + OS_INTR_DSP_AI, + OS_INTR_DSP_ARAM, + OS_INTR_DSP_DSP, + OS_INTR_AI_AI, + OS_INTR_EXI_0_EXI, + OS_INTR_EXI_0_TC, + OS_INTR_EXI_0_EXT, + OS_INTR_EXI_1_EXI, + OS_INTR_EXI_1_TC, + OS_INTR_EXI_1_EXT, + OS_INTR_EXI_2_EXI, + OS_INTR_EXI_2_TC, + OS_INTR_PI_CP, + OS_INTR_PI_PE_TOKEN, + OS_INTR_PI_PE_FINISH, + OS_INTR_PI_SI, + OS_INTR_PI_DI, + OS_INTR_PI_RSW, + OS_INTR_PI_ERROR, + OS_INTR_PI_VI, + OS_INTR_PI_DEBUG, + OS_INTR_PI_HSP, + OS_INTR_PI_ACR, + OS_INTR_28, + OS_INTR_29, + OS_INTR_30, + OS_INTR_31, + + OS_INTR_MAX +} OSInterruptType; + +#define OS_INTRMASK_MEM_0 (0x80000000U >> OS_INTR_MEM_0) +#define OS_INTRMASK_MEM_1 (0x80000000U >> OS_INTR_MEM_1) +#define OS_INTRMASK_MEM_2 (0x80000000U >> OS_INTR_MEM_2) +#define OS_INTRMASK_MEM_3 (0x80000000U >> OS_INTR_MEM_3) +#define OS_INTRMASK_MEM_ADDRESS (0x80000000U >> OS_INTR_MEM_ADDRESS) +#define OS_INTRMASK_DSP_AI (0x80000000U >> OS_INTR_DSP_AI) +#define OS_INTRMASK_DSP_ARAM (0x80000000U >> OS_INTR_DSP_ARAM) +#define OS_INTRMASK_DSP_DSP (0x80000000U >> OS_INTR_DSP_DSP) +#define OS_INTRMASK_AI_AI (0x80000000U >> OS_INTR_AI_AI) +#define OS_INTRMASK_EXI_0_EXI (0x80000000U >> OS_INTR_EXI_0_EXI) +#define OS_INTRMASK_EXI_0_TC (0x80000000U >> OS_INTR_EXI_0_TC) +#define OS_INTRMASK_EXI_0_EXT (0x80000000U >> OS_INTR_EXI_0_EXT) +#define OS_INTRMASK_EXI_1_EXI (0x80000000U >> OS_INTR_EXI_1_EXI) +#define OS_INTRMASK_EXI_1_TC (0x80000000U >> OS_INTR_EXI_1_TC) +#define OS_INTRMASK_EXI_1_EXT (0x80000000U >> OS_INTR_EXI_1_EXT) +#define OS_INTRMASK_EXI_2_EXI (0x80000000U >> OS_INTR_EXI_2_EXI) +#define OS_INTRMASK_EXI_2_TC (0x80000000U >> OS_INTR_EXI_2_TC) +#define OS_INTRMASK_PI_CP (0x80000000U >> OS_INTR_PI_CP) +#define OS_INTRMASK_PI_PE_TOKEN (0x80000000U >> OS_INTR_PI_PE_TOKEN) +#define OS_INTRMASK_PI_PE_FINISH (0x80000000U >> OS_INTR_PI_PE_FINISH) +#define OS_INTRMASK_PI_SI (0x80000000U >> OS_INTR_PI_SI) +#define OS_INTRMASK_PI_DI (0x80000000U >> OS_INTR_PI_DI) +#define OS_INTRMASK_PI_RSW (0x80000000U >> OS_INTR_PI_RSW) +#define OS_INTRMASK_PI_ERROR (0x80000000U >> OS_INTR_PI_ERROR) +#define OS_INTRMASK_PI_VI (0x80000000U >> OS_INTR_PI_VI) +#define OS_INTRMASK_PI_DEBUG (0x80000000U >> OS_INTR_PI_DEBUG) +#define OS_INTRMASK_PI_HSP (0x80000000U >> OS_INTR_PI_HSP) + +#define OS_INTRMASK_MEM \ + (OS_INTRMASK_MEM_0 | OS_INTRMASK_MEM_1 | OS_INTRMASK_MEM_2 | \ + OS_INTRMASK_MEM_3 | OS_INTRMASK_MEM_ADDRESS) + +#define OS_INTRMASK_AI (OS_INTRMASK_AI_AI) + +#define OS_INTRMASK_DSP \ + (OS_INTRMASK_DSP_AI | OS_INTRMASK_DSP_ARAM | OS_INTRMASK_DSP_DSP) + +#define OS_INTRMASK_EXI_0 \ + (OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT) +#define OS_INTRMASK_EXI_1 \ + (OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT) +#define OS_INTRMASK_EXI_2 (OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC) +#define OS_INTRMASK_EXI \ + (OS_INTRMASK_EXI_0_EXI | OS_INTRMASK_EXI_0_TC | OS_INTRMASK_EXI_0_EXT | \ + OS_INTRMASK_EXI_1_EXI | OS_INTRMASK_EXI_1_TC | OS_INTRMASK_EXI_1_EXT | \ + OS_INTRMASK_EXI_2_EXI | OS_INTRMASK_EXI_2_TC) + +#define OS_INTRMASK_PI \ + (OS_INTRMASK_PI_CP | OS_INTRMASK_PI_SI | OS_INTRMASK_PI_DI | \ + OS_INTRMASK_PI_RSW | OS_INTRMASK_PI_ERROR | OS_INTRMASK_PI_VI | \ + OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH | \ + OS_INTRMASK_PI_DEBUG | OS_INTRMASK_PI_HSP) + +#define OS_INTRMASK_PI_PE (OS_INTRMASK_PI_PE_TOKEN | OS_INTRMASK_PI_PE_FINISH) + +typedef void (*OSInterruptHandler)(__OSInterrupt, OSContext*); + +extern volatile u32 __OSLastInterruptSrr0; +extern volatile s16 __OSLastInterrupt; +extern volatile s64 __OSLastInterruptTime; void __RAS_OSDisableInterrupts_begin(void); void __RAS_OSDisableInterrupts_end(void); -#endif \ No newline at end of file +BOOL OSDisableInterrupts(void); +BOOL OSEnableInterrupts(void); +BOOL OSRestoreInterrupts(BOOL); + +OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt, OSInterruptHandler); +OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt); + +void __OSInterruptInit(void); + +u32 __OSMaskInterrupts(u32); +u32 __OSUnmaskInterrupts(u32); + +u32 SetInterruptMask(OSInterruptMask mask, OSInterruptMask current); +void __OSDispatchInterrupt(OSException exception, OSContext* context); + +#endif diff --git a/include/dolphin/os/OSRtc.h b/include/dolphin/os/OSRtc.h index 9c0912c3..4edc389c 100644 --- a/include/dolphin/os/OSRtc.h +++ b/include/dolphin/os/OSRtc.h @@ -1,9 +1,111 @@ -#ifndef OS_RTC_H -#define OS_RTC_H +#ifndef DOLPHIN_OSRTC_H +#define DOLPHIN_OSTRC_H #include "types.h" +#include "dolphin/os/OSExi.h" -u32 __OSSyncSram(void); -void __OSSetBootMode(u8); +#ifdef __cplusplus +extern "C" { +#endif -#endif \ No newline at end of file +#define OS_SOUND_MODE_MONO 0 +#define OS_SOUND_MODE_STEREO 1 + +#define OS_PROGRESSIVE_MODE_OFF 0 +#define OS_PROGRESSIVE_MODE_ON 1 + +#define OS_BOOT_MODE_DEBUG (0 << 7) +#define OS_BOOT_MODE_RETAIL (1 << 7) + +#define RTC_CMD_READ 0x20000000 +#define RTC_CMD_WRITE 0xA0000000 + +#define RTC_SRAM_ADDR 0x00000100 +#define RTC_SRAM_SIZE 64 + +#define RTC_CHAN EXI_CHAN_0 +#define RTC_DEVICE 1 +#define RTC_FREQUENCY 3 + +typedef struct OSSram_s { + u16 checkSum; + u16 checkSumInv; + u32 ead0; + u32 ead1; + u32 counterBias; + s8 displayOffsetH; + u8 ntd; + u8 language; + u8 flags; +} OSSram; + +typedef struct OSSramEx_s { + u8 flashID[2][12]; + u32 wirelessKeyboardID; + u16 wirelessPadID[4]; + u8 dvdErrorCode; + u8 pad0; + u8 flashIDCheckSum[2]; + u16 gbs; + u8 pad1[2]; +} OSSramEx; + +typedef struct SramControlBlock_s { + u8 sram[RTC_SRAM_SIZE]; + u32 offset; + BOOL enabled; + BOOL locked; + BOOL sync; + void (*callback)(void); +} SramControlBlock; + +// static void GetRTC(); +// extern void __OSGetRTC(); +// extern void __OSSetRTC(); +static inline BOOL ReadSram(void* buffer); +static void WriteSramCallback(EXIChannel chan, OSContext* ctx); +static BOOL WriteSram(void* buffer, u32 offset, u32 size); +extern void __OSInitSram(); +static inline void* LockSram(u32 offset); +extern OSSram* __OSLockSram(); +extern OSSramEx* __OSLockSramEx(); +static BOOL UnlockSram(BOOL commit, u32 offset); +extern void __OSUnlockSram(BOOL commit); +extern void __OSUnlockSramEx(BOOL commit); +extern BOOL __OSSyncSram(); +// extern void __OSCheckSram(); +// extern void __OSReadROM(); +// extern void __OSReadROMCallback(); +// extern void __OSReadROMAsync(); +extern u32 OSGetSoundMode(); +extern void OSSetSoundMode(u32 mode); +extern u32 OSGetProgressiveMode(); +extern void OSSetProgressiveMode(u32 on); +// extern void OSGetVideoMode(); +// extern void OSSetVideoMode(); +// extern void OSGetLanguage(); +// extern void OSSetLanguage(); +// extern void __OSGetBootMode(); +extern void __OSSetBootMode(u8 mode); +// extern void OSGetEuRgb60Mode(); +// extern void OSSetEuRgb60Mode(); +extern u16 OSGetWirelessID(u32 chan); +extern void OSSetWirelessID(u32 chan, u16 id); + +#define GET_SOUNDMODE(flags) ((flags) & (1 << 2)) +#define CLR_SOUNDMODE(flags) ((flags) & (~(1 << 2))) +#define SET_SOUNDMODE(mode) (((mode) & 1) << 2) + +#define GET_PROGMODE(flags) ((flags) & (1 << 7)) +#define CLR_PROGMODE(flags) ((flags) & (~(1 << 7))) +#define SET_PROGMODE(mode) (((mode) & 1) << 7) + +#define GET_BOOTMODE(flags) ((flags) & (1 << 7)) +#define CLR_BOOTMODE(flags) ((flags) & (~(1 << 7))) +#define SET_BOOTMODE(mode) (mode) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/libforest/osreport.h b/include/libforest/osreport.h index 8506708a..aeabc687 100644 --- a/include/libforest/osreport.h +++ b/include/libforest/osreport.h @@ -1,19 +1,39 @@ -#ifndef LIB_OS_REPORT_H -#define LIB_OS_REPORT_H +#ifndef OSREPORT_H +#define OSREPORT_H #include "types.h" #include "va_args.h" +#include "dolphin/os/OSMutex.h" +#include "dolphin/os/OSThread.h" -void OSReportDisable(void); -void OSReportEnable(void); +#define DEBUG_MODE 0 +#define RETAIL_MODE 1 -void OSVReport(const char*, va_list); +/* Causes DSI exception */ +#define OSThrow() (*(int*)0 = 0) -void OSReport(const char*,...); -void OSPanic(const char*, u32, const char*,...); +extern void my_fopen(); /* @unused */ +extern void my_fgets(); /* @unused */ +extern void my_fclose(); /* @unused */ +extern void print_section(); /* @unused */ +extern void* OSGetCallerPC(); /* @unused */ +extern void OSDumpStackTrace(); /* @unused */ +extern s32 OSGetActiveThreadID(); /* @unused */ +extern void OSReportMonopoly(); /* @unused */ -void OSChangeBootMode(u32); +extern void OSReportDisable(); +extern void OSReportEnable(); +//void OSVReport(const char* fmt, va_list list); +//void OSReport(const char* fmt, ...); +//void OSPanic(const char* file, u32 line, const char* fmt, ...); +extern void OSChangeBootMode(u32 mode); +extern void OSDVDFatalError(); -void OSDVDFatalError(void); +#define OSChangeToRetail() (OSChangeBootMode(RETAIL_MODE)) +#define OSChangeToDebug() (OSChangeBootMode(DEBUG_MODE)) -#endif \ No newline at end of file +static BOOL __OSReport_disable; +static OSThread* __OSReport_MonopolyThread; +static u8 print_mutex_initialized; + +#endif diff --git a/include/types.h b/include/types.h index fac36120..db668305 100644 --- a/include/types.h +++ b/include/types.h @@ -38,6 +38,18 @@ typedef u32 unknown; #define NULL ((void*)0) #define nullptr 0 +#define AT_ADDRESS(x) : (x) + +#ifndef ATTRIBUTE_ALIGN +#if defined(__MWERKS__) || defined(__GNUC__) +#define ATTRIBUTE_ALIGN(num) __attribute__((aligned(num))) +#elif defined(_MSC_VER) +#define ATTRIBUTE_ALIGN(num) +#else +#error unknown compiler +#endif +#endif + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) diff --git a/src/dolphin/os/OSRtc.c b/src/dolphin/os/OSRtc.c new file mode 100644 index 00000000..9a125d91 --- /dev/null +++ b/src/dolphin/os/OSRtc.c @@ -0,0 +1,230 @@ +#include "dolphin/os/OSRtc.h" + +#include "dolphin/os/OSCache.h" +#include "dolphin/os/OSExi.h" +#include "dolphin/os.h" +#include "types.h" + +static SramControlBlock Scb ATTRIBUTE_ALIGN(32); + +static inline BOOL ReadSram(void* buffer) { + u32 cmd; + BOOL err; + + DCInvalidateRange(buffer, RTC_SRAM_SIZE); + + if (!EXILock(RTC_CHAN, RTC_DEVICE, NULL)) { + return FALSE; + } + + if (!EXISelect(RTC_CHAN, RTC_DEVICE, RTC_FREQUENCY)) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + cmd = RTC_CMD_READ | RTC_SRAM_ADDR; + err = !EXIImm(RTC_CHAN, &cmd, sizeof(u32), EXI_WRITE, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDma(RTC_CHAN, buffer, RTC_SRAM_SIZE, EXI_READ, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + + return !err; +} + +void WriteSramCallback(EXIChannel chan, OSContext* ctx) { + DOLPHIN_ASSERTLINE(!Scb.locked, 258); + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); + DOLPHIN_ASSERTLINE(Scb.sync, 264); + + if (Scb.sync) { + Scb.offset = RTC_SRAM_SIZE; + } +} + +static BOOL WriteSram(void* buffer, u32 offset, u32 size) { + u32 cmd; + BOOL err; + + if (EXILock(RTC_CHAN, 1, WriteSramCallback) == FALSE) { + return FALSE; + } + + if (EXISelect(RTC_CHAN, RTC_DEVICE, RTC_FREQUENCY) == FALSE) { + EXIUnlock(RTC_CHAN); + return FALSE; + } + + offset *= RTC_SRAM_SIZE; + cmd = offset + RTC_SRAM_ADDR | RTC_CMD_WRITE; + err = !EXIImm(RTC_CHAN, &cmd, sizeof(u32), EXI_WRITE, NULL); + err |= !EXISync(RTC_CHAN); + err |= !EXIImmEx(RTC_CHAN, buffer, size, EXI_WRITE); + err |= !EXIDeselect(RTC_CHAN); + EXIUnlock(RTC_CHAN); + return !err; +} + +extern void __OSInitSram() { + Scb.enabled = FALSE; + Scb.locked = FALSE; + Scb.sync = ReadSram(Scb.sram); + DOLPHIN_ASSERTLINE(Scb.sync, 318); + Scb.offset = RTC_SRAM_SIZE; +} + +static inline void* LockSram(u32 offset) { + BOOL enabled = OSDisableInterrupts(); + + DOLPHIN_ASSERTLINE(Scb.locked, 341); + if (Scb.locked != FALSE) { + OSRestoreInterrupts(enabled); + return NULL; + } + + Scb.enabled = enabled; + Scb.locked = TRUE; + return Scb.sram + offset; +} + +extern OSSram* __OSLockSram() { + return (OSSram*)LockSram(0); + //return sram; +} + +extern OSSramEx* __OSLockSramEx() { + return (OSSramEx*)LockSram(sizeof(OSSram)); + //return sramEx; +} + +static BOOL UnlockSram(BOOL commit, u32 offset) { + u16* chksum_p; + + DOLPHIN_ASSERTLINE(Scb.locked, 375); + if (commit) { + if (offset == 0) { + OSSram* sram = (OSSram*)Scb.sram; + if ((sram->flags & 3u) > 2u) { + sram->flags &= (~3u); + } + + sram->checkSum = sram->checkSumInv = 0; + for (chksum_p = (u16*)&sram->counterBias; chksum_p < (u16*)(Scb.sram + sizeof(OSSram)); chksum_p++) { + sram->checkSum += *chksum_p; + sram->checkSumInv += ~*chksum_p; + } + } + + if (offset < Scb.offset) { + Scb.offset = offset; + } + + Scb.sync = WriteSram(Scb.sram + Scb.offset, Scb.offset, RTC_SRAM_SIZE - Scb.offset); + if (Scb.sync) { + Scb.offset = RTC_SRAM_SIZE; + } + } + + Scb.locked = FALSE; + OSRestoreInterrupts(Scb.enabled); + return Scb.sync; +} + +extern void __OSUnlockSram(BOOL commit) { + UnlockSram(commit, 0); +} + +extern void __OSUnlockSramEx(BOOL commit) { + UnlockSram(commit, sizeof(OSSram)); +} + +extern BOOL __OSSyncSram() { + return Scb.sync; +} + +extern u32 OSGetSoundMode() { + OSSram* sram = __OSLockSram(); + u32 mode = GET_SOUNDMODE(sram->flags) ? OS_SOUND_MODE_STEREO : OS_SOUND_MODE_MONO; + __OSUnlockSram(FALSE); + return mode; +} + +extern void OSSetSoundMode(u32 mode) { + u32 flag; + OSSram* sram; + u32 m; + + DOLPHIN_ASSERTLINE(mode == OS_SOUND_MODE_MONO || mode == OS_SOUND_MODE_STEREO, 617); + flag = SET_SOUNDMODE(mode); + sram = (OSSram*)__OSLockSram(); + if (flag == GET_SOUNDMODE(sram->flags)) { + __OSUnlockSram(FALSE); + } + else { + sram->flags = CLR_SOUNDMODE(sram->flags); + sram->flags |= flag; + __OSUnlockSram(TRUE); + } +} + +extern u32 OSGetProgressiveMode() { + OSSram* sram = __OSLockSram(); + u32 mode = GET_PROGMODE(sram->flags) >> 7; + __OSUnlockSram(FALSE); + return mode; +} + +extern void OSSetProgressiveMode(u32 on) { + u32 flag; + OSSram* sram; + u32 m; + + DOLPHIN_ASSERTLINE(on == OS_PROGRESSIVE_MODE_OFF || on == OS_PROGRESSIVE_MODE_ON, 670); + flag = SET_PROGMODE(on); + sram = __OSLockSram(); + + if (flag == GET_PROGMODE(sram->flags)) { + __OSUnlockSram(FALSE); + } + else { + sram->flags = CLR_PROGMODE(sram->flags); + sram->flags |= flag; + __OSUnlockSram(TRUE); + } +} + +extern void __OSSetBootMode(u8 mode) { + OSSram* sram; + u32 m; + + mode &= OS_BOOT_MODE_RETAIL; + sram = __OSLockSram(); + if (mode == (u32)GET_BOOTMODE(sram->ntd)) { + __OSUnlockSram(FALSE); + } + else { + sram->ntd = CLR_BOOTMODE(sram->ntd); + sram->ntd |= mode; + __OSUnlockSram(TRUE); + } +} + +extern u16 OSGetWirelessID(u32 chan) { + OSSramEx* sramEx = __OSLockSramEx(); + u16 id = sramEx->wirelessPadID[chan]; + __OSUnlockSramEx(FALSE); + return id; +} + +extern void OSSetWirelessID(u32 chan, u16 id) { + OSSramEx* sramEx = __OSLockSramEx(); + if (sramEx->wirelessPadID[chan] != id) { + sramEx->wirelessPadID[chan] = id; + __OSUnlockSramEx(TRUE); + } + else { + __OSUnlockSramEx(FALSE); + } +} + diff --git a/src/libforest/osreport.c b/src/libforest/osreport.c index a7524a30..b72761ab 100644 --- a/src/libforest/osreport.c +++ b/src/libforest/osreport.c @@ -1,60 +1,55 @@ #include "libforest/osreport.h" #include "dolphin/os/OSInterrupt.h" -#include "dolphin/os/OSThread.h" #include "dolphin/os/OSRtc.h" -#include "dolphin/os/OSMutex.h" + #include "MSL_C/printf.h" OSMutex print_mutex; -u8 print_mutex_initialized; -static void* __OSReport_MonopolyThread; -static s32 __OSReport_disable; - -void OSReportDisable (void){ - __OSReport_disable = 1; +extern void OSReportDisable() { + __OSReport_disable = TRUE; } -void OSReportEnable (void){ - __OSReport_disable = 0; +extern void OSReportEnable() { + __OSReport_disable = FALSE; } -void OSVReport(const char* fmt, va_list list){ - +void OSVReport(const char* fmt, va_list list) { OSThread* cur_thread; u32 enable; - if(__OSReport_disable == 0){ + + if (__OSReport_disable == FALSE) { cur_thread = OSGetCurrentThread(); - if((cur_thread != NULL) && (cur_thread->state !=2)) { + if ((cur_thread != NULL) && (cur_thread->state != (u32)OS_THREAD_STATE_RUNNING)) { cur_thread = NULL; } - if((__OSReport_MonopolyThread == NULL) || (__OSReport_MonopolyThread == cur_thread)){ + if ((__OSReport_MonopolyThread == NULL) || (__OSReport_MonopolyThread == cur_thread)) { enable = OSDisableInterrupts(); - if(print_mutex_initialized == 0){ + if (print_mutex_initialized == FALSE) { OSInitMutex(&print_mutex); - print_mutex_initialized = 1; + print_mutex_initialized = TRUE; printf("*** OSVReport - OSInitMutex ***"); } OSRestoreInterrupts(enable); - if(cur_thread != NULL){ + if (cur_thread != NULL) { OSLockMutex(&print_mutex); } vprintf(fmt, list); - if(cur_thread != NULL){ + if (cur_thread != NULL) { OSUnlockMutex(&print_mutex); } } } } -void OSReport(const char* fmt,...){ - va_list list; - va_start(list, fmt); - OSVReport(fmt, list); - va_end(list); +void OSReport(const char* fmt, ...) { + va_list arg; + va_start(arg, fmt); + OSVReport(fmt, arg); + va_end(arg); } -void OSPanic(const char* file, u32 line, const char* fmt, ...){ +void OSPanic(const char* file, int line, const char* fmt, ...) { va_list list; u32 enable; OSThread* thread; @@ -68,21 +63,18 @@ void OSPanic(const char* file, u32 line, const char* fmt, ...){ thread = OSGetCurrentThread(); - OSSetThreadPriority(thread, 0x1f); + OSSetThreadPriority(thread, OS_PRIORITY_IDLE); OSRestoreInterrupts(enable); - *(int*)0 = 0; //why lol + OSThrow(); /* Stop processor execution forcefully */ } -void OSChangeBootMode(u32 mode){ - __OSSetBootMode(mode ? 0x80 : 0); - - while(__OSSyncSram() == 0) { } +extern void OSChangeBootMode(u32 mode) { + __OSSetBootMode(mode ? OS_BOOT_MODE_RETAIL : OS_BOOT_MODE_DEBUG); + while(__OSSyncSram() == FALSE) { } } -void OSDVDFatalError(void){ +extern void OSDVDFatalError(void) { OSReport("OSDVDFatalError called.\nExitThread.\n"); - OSExitThread(0); + OSExitThread(NULL); } - - diff --git a/tools/frank.py b/tools/frank.py new file mode 100644 index 00000000..489c8ec0 --- /dev/null +++ b/tools/frank.py @@ -0,0 +1,215 @@ +#! /usr/bin/env python3 + +# Written by Ethan Roseman (ethteck) +# MIT License +# Copyright 2021 + +# Modified by EpochFlame + +import argparse +import sys + +# Byte sequence that marks code size +CODESIZE_MAGIC = b"\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x34" +BLR_BYTE_SEQ = b"\x4E\x80\x00\x20" +MTLR_BYTE_SEQ = b"\x7C\x08\x03\xA6" +PROFILE_EXTRA_BYTES = b"\x48\x00\x00\x01\x60\x00\x00\x00" + +LWZ_BYTE = b"\x80" + +# Byte sequence array for branches to link register +BLR_BYTE_SEQ_ARRAY = [BLR_BYTE_SEQ, +b"\x4D\x80\x00\x20", b"\x4D\x80\x00\x21", b"\x4C\x81\x00\x20", b"\x4C\x81\x00\x21", +b"\x4D\x82\x00\x20", b"\x4D\x82\x00\x21", b"\x4C\x80\x00\x20", b"\x4C\x80\x00\x21", +b"\x4D\x81\x00\x20", b"\x4D\x81\x00\x21", b"\x4C\x80\x00\x20", b"\x4C\x80\x00\x21", +b"\x4C\x82\x00\x20", b"\x4C\x82\x00\x21", b"\x4C\x81\x00\x20", b"\x4C\x81\x00\x21", +b"\x4D\x83\x00\x20", b"\x4D\x83\x00\x21", b"\x4C\x83\x00\x20", b"\x4C\x83\x00\x21", +b"\x4D\x83\x00\x20", b"\x4D\x83\x00\x21", b"\x4C\x83\x00\x20", b"\x4C\x83\x00\x21"] + +# Example invocation: ./frank.py vanilla.o profile.o output.o +parser = argparse.ArgumentParser() +parser.add_argument("vanilla", help="Path to the vanilla object", type=argparse.FileType('rb')) +parser.add_argument("profile", help="Path to the profile object", type=argparse.FileType('rb')) +parser.add_argument("target", help="Path to the target object (to write)") + +args = parser.parse_args() + +# Read contents into bytearrays and close files +vanilla_bytes = args.vanilla.read() +args.vanilla.close() + +# If the file contains no code, the codesize magic will not be found. +# The vanilla object requires no modification. +code_size_magic_idx = vanilla_bytes.find(CODESIZE_MAGIC) +if code_size_magic_idx == -1: + with open(args.target, "wb") as f: + f.write(vanilla_bytes) + sys.exit(0) + +profile_bytes = args.profile.read() +args.profile.close() + +# Peephole rescheduling +# +# This is the pattern we will detect: +# (A) lwz <--. .--> (A) li +# (B) li <---\-' bl +# \ nop +# '---> (B) lwz +# +# If the profiled schedule swaps the +# instructions around the bl/nop, we +# instead use the vanilla schedule. +# +idx = 8 +shift = 0 # difference between vanilla and profile code, due to bl/nops +while idx < len(profile_bytes) - 16: + # Find next epilogue + epi_pos = profile_bytes.find(PROFILE_EXTRA_BYTES, idx) + if epi_pos == -1: + break # break while loop when no targets remain + if epi_pos % 4 != 0: # check 4-byte alignment + idx += 4 + continue + + v_pos = epi_pos - shift + shift += 8 + + vanilla_inst_a = vanilla_bytes[v_pos-4:v_pos] + vanilla_inst_b = vanilla_bytes[v_pos:v_pos+4] + vanilla_inst_c = vanilla_bytes[v_pos+4:v_pos+8] + profile_inst_a = profile_bytes[epi_pos-4:epi_pos] + profile_inst_b = profile_bytes[epi_pos+8:epi_pos+12] + profile_inst_c = profile_bytes[epi_pos+12:epi_pos+16] + + opcode_a = vanilla_inst_a[0] >> 2 + opcode_b = vanilla_inst_b[0] >> 2 + opcode_c = vanilla_inst_c[0] >> 2 + + LWZ = 0x80 >> 2 + LFS = 0xC0 >> 2 + ADDI = 0x38 >> 2 + LI = ADDI # an LI instruction is just an ADDI with RA=0 + LMW = 0xB8 >> 2 + FDIVS = 0xEC >> 2 + + # Adjust LWZ and LMW loading from r1. + if opcode_a in [LWZ, LMW] and vanilla_inst_a[2] == 0x00 and \ + opcode_b in [LI, LFS, FDIVS] and \ + vanilla_inst_a == profile_inst_b and \ + vanilla_inst_b == profile_inst_a and \ + vanilla_inst_c == profile_inst_c and \ + opcode_c != ADDI: # <- don't reorder if at the very end of the epilogue + + # Swap instructions (A) and (B) + profile_bytes = profile_bytes[:epi_pos-4] \ + + vanilla_inst_a \ + + PROFILE_EXTRA_BYTES \ + + vanilla_inst_b \ + + profile_bytes[epi_pos+12:] + + # Similar reordering for lwz/lmw, except both insns follow the bl/nop + elif opcode_b == LWZ and \ + opcode_c == LMW and \ + vanilla_inst_b == profile_inst_c and \ + vanilla_inst_c == profile_inst_b: + + profile_bytes = profile_bytes[:epi_pos+8] \ + + vanilla_inst_b \ + + vanilla_inst_c \ + + profile_bytes[epi_pos+16:] + + idx = epi_pos + 8 + +# Remove byte sequence +stripped_bytes = profile_bytes.replace(PROFILE_EXTRA_BYTES, b"") + +# Find end of code sections in vanilla and stripped bytes +code_size_offset = code_size_magic_idx + len(CODESIZE_MAGIC) +code_size_bytes = vanilla_bytes[code_size_offset:code_size_offset+4] +code_size = int.from_bytes(code_size_bytes, byteorder='big') + +eoc_offset = 0x34 + code_size + +# Break if the eoc is not found +assert(eoc_offset != len(vanilla_bytes)) + +# Replace 0x34 - eoc in vanilla with bytes from stripped +final_bytes = vanilla_bytes[:0x34] + stripped_bytes[0x34:eoc_offset] + vanilla_bytes[eoc_offset:] + +# Fix branches to link register +for seq in BLR_BYTE_SEQ_ARRAY: + idx = 0 + + while idx < len(vanilla_bytes): + found_pos = vanilla_bytes.find(seq, idx) + if found_pos == -1: + break # break while loop when no targets remain + if found_pos % 4 != 0: # check 4-byte alignment + idx += 4 + continue + final_bytes = final_bytes[:found_pos] + vanilla_bytes[found_pos:found_pos+4] + final_bytes[found_pos+4:] + idx = found_pos + len(seq) + +# Reunify mtlr/blr instructions, shifting intermediary instructions up +idx = 0 + +while idx < len(final_bytes): + # Find mtlr position + mtlr_found_pos = final_bytes.find(MTLR_BYTE_SEQ, idx) + if mtlr_found_pos == -1: + break # break while loop when no targets remain + if mtlr_found_pos % 4 != 0: # check 4-byte alignment + idx += 4 + continue + # Find paired blr position + blr_found_pos = final_bytes.find(BLR_BYTE_SEQ, mtlr_found_pos) + if blr_found_pos == -1: + break # break while loop when no targets remain + if blr_found_pos % 4 != 0: # check 4-byte alignment + idx += 4 + continue + if mtlr_found_pos + 4 == blr_found_pos: + idx += 4 + continue # continue if mtlr is followed directly by blr + + final_bytes = final_bytes[:mtlr_found_pos] + final_bytes[mtlr_found_pos+4:blr_found_pos] + final_bytes[mtlr_found_pos:mtlr_found_pos+4] + final_bytes[blr_found_pos:] + idx = mtlr_found_pos + len(MTLR_BYTE_SEQ) + +# Reorder lmw/lwz/lfd instructions, if needed (@Altafen) +# Specifically, if this sequence shows up in the stripped profiler code: "LMW, LWZ, LFD*" +# And this sequence shows up in the vanilla code: "LWZ, LFD*, LMW" +# (LFD* = any number of LFDs, including zero) +# If all bytes match between the two (except for the reordering), then use the vanilla ordering. +# This could be written to anchor around the "BL, NOP" instructions in unstripped profiler code, +# or to check for the presence of "ADDI, MTLR, BLR" soon after. +# This also could be written to decode the operands of each instruction to make sure the reorder is harmless. +# Neither of these safeguards are necessary at the moment. +LWZ = 32 +LMW = 46 +LFD = 50 +idx = 0 +while idx+4 < len(final_bytes): + if final_bytes[idx] >> 2 == LMW and final_bytes[idx+4] >> 2 == LWZ and vanilla_bytes[idx] >> 2 == LWZ: + start_idx = idx + lmw_bytes = final_bytes[idx:idx+4] + lwz_bytes = final_bytes[idx+4:idx+8] + if vanilla_bytes[idx:idx+4] != lwz_bytes: + idx += 4 + continue + lfd_bytes = b"" + idx += 4 + while vanilla_bytes[idx] >> 2 == LFD: + lfd_bytes += vanilla_bytes[idx:idx+4] + idx += 4 + if vanilla_bytes[idx:idx+4] != lmw_bytes: + continue + if final_bytes[start_idx+8:start_idx+8+len(lfd_bytes)] != lfd_bytes: + continue + idx += 4 + final_bytes = final_bytes[:start_idx] + lwz_bytes + lfd_bytes + lmw_bytes + final_bytes[idx:] + continue + idx += 4 + +with open(args.target, "wb") as f: + f.write(final_bytes) diff --git a/tools/franklite.py b/tools/franklite.py new file mode 100644 index 00000000..ef8f2c8a --- /dev/null +++ b/tools/franklite.py @@ -0,0 +1,52 @@ +#! /usr/bin/env python3 + +# Written by Ethan Roseman (ethteck) +# MIT License +# Copyright 2021 + +# Modified by EpochFlame + +import argparse + +# Byte sequences +BLR_BYTE_SEQ = b"\x4E\x80\x00\x20" +MTLR_BYTE_SEQ = b"\x7C\x08\x03\xA6" + +# Example invocation: ./frank.py vanilla.o profile.o output.o +parser = argparse.ArgumentParser() +parser.add_argument("vanilla", help="Path to the vanilla object", type=argparse.FileType('rb')) +parser.add_argument("target", help="Path to the target object (to write)") + +args = parser.parse_args() + +# Read contents into bytearrays and close files +vanilla_bytes = args.vanilla.read() +args.vanilla.close() + +# Reunify mtlr/blr instructions, shifting intermediary instructions up +idx = 0 + +while idx < len(vanilla_bytes): + # Find mtlr position + mtlr_found_pos = vanilla_bytes.find(MTLR_BYTE_SEQ, idx) + if mtlr_found_pos == -1: + break # break while loop when no targets remain + if mtlr_found_pos % 4 != 0: # check 4-byte alignment + idx += 4 + continue + # Find paired blr position + blr_found_pos = vanilla_bytes.find(BLR_BYTE_SEQ, mtlr_found_pos) + if blr_found_pos == -1: + break # break while loop when no targets remain + if blr_found_pos % 4 != 0: # check 4-byte alignment + idx += 4 + continue + if mtlr_found_pos + 4 == blr_found_pos: + idx += 4 + continue # continue if mtlr is followed directly by blr + + vanilla_bytes = vanilla_bytes[:mtlr_found_pos] + vanilla_bytes[mtlr_found_pos+4:blr_found_pos] + vanilla_bytes[mtlr_found_pos:mtlr_found_pos+4] + vanilla_bytes[blr_found_pos:] + idx = mtlr_found_pos + len(MTLR_BYTE_SEQ) + +with open(args.target, "wb") as f: + f.write(vanilla_bytes)