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
019 #include "segment.h"
020
021 .file "irq_wrappers.S"
022
023 .text
024
025 /** The address of the table of handlers (defined in irq.c) */
026 .extern sos_irq_handler_array
027
028 /** The address of the table of wrappers (defined below, and shared
029 with irq.c */
030 .globl sos_irq_wrapper_array
031
032 /** The variable holding the nested level of the IRQ handlers */
033 .extern sos_irq_nested_level_counter
034
035 /** Update the interrupted current thread's CPU context
036 Its prototype is:
037 sos_thread_prepare_irq_servicing(struct sos_cpu_state *);
038 */
039 .extern sos_thread_prepare_irq_servicing
040
041 /** Update the kernel TSS in case we are switching to a thread in user
042 mode in order to come back into the correct kernel stack */
043 .extern sos_cpu_context_update_kernel_tss
044
045 /** Select a thread to set on CPU (this enables user-threads
046 preemption) and configure the MMU to match that of the destination
047 thread.
048 Its prototype is:
049 struct sos_cpu_state * // Selected CPU context
050 sos_thread_prepare_irq_switch_back();
051 */
052 .extern sos_thread_prepare_irq_switch_back
053
054 /* These pre-handlers are for IRQ (Master PIC) */
055 .irp id, 0,1,2,3,4,5,6,7
056
057 .p2align 2, 0x90
058
059 sos_irq_wrapper_\id:
060 .type sos_irq_wrapper_\id,@function
061
062 /*
063 * Backup the CPU context
064 */
065
066 /* Fake error code */
067 pushl $0
068
069 /* Backup the actual context */
070 pushl %ebp
071 movl %esp, %ebp
072
073 pushl %edi
074 pushl %esi
075 pushl %edx
076 pushl %ecx
077 pushl %ebx
078 pushl %eax
079 subl $2,%esp
080 pushw %ss
081 pushw %ds
082 pushw %es
083 pushw %fs
084 pushw %gs
085
086 /* Set correct kernel segment descriptors' value */
087 movw $SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA), %di
088 pushw %di ; popw %ds
089 pushw %di ; popw %es
090 pushw %di ; popw %fs
091 pushw %di ; popw %gs
092
093 /*
094 * Increment IRQ nested level
095 */
096 incl sos_irq_nested_level_counter
097 /* Outermost IRQ only: store the interrupted context
098 of the current thread */
099 cmpl $1, sos_irq_nested_level_counter
100 jne 1f
101 pushl %esp
102 call sos_thread_prepare_irq_servicing
103 addl $4, %esp
104
105 1:
106
107 /* Send EOI to PIC. See Intel 8259 datasheet
108 available on Kos website */
109 movb $0x20, %al
110 outb %al, $0x20
111
112 /*
113 * Call the handler with IRQ number as argument
114 */
115 pushl $\id
116 leal sos_irq_handler_array,%edi
117 call *\id*4(%edi)
118 addl $4, %esp
119
120 /*
121 * Decrement IRQ nested level
122 */
123 cli /* Just in case we messed up everything in the handler */
124 subl $1, sos_irq_nested_level_counter
125
126 /* sos_irq_nested_level_counter went below 0 ?! */
127 jnc 2f
128
129 1: /* Yes: Print fatal error message */
130 pushl $msg_nested_level_overflow
131 call sos_display_fatal_error
132 addl $4, %esp ; jmp 1b
133 /* Never returns */
134
135 2: /* No: all right ! */
136
137 /* Was this the outermost IRQ handler ? */
138 jnz 3f
139
140 /* Yes: reschedule */
141 call sos_thread_prepare_irq_switch_back
142 /* Establish new context: context switch ! */
143 movl %eax, %esp
144
145 /* Prepare kernel TSS in case we are switching to a
146 user thread: we make sure that we will come back
147 into the kernel at a correct stack location */
148 pushl %esp /* Pass the location of the context we are
149 restoring to the function */
150 call sos_cpu_context_update_kernel_tss
151 addl $4, %esp
152 3:
153 /* Restore the context */
154 popw %gs
155 popw %fs
156 popw %es
157 popw %ds
158 popw %ss
159 addl $2,%esp
160 popl %eax
161 popl %ebx
162 popl %ecx
163 popl %edx
164 popl %esi
165 popl %edi
166 popl %ebp
167
168 /* Remove fake error code */
169 addl $4, %esp
170
171 iret
172 .endr
173
174
175 /* These pre-handlers are for IRQ (Slave PIC) */
176 .irp id, 8,9,10,11,12,13,14,15
177
178 .p2align 2, 0x90
179
180 sos_irq_wrapper_\id:
181 .type sos_irq_wrapper_\id,@function
182
183 /*
184 * Backup the CPU context
185 */
186
187 /* Fake error code */
188 pushl $0
189
190 /* Backup the actual context */
191 pushl %ebp
192 movl %esp, %ebp
193
194 pushl %edi
195 pushl %esi
196 pushl %edx
197 pushl %ecx
198 pushl %ebx
199 pushl %eax
200 subl $2,%esp
201 pushw %ss
202 pushw %ds
203 pushw %es
204 pushw %fs
205 pushw %gs
206
207 /* Set correct kernel segment descriptors' value */
208 movw $SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA), %di
209 pushw %di ; popw %ds
210 pushw %di ; popw %es
211 pushw %di ; popw %fs
212 pushw %di ; popw %gs
213
214 /*
215 * Increment IRQ nested level
216 */
217 incl sos_irq_nested_level_counter
218 /* Outermost IRQ only: store the interrupted context
219 of the current thread */
220 cmpl $1, sos_irq_nested_level_counter
221 jne 1f
222 pushl %esp
223 call sos_thread_prepare_irq_servicing
224 addl $4, %esp
225
226 1:
227
228 /* Send EOI to PIC. See Intel 8259 datasheet
229 available on Kos website */
230 movb $0x20, %al
231 outb %al, $0xa0
232 outb %al, $0x20
233
234 /*
235 * Call the handler with IRQ number as argument
236 */
237 pushl $\id
238 leal sos_irq_handler_array,%edi
239 call *\id*4(%edi)
240 addl $4, %esp
241
242 /*
243 * Decrement IRQ nested level
244 */
245 cli /* Just in case we messed up everything in the handler */
246 subl $1, sos_irq_nested_level_counter
247
248 /* sos_irq_nested_level_counter went below 0 ?! */
249 jnc 2f
250
251 1: /* Yes: Print fatal error message */
252 pushl $msg_nested_level_overflow
253 call sos_display_fatal_error
254 addl $4, %esp ; jmp 1b
255 /* Never returns */
256
257 2: /* No: all right ! */
258
259 /* Was this the outermost IRQ handler ? */
260 jnz 3f
261
262 /* Yes: reschedule */
263 call sos_thread_prepare_irq_switch_back
264 /* Establish new context: context switch ! */
265 movl %eax, %esp
266
267 /* Prepare kernel TSS in case we are switching to a
268 user thread: we make sure that we will come back
269 into the kernel at a correct stack location */
270 pushl %esp /* Pass the location of the context we are
271 restoring to the function */
272 call sos_cpu_context_update_kernel_tss
273 addl $4, %esp
274 3:
275 /* Restore the context */
276 popw %gs
277 popw %fs
278 popw %es
279 popw %ds
280 popw %ss
281 addl $2,%esp
282 popl %eax
283 popl %ebx
284 popl %ecx
285 popl %edx
286 popl %esi
287 popl %edi
288 popl %ebp
289
290 /* Remove fake error code */
291 addl $4, %esp
292
293 iret
294 .endr
295
296 .section ".rodata"
297 msg_nested_level_overflow:
298 .string "irq_wrappers.S: IRQ Nested level overflow ! System halted."
299
300 /* Build the sos_irq_wrapper_array, shared with irq.c */
301 .p2align 5, 0x0
302 sos_irq_wrapper_array:
303 .irp id, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
304 .long (sos_irq_wrapper_\id)
305 .endr