ARM11 exception handlers (not working yet, it fails to retrieve the data after the reboot)
Uncomment the appropriate line in firm.c to test.
This commit is contained in:
parent
b77d619873
commit
2d7dde9cf9
9
Makefile
9
Makefile
@ -18,6 +18,7 @@ dir_source := source
|
|||||||
dir_patches := patches
|
dir_patches := patches
|
||||||
dir_loader := loader
|
dir_loader := loader
|
||||||
dir_arm9_exceptions := exceptions/arm9
|
dir_arm9_exceptions := exceptions/arm9
|
||||||
|
dir_arm11_exceptions := exceptions/arm11
|
||||||
dir_screeninit := screeninit
|
dir_screeninit := screeninit
|
||||||
dir_injector := injector
|
dir_injector := injector
|
||||||
dir_mset := CakeHax
|
dir_mset := CakeHax
|
||||||
@ -34,7 +35,7 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/injector.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
bundled = $(dir_build)/rebootpatch.h $(dir_build)/emunandpatch.h $(dir_build)/arm9_exceptions.h $(dir_build)/arm11_exceptions.h $(dir_build)/injector.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: launcher a9lh ninjhax
|
all: launcher a9lh ninjhax
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ clean:
|
|||||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
||||||
@$(MAKE) -C $(dir_loader) clean
|
@$(MAKE) -C $(dir_loader) clean
|
||||||
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
||||||
|
@$(MAKE) -C $(dir_arm11_exceptions) clean
|
||||||
@$(MAKE) -C $(dir_screeninit) clean
|
@$(MAKE) -C $(dir_screeninit) clean
|
||||||
@$(MAKE) -C $(dir_injector) clean
|
@$(MAKE) -C $(dir_injector) clean
|
||||||
@rm -rf $(dir_out) $(dir_build)
|
@rm -rf $(dir_out) $(dir_build)
|
||||||
@ -63,6 +65,7 @@ clean:
|
|||||||
$(dir_out):
|
$(dir_out):
|
||||||
@mkdir -p "$(dir_out)/luma/payloads"
|
@mkdir -p "$(dir_out)/luma/payloads"
|
||||||
@mkdir -p "$(dir_out)/luma/dumps/arm9"
|
@mkdir -p "$(dir_out)/luma/dumps/arm9"
|
||||||
|
@mkdir -p "$(dir_out)/luma/dumps/arm11"
|
||||||
|
|
||||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||||
@ -108,6 +111,10 @@ $(dir_build)/arm9_exceptions.h: $(dir_arm9_exceptions)/Makefile
|
|||||||
@$(MAKE) -C $(dir_arm9_exceptions)
|
@$(MAKE) -C $(dir_arm9_exceptions)
|
||||||
@bin2c -o $@ -n arm9_exceptions $(@D)/arm9_exceptions.bin
|
@bin2c -o $@ -n arm9_exceptions $(@D)/arm9_exceptions.bin
|
||||||
|
|
||||||
|
$(dir_build)/arm11_exceptions.h: $(dir_arm11_exceptions)/Makefile
|
||||||
|
@$(MAKE) -C $(dir_arm11_exceptions)
|
||||||
|
@bin2c -o $@ -n arm11_exceptions $(@D)/arm11_exceptions.bin
|
||||||
|
|
||||||
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
||||||
@$(MAKE) -C $(dir_screeninit)
|
@$(MAKE) -C $(dir_screeninit)
|
||||||
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
||||||
|
47
exceptions/arm11/Makefile
Normal file
47
exceptions/arm11/Makefile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
|
CC := arm-none-eabi-gcc
|
||||||
|
AS := arm-none-eabi-as
|
||||||
|
LD := arm-none-eabi-ld
|
||||||
|
OC := arm-none-eabi-objcopy
|
||||||
|
|
||||||
|
name := arm11_exceptions
|
||||||
|
|
||||||
|
dir_source := source
|
||||||
|
dir_build := build
|
||||||
|
|
||||||
|
ASFLAGS := -mcpu=mpcore -mfpu=vfp
|
||||||
|
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||||
|
LDFLAGS := -nostdlib
|
||||||
|
|
||||||
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: ../../$(dir_build)/$(name).bin
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
|
../../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf
|
||||||
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
|
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
|
include $(call rwildcard, $(dir_build), *.d)
|
11
exceptions/arm11/linker.ld
Normal file
11
exceptions/arm11/linker.ld
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0;
|
||||||
|
.text.start : { *(.text.start) }
|
||||||
|
.text : { *(.text) }
|
||||||
|
.data : { *(.data) }
|
||||||
|
.bss : { *(.bss COMMON) }
|
||||||
|
.rodata : { *(.rodata) }
|
||||||
|
. = ALIGN(4);
|
||||||
|
}
|
14
exceptions/arm11/source/handlers.h
Normal file
14
exceptions/arm11/source/handlers.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* handlers.h
|
||||||
|
* by TuxSH
|
||||||
|
*
|
||||||
|
* This is part of Luma3DS, see LICENSE.txt for details
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) mcuReboot(void);
|
||||||
|
void FIQHandler(void);
|
||||||
|
void undefinedInstructionHandler(void);
|
||||||
|
void dataAbortHandler(void);
|
||||||
|
void prefetchAbortHandler(void);
|
95
exceptions/arm11/source/handlers.s
Normal file
95
exceptions/arm11/source/handlers.s
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
@
|
||||||
|
@ handlers.s
|
||||||
|
@ by TuxSH
|
||||||
|
@
|
||||||
|
@ This is part of Luma3DS, see LICENSE.txt for details
|
||||||
|
@
|
||||||
|
|
||||||
|
.macro GEN_HANDLER name
|
||||||
|
.global \name
|
||||||
|
.type \name, %function
|
||||||
|
\name:
|
||||||
|
ldr sp, =#0xffff3000
|
||||||
|
stmfd sp!, {r0-r7}
|
||||||
|
mov r1, #\@ @ macro expansion counter
|
||||||
|
b _commonHandler
|
||||||
|
|
||||||
|
.size \name, . - \name
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.text
|
||||||
|
.arm
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global _commonHandler
|
||||||
|
.type _commonHandler, %function
|
||||||
|
_commonHandler:
|
||||||
|
clrex
|
||||||
|
cpsid aif
|
||||||
|
mrs r2, spsr
|
||||||
|
mov r6, sp
|
||||||
|
mrs r3, cpsr
|
||||||
|
|
||||||
|
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||||
|
moveq r4, #0xf @ usr => sys
|
||||||
|
bic r5, r3, #0xf
|
||||||
|
orr r5, r4
|
||||||
|
msr cpsr_c, r5 @ change processor mode
|
||||||
|
stmfd r6!, {r8-lr}
|
||||||
|
msr cpsr_c, r3 @ restore processor mode
|
||||||
|
mov sp, r6
|
||||||
|
vmrs r3, fpexc
|
||||||
|
|
||||||
|
cmp r1, #1
|
||||||
|
bne noFPUInit
|
||||||
|
tst r5, #0x20
|
||||||
|
bne noFPUInit
|
||||||
|
|
||||||
|
ldr r4, [lr, #-4]
|
||||||
|
lsl r4, #4
|
||||||
|
sub r4, #0xc0000000
|
||||||
|
cmp r4, #0x30000000
|
||||||
|
bcs noFPUInit
|
||||||
|
tst r3, #0x40000000
|
||||||
|
bne noFPUInit
|
||||||
|
|
||||||
|
sub lr, #4
|
||||||
|
srsfd sp!, #0x13
|
||||||
|
add sp, #28 @ restore context
|
||||||
|
ldmfd sp!, {r0-r7}
|
||||||
|
cps #0x13 @ FPU init
|
||||||
|
stmfd sp, {r0-r3, r11-lr}^
|
||||||
|
sub sp, #0x20
|
||||||
|
bl . @ will be replaced
|
||||||
|
ldmfd sp, {r0-r3, r11-lr}^
|
||||||
|
add sp, #0x20
|
||||||
|
rfefd sp!
|
||||||
|
|
||||||
|
noFPUInit:
|
||||||
|
stmfd sp!, {r2,lr} @ it's a bit of a mess, but we will fix that later
|
||||||
|
@ order of saved regs now: cpsr, pc + (2/4/8), r8-r14, r0-r7
|
||||||
|
|
||||||
|
ldr r4, =#0xdfff3ffc
|
||||||
|
ldr r5, =#0xffff0014
|
||||||
|
ldr r5, [r5] @ 0xeafffffe
|
||||||
|
mov r6, #0
|
||||||
|
poisonLoop:
|
||||||
|
str r5, [r4, #4]! @ poison exception vectors in order to hang the other threads
|
||||||
|
add r6, #1
|
||||||
|
cmp r6, #8
|
||||||
|
blt poisonLoop
|
||||||
|
|
||||||
|
mov r0, sp
|
||||||
|
mrc p15,0,r2,c0,c0,5 @ CPU ID register
|
||||||
|
|
||||||
|
b mainHandler
|
||||||
|
|
||||||
|
GEN_HANDLER FIQHandler
|
||||||
|
GEN_HANDLER undefinedInstructionHandler
|
||||||
|
GEN_HANDLER prefetchAbortHandler
|
||||||
|
GEN_HANDLER dataAbortHandler
|
||||||
|
|
||||||
|
.global mcuReboot
|
||||||
|
.type mcuReboot, %function
|
||||||
|
mcuReboot:
|
||||||
|
b . @ will be replaced
|
71
exceptions/arm11/source/mainHandler.c
Normal file
71
exceptions/arm11/source/mainHandler.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* mainHandler.c
|
||||||
|
* by TuxSH
|
||||||
|
*
|
||||||
|
* This is part of Luma3DS, see LICENSE.txt for details
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "handlers.h"
|
||||||
|
|
||||||
|
#define FINAL_BUFFER 0xE5000000 //0x25000000
|
||||||
|
|
||||||
|
#define REG_DUMP_SIZE (4*18)
|
||||||
|
#define CODE_DUMP_SIZE 48
|
||||||
|
#define STACK_DUMP_SIZE 0x2000
|
||||||
|
#define OTHER_DATA_SIZE 0
|
||||||
|
|
||||||
|
void __attribute__((noreturn)) mainHandler(u32 regs[18], u32 type, u32 cpuId, u32 fpexc)
|
||||||
|
{
|
||||||
|
u32 dump[(40 + REG_DUMP_SIZE + CODE_DUMP_SIZE) / 4];
|
||||||
|
vu32 *final = (vu32 *)FINAL_BUFFER;
|
||||||
|
|
||||||
|
while(final[0] == 0xDEADC0DE && final[1] == 0xDEADCAFE && ((final[3] & 0xFFFF) == 9 || (final[3] & 0xFFFF) == 11));
|
||||||
|
|
||||||
|
dump[0] = 0xDEADC0DE; //Magic
|
||||||
|
dump[1] = 0xDEADCAFE; //Magic
|
||||||
|
dump[2] = (1 << 16) | 0; //Dump format version number
|
||||||
|
dump[3] = ((cpuId & 0xf) << 16) | 11; //Processor
|
||||||
|
dump[4] = type; //Exception type
|
||||||
|
dump[6] = REG_DUMP_SIZE; //Register dump size (r0-r12, sp, lr, pc, cpsr, fpexc)
|
||||||
|
dump[7] = CODE_DUMP_SIZE; //Code dump size (10 ARM instructions, up to 20 Thumb instructions).
|
||||||
|
dump[8] = STACK_DUMP_SIZE; //Stack dump size
|
||||||
|
dump[9] = OTHER_DATA_SIZE; //Other data size
|
||||||
|
dump[5] = 40 + REG_DUMP_SIZE + CODE_DUMP_SIZE + STACK_DUMP_SIZE + OTHER_DATA_SIZE; //Total size
|
||||||
|
|
||||||
|
//Dump registers
|
||||||
|
//Current order of saved regs: cpsr, pc, r8-r12, sp, lr, r0-r7
|
||||||
|
u32 *regdump = dump + 10;
|
||||||
|
|
||||||
|
u32 cpsr = regs[0];
|
||||||
|
u32 pc = regs[1] - ((type < 3) ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
||||||
|
|
||||||
|
regdump[15] = pc;
|
||||||
|
regdump[16] = cpsr;
|
||||||
|
regdump[17] = fpexc;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 7; i++)
|
||||||
|
regdump[8 + i] = regs[2 + i];
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
regdump[i] = regs[9 + i];
|
||||||
|
|
||||||
|
//Dump code
|
||||||
|
u16 *codedump = (u16 *)(regdump + dump[6] / 4);
|
||||||
|
u16 *instr = (u16 *)pc - dump[7] / 2 + 1;
|
||||||
|
for(u32 i = 0; i < dump[7] / 2; i++)
|
||||||
|
codedump[i] = instr[i];
|
||||||
|
|
||||||
|
//Dump stack in place
|
||||||
|
vu32 *sp = (vu32 *)regdump[13];
|
||||||
|
vu32 *stackdump = (vu32 *)((vu8 *)FINAL_BUFFER + 40 + REG_DUMP_SIZE + CODE_DUMP_SIZE);
|
||||||
|
|
||||||
|
for(u32 i = 0; i < dump[8] / 4; i++)
|
||||||
|
stackdump[i] = sp[i];
|
||||||
|
|
||||||
|
for(u32 i = 0; i < (40 + REG_DUMP_SIZE + CODE_DUMP_SIZE) / 4; i++)
|
||||||
|
final[i] = dump[i];
|
||||||
|
|
||||||
|
while(final[0] != 0xDEADC0DE);
|
||||||
|
mcuReboot();
|
||||||
|
}
|
11
exceptions/arm11/source/start.s
Normal file
11
exceptions/arm11/source/start.s
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.section .text.start
|
||||||
|
.align 4
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
.word FIQHandler
|
||||||
|
.word undefinedInstructionHandler
|
||||||
|
.word prefetchAbortHandler
|
||||||
|
.word dataAbortHandler
|
13
exceptions/arm11/source/types.h
Normal file
13
exceptions/arm11/source/types.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//Common data types
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef volatile u8 vu8;
|
||||||
|
typedef volatile u16 vu16;
|
||||||
|
typedef volatile u32 vu32;
|
||||||
|
typedef volatile u64 vu64;
|
@ -67,7 +67,7 @@ def makeRegisterLine(A, rA, B, rB):
|
|||||||
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
|
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
|
||||||
|
|
||||||
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
|
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
|
||||||
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr")
|
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr", "fpexc")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
|
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
|
||||||
@ -80,23 +80,31 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
processor, exceptionType, _, _, codeDumpSize, stackDumpSize = unpack_from("<6I", data, 12)
|
processor, exceptionType, _, _, codeDumpSize, stackDumpSize = unpack_from("<6I", data, 12)
|
||||||
|
|
||||||
print("Processor: ARM{0}".format(processor))
|
if processor == 9: print("Processor: ARM9")
|
||||||
|
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
||||||
|
|
||||||
print("Exception type: {0}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType]))
|
print("Exception type: {0}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType]))
|
||||||
|
|
||||||
registers = unpack_from("<17I", data, 40)
|
registers = []
|
||||||
print("\nRegister dump:\n")
|
print("\nRegister dump:\n")
|
||||||
for i in range(0, 16, 2):
|
if processor == 9:
|
||||||
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
|
registers = unpack_from("<17I", data, 40)
|
||||||
print("{0:<15}{1:<20}".format(registerNames[-1], "{0:08x}".format(registers[-1])))
|
for i in range(0, 16, 2):
|
||||||
|
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
|
||||||
|
print("{0:<15}{1:<20}".format(registerNames[-2], "{0:08x}".format(registers[-1])))
|
||||||
|
else:
|
||||||
|
registers = unpack_from("<18I", data, 40)
|
||||||
|
for i in range(0, 18, 2):
|
||||||
|
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
|
||||||
|
|
||||||
codeDump = data[40+4*17 : 40+4*17 + codeDumpSize]
|
codeDump = data[40+4*len(registers) : 40+4*len(registers) + codeDumpSize]
|
||||||
print("\nCode dump:\n")
|
print("\nCode dump:\n")
|
||||||
print(hexdump(registers[15] - codeDumpSize + 2, codeDump))
|
print(hexdump(registers[15] - codeDumpSize + 2, codeDump))
|
||||||
|
|
||||||
# Homebrew/CFW set their stack at 0x27000000, let's detect it
|
# Homebrew/CFW set their stack at 0x27000000, let's detect it
|
||||||
if 0 <= 0x27000000 - registers[13] <= stackDumpSize: stackDumpSize = 0x27000000 - registers[13]
|
if 0 <= 0x27000000 - registers[13] <= stackDumpSize: stackDumpSize = 0x27000000 - registers[13]
|
||||||
|
|
||||||
stackOffset = 40+4*17 + codeDumpSize
|
stackOffset = 40+4*len(registers) + codeDumpSize
|
||||||
stackDump = data[stackOffset : stackOffset + stackDumpSize]
|
stackDump = data[stackOffset : stackOffset + stackDumpSize]
|
||||||
print("\nStack dump:\n")
|
print("\nStack dump:\n")
|
||||||
print(hexdump(registers[13], stackDump))
|
print(hexdump(registers[13], stackDump))
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "../build/arm9_exceptions.h"
|
#include "../build/arm9_exceptions.h"
|
||||||
|
#include "../build/arm11_exceptions.h"
|
||||||
|
|
||||||
|
|
||||||
#define _U __attribute__((unused)) //Silence "unused parameter" warnings
|
#define _U __attribute__((unused)) //Silence "unused parameter" warnings
|
||||||
static void __attribute__((naked)) setupStack(_U u32 mode, _U void* SP)
|
static void __attribute__((naked)) setupStack(_U u32 mode, _U void* SP)
|
||||||
@ -55,6 +57,40 @@ void installArm9Handlers(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||||
|
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||||
|
|
||||||
|
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr)
|
||||||
|
{
|
||||||
|
u32 *initFPU;
|
||||||
|
for(initFPU = exceptionsPage; initFPU < (exceptionsPage + 0x400) && (initFPU[0] != 0xE59F0008 || initFPU[1] != 0xE5900000); initFPU += 1);
|
||||||
|
|
||||||
|
u32 *mcuReboot;
|
||||||
|
for(mcuReboot = exceptionsPage; mcuReboot < (exceptionsPage + 0x400) && (mcuReboot[0] != 0xE59F4104 || mcuReboot[1] != 0xE3A0A0C2); mcuReboot += 1);
|
||||||
|
|
||||||
|
u32 *freeSpace;
|
||||||
|
for(freeSpace = initFPU; freeSpace < (exceptionsPage + 0x400) && (freeSpace[0] != 0xFFFFFFFF || freeSpace[1] != 0xFFFFFFFF); freeSpace += 1);
|
||||||
|
//freeSpace += 4 - ((u32)(freeSpace - exceptionsPage) & 3);
|
||||||
|
memcpy(freeSpace, arm11_exceptions + 20, arm11_exceptions_size - 20);
|
||||||
|
|
||||||
|
exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 8) - 20); //Undefined Instruction
|
||||||
|
exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 12) - 20); //Prefetch Abort
|
||||||
|
exceptionsPage[4] = MAKE_BRANCH(exceptionsPage + 4, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 16) - 20); //Data Abort
|
||||||
|
exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions + 4) - 20); //FIQ
|
||||||
|
|
||||||
|
for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_size - 20); pos++)
|
||||||
|
{
|
||||||
|
switch(*pos)
|
||||||
|
{
|
||||||
|
case 0xFFFF3000: *pos = stackAddr; break;
|
||||||
|
case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break;
|
||||||
|
case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break;
|
||||||
|
case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 20; break; // bx r12 (mainHandler)
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void hexItoa(u32 n, char *out)
|
static void hexItoa(u32 n, char *out)
|
||||||
{
|
{
|
||||||
const char hexDigits[] = "0123456789ABCDEF";
|
const char hexDigits[] = "0123456789ABCDEF";
|
||||||
@ -77,29 +113,43 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
|
|
||||||
const char *registerNames[] = {
|
const char *registerNames[] = {
|
||||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
|
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
|
||||||
"SP", "LR", "PC", "CPSR"
|
"SP", "LR", "PC", "CPSR", "FPEXC"
|
||||||
};
|
};
|
||||||
|
|
||||||
char hexstring[] = "00000000";
|
char hexstring[] = "00000000";
|
||||||
|
|
||||||
vu32 *dump = (u32 *)0x25000000;
|
vu32 *dump = (vu32 *)0x25000000;
|
||||||
|
|
||||||
if(dump[0] == 0xDEADC0DE && dump[1] == 0xDEADCAFE && dump[3] == 9)
|
if(dump[0] == 0xDEADC0DE && dump[1] == 0xDEADCAFE && (dump[3] == 9 || (dump[3] & 0xFFFF) == 11))
|
||||||
{
|
{
|
||||||
char path[41] = "/luma/dumps/arm9";
|
char path9[41] = "/luma/dumps/arm9";
|
||||||
|
char path11[42] = "/luma/dumps/arm11";
|
||||||
char fileName[] = "crash_dump_00000000.dmp";
|
char fileName[] = "crash_dump_00000000.dmp";
|
||||||
|
|
||||||
findDumpFile(path, fileName);
|
if(dump[3] == 9)
|
||||||
|
{
|
||||||
|
findDumpFile(path9, fileName);
|
||||||
|
path9[16] = '/';
|
||||||
|
memcpy(&path9[17], fileName, sizeof(fileName));
|
||||||
|
fileWrite((void *)dump, path9, dump[5]);
|
||||||
|
}
|
||||||
|
|
||||||
path[16] = '/';
|
else
|
||||||
memcpy(&path[17], fileName, sizeof(fileName));
|
{
|
||||||
|
findDumpFile(path11, fileName);
|
||||||
|
path11[17] = '/';
|
||||||
|
memcpy(&path11[18], fileName, sizeof(fileName));
|
||||||
|
fileWrite((void *)dump, path11, dump[5]);
|
||||||
|
}
|
||||||
|
|
||||||
fileWrite((void *)dump, path, dump[5]);
|
|
||||||
|
char arm11Str[] = "Processor: ARM11 (core X)";
|
||||||
|
if((dump[3] & 0xFFFF) == 11) arm11Str[28] = '0' + (char)(dump[3] >> 16);
|
||||||
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("An exception occurred", 10, 10, COLOR_RED);
|
drawString("An exception occurred", 10, 10, COLOR_RED);
|
||||||
int posY = drawString("Processor: ARM9", 10, 30, COLOR_WHITE) + SPACING_Y;
|
int posY = drawString(((dump[3] & 0xFFFF) == 11) ? arm11Str : "Processor: ARM9", 10, 30, COLOR_WHITE) + SPACING_Y;
|
||||||
posY = drawString("Exception type: ", 10, posY, COLOR_WHITE);
|
posY = drawString("Exception type: ", 10, posY, COLOR_WHITE);
|
||||||
posY = drawString(handledExceptionNames[dump[4]], 10 + 16 * SPACING_X, posY, COLOR_WHITE);
|
posY = drawString(handledExceptionNames[dump[4]], 10 + 16 * SPACING_X, posY, COLOR_WHITE);
|
||||||
|
|
||||||
@ -110,7 +160,7 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
hexItoa(dump[10 + i], hexstring);
|
hexItoa(dump[10 + i], hexstring);
|
||||||
posY = drawString(hexstring, 10 + 7 * SPACING_X, posY, COLOR_WHITE);
|
posY = drawString(hexstring, 10 + 7 * SPACING_X, posY, COLOR_WHITE);
|
||||||
|
|
||||||
if(i != 16)
|
if(dump[3] != 9 || i != 16)
|
||||||
{
|
{
|
||||||
posY = drawString(registerNames[i + 1], 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
posY = drawString(registerNames[i + 1], 10 + 22 * SPACING_X, posY, COLOR_WHITE);
|
||||||
hexItoa(dump[10 + i + 1], hexstring);
|
hexItoa(dump[10 + i + 1], hexstring);
|
||||||
@ -122,7 +172,7 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
|
|
||||||
posY += 2 * SPACING_Y;
|
posY += 2 * SPACING_Y;
|
||||||
posY = drawString("You can find a dump in the following file:", 10, posY, COLOR_WHITE) + SPACING_Y;
|
posY = drawString("You can find a dump in the following file:", 10, posY, COLOR_WHITE) + SPACING_Y;
|
||||||
posY = drawString(path, 10, posY, COLOR_WHITE) + 2 * SPACING_Y;
|
posY = drawString((dump[3] == 9) ? path9 : path11, 10, posY, COLOR_WHITE) + 2 * SPACING_Y;
|
||||||
drawString("Press any button to shutdown", 10, posY, COLOR_WHITE);
|
drawString("Press any button to shutdown", 10, posY, COLOR_WHITE);
|
||||||
|
|
||||||
waitInput();
|
waitInput();
|
||||||
|
@ -8,4 +8,5 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void installArm9Handlers(void);
|
void installArm9Handlers(void);
|
||||||
|
void installArm11Handlers(u32 *exceptionsPage, u32 stackAddr);
|
||||||
void detectAndProcessExceptionDumps(void);
|
void detectAndProcessExceptionDumps(void);
|
@ -332,6 +332,11 @@ static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhMode)
|
|||||||
//Apply UNITINFO patch
|
//Apply UNITINFO patch
|
||||||
if(DEVMODE == 2) patchUnitInfoValueSet(arm9Section, section[2].size);
|
if(DEVMODE == 2) patchUnitInfoValueSet(arm9Section, section[2].size);
|
||||||
|
|
||||||
|
//Install arm11 exception handlers
|
||||||
|
u32 stackAddress;
|
||||||
|
u32 *exceptionsPage = getInfoForArm11ExceptionHandlers(arm11Section1, section[1].size, &stackAddress);
|
||||||
|
//installArm11Handlers(exceptionsPage, stackAddress);
|
||||||
|
|
||||||
//Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
|
//Make FCRAM (and VRAM as a side effect) globally executable from arm11 kernel
|
||||||
patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size);
|
patchKernelFCRAMAndVRAMMappingPermissions(arm11Section1, section[1].size);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "../build/rebootpatch.h"
|
#include "../build/rebootpatch.h"
|
||||||
|
|
||||||
|
static u32 *exceptionsPage = NULL;
|
||||||
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||||
{
|
{
|
||||||
u8 *off = memsearch(pos, "ess9", size, 4);
|
u8 *off = memsearch(pos, "ess9", size, 4);
|
||||||
@ -18,6 +20,20 @@ u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
|||||||
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
|
return off - 0x204 + (*(u32 *)(off - 0x64) * 0x200) + 0x200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr)
|
||||||
|
{
|
||||||
|
//This function has to succeed. Crash if it doesn't (we'll get an exception dump of it anyways)
|
||||||
|
|
||||||
|
const u8 callExceptionDispatcherPattern[] = {0x0F, 0x00, 0xBD, 0xE8, 0x13, 0x00, 0x02, 0xF1};
|
||||||
|
const u8 exceptionsPagePattern[] = {0x00, 0xB0, 0x9C, 0xE5};
|
||||||
|
|
||||||
|
*stackAddr = *((u32 *)memsearch(pos, callExceptionDispatcherPattern, size, 8) + 3);
|
||||||
|
|
||||||
|
if(exceptionsPage == NULL) exceptionsPage = (u32 *)memsearch(pos, exceptionsPagePattern, size, 4) - 0xB;
|
||||||
|
|
||||||
|
return exceptionsPage;
|
||||||
|
}
|
||||||
|
|
||||||
void patchSignatureChecks(u8 *pos, u32 size)
|
void patchSignatureChecks(u8 *pos, u32 size)
|
||||||
{
|
{
|
||||||
const u16 sigPatch[2] = {0x2000, 0x4770};
|
const u16 sigPatch[2] = {0x2000, 0x4770};
|
||||||
@ -152,7 +168,7 @@ void reimplementSvcBackdoor(u8 *pos, u32 size)
|
|||||||
|
|
||||||
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
|
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; //cpsid aif
|
||||||
|
|
||||||
u32 *exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
|
if(exceptionsPage == NULL) exceptionsPage = (u32 *)memsearch(pos, pattern, size, 4) - 0xB;
|
||||||
|
|
||||||
u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
u32 svcOffset = (-((exceptionsPage[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||||
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
|
u32 *svcTable = (u32 *)(pos + *(u32 *)(pos + 0xFFFF0008 - svcOffset - 0xFFF00000 + 8) - 0xFFF00000); //SVC handler address
|
||||||
|
@ -16,6 +16,7 @@ typedef struct patchData {
|
|||||||
} patchData;
|
} patchData;
|
||||||
|
|
||||||
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||||
|
u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr);
|
||||||
void patchSignatureChecks(u8 *pos, u32 size);
|
void patchSignatureChecks(u8 *pos, u32 size);
|
||||||
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
|
void patchTitleInstallMinVersionCheck(u8 *pos, u32 size);
|
||||||
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
void patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
||||||
|
Reference in New Issue
Block a user