/* Copyright (C) 2004 The KOS Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "segment.h" .file "irq_wrappers.S" .text /** The address of the table of handlers (defined in irq.c) */ .extern sos_irq_handler_array /** The address of the table of wrappers (defined below, and shared with irq.c */ .globl sos_irq_wrapper_array /** The variable holding the nested level of the IRQ handlers */ .extern sos_irq_nested_level_counter /** Update the interrupted current thread's CPU context Its prototype is: sos_thread_prepare_irq_servicing(struct sos_cpu_state *); */ .extern sos_thread_prepare_irq_servicing /** Update the kernel TSS in case we are switching to a thread in user mode in order to come back into the correct kernel stack */ .extern sos_cpu_context_update_kernel_tss /** Select a thread to set on CPU (this enables user-threads preemption) and configure the MMU to match that of the destination thread. Its prototype is: struct sos_cpu_state * // Selected CPU context sos_thread_prepare_irq_switch_back(); */ .extern sos_thread_prepare_irq_switch_back /* These pre-handlers are for IRQ (Master PIC) */ .irp id, 0,1,2,3,4,5,6,7 .p2align 2, 0x90 sos_irq_wrapper_\id: .type sos_irq_wrapper_\id,@function /* * Backup the CPU context */ /* Fake error code */ pushl $0 /* Backup the actual context */ pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %edx pushl %ecx pushl %ebx pushl %eax subl $2,%esp pushw %ss pushw %ds pushw %es pushw %fs pushw %gs /* Set correct kernel segment descriptors' value */ movw $SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA), %di pushw %di ; popw %ds pushw %di ; popw %es pushw %di ; popw %fs pushw %di ; popw %gs /* * Increment IRQ nested level */ incl sos_irq_nested_level_counter /* Outermost IRQ only: store the interrupted context of the current thread */ cmpl $1, sos_irq_nested_level_counter jne 1f pushl %esp call sos_thread_prepare_irq_servicing addl $4, %esp 1: /* Send EOI to PIC. See Intel 8259 datasheet available on Kos website */ movb $0x20, %al outb %al, $0x20 /* * Call the handler with IRQ number as argument */ pushl $\id leal sos_irq_handler_array,%edi call *\id*4(%edi) addl $4, %esp /* * Decrement IRQ nested level */ cli /* Just in case we messed up everything in the handler */ subl $1, sos_irq_nested_level_counter /* sos_irq_nested_level_counter went below 0 ?! */ jnc 2f 1: /* Yes: Print fatal error message */ pushl $msg_nested_level_overflow call sos_display_fatal_error addl $4, %esp ; jmp 1b /* Never returns */ 2: /* No: all right ! */ /* Was this the outermost IRQ handler ? */ jnz 3f /* Yes: reschedule */ call sos_thread_prepare_irq_switch_back /* Establish new context: context switch ! */ movl %eax, %esp /* Prepare kernel TSS in case we are switching to a user thread: we make sure that we will come back into the kernel at a correct stack location */ pushl %esp /* Pass the location of the context we are restoring to the function */ call sos_cpu_context_update_kernel_tss addl $4, %esp 3: /* Restore the context */ popw %gs popw %fs popw %es popw %ds popw %ss addl $2,%esp popl %eax popl %ebx popl %ecx popl %edx popl %esi popl %edi popl %ebp /* Remove fake error code */ addl $4, %esp iret .endr /* These pre-handlers are for IRQ (Slave PIC) */ .irp id, 8,9,10,11,12,13,14,15 .p2align 2, 0x90 sos_irq_wrapper_\id: .type sos_irq_wrapper_\id,@function /* * Backup the CPU context */ /* Fake error code */ pushl $0 /* Backup the actual context */ pushl %ebp movl %esp, %ebp pushl %edi pushl %esi pushl %edx pushl %ecx pushl %ebx pushl %eax subl $2,%esp pushw %ss pushw %ds pushw %es pushw %fs pushw %gs /* Set correct kernel segment descriptors' value */ movw $SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA), %di pushw %di ; popw %ds pushw %di ; popw %es pushw %di ; popw %fs pushw %di ; popw %gs /* * Increment IRQ nested level */ incl sos_irq_nested_level_counter /* Outermost IRQ only: store the interrupted context of the current thread */ cmpl $1, sos_irq_nested_level_counter jne 1f pushl %esp call sos_thread_prepare_irq_servicing addl $4, %esp 1: /* Send EOI to PIC. See Intel 8259 datasheet available on Kos website */ movb $0x20, %al outb %al, $0xa0 outb %al, $0x20 /* * Call the handler with IRQ number as argument */ pushl $\id leal sos_irq_handler_array,%edi call *\id*4(%edi) addl $4, %esp /* * Decrement IRQ nested level */ cli /* Just in case we messed up everything in the handler */ subl $1, sos_irq_nested_level_counter /* sos_irq_nested_level_counter went below 0 ?! */ jnc 2f 1: /* Yes: Print fatal error message */ pushl $msg_nested_level_overflow call sos_display_fatal_error addl $4, %esp ; jmp 1b /* Never returns */ 2: /* No: all right ! */ /* Was this the outermost IRQ handler ? */ jnz 3f /* Yes: reschedule */ call sos_thread_prepare_irq_switch_back /* Establish new context: context switch ! */ movl %eax, %esp /* Prepare kernel TSS in case we are switching to a user thread: we make sure that we will come back into the kernel at a correct stack location */ pushl %esp /* Pass the location of the context we are restoring to the function */ call sos_cpu_context_update_kernel_tss addl $4, %esp 3: /* Restore the context */ popw %gs popw %fs popw %es popw %ds popw %ss addl $2,%esp popl %eax popl %ebx popl %ecx popl %edx popl %esi popl %edi popl %ebp /* Remove fake error code */ addl $4, %esp iret .endr .section ".rodata" msg_nested_level_overflow: .string "irq_wrappers.S: IRQ Nested level overflow ! System halted." /* Build the sos_irq_wrapper_array, shared with irq.c */ .p2align 5, 0x0 sos_irq_wrapper_array: .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 .long (sos_irq_wrapper_\id) .endr