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.
This commit is contained in:
Ithamar R. Adema
2012-11-05 01:45:24 +01:00
parent be7195d0f7
commit 02081e0950
3 changed files with 320 additions and 70 deletions
+1 -1
View File
@@ -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
@@ -0,0 +1,176 @@
/*
* Copyright 2012, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ithamar R. Adema <ithamar@upgrade-android.com>
*
*/
#include <asm_defs.h>
.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 }^
+143 -69
View File
@@ -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 <[email protected]>
* Ingo Weinhold <[email protected]>
* François Revol <[email protected]>
* Ithamar R. Adema <[email protected]>
*
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
@@ -30,27 +31,35 @@
#include <string.h>
//#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);
}