/* 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 "exception.h" #include "segment.h" .file "exception_wrappers.S" .text /* The address of the table of handlers (defined in exception.c) */ .extern sos_exception_handler_array /* The address of the table of wrappers (defined below, and shared with exception.c */ .globl sos_exception_wrapper_array /** 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 /* The address of the function to call to set back the user thread's MMU configuration upon return to user context */ .extern sos_thread_prepare_exception_switch_back /** * For exceptions with/without error code, refer to Intel x86 doc vol 3, * section 5.12 */ /* These wrappers are for exceptions without error code */ .irp id, \ SOS_EXCEPT_DIVIDE_ERROR, \ SOS_EXCEPT_DEBUG, \ SOS_EXCEPT_NMI_INTERRUPT, \ SOS_EXCEPT_BREAKPOINT, \ SOS_EXCEPT_OVERFLOW, \ SOS_EXCEPT_BOUND_RANGE_EXCEDEED, \ SOS_EXCEPT_INVALID_OPCODE, \ SOS_EXCEPT_DEVICE_NOT_AVAILABLE, \ SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN, \ SOS_EXCEPT_INTEL_RESERVED_1, \ SOS_EXCEPT_FLOATING_POINT_ERROR, \ SOS_EXCEPT_MACHINE_CHECK, \ SOS_EXCEPT_INTEL_RESERVED_2, \ SOS_EXCEPT_INTEL_RESERVED_3, \ SOS_EXCEPT_INTEL_RESERVED_4, \ SOS_EXCEPT_INTEL_RESERVED_5, \ SOS_EXCEPT_INTEL_RESERVED_6, \ SOS_EXCEPT_INTEL_RESERVED_7, \ SOS_EXCEPT_INTEL_RESERVED_8, \ SOS_EXCEPT_INTEL_RESERVED_9, \ SOS_EXCEPT_INTEL_RESERVED_10, \ SOS_EXCEPT_INTEL_RESERVED_11, \ SOS_EXCEPT_INTEL_RESERVED_12, \ SOS_EXCEPT_INTEL_RESERVED_13, \ SOS_EXCEPT_INTEL_RESERVED_14 .p2align 2, 0x90 sos_exception_wrapper_\id: .type sos_exception_wrapper_\id,@function /* Fake error code */ pushl $0 /* Backup the 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 /* * Call the handler with the exception number and the * address of the stored CPU context as arguments */ pushl %esp pushl $\id leal sos_exception_handler_array,%edi call *\id*4(%edi) /* Unallocate the arguments passed to the handler */ addl $8, %esp /* Reconfigure the MMU if needed */ pushl %esp /* cpu_ctxt */ call sos_thread_prepare_exception_switch_back addl $4, %esp /* Unallocate the stack */ /* 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 /* 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 wrappers are for exceptions with error code */ .irp id, \ SOS_EXCEPT_INVALID_TSS, \ SOS_EXCEPT_SEGMENT_NOT_PRESENT, \ SOS_EXCEPT_STACK_SEGMENT_FAULT, \ SOS_EXCEPT_GENERAL_PROTECTION, \ SOS_EXCEPT_PAGE_FAULT, \ SOS_EXCEPT_ALIGNEMENT_CHECK .p2align 2, 0x90 sos_exception_wrapper_\id: .type sos_exception_wrapper_\id,@function /* ret eflags */ /* ret cs */ /* ret eip */ /* Error code */ /* Backup the 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 /* * Call the handler with the exception number and the * address of the stored CPU context as arguments */ pushl %esp pushl $\id leal sos_exception_handler_array,%edi call *\id*4(%edi) /* Unallocate the arguments passed to the handler */ addl $8, %esp /* Reconfigure the MMU if needed */ pushl %esp /* cpu_ctxt */ call sos_thread_prepare_exception_switch_back addl $4, %esp /* Unallocate the stack */ /* 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 /* 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 /* Error code isn't compatible with iretd */ addl $4, %esp iret .endr /* Double fault handler not supported. We must define it since we define an entry for it in the sos_exception_wrapper_array. It simply uses an alternate stack to display a message and stop the system. qemu won't handle it correctly (see comment in qemu's sources). */ #define ALTERNATE_DOUBLE_FAULT_STACK_SIZE 512 .irp id, SOS_EXCEPT_DOUBLE_FAULT .p2align 2, 0x90 sos_exception_wrapper_\id: .type sos_exception_wrapper_\id,@function 1: cli /* Not necessary */ movl $double_fault_alternate_stack, %eax addl $ALTERNATE_DOUBLE_FAULT_STACK_SIZE, %eax movl %eax, %esp pushl $msg_double_fault_not_supported call sos_display_fatal_error ; jmp 1b /* Not necessary */ .endr .section ".rodata" msg_double_fault_not_supported: .string "exception_wrappers.S: Double fault detected ! NOT SUPPORTED yet. System Halted." /* Build the sos_irq_wrapper_array, shared with interrupt.c */ .p2align 5, 0x0 sos_exception_wrapper_array: .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \ 16,17,18,19,20,21,22,23,24,25,26,27,29,30,31 .long (sos_exception_wrapper_\id) .endr /* Alternate stack for double fault handler */ .bss .p2align 2, 0x0 .size double_fault_alternate_stack, ALTERNATE_DOUBLE_FAULT_STACK_SIZE double_fault_alternate_stack: .fill ALTERNATE_DOUBLE_FAULT_STACK_SIZE, 1, 0x0