forked from Imagelibrary/rtems
2002-07-17 Jay Monkman <jtm@smoothsmoothie.com>
* irq/irq_asm.S: Significant rework in attempt to make interrupts work. They appear to be very close to correct but not 100%.
This commit is contained in:
@@ -2,9 +2,15 @@
|
||||
*
|
||||
* This file contains the implementation of the IRQ handler
|
||||
*
|
||||
* Copyright (c) 2002 Advent Networks, Inc.
|
||||
* Jay Monkman <jmonkman@adventnetworks.com>
|
||||
*
|
||||
* CopyRight (C) 2000 Canon Research France SA.
|
||||
* Emmanuel Raguet, mailto:raguet@crf.canon.fr
|
||||
*
|
||||
* Modified Andy Dachs <a.dachs@sstl.co.uk>
|
||||
* Copyright (c) 2001 Surrey Satellite Technolgy Limited
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in found in the file LICENSE in this distribution or at
|
||||
* http://www.OARcorp.com/rtems/license.html.
|
||||
@@ -14,96 +20,150 @@
|
||||
|
||||
#include "asm.h"
|
||||
#define __asm__
|
||||
#include <registers.h>
|
||||
|
||||
.globl _ISR_Handler
|
||||
_ISR_Handler:
|
||||
stmdb sp!, {r0, r1, r2, r3} /* save regs on INT stack */
|
||||
stmdb sp!, {lr} /* now safe to call C funcs */
|
||||
|
||||
|
||||
/*
|
||||
* WARNING : register r5 is important. If you need to use it,
|
||||
* to forget to save it !!!!!!!!!!
|
||||
*/
|
||||
|
||||
.globl _ISR_Handler
|
||||
_ISR_Handler:
|
||||
stmdb sp!, {r4,r5,lr} /* save regs on INT stack */
|
||||
mrs r4, cpsr /* save current CSPR */
|
||||
mov r5, r4 /* copy CSPR */
|
||||
orr r4, r4, #3
|
||||
msr cpsr, r4 /* switch to SVC mode */
|
||||
|
||||
stmdb sp!, {r0-r3,r12,r14} /* save scratch regs on SVC stack */
|
||||
/* one nest level deeper */
|
||||
ldr r0, =_ISR_Nest_level
|
||||
ldr r1, [r0]
|
||||
add r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
/* disable multitasking */
|
||||
ldr r0, =_Thread_Dispatch_disable_level
|
||||
ldr r1, [r0]
|
||||
add r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
msr cpsr, r5 /* switch back to INT mode */
|
||||
/* BSP specific function to INT handler */
|
||||
/* FIXME: I'm not sure why I can't save just r12. I'm also */
|
||||
/* not sure which of r1-r3 are important. */
|
||||
stmdb sp!, {r0-r12}
|
||||
bl ExecuteITHandler
|
||||
ldmia sp!, {r0-r12}
|
||||
|
||||
/* one less nest level */
|
||||
ldr r0, =_ISR_Nest_level
|
||||
ldr r1, [r0]
|
||||
sub r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
/* unnest multitasking */
|
||||
ldr r0, =_Thread_Dispatch_disable_level
|
||||
ldr r1, [r0]
|
||||
sub r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, =_ISR_Nest_level /* one nest level deeper */
|
||||
ldr r1, [r0]
|
||||
add r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, =_Thread_Dispatch_disable_level /* disable multitasking */
|
||||
ldr r1, [r0]
|
||||
add r1, r1,#1
|
||||
str r1, [r0]
|
||||
/* If thread dispatching is disabled, exit */
|
||||
cmp r1, #0
|
||||
bne exitit
|
||||
|
||||
b ExecuteITHandler /* BSP specific function to INT handler */
|
||||
/* If a task switch is necessary, call scheduler */
|
||||
ldr r0, =_Context_Switch_necessary
|
||||
ldr r1, [r0]
|
||||
cmp r1, #0
|
||||
|
||||
/* since bframe is going to clear _ISR_Signals_to_thread_executing, */
|
||||
/* we need to load it here */
|
||||
ldr r0, =_ISR_Signals_to_thread_executing
|
||||
ldr r1, [r0]
|
||||
bne bframe
|
||||
|
||||
/* If a signals to be sent (_ISR_Signals_to_thread_executing != 0), */
|
||||
/* call scheduler */
|
||||
cmp r1, #0
|
||||
beq exitit
|
||||
|
||||
/* _ISR_Signals_to_thread_executing = FALSE */
|
||||
mov r1, #0
|
||||
str r1, [r0]
|
||||
|
||||
.globl ReturnFromHandler
|
||||
ReturnFromHandler :
|
||||
ldr r0, =_ISR_Nest_level /* one less nest level */
|
||||
ldr r1, [r0]
|
||||
sub r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, =_Thread_Dispatch_disable_level /* unnest multitasking */
|
||||
ldr r1, [r0]
|
||||
sub r1, r1,#1
|
||||
str r1, [r0]
|
||||
|
||||
cmp r1, #0 /* is dispatch enabled */
|
||||
bne exitit /* Yes, then exit */
|
||||
|
||||
ldr r0, =_Context_Switch_necessary /* task switch necessary ? */
|
||||
ldr r1, [r0]
|
||||
cmp r1, #0
|
||||
bne schedule /* yes, call scheduler */
|
||||
|
||||
ldr r0, =_ISR_Signals_to_thread_executing
|
||||
ldr r1, [r0] /* signals sent to Run_thread */
|
||||
cmp r1, #0 /* while in interrupt handler ? */
|
||||
beq exitit /* No, exit */
|
||||
|
||||
bframe:
|
||||
mov r1, #0 /* _ISR_Signals_to_thread_executing = FALSE */
|
||||
str r1, [r0]
|
||||
/*
|
||||
* At this point, we need a complete exception context for the
|
||||
* current thread. We need to complete the interrupt exception
|
||||
* with the "not-yet-saved" registers
|
||||
*/
|
||||
/*
|
||||
* currently exception context = interrupt handler
|
||||
* it needs to be optimized
|
||||
*/
|
||||
bl _ThreadProcessSignalsFromIrq
|
||||
b exitit
|
||||
|
||||
schedule:
|
||||
/*
|
||||
* the scratch registers have already been saved and we are already
|
||||
* back on the thread system stack. So we can call _Thread_Displatch
|
||||
* directly
|
||||
*/
|
||||
bl _Thread_Dispatch
|
||||
/*
|
||||
* fall through exit to restore complete contex (scratch registers
|
||||
* eip, CS, Flags).
|
||||
*/
|
||||
exitit:
|
||||
b AckControler /* BSP specific function to ack PIC */
|
||||
|
||||
.globl ReturnFromAck
|
||||
ReturnFromAck :
|
||||
ldmia sp!, {r0-r3,r12,r14} /* restore regs from SVC stack */
|
||||
msr cpsr, r5 /* switch back to INT mode */
|
||||
ldmia sp!, {r4,r5,lr} /* restore regs from INT stack */
|
||||
subs pc,r14,#4 /* return */
|
||||
|
||||
/* Now we need to set up the return from this ISR to be _ISR_Dispatch */
|
||||
/* To do that, we need to save the current lr_int and spsr_int on the */
|
||||
/* SVC stack */
|
||||
mrs r0, spsr
|
||||
ldmia sp!, {r1} /* get lr off stack */
|
||||
stmdb sp!, {r1}
|
||||
mrs r2, cpsr
|
||||
orr r3, r2, #0x1 /* change to SVC mode */
|
||||
msr cpsr_c, r3
|
||||
|
||||
/* now in SVC mode */
|
||||
stmdb sp!, {r0, r1} /* put spsr_int and lr_int on SVC stack */
|
||||
msr cpsr_c, r2 /* change back to INT mode */
|
||||
|
||||
/* now in INT mode */
|
||||
|
||||
/* replace lr with address of _ISR_Dispatch */
|
||||
ldr lr, =_ISR_Dispatch
|
||||
add lr, lr, #0x4 /* On entry to an ISR, the lr is */
|
||||
/* the return address + 4, so */
|
||||
/* we have to emulate that */
|
||||
ldmia sp!, {r0} /* out with the old */
|
||||
stmdb sp!, {lr} /* in with the new (lr) */
|
||||
|
||||
|
||||
mrs r0, spsr
|
||||
orr r0, r0, #0xc0
|
||||
msr spsr, r0
|
||||
|
||||
exitit:
|
||||
ldmia sp!, {lr} /* restore regs from INT stack */
|
||||
ldmia sp!, {r0, r1, r2, r3} /* restore regs from INT stack */
|
||||
subs pc, lr, #4 /* return */
|
||||
|
||||
|
||||
|
||||
/* on entry to _ISR_Dispatch, we're in SVC mode */
|
||||
.globl _ISR_Dispatch
|
||||
_ISR_Dispatch:
|
||||
stmdb sp!, {r0-r12,lr} /* save regs on SVC stack */
|
||||
/* (now safe to call C funcs) */
|
||||
/* we don't save lr, since */
|
||||
/* it's just going to get */
|
||||
/* overwritten */
|
||||
|
||||
bl _Thread_Dispatch
|
||||
ldmia sp!, {r0-r12, lr}
|
||||
|
||||
stmdb sp!, {r0-r2}
|
||||
/* Now we have to screw with the stack */
|
||||
mov r0, sp /* copy the SVC stack pointer */
|
||||
|
||||
mrs r1, cpsr
|
||||
bic r2, r1, #0x1 /* change to INT mode */
|
||||
orr r2, r2, #0xc0 /* disable interrupts */
|
||||
msr cpsr_c, r2
|
||||
|
||||
/* now in INT mode */
|
||||
stmdb sp!, {r4, r5, r6} /* save temp vars on INT stack */
|
||||
ldmia r0!, {r4, r5, r6} /* Get r0-r3 from SVC stack */
|
||||
stmdb sp!, {r4, r5, r6} /* and save them on INT stack */
|
||||
|
||||
ldmia r0!, {r4, r5} /* get saved values from SVC stack */
|
||||
/* r4=spsr, r5=lr */
|
||||
mov lr, r5 /* restore lr_int */
|
||||
msr spsr, r4 /* restore spsr_int */
|
||||
|
||||
/* switch to SVC mode, update sp, then return to INT mode */
|
||||
msr cpsr_c, r1 /* switch to SVC mode */
|
||||
mov sp, r0 /* update sp_svc */
|
||||
msr cpsr_c, r2 /* switch back to INT mode */
|
||||
|
||||
/* pop all the registers from the stack */
|
||||
ldmia sp!, {r0, r1, r2}
|
||||
ldmia sp!, {r4, r5, r6}
|
||||
|
||||
/* Finally, we can return to the interrupted task */
|
||||
subs pc, lr, #4
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user