Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2234 → Rev 2235

/branches/arm/kernel/arch/arm32/src/exception.c
1,4 → 1,4
/*
/*
* Copyright (c) 2007 Petr Stepan
* All rights reserved.
*
36,61 → 36,203
#include <arch/exception.h>
#include "aux_print/printf.h"
#include <arch/memstr.h>
#include <arch/regutils.h>
#include <interrupt.h>
 
 
#define PREFETCH_OFFSET 0x8
#define BRANCH_OPCODE 0xea000000
#define LDR_OPCODE 0xe59ff000
#define VALID_BRANCH_MASK 0xff000000
#define EXC_VECTORS_SIZE 0x20
#define EXC_VECTORS 0x8
 
/** Updates specified exception vector to jump to given handler.
/* GXEmul interrupt controller macros
TODO might go to drivers/ together with servicing functions
*/
static void install_handler (unsigned* handler, unsigned* vector) {
volatile unsigned vec;
/* IRQ Controller device is added in a special premium gxemul
* edition at www.ms.mff.cuni.cz/~stepp3am/mygxemul-0.4.4.1.tar.gz
* :)
*/
#define IRQ_CONTROLLER_CAUSE 0x0000000016000000
#define IRQ_CONTROLLER_MAX_IRQ 8
 
/* IRQs */
#define CONSOLE_IRQ 2
#define TIMER_IRQ 4
 
 
#define SAVE_REGS_TO_STACK \
asm("stmfd sp!, {r0-r12, sp, lr}"); \
asm("mrs r14, spsr"); \
asm("stmfd sp!, {r14}");
 
#define CALL_EXC_DISPATCH(exception) \
asm("mov r0, %0" : : "i" (exception)); \
asm("mov r1, sp"); \
asm("bl exc_dispatch");
 
/**Loads registers from the stack and resets SPSR before exitting exception
* handler.
*/
#define LOAD_REGS_FROM_STACK \
asm("ldmfd sp!, {r14}"); \
asm("msr spsr, r14"); \
asm("ldmfd sp!, {r0-r12, sp, pc}^");
/* calculate relative distance */
vec = ((unsigned)handler - (unsigned)vector - PREFETCH_OFFSET);
/** General exception handler.
* Stores registers, dispatches the exception,
* and finally restores registers and returns from exception processing.
*/
#define PROCESS_EXCEPTION(exception) \
SAVE_REGS_TO_STACK \
CALL_EXC_DISPATCH(exception) \
LOAD_REGS_FROM_STACK
 
/** Updates specified exception vector to jump to given handler.
* Addresses of handlers are stored in memory following exception vectors.
*/
static void install_handler (unsigned handler_addr, unsigned* vector)
{
/* relative address (related to exc. vector) of the word
* where handler's address is stored
*/
volatile uint32_t handler_address_ptr = EXC_VECTORS_SIZE - PREFETCH_OFFSET;
/* word offset */
vec >>= 2;
/* make it LDR instruction and store at exception vector */
*vector = handler_address_ptr | LDR_OPCODE;
/* check if haven't jumped beyond 32 MB */
if ((vec & VALID_BRANCH_MASK) != 0) {
/*panic("exception handler beyond 32MB.");*/
return;
}
/* make it branch instruction */
vec |= BRANCH_OPCODE;
*vector = vec;
aux_printf("installed handler to %p, to vector %p\n.", handler, vector);
/* store handler's address */
*(vector + EXC_VECTORS) = handler_addr;
}
 
/* TODO add other exception handlers */
static void dummy_exception(){
asm("bkpt");
static void reset_exception_entry()
{
PROCESS_EXCEPTION(EXC_RESET);
}
 
/** IRQ Exception handler */
static void irq_exception(){
asm("bkpt");
/** Low-level Software Interrupt Exception handler */
static void swi_exception_entry()
{
PROCESS_EXCEPTION(EXC_SWI);
}
 
/** Low-level Undefined Instruction Exception handler */
static void undef_instr_exception_entry()
{
PROCESS_EXCEPTION(EXC_UNDEF_INSTR);
}
 
/** Low-level Fast Interrupt Exception handler */
static void fiq_exception_entry()
{
PROCESS_EXCEPTION(EXC_FIQ);
}
 
/** Low-level Prefetch Abort Exception handler */
static void prefetch_abort_exception_entry()
{
asm("sub lr, lr, #4");
PROCESS_EXCEPTION(EXC_PREFETCH_ABORT);
}
 
/** Low-level Data Abort Exception handler */
static void data_abort_exception_entry()
{
asm("sub lr, lr, #8");
PROCESS_EXCEPTION(EXC_DATA_ABORT);
}
 
 
/** Low-level Interrupt Exception handler */
static void irq_exception_entry()
{
asm("sub lr, lr, #4");
PROCESS_EXCEPTION(EXC_IRQ);
}
 
 
/** Interrupt Exception handler.
* Determines the sources of interrupt, and calls their handlers.
*/
static void irq_exception(int exc_no, istate_t* istate)
{
/* TODO this will call interrupt dispatching routine
*
*/
 
uint32_t sources = *(uint32_t*) IRQ_CONTROLLER_CAUSE;
int i = 0;
int noirq = 1;
for (; i < IRQ_CONTROLLER_MAX_IRQ; i++) {
if (sources & (1 << i)) {
noirq = 0;
if (i == CONSOLE_IRQ) {
char readchar = *(char*)0x10000000;
if (readchar == 0) {
aux_puts("?");
}
else {
aux_printf("%c", readchar);
}
}
else if (i == TIMER_IRQ) {
aux_printf("\n.\n");
/* acknowledge */
*(uint32_t*)0x15000110 = 0;
}
}
}
 
if (noirq)
aux_puts("IRQ exception without source\n");
}
 
/** Fills exception vectors with appropriate exception handlers.
*/
void install_exception_handlers(void) {
install_handler((unsigned*)dummy_exception, (unsigned*)EXC_RESET_VEC);
install_handler((unsigned*)dummy_exception, (unsigned*)EXC_UNDEF_INSTR_VEC);
install_handler((unsigned*)dummy_exception, (unsigned*)EXC_SWI_VEC);
install_handler((unsigned*)dummy_exception, (unsigned*)EXC_PREFETCH_ABORT_VEC);
install_handler((unsigned*)dummy_exception, (unsigned*)EXC_DATA_ABORT_VEC);
install_handler((unsigned*)irq_exception, (unsigned*)EXC_IRQ_VEC);
install_handler((unsigned*)dummy_exception, (unsigned*)EXC_FIQ_VEC);
void install_exception_handlers(void)
{
install_handler((unsigned)reset_exception_entry,
(unsigned*)EXC_RESET_VEC);
install_handler((unsigned)undef_instr_exception_entry,
(unsigned*)EXC_UNDEF_INSTR_VEC);
install_handler((unsigned)swi_exception_entry,
(unsigned*)EXC_SWI_VEC);
install_handler((unsigned)prefetch_abort_exception_entry,
(unsigned*)EXC_PREFETCH_ABORT_VEC);
install_handler((unsigned)data_abort_exception_entry,
(unsigned*)EXC_DATA_ABORT_VEC);
install_handler((unsigned)irq_exception_entry,
(unsigned*)EXC_IRQ_VEC);
install_handler((unsigned)fiq_exception_entry,
(unsigned*)EXC_FIQ_VEC);
}
 
/** Registers exceptions and their handlers to kernel exception dispatcher. */
void exception_init(void){
/* TODO */
void exception_init(void)
{
exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception);
/* TODO add next */
}
 
/* TODO change soon, temporary hack. */
void setup_exception_stacks()
{
/* switch to particular mode and set "sp" there */
uint32_t cspr = current_status_reg_read();
current_status_reg_control_write(
(cspr & ~STATUS_REG_MODE_MASK) | IRQ_MODE
);
asm("ldr sp, =irq_stack");
current_status_reg_control_write( cspr);
}
 
/** @}
*/