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:
TuxSH
2016-06-02 22:33:44 +02:00
parent b77d619873
commit 2d7dde9cf9
14 changed files with 375 additions and 25 deletions

47
exceptions/arm11/Makefile Normal file
View 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)

View File

@@ -0,0 +1,11 @@
ENTRY(_start)
SECTIONS
{
. = 0;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

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

View 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

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

View 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

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

View File

@@ -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))
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__":
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
@@ -80,23 +80,31 @@ if __name__ == "__main__":
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]))
registers = unpack_from("<17I", data, 40)
registers = []
print("\nRegister dump:\n")
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[-1], "{0:08x}".format(registers[-1])))
if processor == 9:
registers = unpack_from("<17I", data, 40)
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(hexdump(registers[15] - codeDumpSize + 2, codeDump))
# Homebrew/CFW set their stack at 0x27000000, let's detect it
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]
print("\nStack dump:\n")
print(hexdump(registers[13], stackDump))