/* 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 .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: * * = | irq_mask_or_tbl[] */ 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