sos-code-article7/hwcore/exception_wrappers.S

272 lines
8.9 KiB
ArmAsm

/* 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