001 /* Copyright (C) 2004 The KOS Team
002
003 This program is free software; you can redistribute it and/or
004 modify it under the terms of the GNU General Public License
005 as published by the Free Software Foundation; either version 2
006 of the License, or (at your option) any later version.
007
008 This program is distributed in the hope that it will be useful,
009 but WITHOUT ANY WARRANTY; without even the implied warranty of
010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011 GNU General Public License for more details.
012
013 You should have received a copy of the GNU General Public License
014 along with this program; if not, write to the Free Software
015 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016 USA.
017 */
018 #include "exception.h"
019
020 #include "segment.h"
021
022 .file "exception_wrappers.S"
023
024 .text
025
026 /* The address of the table of handlers (defined in exception.c) */
027 .extern sos_exception_handler_array
028
029 /* The address of the table of wrappers (defined below, and shared
030 with exception.c */
031 .globl sos_exception_wrapper_array
032
033 /** Update the kernel TSS in case we are switching to a thread in user
034 mode in order to come back into the correct kernel stack */
035 .extern sos_cpu_context_update_kernel_tss
036
037 /* The address of the function to call to set back the user thread's
038 MMU configuration upon return to user context */
039 .extern sos_thread_prepare_exception_switch_back
040
041 /**
042 * For exceptions with/without error code, refer to Intel x86 doc vol 3,
043 * section 5.12
044 */
045
046 /* These wrappers are for exceptions without error code */
047 .irp id, \
048 SOS_EXCEPT_DIVIDE_ERROR, \
049 SOS_EXCEPT_DEBUG, \
050 SOS_EXCEPT_NMI_INTERRUPT, \
051 SOS_EXCEPT_BREAKPOINT, \
052 SOS_EXCEPT_OVERFLOW, \
053 SOS_EXCEPT_BOUND_RANGE_EXCEDEED, \
054 SOS_EXCEPT_INVALID_OPCODE, \
055 SOS_EXCEPT_DEVICE_NOT_AVAILABLE, \
056 SOS_EXCEPT_COPROCESSOR_SEGMENT_OVERRUN, \
057 SOS_EXCEPT_INTEL_RESERVED_1, \
058 SOS_EXCEPT_FLOATING_POINT_ERROR, \
059 SOS_EXCEPT_MACHINE_CHECK, \
060 SOS_EXCEPT_INTEL_RESERVED_2, \
061 SOS_EXCEPT_INTEL_RESERVED_3, \
062 SOS_EXCEPT_INTEL_RESERVED_4, \
063 SOS_EXCEPT_INTEL_RESERVED_5, \
064 SOS_EXCEPT_INTEL_RESERVED_6, \
065 SOS_EXCEPT_INTEL_RESERVED_7, \
066 SOS_EXCEPT_INTEL_RESERVED_8, \
067 SOS_EXCEPT_INTEL_RESERVED_9, \
068 SOS_EXCEPT_INTEL_RESERVED_10, \
069 SOS_EXCEPT_INTEL_RESERVED_11, \
070 SOS_EXCEPT_INTEL_RESERVED_12, \
071 SOS_EXCEPT_INTEL_RESERVED_13, \
072 SOS_EXCEPT_INTEL_RESERVED_14
073
074 .p2align 2, 0x90
075 sos_exception_wrapper_\id:
076 .type sos_exception_wrapper_\id,@function
077
078 /* Fake error code */
079 pushl $0
080 /* Backup the context */
081 pushl %ebp
082 movl %esp, %ebp
083
084 pushl %edi
085 pushl %esi
086 pushl %edx
087 pushl %ecx
088 pushl %ebx
089 pushl %eax
090 subl $2,%esp
091 pushw %ss
092 pushw %ds
093 pushw %es
094 pushw %fs
095 pushw %gs
096
097 /* Set correct kernel segment descriptors' value */
098 movw $SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA), %di
099 pushw %di ; popw %ds
100 pushw %di ; popw %es
101 pushw %di ; popw %fs
102 pushw %di ; popw %gs
103
104 /*
105 * Call the handler with the exception number and the
106 * address of the stored CPU context as arguments
107 */
108 pushl %esp
109 pushl $\id
110 leal sos_exception_handler_array,%edi
111 call *\id*4(%edi)
112 /* Unallocate the arguments passed to the handler */
113 addl $8, %esp
114
115 /* Reconfigure the MMU if needed */
116 pushl %esp /* cpu_ctxt */
117 call sos_thread_prepare_exception_switch_back
118 addl $4, %esp /* Unallocate the stack */
119
120 /* Prepare kernel TSS in case we are switching to a
121 user thread: we make sure that we will come back
122 into the kernel at a correct stack location */
123 pushl %esp /* Pass the location of the context we are
124 restoring to the function */
125 call sos_cpu_context_update_kernel_tss
126 addl $4, %esp
127
128 /* Restore the context */
129 popw %gs
130 popw %fs
131 popw %es
132 popw %ds
133 popw %ss
134 addl $2,%esp
135 popl %eax
136 popl %ebx
137 popl %ecx
138 popl %edx
139 popl %esi
140 popl %edi
141
142 popl %ebp
143 /* Remove fake error code */
144 addl $4, %esp
145 iret
146 .endr
147
148 /* These wrappers are for exceptions with error code */
149 .irp id, \
150 SOS_EXCEPT_INVALID_TSS, \
151 SOS_EXCEPT_SEGMENT_NOT_PRESENT, \
152 SOS_EXCEPT_STACK_SEGMENT_FAULT, \
153 SOS_EXCEPT_GENERAL_PROTECTION, \
154 SOS_EXCEPT_PAGE_FAULT, \
155 SOS_EXCEPT_ALIGNEMENT_CHECK
156
157 .p2align 2, 0x90
158 sos_exception_wrapper_\id:
159 .type sos_exception_wrapper_\id,@function
160
161 /* ret eflags */
162 /* ret cs */
163 /* ret eip */
164 /* Error code */
165
166 /* Backup the context */
167 pushl %ebp
168 movl %esp, %ebp
169
170 pushl %edi
171 pushl %esi
172 pushl %edx
173 pushl %ecx
174 pushl %ebx
175 pushl %eax
176 subl $2,%esp
177 pushw %ss
178 pushw %ds
179 pushw %es
180 pushw %fs
181 pushw %gs
182
183 /* Set correct kernel segment descriptors' value */
184 movw $SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA), %di
185 pushw %di ; popw %ds
186 pushw %di ; popw %es
187 pushw %di ; popw %fs
188 pushw %di ; popw %gs
189
190 /*
191 * Call the handler with the exception number and the
192 * address of the stored CPU context as arguments
193 */
194 pushl %esp
195 pushl $\id
196 leal sos_exception_handler_array,%edi
197 call *\id*4(%edi)
198 /* Unallocate the arguments passed to the handler */
199 addl $8, %esp
200
201 /* Reconfigure the MMU if needed */
202 pushl %esp /* cpu_ctxt */
203 call sos_thread_prepare_exception_switch_back
204 addl $4, %esp /* Unallocate the stack */
205
206 /* Prepare kernel TSS in case we are switching to a
207 user thread: we make sure that we will come back
208 into the kernel at a correct stack location */
209 pushl %esp /* Pass the location of the context we are
210 restoring to the function */
211 call sos_cpu_context_update_kernel_tss
212 addl $4, %esp
213
214 /* Restore the context */
215 popw %gs
216 popw %fs
217 popw %es
218 popw %ds
219 popw %ss
220 addl $2,%esp
221 popl %eax
222 popl %ebx
223 popl %ecx
224 popl %edx
225 popl %esi
226 popl %edi
227 popl %ebp
228
229 /* Error code isn't compatible with iretd */
230 addl $4, %esp
231
232 iret
233 .endr
234
235
236 /* Double fault handler not supported. We must define it since we
237 define an entry for it in the sos_exception_wrapper_array. It
238 simply uses an alternate stack to display a message and stop the
239 system. qemu won't handle it correctly (see comment in qemu's
240 sources). */
241 #define ALTERNATE_DOUBLE_FAULT_STACK_SIZE 512
242 .irp id, SOS_EXCEPT_DOUBLE_FAULT
243 .p2align 2, 0x90
244 sos_exception_wrapper_\id:
245 .type sos_exception_wrapper_\id,@function
246 1: cli /* Not necessary */
247 movl $double_fault_alternate_stack, %eax
248 addl $ALTERNATE_DOUBLE_FAULT_STACK_SIZE, %eax
249 movl %eax, %esp
250 pushl $msg_double_fault_not_supported
251 call sos_display_fatal_error ; jmp 1b /* Not necessary */
252 .endr
253
254 .section ".rodata"
255 msg_double_fault_not_supported:
256 .string "exception_wrappers.S: Double fault detected ! NOT SUPPORTED yet. System Halted."
257
258 /* Build the sos_irq_wrapper_array, shared with interrupt.c */
259 .p2align 5, 0x0
260 sos_exception_wrapper_array:
261 .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, \
262 16,17,18,19,20,21,22,23,24,25,26,27,29,30,31
263 .long (sos_exception_wrapper_\id)
264 .endr
265
266 /* Alternate stack for double fault handler */
267 .bss
268 .p2align 2, 0x0
269 .size double_fault_alternate_stack, ALTERNATE_DOUBLE_FAULT_STACK_SIZE
270 double_fault_alternate_stack:
271 .fill ALTERNATE_DOUBLE_FAULT_STACK_SIZE, 1, 0x0