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); +}