From 930b646008af483dc6139c2b2dd32be2857834b5 Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Tue, 8 Aug 2017 23:04:17 -0300 Subject: [PATCH] Improved MPcore interrupt handler --- Makefile | 12 ++++----- common/arm.h | 15 +++++++++++ common/types.h | 1 + screeninit/Makefile | 14 +++++----- screeninit/linker.ld | 5 ++-- screeninit/source/boot.s | 10 +++---- screeninit/source/gic.c | 36 +++++++++++++++----------- screeninit/source/gic.h | 56 ++++++++++++---------------------------- screeninit/source/irq.s | 29 +++++++++++++++++++++ screeninit/source/main.c | 2 +- source/start.s | 4 ++- 11 files changed, 106 insertions(+), 78 deletions(-) create mode 100644 common/arm.h create mode 100644 screeninit/source/irq.s diff --git a/Makefile b/Makefile index 0082a56..026c1d1 100644 --- a/Makefile +++ b/Makefile @@ -28,13 +28,12 @@ INCLUDES := common source source/common source/font source/filesys source/crypto #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -ARCH := -mthumb -mthumb-interwork -flto +ARCH := -DARM9 -march=armv5te -mthumb -mthumb-interwork -flto -CFLAGS := -g -Wall -Wextra -Wpedantic -Wcast-align -Wno-main -O2\ - -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math -std=gnu11\ - $(ARCH) - -CFLAGS += $(INCLUDE) -DARM9 +ASFLAGS := $(ARCH) -g -x assembler-with-cpp $(INCLUDE) +CFLAGS := $(ARCH) -g -Wall -Wextra -Wpedantic -Wcast-align -Wno-main -O2 \ + -mtune=arm946e-s -fomit-frame-pointer -ffast-math -std=gnu11 \ + $(INCLUDE) CFLAGS += -DBUILD_NAME="\"$(TARGET) (`date +'%Y/%m/%d'`)\"" @@ -64,7 +63,6 @@ endif CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -ASFLAGS := -g $(ARCH) LDFLAGS = -T../link.ld -nostartfiles -g $(ARCH) -Wl,-Map,$(TARGET).map LIBS := diff --git a/common/arm.h b/common/arm.h new file mode 100644 index 0000000..ced1d62 --- /dev/null +++ b/common/arm.h @@ -0,0 +1,15 @@ +#pragma once + +/* Status Register flags */ +#define SR_USR_MODE (0x10) +#define SR_FIQ_MODE (0x11) +#define SR_IRQ_MODE (0x12) +#define SR_SVC_MODE (0x13) +#define SR_ABT_MODE (0x17) +#define SR_UND_MODE (0x1B) +#define SR_SYS_MODE (0x1F) +#define SR_PMODE_MASK (0x1F) + +#define SR_THUMB (1 << 5) +#define SR_FIQ (1 << 6) +#define SR_IRQ (1 << 7) diff --git a/common/types.h b/common/types.h index 2d52816..03cf23a 100644 --- a/common/types.h +++ b/common/types.h @@ -7,6 +7,7 @@ #endif #include +#include #define BIT(x) (1<<(x)) diff --git a/screeninit/Makefile b/screeninit/Makefile index ca57208..70514ec 100644 --- a/screeninit/Makefile +++ b/screeninit/Makefile @@ -12,10 +12,12 @@ dir_source := source dir_build := build dir_out := ../$(dir_build) -ASFLAGS := -mcpu=mpcore -mfloat-abi=soft -CFLAGS := -DARM11 -Wall -Wextra -MMD -MP -marm -mno-thumb-interwork \ - $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math \ - -I$(dir_source) -I../common +ARCH := -DARM11 -mcpu=mpcore -mfloat-abi=soft -marm -mno-thumb-interwork +INCLUDE := -I$(dir_source) -I../common + +ASFLAGS := $(ARCH) -x assembler-with-cpp $(INCLUDE) +CFLAGS := $(ARCH) -Wall -Wextra -MMD -MP -fno-builtin \ + -std=c11 -O2 -flto -ffast-math -Wno-main $(INCLUDE) LDFLAGS := -nostdlib -nostartfiles objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ @@ -37,8 +39,8 @@ $(dir_out)/$(name).elf: $(objects) $(dir_build)/%.o: $(dir_source)/%.c @mkdir -p "$(@D)" - $(COMPILE.c) $(OUTPUT_OPTION) $< + $(CC) -c $(CFLAGS) -o $@ $< $(dir_build)/%.o: $(dir_source)/%.s @mkdir -p "$(@D)" - $(COMPILE.s) $(OUTPUT_OPTION) $< + $(CC) -c $(ASFLAGS) -o $@ $< diff --git a/screeninit/linker.ld b/screeninit/linker.ld index c2855bb..801211c 100644 --- a/screeninit/linker.ld +++ b/screeninit/linker.ld @@ -6,13 +6,12 @@ SECTIONS { . = 0x1FF80000; - .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } + .text : ALIGN(4) { *(.text.boot) *(.text*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } .data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); } .bss : ALIGN(4) { __bss_start = .; *(.bss*); __bss_end = .; } . = ALIGN(4); - __irq_stack = 0x1FFFF800; - __prg_stack = 0x1FFFF400; + __stack_top = 0x1FFFF800; } diff --git a/screeninit/source/boot.s b/screeninit/source/boot.s index da173fd..e8ec828 100644 --- a/screeninit/source/boot.s +++ b/screeninit/source/boot.s @@ -3,10 +3,12 @@ .section .text.boot .arm +#include + .global __boot __boot: @ Disable interrupts and switch to IRQ - cpsid aif, #0x12 + cpsid aif, #(SR_SVC_MODE) @ Writeback and invalidate caches mov r0, #0 @@ -14,11 +16,7 @@ __boot: mcr p15, 0, r0, c7, c14, 0 mcr p15, 0, r0, c7, c10, 4 - ldr sp, =__irq_stack - - @ Switch to SVC - cpsid aif, #0x13 - ldr sp, =__prg_stack + ldr sp, =__stack_top @ Reset values ldr r0, =0x00054078 diff --git a/screeninit/source/gic.c b/screeninit/source/gic.c index 2236cd1..d1f1a9c 100644 --- a/screeninit/source/gic.c +++ b/screeninit/source/gic.c @@ -10,18 +10,17 @@ #define IRQ_BASE ((vu32*)0x1FFFFFA0) irq_handler handler_table[MAX_IRQ]; +extern void (*main_irq_handler)(void); -void __attribute__((interrupt("IRQ"))) gic_irq_handler(void) +irq_handler GIC_AckIRQ(void) { - u32 xrq, ss; - CPU_EnterCritical(&ss); - xrq = *GIC_IRQACK; + u32 xrq = *GIC_IRQACK; + irq_handler ret = NULL; if (xrq < MAX_IRQ && handler_table[xrq]) { - (handler_table[xrq])(xrq); + ret = handler_table[xrq]; + *GIC_IRQEND = xrq; } - *GIC_IRQEND = xrq; - CPU_LeaveCritical(&ss); - return; + return ret; } void GIC_Configure(u32 irq_id, irq_handler hndl) @@ -35,23 +34,30 @@ void GIC_Configure(u32 irq_id, irq_handler hndl) void GIC_Reset(void) { + *DIC_CONTROL = 0; *GIC_CONTROL = 0; - *GIC_PRIOMASK = ~0; - for (int i = 0; i < (BIT(9)-1); i++) { - *GIC_IRQEND |= i; + *GIC_PRIOMASK = ~0; + for (int i = 0; i < 0x80; i++) { + *GIC_IRQEND = i; } - *DIC_CONTROL = 0; for (int i = 0; i < (0x20/4); i++) { DIC_CLRENABLE[i] = ~0; DIC_PRIORITY[i] = 0; } - *DIC_CONTROL = 1; - *GIC_CONTROL = 1; + while(*GIC_PENDING != SPURIOUS_IRQ) { + for (int i=0; i < (0x20/4); i++) { + DIC_CLRPENDING[i] = ~0; + } + } - IRQ_BASE[1] = (u32)gic_irq_handler; + IRQ_BASE[1] = (u32)&main_irq_handler; IRQ_BASE[0] = 0xE51FF004; + + *GIC_CONTROL = 1; + *DIC_CONTROL = 1; + return; } diff --git a/screeninit/source/gic.h b/screeninit/source/gic.h index 82ae829..f0a5e8d 100644 --- a/screeninit/source/gic.h +++ b/screeninit/source/gic.h @@ -6,51 +6,29 @@ #pragma once #include -typedef void (*irq_handler)(u32); +typedef void (*irq_handler)(void); -#define MAX_IRQ (0x80) +#define MAX_IRQ (0x80) + +#define SPURIOUS_IRQ (1023) #define GIC_BASE (0x17E00100) #define DIC_BASE (0x17E01000) -/* Setting bit 0 enables the GIC */ -#define GIC_CONTROL ((vu32*)(GIC_BASE + 0x00)) -/* Bits [7:0] control the min priority accepted */ -#define GIC_PRIOMASK ((vu32*)(GIC_BASE + 0x04)) -/* When an IRQ occurrs, this register holds the IRQ ID */ -#define GIC_IRQACK ((vu32*)(GIC_BASE + 0x0C)) -/* Write the IRQ ID here to acknowledge it */ -#define GIC_IRQEND ((vu32*)(GIC_BASE + 0x10)) +#define GIC_CONTROL ((vu32*)(GIC_BASE + 0x00)) +#define GIC_PRIOMASK ((vu32*)(GIC_BASE + 0x04)) +#define GIC_IRQACK ((vu32*)(GIC_BASE + 0x0C)) +#define GIC_IRQEND ((vu32*)(GIC_BASE + 0x10)) +#define GIC_PENDING ((vu32*)(GIC_BASE + 0x18)) +#define DIC_CONTROL ((vu32*)(DIC_BASE + 0x000)) +#define DIC_SETENABLE ((vu32*)(DIC_BASE + 0x100)) +#define DIC_CLRENABLE ((vu32*)(DIC_BASE + 0x180)) +#define DIC_SETPENDING ((vu32*)(DIC_BASE + 0x200)) +#define DIC_CLRPENDING ((vu32*)(DIC_BASE + 0x280)) +#define DIC_PRIORITY ((vu32*)(DIC_BASE + 0x400)) +#define DIC_PROCTGT ((vu8*) (DIC_BASE + 0x800)) +#define DIC_CFGREG ((vu32*)(DIC_BASE + 0xC00)) -/* Setting bit 0 enables the DIC */ -#define DIC_CONTROL ((vu32*)(DIC_BASE + 0x000)) -/* - Write here to enable an IRQ ID - The register address is DIC_SETENABLE + (N/32)*4 and its - corresponding bit index is (N%32) -*/ -#define DIC_SETENABLE ((vu32*)(DIC_BASE + 0x100)) - -/* same as above but disables the IRQ */ -#define DIC_CLRENABLE ((vu32*)(DIC_BASE + 0x180)) - -/* sets the IRQ priority */ -#define DIC_PRIORITY ((vu32*)(DIC_BASE + 0x400)) - -/* specifies which CPUs are allowed to be forwarded the IRQ */ -#define DIC_PROCTGT ((vu8*)(DIC_BASE + 0x800)) - -/* - each irq has 2 bits assigned - bit 0 = 0: uses 1-N model - 1: uses N-N model - - bit 1 = 0: level high active - 1: rising edge sensitive - */ -#define DIC_CFGREG ((vu32*)(DIC_BASE + 0xC00)) - -void gic_irq_handler(void); void GIC_Configure(u32 irq_id, irq_handler hndl); void GIC_Reset(void); diff --git a/screeninit/source/irq.s b/screeninit/source/irq.s new file mode 100644 index 0000000..265932c --- /dev/null +++ b/screeninit/source/irq.s @@ -0,0 +1,29 @@ +.section .text +.arm + +#include + +.global main_irq_handler +.type main_irq_handler, %function +main_irq_handler: + sub lr, lr, #4 @ Fix return address + srsdb sp!, #(SR_SVC_MODE) @ Store IRQ mode LR and SPSR on the SVC stack + cps #(SR_SVC_MODE) @ Switch to SVC mode + push {r0-r3,r12} @ Preserve registers + and r1, sp, #4 + sub sp, sp, r1 @ Word-align stack + push {r1,lr} + + bl GIC_AckIRQ @ Acknowledge interrupt, get handler address + cmp r0, #0 + beq .Lskip_irq + + cpsie i + blx r0 @ Branch to interrupt handler with IRQs enabled + cpsid i + + .Lskip_irq: + pop {r1,lr} + add sp, sp, r1 @ Restore stack pointer + pop {r0-r3,lr} @ Restore registers + rfeia sp! @ Return From Exception diff --git a/screeninit/source/main.c b/screeninit/source/main.c index a75e98b..90f0bf6 100644 --- a/screeninit/source/main.c +++ b/screeninit/source/main.c @@ -133,7 +133,7 @@ void set_brightness(u8 brightness) *(vu32 *)0x10202A40 = brightness; } -void pxi_interrupt_handler(__attribute__((unused)) u32 xrq_n) +void pxi_interrupt_handler(void) { u8 msg = PXI_GetRemote(); switch(msg) { diff --git a/source/start.s b/source/start.s index 8a5beb3..a665b29 100644 --- a/source/start.s +++ b/source/start.s @@ -2,11 +2,13 @@ .align 4 .arm +#include + @ make sure not to clobber r0-r2 .global _start _start: @ Switch to supervisor mode and disable interrupts - msr cpsr_c, #0xD3 + msr cpsr_c, #(SR_SVC_MODE | SR_IRQ | SR_FIQ) @ Short delay (not always necessary, just in case) mov r3, #0x40000