summary |
shortlog |
changelog |
graph |
tags |
branches |
files |
changeset |
file |
revisions |
annotate |
diff |
raw
kernel/arch/i386/interrupts.S
| author | Rink Springer <rink@rink.nu> |
| Mon Jan 23 08:57:24 2012 +0100 (3 months ago ago) | |
| changeset 1334 | 1374b6733ab0 |
| parent 1331 | 17f6e1bc8a69 |
| child 1342 | 7c4f300504ea |
| permissions | -rw-r--r-- |
i386: Remove two exported symbols that don't exist anymore
1 /*
2 * Low-level assembly code to pass an interrupt to a higher-level handler.
3 */
4 .text
5 .globl exception0, exception1, exception2, exception3, exception4, exception5
6 .globl exception6, exception7, exception8, exception9, exception10, exception11
7 .globl exception12, exception13, exception14, exception16, exception17
8 .globl exception18, exception19
9 .globl irq0, irq1, irq2, irq3, irq4, irq5, irq6, irq7, irq8, irq9
10 .globl irq10, irq11, irq12, irq13, irq14, irq15
11 .globl syscall_int
12 .globl clone_return
13 .globl userland_trampoline, kthread_trampoline
15 #include "options.h"
16 #include "machine/param.h"
17 #include "machine/vm.h"
18 #include "asmsyms.h"
20 #define SANITY_CHECKS
22 #define SAVE_REGISTERS \
23 movl %eax, SF_EAX(%esp); \
24 movl %ebx, SF_EBX(%esp); \
25 movl %ecx, SF_ECX(%esp); \
26 movl %edx, SF_EDX(%esp); \
27 movl %ebp, SF_EBP(%esp); \
28 movl %esp, SF_ESP(%esp); \
29 movl %edi, SF_EDI(%esp); \
30 movl %esi, SF_ESI(%esp);
32 #define SAVE_SEGS \
33 xorl %eax, %eax; \
34 movw %ds, %ax; \
35 movl %eax, SF_DS(%esp); \
36 movw %es, %ax; \
37 movl %eax, SF_ES(%esp); \
38 movw %fs, %ax; \
39 movl %eax, SF_FS(%esp); \
40 movw %gs, %ax; \
41 movl %eax, SF_GS(%esp);
43 #define RESTORE_REGISTERS \
44 movl SF_EAX(%esp), %eax; \
45 movl SF_EBX(%esp), %ebx; \
46 movl SF_ECX(%esp), %ecx; \
47 movl SF_EDX(%esp), %edx; \
48 movl SF_EBP(%esp), %ebp; \
49 /* movl SF_ESP(%esp), %esp; */ \
50 movl SF_EDI(%esp), %edi; \
51 movl SF_ESI(%esp), %esi;
53 #define RESTORE_SEGS \
54 movl SF_DS(%esp), %eax; \
55 movw %ax, %ds; \
56 movl SF_ES(%esp), %eax; \
57 movw %ax, %es; \
58 movl SF_FS(%esp), %eax; \
59 movw %ax, %fs; \
60 movl SF_GS(%esp), %eax; \
61 movw %ax, %gs;
63 do_irq:
64 SAVE_REGISTERS
65 SAVE_SEGS
67 /* Set up kernel data */
68 movl $GDT_SEL_KERNEL_DATA, %eax
69 movw %ax, %ds
70 movw %ax, %es
72 /* Ensure per-cpu stuff works */
73 movl $GDT_SEL_KERNEL_PCPU, %eax
74 movw %ax, %fs
76 /* Increment the nested IRQ count */
77 incl %fs:(PCPU_NESTEDIRQ)
79 /* Restore the interrupt flag */
80 movl SF_EFLAGS(%esp), %eax
81 testl $0x200, %eax
82 jz 1f
84 sti
86 1: /* Call the interrupt handler */
87 pushl %esp
88 call interrupt_handler
89 addl $4, %esp
91 /* Restore previous state */
92 RESTORE_SEGS
93 RESTORE_REGISTERS
94 addl $SF_EIP, %esp
95 iret
97 do_exception:
98 SAVE_REGISTERS
99 SAVE_SEGS
101 /* Set up kernel data */
102 movl $GDT_SEL_KERNEL_DATA, %eax
103 movw %ax, %ds
104 movw %ax, %es
106 /* Ensure per-cpu stuff works */
107 movl $GDT_SEL_KERNEL_PCPU, %eax
108 movw %ax, %fs
110 /* Call the exception handler */
111 pushl %esp
112 call exception_handler
113 addl $4, %esp
115 /* Restore previous state */
116 RESTORE_SEGS
117 RESTORE_REGISTERS
118 addl $SF_EIP, %esp
119 iret
121 /*
122 * There exist two versions of exceptions: those with an error code, and those
123 * without one. Our handler code expects to be called with an error code, so
124 * we add a fake zero one if needed for those exceptions that don't have one.
125 */
126 #define EXCEPTION_HANDLER_ERRORCODE(num) \
127 exception ## num: \
128 subl $SF_ERRNUM, %esp; \
129 movl $num, SF_TRAPNO(%esp); \
130 jmp do_exception
132 #define EXCEPTION_HANDLER(num) \
133 exception ## num: \
134 subl $SF_EIP, %esp; \
135 movl $num, SF_TRAPNO(%esp); \
136 movl $0, SF_ERRNUM(%esp); \
137 jmp do_exception
139 /* IRQ handlers are a lot simpler: they come in a single easy flavour */
140 #define IRQ_HANDLER(num) \
141 irq ## num: \
142 subl $SF_EIP, %esp; \
143 movl $num, SF_TRAPNO(%esp); \
144 jmp do_irq
146 /*
147 * System call interrupt; system call number should be placed in %eax, all
148 * arguments are expected to be placed on the stack. Note that we only
149 * preserve what's needed by the System V ABI because that's what everyone
150 * seems to use anyway.
151 */
152 syscall_int:
153 /*
154 * System V ABI for Intel386 Architecture says we only have to
155 * preserve %ebx, %esi, %edi, %ebp and %esp (the latter is done
156 * implicitely by the hardware).
157 */
158 pushl %ebp
159 pushl %ebx
160 pushl %esi
161 pushl %edi
163 /* Save segment registers as well; we only use ds/es/fs */
164 pushl %ds
165 pushl %es
166 pushl %fs
168 #ifdef SANITY_CHECKS
169 /*
170 * Sanity check: a system call must be made from userland, thus %ds
171 * must be userland version
172 */
173 movw %ds, %bx
174 cmpw $(GDT_SEL_USER_DATA + 3), %bx
175 je syscall_start_dsok
177 int $3
179 syscall_start_dsok:
180 /* Sanity check: interrupts must be enabled when entering */
181 movl 36(%esp), %ebx
182 andl $0x200, %ebx
183 orl %ebx, %ebx
184 jne syscall_start_ifok
186 int $3
188 syscall_start_ifok:
189 #endif
191 /*
192 * Switch to kernel segment register context (ds/es/fs); this ensures
193 * the stores below will work (%esi uses %ds implicitely)
194 */
195 movw $GDT_SEL_KERNEL_DATA, %bx
196 movw %bx, %ds
197 movw %bx, %es
198 movw $GDT_SEL_KERNEL_PCPU, %bx
199 movw %bx, %fs
201 /*
202 * Fetch the caller's stack pointer; this will be saved at our
203 * current stack - but note that we have already created a
204 * stackframe, so we just use that as base.
205 *
206 * The 40 comes from stored fs es ds edi esi ebx ebp eip cs flg esp ss
207 * as they occur on offsets 0 4 8 12 16 20 24 28 32 36 40 44
208 */
209 movl 40(%esp), %esi
211 /*
212 * Set up a pointer to the structure, and copy 6 arguments
213 * in place. Note that the stack grows backward, so we need
214 * to place them in reverse order.
215 */
216 pushl 20(%esi)
217 pushl 16(%esi)
218 pushl 12(%esi)
219 pushl 8(%esi)
220 pushl 4(%esi)
221 pushl %eax
223 /*
224 * Invoke the generic syscall hander; return values will be passed in
225 * %eax, so we cannot thrash that. Note that our argument is pushed
226 * beforehand, which simply points to the syscall values.
227 */
228 pushl %esp
229 call syscall
230 addl $28, %esp /* 6 regs + esp */
232 syscall_return:
234 /* Restore registers */
235 popl %fs
236 popl %es
237 popl %ds
239 #ifdef SANITY_CHECKS
240 /*
241 * Sanity check: we must have restored an userland ds; if we don't,
242 * iret will reset %ds to null because it can't be accessed in ring 3,
243 * leading to hard-to-debug problems. Best to verify it here.
244 */
245 movw %ds, %bx
246 cmpw $(GDT_SEL_USER_DATA + 3), %bx
247 je syscall_end_dsok
249 int $3
251 syscall_end_dsok:
252 /* Sanity check: interrupts must be enabled when a syscall is done */
253 movl 24(%esp), %ebx
254 andl $0x200, %ebx
255 orl %ebx, %ebx
256 jne syscall_end_ifok
258 int $3
260 syscall_end_ifok:
261 #endif
263 popl %edi
264 popl %esi
265 popl %ebx
266 popl %ebp
267 iret
269 clone_return:
270 /*
271 * Once here, the to-be-cloned thread is scheduled to be
272 * resumed. We are returning to a new thread, so we'll
273 * need to restore the context exactly as it were when
274 * the thread did the syscall.
275 *
276 * However, the top of the kernel stack will still have
277 * the stackframe set up by our syscall routine (as there
278 * is no other way to do a clone) - we can use that
279 * information to restore the caller.
280 *
281 * Note that the ABI dictates that %eax is used to return
282 * a value to the new thread, so we'll have to restore it.
283 */
285 /* Rewind the stack as created by syscall_int */
286 movl %fs:(PCPU_CURTHREAD), %ebx
287 movl T_ESP0(%ebx), %esp
288 subl $48, %esp
290 /* Fetch return value */
291 movl T_ARG1(%ebx), %eax
293 /* And terminate the system call */
294 jmp syscall_return
296 #ifdef OPTION_SMP
297 spurious_irq:
298 iret
299 #endif
301 /* Now we just need to list the exception handlers */
302 EXCEPTION_HANDLER(0)
303 EXCEPTION_HANDLER(1)
304 EXCEPTION_HANDLER(2)
305 EXCEPTION_HANDLER(3)
306 EXCEPTION_HANDLER(4)
307 EXCEPTION_HANDLER(5)
308 EXCEPTION_HANDLER(6)
309 EXCEPTION_HANDLER(7)
310 EXCEPTION_HANDLER_ERRORCODE(8)
311 EXCEPTION_HANDLER(9)
312 EXCEPTION_HANDLER_ERRORCODE(10)
313 EXCEPTION_HANDLER_ERRORCODE(11)
314 EXCEPTION_HANDLER_ERRORCODE(12)
315 EXCEPTION_HANDLER_ERRORCODE(13)
316 EXCEPTION_HANDLER_ERRORCODE(14)
317 EXCEPTION_HANDLER(16)
318 EXCEPTION_HANDLER_ERRORCODE(17)
319 EXCEPTION_HANDLER(18)
320 EXCEPTION_HANDLER(19)
322 /* ...and the IRQ handlers */
323 IRQ_HANDLER(0)
324 IRQ_HANDLER(1)
325 IRQ_HANDLER(2)
326 IRQ_HANDLER(3)
327 IRQ_HANDLER(4)
328 IRQ_HANDLER(5)
329 IRQ_HANDLER(6)
330 IRQ_HANDLER(7)
331 IRQ_HANDLER(8)
332 IRQ_HANDLER(9)
333 IRQ_HANDLER(10)
334 IRQ_HANDLER(11)
335 IRQ_HANDLER(12)
336 IRQ_HANDLER(13)
337 IRQ_HANDLER(14)
338 IRQ_HANDLER(15)
340 kthread_trampoline:
341 /* Fetch arguments; arg1 is the %eip and arg2 is the argument */
342 movl %fs:(PCPU_CURTHREAD), %ebx
343 movl T_ARG1(%ebx), %eax /* eax = eip */
344 pushl T_ARG2(%ebx)
346 /* Call the kthread code with interrupts enabled */
347 pushl $0x200
348 pushl $GDT_SEL_KERNEL_CODE
349 pushl %eax
350 iret
352 userland_trampoline:
353 /* Fetch arguments; arg1 is the %eip and arg2 is the argument */
354 movl %fs:(PCPU_CURTHREAD), %ebx
355 movl T_ARG1(%ebx), %eax /* eax = eip */
356 movl T_ARG2(%ebx), %esi /* esi = arg */
358 /* Set up %ds/%es to point to the userland segments */
359 movl $(GDT_SEL_USER_DATA + 3), %edx
360 movl %dx, %ds
361 movl %dx, %es
363 pushl $(GDT_SEL_USER_DATA + 3) /* ss */
364 pushl $(USERLAND_STACK_ADDR + THREAD_STACK_SIZE) /* esp */
365 pushl $0x200 /* eflags */
366 pushl $(GDT_SEL_USER_CODE + 3) /* cs */
367 pushl %eax /* eip */
368 iret