From 02081e0950d201a246c8adb86a92a8bb65e28490 Mon Sep 17 00:00:00 2001 From: "Ithamar R. Adema" Date: Mon, 5 Nov 2012 01:36:41 +0100 Subject: [PATCH] ARM: Initial implementation of interrupt/exception handling. This contains both the common ARM(v5) vector handling as well as the PXA(verdex) specific interrupt controller code, to be seperated when ARM support for FDT is implemented. Functional enough to handle interrupts, needs work on KDL support. --- src/system/kernel/arch/arm/Jamfile | 2 +- src/system/kernel/arch/arm/arch_exceptions.S | 176 +++++++++++++++ src/system/kernel/arch/arm/arch_int.cpp | 212 +++++++++++++------ 3 files changed, 320 insertions(+), 70 deletions(-) create mode 100644 src/system/kernel/arch/arm/arch_exceptions.S diff --git a/src/system/kernel/arch/arm/Jamfile b/src/system/kernel/arch/arm/Jamfile index 13a56e44e6..68124ed9b9 100644 --- a/src/system/kernel/arch/arm/Jamfile +++ b/src/system/kernel/arch/arm/Jamfile @@ -17,7 +17,7 @@ KernelMergeObject kernel_arch_arm.o : arch_debug_console.cpp arch_debug.cpp arch_elf.cpp -# arch_exceptions.S + arch_exceptions.S arch_int.cpp arch_platform.cpp arch_real_time_clock.cpp diff --git a/src/system/kernel/arch/arm/arch_exceptions.S b/src/system/kernel/arch/arm/arch_exceptions.S new file mode 100644 index 0000000000..cffb1f87f8 --- /dev/null +++ b/src/system/kernel/arch/arm/arch_exceptions.S @@ -0,0 +1,176 @@ +/* + * Copyright 2012, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ithamar R. Adema + * + */ + +#include + + .text + +.globl _vectors_start +_vectors_start: + ldr pc, _arm_reset + ldr pc, _arm_undefined + ldr pc, _arm_syscall + ldr pc, _arm_prefetch_abort + ldr pc, _arm_data_abort + ldr pc, _arm_reserved + ldr pc, _arm_irq + ldr pc, _arm_fiq + +_arm_reset: + .word arm_reserved // actually reset, but not used when mapped +_arm_undefined: + .word arm_undefined +_arm_syscall: + .word arm_syscall +_arm_prefetch_abort: + .word arm_prefetch_abort +_arm_data_abort: + .word arm_data_abort +_arm_reserved: + .word arm_reserved +_arm_irq: + .word arm_irq +_arm_fiq: + .word arm_fiq +.globl _vectors_end +_vectors_end: + + + .rept 64 + .word 0xaabbccdd + .endr +abort_stack: + .word . + +FUNCTION(arm_undefined): + stmfd sp!, { r0-r12, r14 } + sub sp, sp, #12 + mov r0, sp + mrs r1, spsr + stmia r0, { r1, r13-r14 } + b arch_arm_undefined + b . + +FUNCTION(arm_syscall): + stmfd sp!, { r0-r12, r14 } + sub sp, sp, #12 + mov r0, sp + mrs r1, spsr + stmia r0, { r1, r13-r14 } + b arch_arm_syscall + b . + +FUNCTION(arm_prefetch_abort): + ldr sp, abort_stack + stmfd sp!, { r0-r12, r14 } + sub sp, sp, #12 + mov r0, sp + mrs r1, spsr + stmia r0, { r1, r13-r14 } + b arch_arm_prefetch_abort + b . + +FUNCTION(arm_data_abort): + ldr sp, abort_stack + /* XXX only deals with interrupting supervisor mode */ + + /* save r4-r6 and use as a temporary place to save while we switch into supervisor mode */ + stmia r13, { r4-r6 } + mov r4, r13 + sub r5, lr, #8 + mrs r6, spsr + + /* move into supervisor mode. irq/fiq disabled */ + msr cpsr_c, #0x13 + + /* save the return address */ + stmfd sp!, { r5 } + + /* save C trashed regs, supervisor lr */ + stmfd sp!, { r0-r3, r12, lr } + + /* save spsr */ + stmfd sp!, { r6 } + + /* restore r4-r6 */ + ldmia r4, { r4-r6 } + + /* call into higher level code */ + mrc p15, 0, r2, c5, c0, 0 @ get FSR + mrc p15, 0, r3, c6, c0, 0 @ get FAR + sub sp, sp, #20 + mov r0, sp /* iframe */ + stmia r0, { r6,r2,r3,r4,r5 } + bl arch_arm_data_abort + add sp, sp, #20 + + /* restore spsr */ + ldmfd sp!, { r0 } + msr spsr_cxsf, r0 + + /* restore back to where we came from */ + ldmfd sp!, { r0-r3, r12, lr, pc }^ + +FUNCTION(arm_reserved): + b . + +FUNCTION(arm_irq): + ldr sp, abort_stack + /* XXX only deals with interrupting supervisor mode */ + + /* save r4-r6 and use as a temporary place to save while we switch into supervisor mode */ + stmia r13, { r4-r6 } + mov r4, r13 + sub r5, lr, #4 + mrs r6, spsr + + /* move into supervisor mode. irq/fiq disabled */ + msr cpsr_c, #(3<<6 | 0x13) + + /* save the return address */ + stmfd sp!, { r5 } + + /* save C trashed regs, supervisor lr */ + stmfd sp!, { r0-r3, r12, lr } + + /* save spsr */ + stmfd sp!, { r6 } + + /* restore r4-r6 */ + ldmia r4, { r4-r6 } + + /* call into higher level code */ + mov r0, sp /* iframe */ + bl arch_arm_irq + + /* restore spsr */ + ldmfd sp!, { r0 } + msr spsr_cxsf, r0 + + /* restore back to where we came from */ + ldmfd sp!, { r0-r3, r12, lr, pc }^ + +.bss +.align 2 + .global irq_save_spot +irq_save_spot: + .word 0 /* r4 */ + .word 0 /* r5 */ + .word 0 /* r6 */ + +.text +FUNCTION(arm_fiq): + ldr sp, abort_stack + sub lr, lr, #4 + stmfd sp!, { r0-r3, r12, lr } + + bl arch_arm_fiq + + ldmfd sp!, { r0-r3, r12, pc }^ + diff --git a/src/system/kernel/arch/arm/arch_int.cpp b/src/system/kernel/arch/arm/arch_int.cpp index 1337705665..97a735aa4a 100644 --- a/src/system/kernel/arch/arm/arch_int.cpp +++ b/src/system/kernel/arch/arm/arch_int.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2003-2010, Haiku Inc. All rights reserved. + * Copyright 2003-2012, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Axel Dörfler * Ingo Weinhold * François Revol + * Ithamar R. Adema * * Copyright 2001, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. @@ -30,27 +31,35 @@ #include -//#define TRACE_ARCH_INT +#define TRACE_ARCH_INT #ifdef TRACE_ARCH_INT # define TRACE(x) dprintf x #else # define TRACE(x) ; #endif -/*typedef void (*m68k_exception_handler)(void); -#define M68K_EXCEPTION_VECTOR_COUNT 256 -#warning M68K: align on 4 ? -//m68k_exception_handler gExceptionVectors[M68K_EXCEPTION_VECTOR_COUNT]; -m68k_exception_handler *gExceptionVectors; +#define VECTORPAGE_SIZE 64 +#define USER_VECTOR_ADDR_LOW 0x00000000 +#define USER_VECTOR_ADDR_HIGH 0xffff0000 -// defined in arch_exceptions.S -extern "C" void __m68k_exception_noop(void); -extern "C" void __m68k_exception_common(void); -*/ -extern int __irqvec_start; -extern int __irqvec_end; +#define PXA_INTERRUPT_PHYS_BASE 0x40D00000 +#define PXA_INTERRUPT_SIZE 0x00000034 -//extern"C" void m68k_exception_tail(void); +#define PXA_ICIP 0x00 +#define PXA_ICMR 0x01 +#define PXA_ICFP 0x03 +#define PXA_ICMR2 0x28 + +static area_id sPxaInterruptArea; +static uint32 *sPxaInterruptBase; + +extern int _vectors_start; +extern int _vectors_end; + +static area_id sVectorPageArea; +static void *sVectorPageAddress; +static area_id sUserVectorPageArea; +static void *sUserVectorPageAddress; // current fault handler addr_t gFaultHandler; @@ -59,35 +68,48 @@ addr_t gFaultHandler; // threads yet. struct iframe_stack gBootFrameStack; -// interrupt controller interface (initialized -// in arch_int_init_post_device_manager()) -//static struct interrupt_controller_module_info *sPIC; -//static void *sPICCookie; + +uint32 +mmu_read_c1() +{ + uint32 controlReg = 0; + asm volatile("MRC p15, 0, %[c1out], c1, c0, 0":[c1out] "=r" (controlReg)); + return controlReg; +} + + +void +mmu_write_c1(uint32 value) +{ + asm volatile("MCR p15, 0, %[c1in], c1, c0, 0"::[c1in] "r" (value)); +} void arch_int_enable_io_interrupt(int irq) { - #warning ARM WRITEME - //if (!sPIC) - // return; + TRACE(("arch_int_enable_io_interrupt(%d)\n", irq)); - // TODO: I have no idea, what IRQ type is appropriate. - //sPIC->enable_io_interrupt(sPICCookie, irq, IRQ_TYPE_LEVEL); -// M68KPlatform::Default()->EnableIOInterrupt(irq); + if (irq <= 31) { + sPxaInterruptBase[PXA_ICMR] |= 1 << irq; + return; + } + + sPxaInterruptBase[PXA_ICMR2] |= 1 << (irq - 32); } void arch_int_disable_io_interrupt(int irq) { - #warning ARM WRITEME + TRACE(("arch_int_disable_io_interrupt(%d)\n", irq)); - //if (!sPIC) - // return; + if (irq <= 31) { + sPxaInterruptBase[PXA_ICMR] &= ~(1 << irq); + return; + } - //sPIC->disable_io_interrupt(sPICCookie, irq); -// M68KPlatform::Default()->DisableIOInterrupt(irq); + sPxaInterruptBase[PXA_ICMR2] &= ~(1 << (irq - 32)); } @@ -97,60 +119,67 @@ arch_int_disable_io_interrupt(int irq) static void print_iframe(struct iframe *frame) { - #if 0 - dprintf("r0-r3: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r0, frame->r1, - frame->r2, frame->r3); - dprintf("r4-r7: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r4, frame->r5, - frame->r6, frame->r7); - dprintf("r8-r11: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r8, frame->r9, - frame->r10, frame->r11); - dprintf("r12-r15: 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", frame->r12, frame->r13, - frame->a6, frame->a7); - dprintf(" pc 0x%08lx sr 0x%08lx\n", frame->pc, frame->sr); - #endif - - #warning ARM WRITEME } status_t arch_int_init(kernel_args *args) { - #if 0 - status_t err; - addr_t vbr; - int i; + // see if high vectors are enabled + if (mmu_read_c1() & (1<<13)) + dprintf("High vectors already enabled\n"); + else { + mmu_write_c1(mmu_read_c1() | (1<<13)); - gExceptionVectors = (m68k_exception_handler *)args->arch_args.vir_vbr; + if (!(mmu_read_c1() & (1<<13))) + dprintf("Unable to enable high vectors!\n"); + else + dprintf("Enabled high vectors\n"); + } - /* fill in the vector table */ - for (i = 0; i < M68K_EXCEPTION_VECTOR_COUNT; i++) - gExceptionVectors[i] = &__m68k_exception_common; + return B_OK; +} - vbr = args->arch_args.phys_vbr; - /* point VBR to the new table */ - asm volatile ("movec %0,%%vbr" : : "r"(vbr):); - #endif - #warning ARM WRITEME +status_t +arch_int_init_post_vm(kernel_args *args) +{ + // create a read/write kernel area + sVectorPageArea = create_area("vectorpage", (void **)&sVectorPageAddress, + B_ANY_ADDRESS, VECTORPAGE_SIZE, B_FULL_LOCK, + B_KERNEL_WRITE_AREA | B_KERNEL_READ_AREA); + + if (sVectorPageArea < 0) + panic("vector page could not be created!"); + + // clone it at a fixed address with user read/only permissions + sUserVectorPageAddress = (addr_t*)USER_VECTOR_ADDR_HIGH; + sUserVectorPageArea = clone_area("user_vectorpage", + (void **)&sUserVectorPageAddress, B_EXACT_ADDRESS, + B_READ_AREA | B_EXECUTE_AREA, sVectorPageArea); + + if (sUserVectorPageArea < 0) + panic("user vector page @ %p could not be created (%lx)!", sVectorPageAddress, sUserVectorPageArea); + + // copy vectors into the newly created area + memcpy(sVectorPageAddress, &_vectors_start, VECTORPAGE_SIZE); + + sPxaInterruptArea = map_physical_memory("pxa_intc", PXA_INTERRUPT_PHYS_BASE, + PXA_INTERRUPT_SIZE, 0, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&sPxaInterruptBase); + + if (sPxaInterruptArea < 0) + return sPxaInterruptArea; + + sPxaInterruptBase[PXA_ICMR] = 0; + sPxaInterruptBase[PXA_ICMR2] = 0; return B_OK; } -status_t -arch_int_init_post_vm(kernel_args *args) -{ - status_t err; - // err = M68KPlatform::Default()->InitPIC(args); - #warning ARM WRITEME - - return err; -} - - status_t arch_int_init_io(kernel_args* args) { + TRACE(("arch_int_init_io(%p)\n", args)); return B_OK; } @@ -158,8 +187,53 @@ arch_int_init_io(kernel_args* args) status_t arch_int_init_post_device_manager(struct kernel_args *args) { - // no PIC found - panic("arch_int_init_post_device_manager(): Found no supported PIC!"); - return B_ENTRY_NOT_FOUND; } + + +extern "C" void arch_arm_undefined(struct iframe *iframe) +{ + panic("Undefined instruction!"); +} + +extern "C" void arch_arm_syscall(struct iframe *iframe) +{ + panic("Software interrupt!\n"); +} + +extern "C" void arch_arm_data_abort(struct iframe *iframe) +{ + addr_t newip; + status_t res = vm_page_fault(iframe->r2 /* FAR */, iframe->r4 /* lr */, + true /* TODO how to determine read/write? */, + false /* only kernelspace for now */, + &newip); + + if (res != B_HANDLED_INTERRUPT) { + panic("Data Abort: %08x %08x %08x %08x (res=%lx)", iframe->r0 /* spsr */, + iframe->r1 /* FSR */, iframe->r2 /* FAR */, + iframe->r4 /* lr */, + res); + } else { + //panic("vm_page_fault was ok (%08lx/%08lx)!", iframe->r2 /* FAR */, iframe->r0 /* spsr */); + } +} + +extern "C" void arch_arm_prefetch_abort(struct iframe *iframe) +{ + panic("Prefetch Abort: %08x %08x %08x", iframe->r0, iframe->r1, iframe->r2); +} + +extern "C" void arch_arm_irq(struct iframe *iframe) +{ + for (int i=0; i < 32; i++) + if (sPxaInterruptBase[PXA_ICIP] & (1 << i)) + int_io_interrupt_handler(i, true); +} + +extern "C" void arch_arm_fiq(struct iframe *iframe) +{ + for (int i=0; i < 32; i++) + if (sPxaInterruptBase[PXA_ICIP] & (1 << i)) + dprintf("arch_arm_fiq: help me, FIQ %d was triggered but no FIQ support!\n", i); +}