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:
Joel Sherrill
2002-07-17 17:17:53 +00:00
parent 3e2f5cc1e4
commit d5136d9639
2 changed files with 150 additions and 85 deletions

View File

@@ -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