summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386/shared/irq/irq_asm.s
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/i386/shared/irq/irq_asm.s')
-rw-r--r--c/src/lib/libbsp/i386/shared/irq/irq_asm.s261
1 files changed, 261 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/i386/shared/irq/irq_asm.s b/c/src/lib/libbsp/i386/shared/irq/irq_asm.s
new file mode 100644
index 0000000000..7765a9dd22
--- /dev/null
+++ b/c/src/lib/libbsp/i386/shared/irq/irq_asm.s
@@ -0,0 +1,261 @@
+/* irq.c
+ *
+ * This file contains the implementation of the function described in irq.h
+ *
+ * CopyRight (C) 1998 valette@crf.canon.fr
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "asm.h"
+#include <irq_asm.h>
+
+.set SAVED_REGS , 32 # space consumed by saved regs
+.set EIP_OFFSET , SAVED_REGS # offset of tasks eip
+.set CS_OFFSET , EIP_OFFSET+4 # offset of tasks code segment
+.set EFLAGS_OFFSET , CS_OFFSET+4 # offset of tasks eflags
+
+
+/*PAGE
+ * void _new_ISR_Displatch()
+ *
+ * Entry point from the outermost interrupt service routine exit.
+ * The current stack is the supervisor mode stack.
+ */
+
+ PUBLIC (_new_ISR_Displatch)
+SYM (_New_ISR_Displatch):
+
+ call SYM (_Thread_Dispatch) # invoke Dispatcher
+
+ /*
+ * BEGINNING OF DE-ESTABLISH SEGMENTS
+ *
+ * NOTE: Make sure there is code here if code is added to
+ * load the segment registers.
+ *
+ */
+
+ /***** DE-ESTABLISH SEGMENTS CODE GOES HERE ****/
+
+ /*
+ * END OF DE-ESTABLISH SEGMENTS
+ */
+
+ popa # restore general registers
+ iret # return to interrupted thread
+
+
+SYM (_New_ISR_Handler):
+ /*
+ * Before this was point is reached the vectors unique
+ * entry point did the following:
+ *
+ * 1. saved sctach registers registers eax edx ecx"
+ * 2. put the vector number in ecx.
+ *
+ * BEGINNING OF ESTABLISH SEGMENTS
+ *
+ * WARNING: If an interrupt can occur when the segments are
+ * not correct, then this is where we should establish
+ * the segments. In addition to establishing the
+ * segments, it may be necessary to establish a stack
+ * in the current data area on the outermost interrupt.
+ *
+ * NOTE: If the previous values of the segment registers are
+ * pushed, do not forget to adjust SAVED_REGS.
+ *
+ * NOTE: Make sure the exit code which restores these
+ * when this type of code is needed.
+ */
+
+ /***** ESTABLISH SEGMENTS CODE GOES HERE ******/
+
+ /*
+ * END OF ESTABLISH SEGMENTS
+ */
+
+ /*
+ * Now switch stacks if necessary
+ */
+
+ movw SYM (i8259s_cache), ax # move current i8259 interrupt mask in ax
+ pushl eax # push it on the stack
+ /*
+ * compute the new PIC mask:
+ *
+ * <new mask> = <old mask> | irq_mask_or_tbl[<intr number aka ecx>]
+ */
+ movw SYM (irq_mask_or_tbl) (,ecx,2), dx
+ orw dx, ax
+ /*
+ * Install new computed value on the i8259 and update cache
+ * accordingly
+ */
+ movw ax, SYM (i8259s_cache)
+ outb $PIC_MASTER_IMR_IO_PORT
+ movb ah, al
+ outb $PIC_SLAVE_IMR_IO_PORT
+
+ /*
+ * acknowledge the interrupt
+ *
+ */
+ movb $PIC_EOI, al
+ cmpl $7, ecx
+ jbe .master
+ outb $PIC_SLAVE_COMMAND_IO_PORT
+.master:
+ outb $PIC_MASTER_COMMAND_IO_PORT
+
+.check_stack_switch:
+ pushl ebp
+ movl esp, ebp # ebp = previous stack pointer
+ cmpl $0, SYM (_ISR_Nest_level) # is this the outermost interrupt?
+ jne nested # No, then continue
+ movl SYM (_CPU_Interrupt_stack_high), esp
+
+ /*
+ * We want to insure that the old stack pointer is on the
+ * stack we will be on at the end of the ISR when we restore it.
+ * By saving it on every interrupt, all we have to do is pop it
+ * near the end of every interrupt.
+ */
+
+nested:
+ incl SYM (_ISR_Nest_level) # one nest level deeper
+ incl SYM (_Thread_Dispatch_disable_level) # disable multitasking
+ /*
+ * re-enable interrupts at processor level as the current
+ * interrupt source is now masked via i8259
+ */
+ sti
+
+ /*
+ * ECX is preloaded with the vector number but it is a scratch register
+ * so we must save it again.
+ */
+
+ pushl ecx # push vector number
+ mov SYM (current_irq) (,ecx,4),eax
+ # eax = Users handler
+ call *eax # invoke user ISR
+ /*
+ * disable interrupts_again
+ */
+ cli
+ popl ecx # ecx = vector number
+ /*
+ * restore stack
+ */
+ movl ebp, esp
+ popl ebp
+
+ /*
+ * restore the original i8259 masks
+ */
+ popl eax
+ movw ax, SYM (i8259s_cache)
+ outb $PIC_MASTER_IMR_IO_PORT
+ movb ah, al
+ outb $PIC_SLAVE_IMR_IO_PORT
+
+
+ decl SYM (_ISR_Nest_level) # one less ISR nest level
+ # If interrupts are nested,
+ # then dispatching is disabled
+
+ decl SYM (_Thread_Dispatch_disable_level)
+ # unnest multitasking
+ # Is dispatch disabled
+ jne .exit # Yes, then exit
+
+ cmpl $0, SYM (_Context_Switch_necessary)
+ # Is task switch necessary?
+ jne bframe # Yes, then build stack
+
+ cmpl $0, SYM (_ISR_Signals_to_thread_executing)
+ # signals sent to Run_thread
+ # while in interrupt handler?
+ je .exit # No, exit
+
+bframe:
+ movl $0, SYM (_ISR_Signals_to_thread_executing)
+ /*
+ * complete code as if a pusha had been executed on entry
+ */
+ pushl ebx
+ pushl esp
+ pushl ebp
+ pushl esi
+ pushl edi
+ # push the isf for Isr_dispatch
+ pushl EFLAGS_OFFSET(esp) # push tasks eflags
+ push cs # cs of Isr_dispatch
+ pushl $ SYM (_New_ISR_Displatch)# entry point
+ iret
+
+.exit:
+ /*
+ * BEGINNING OF DE-ESTABLISH SEGMENTS
+ *
+ * NOTE: Make sure there is code here if code is added to
+ * load the segment registers.
+ *
+ */
+
+ /******* DE-ESTABLISH SEGMENTS CODE GOES HERE ********/
+
+ /*
+ * END OF DE-ESTABLISH SEGMENTS
+ */
+ popl edx
+ popl ecx
+ popl eax
+ iret
+
+#define DISTINCT_INTERRUPT_ENTRY(_vector) \
+ .p2align 4 ; \
+ PUBLIC (rtems_irq_prologue_ ## _vector ) ; \
+SYM (rtems_irq_prologue_ ## _vector ): \
+ pushl eax ; \
+ pushl ecx ; \
+ pushl edx ; \
+ movl $ _vector, ecx ; \
+ jmp SYM (_New_ISR_Handler) ;
+
+DISTINCT_INTERRUPT_ENTRY(0)
+DISTINCT_INTERRUPT_ENTRY(1)
+DISTINCT_INTERRUPT_ENTRY(2)
+DISTINCT_INTERRUPT_ENTRY(3)
+DISTINCT_INTERRUPT_ENTRY(4)
+DISTINCT_INTERRUPT_ENTRY(5)
+DISTINCT_INTERRUPT_ENTRY(6)
+DISTINCT_INTERRUPT_ENTRY(7)
+DISTINCT_INTERRUPT_ENTRY(8)
+DISTINCT_INTERRUPT_ENTRY(9)
+DISTINCT_INTERRUPT_ENTRY(10)
+DISTINCT_INTERRUPT_ENTRY(11)
+DISTINCT_INTERRUPT_ENTRY(12)
+DISTINCT_INTERRUPT_ENTRY(13)
+DISTINCT_INTERRUPT_ENTRY(14)
+DISTINCT_INTERRUPT_ENTRY(15)
+
+ /*
+ * routine used to initialize the IDT by default
+ */
+
+PUBLIC (default_raw_idt_handler)
+PUBLIC (raw_idt_notify)
+
+SYM (default_raw_idt_handler):
+ pusha
+ cld
+ call raw_idt_notify
+ popa
+ iret
+