headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / arch / x86 / 32 / interrupts.S
bloba3fea3209659324006dd5385b139716b381d449d
1 /*
2  * Copyright 2002-2016, The Haiku Team. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6  * Copyright 2002, Michael Noisternig. All rights reserved.
7  * Distributed under the terms of the NewOS License.
8  */
10 #include <arch/user_debugger.h>
11 #include <arch/x86/arch_cpu.h>
12 #include <arch/x86/arch_kernel.h>
13 #include <arch/x86/descriptors.h>
14 #include <asm_defs.h>
15 #include <commpage_defs.h>
16 #include <thread_types.h>
18 #include "tracing_config.h"
20 #include "asm_offsets.h"
21 #include "syscall_numbers.h"
22 #include "syscall_table.h"
25 #define LOCK_THREAD_TIME()                                                                      \
26         lea             THREAD_time_lock(%edi), %eax;                                   \
27         pushl   %eax;                                                                                   \
28         call    acquire_spinlock;
29                 /* leave spinlock address on stack for UNLOCK_THREAD_TIME() */
31 #define UNLOCK_THREAD_TIME()                                                            \
32         /* spinlock address still on stack from */                              \
33         /* LOCK_THREAD_TIME() */                                                                \
34         call    release_spinlock;                                                               \
35         addl    $4, %esp;
37 #define UPDATE_THREAD_USER_TIME_COMMON()                                        \
38         movl    %eax, %ebx;                             /* save for later */    \
39         movl    %edx, %ecx;                                                                             \
40                                                                                                                         \
41         /* thread->user_time += now - thread->last_time; */             \
42         sub             THREAD_last_time(%edi), %eax;                                   \
43         sbb             (THREAD_last_time + 4)(%edi), %edx;                             \
44         add             %eax, THREAD_user_time(%edi);                                   \
45         adc             %edx, (THREAD_user_time + 4)(%edi);                             \
46                                                                                                                         \
47         /* thread->last_time = now; */                                                  \
48         movl    %ebx, THREAD_last_time(%edi);                                   \
49         movl    %ecx, (THREAD_last_time + 4)(%edi);                             \
50                                                                                                                         \
51         /* thread->in_kernel = true; */                                                 \
52         movb    $1, THREAD_in_kernel(%edi);
54 #define UPDATE_THREAD_USER_TIME()                                                       \
55         LOCK_THREAD_TIME()                                                                              \
56         call    system_time;                                                                    \
57         UPDATE_THREAD_USER_TIME_COMMON()                                                \
58         UNLOCK_THREAD_TIME()
60 #define UPDATE_THREAD_USER_TIME_PUSH_TIME()                                     \
61         call    system_time;                                                                    \
62         push    %edx;                                                                                   \
63         push    %eax;                                                                                   \
64                                                                                                                         \
65         LOCK_THREAD_TIME()                                                                              \
66                                                                                                                         \
67         /* recover the system time, note that */                                \
68         /* LOCK_THREAD_TIME() leaves an address on the stack */ \
69         movl    4(%esp), %eax;                                                                  \
70         movl    8(%esp), %edx;                                                                  \
71                                                                                                                         \
72         UPDATE_THREAD_USER_TIME_COMMON()                                                \
73                                                                                                                         \
74         UNLOCK_THREAD_TIME()
76 #define UPDATE_THREAD_KERNEL_TIME()                                                     \
77         LOCK_THREAD_TIME()                                                                              \
78                                                                                                                         \
79         call    system_time;                                                                    \
80                                                                                                                         \
81         movl    %eax, %ebx;                             /* save for later */    \
82         movl    %edx, %ecx;                                                                             \
83                                                                                                                         \
84         /* thread->kernel_time += now - thread->last_time; */   \
85         sub             THREAD_last_time(%edi), %eax;                                   \
86         sbb             (THREAD_last_time + 4)(%edi), %edx;                             \
87         add             %eax, THREAD_kernel_time(%edi);                                 \
88         adc             %edx, (THREAD_kernel_time + 4)(%edi);                   \
89                                                                                                                         \
90         /* thread->last_time = now; */                                                  \
91         movl    %ebx, THREAD_last_time(%edi);                                   \
92         movl    %ecx, (THREAD_last_time + 4)(%edi);                             \
93                                                                                                                         \
94         /* thread->in_kernel = false; */                                                \
95         movb    $0, THREAD_in_kernel(%edi);                                             \
96                                                                                                                         \
97         UNLOCK_THREAD_TIME()                                                                    \
99 #define PUSH_IFRAME_BOTTOM(iframeType)  \
100         pusha;                                                          \
101         push    %ds;                                            \
102         push    %es;                                            \
103         push    %fs;                                            \
104         push    %gs;                                            \
105         pushl   $iframeType
107 #define PUSH_IFRAME_BOTTOM_SYSCALL()    \
108         pushl   $0;                                                     \
109         pushl   $99;                                            \
110         pushl   %edx;                                           \
111         pushl   %eax;                                           \
112         PUSH_IFRAME_BOTTOM(IFRAME_TYPE_SYSCALL)
114 #define POP_IFRAME_AND_RETURN()                                                                         \
115         /* skip iframe type */                                                                                  \
116         lea             4(%ebp), %esp;                                                                                  \
117                                                                                                                                         \
118         pop             %gs;                                                                                                    \
119         addl    $4, %esp;       /* we skip %fs, as this contains the CPU        \
120                                                    dependent TLS segment */                                     \
121         pop             %es;                                                                                                    \
122         pop             %ds;                                                                                                    \
123                                                                                                                                         \
124         popa;                                                                                                                   \
125         addl    $16,%esp;       /* ignore the vector, error code, and           \
126                                                    original eax/edx values */                           \
127         iret
129 #define STOP_USER_DEBUGGING()                                                                                   \
130         testl   $(THREAD_FLAGS_BREAKPOINTS_INSTALLED                                            \
131                                 | THREAD_FLAGS_SINGLE_STEP), THREAD_flags(%edi);                \
132         jz              1f;                                                                                                                     \
133         call    x86_exit_user_debug_at_kernel_entry;                                            \
134   1:
136 #define COPY_SYSCALL_PARAMETERS()                                                                               \
137         /* make room for the syscall params */                                                          \
138         subl    $80, %esp;                                                                                                      \
139                                                                                                                                                 \
140         /* get the address of the syscall parameters */                                         \
141         movl    IFRAME_user_sp(%ebp), %esi;                                                                     \
142         addl    $4, %esi;                                                                                                       \
143         cmp             $KERNEL_BASE, %esi;             /* must not be a kernel address */      \
144         jae             bad_syscall_params;                                                                                     \
145                                                                                                                                                 \
146         /* set the fault handler */                                                                                     \
147         movl    $bad_syscall_params, THREAD_fault_handler(%edi);                        \
148                                                                                                                                                 \
149         /* target address is our stack */                                                                       \
150         movl    %esp, %edi;                                                                                                     \
151                                                                                                                                                 \
152         /* number of syscall parameter words */                                                         \
153         movl    SYSCALL_INFO_parameter_size(%edx), %ecx;                                        \
154         shrl    $2, %ecx;                                                                                                       \
155                                                                                                                                                 \
156         /* copy */                                                                                                                      \
157         cld;                                                                                                                            \
158         rep movsl;                                                                                                                      \
159                                                                                                                                                 \
160         /* restore pointers and clear fault handler */                                          \
161         movl    %edx, %esi;                             /* syscall info pointer */                      \
162         movl    %gs:0, %edi;                    /* thread pointer */                            \
163         movl    $0, THREAD_fault_handler(%edi)
165 #if SYSCALL_TRACING
166 #       define TRACE_PRE_SYSCALL()      \
167                 movl    %esp, %eax;                                             /* syscall parameters */        \
168                 push    %eax;                                                                                                           \
169                 movl    IFRAME_orig_eax(%ebp), %eax;    /* syscall number */            \
170                 push    %eax;                                                                                                           \
171                 call    trace_pre_syscall;                                                                                      \
172                 addl    $8, %esp;
174 #       define TRACE_POST_SYSCALL()     \
175                 testl   $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi);        \
176                 jnz             1f;                                                                                                                     \
177                 xor             %edx, %edx;                                                                                                     \
178 1:                                                                                                                                                      \
179                 push    %edx;                                                   /* syscall return value */      \
180                 push    %eax;                                                                                                           \
181                 movl    IFRAME_orig_eax(%ebp), %eax;    /* syscall number */            \
182                 push    %eax;                                                                                                           \
183                 call    trace_post_syscall;                                                                                     \
184                 addl    $12, %esp
185 #else
186 #       define TRACE_PRE_SYSCALL()
187 #       define TRACE_POST_SYSCALL()
188 #endif
191 .text
193 #define TRAP_ERRC(name, vector) \
194 .align 8; \
195 FUNCTION(name): \
196         pushl   $vector; \
197         pushl   %edx; \
198         pushl   %eax; \
199         jmp             int_bottom;     \
200 FUNCTION_END(name)
202 #define TRAP(name, vector) \
203 .align 8; \
204 FUNCTION(name): \
205         pushl   $0; \
206         pushl   $vector; \
207         pushl   %edx; \
208         pushl   %eax; \
209         jmp             int_bottom; \
210 FUNCTION_END(name)
212 TRAP(trap0, 0)
213 TRAP(trap1, 1)
214 TRAP(trap2, 2)
215 TRAP(trap3, 3)
216 TRAP(trap4, 4)
217 TRAP(trap5, 5)
218 TRAP(trap6, 6)
219 TRAP(trap7, 7)
221 .align 8;
222 FUNCTION(double_fault):
223         pushl   $-1;    // user-ss
224         pushl   $-1;    // user-esp
225         pushl   $-1;    // flags
226         pushl   $KERNEL_CODE_SELECTOR   // cs
227         pushl   $-1;    // eip
228         pushl   $0;             // error-code
229         pushl   $8;
230         pushl   $-1;
231         pushl   $-1;
233         PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
235         movl    %esp, %ebp              // frame pointer is the iframe
237         pushl   %ebp
238         call    x86_double_fault_exception
240         // Well, there's no returning from a double fault, but maybe a real hacker
241         // can repair things in KDL.
242         POP_IFRAME_AND_RETURN()
243 FUNCTION_END(double_fault)
246 TRAP(trap9, 9)
247 TRAP_ERRC(trap10, 10)
248 TRAP_ERRC(trap11, 11)
249 TRAP_ERRC(trap12, 12)
250 TRAP_ERRC(trap13, 13)
251 TRAP_ERRC(trap14, 14)
252 /*TRAP(trap15, 15)*/
253 TRAP(trap16, 16)
254 TRAP_ERRC(trap17, 17)
255 TRAP(trap18, 18)
256 TRAP(trap19, 19)
258 // legacy or ioapic interrupts
259 TRAP(trap32, 32)
260 TRAP(trap33, 33)
261 TRAP(trap34, 34)
262 TRAP(trap35, 35)
263 TRAP(trap36, 36)
264 TRAP(trap37, 37)
265 TRAP(trap38, 38)
266 TRAP(trap39, 39)
267 TRAP(trap40, 40)
268 TRAP(trap41, 41)
269 TRAP(trap42, 42)
270 TRAP(trap43, 43)
271 TRAP(trap44, 44)
272 TRAP(trap45, 45)
273 TRAP(trap46, 46)
274 TRAP(trap47, 47)
276 // additional ioapic interrupts
277 TRAP(trap48, 48)
278 TRAP(trap49, 49)
279 TRAP(trap50, 50)
280 TRAP(trap51, 51)
281 TRAP(trap52, 52)
282 TRAP(trap53, 53)
283 TRAP(trap54, 54)
284 TRAP(trap55, 55)
286 // configurable msi or msi-x interrupts
287 TRAP(trap56, 56)
288 TRAP(trap57, 57)
289 TRAP(trap58, 58)
290 TRAP(trap59, 59)
291 TRAP(trap60, 60)
292 TRAP(trap61, 61)
293 TRAP(trap62, 62)
294 TRAP(trap63, 63)
295 TRAP(trap64, 64)
296 TRAP(trap65, 65)
297 TRAP(trap66, 66)
298 TRAP(trap67, 67)
299 TRAP(trap68, 68)
300 TRAP(trap69, 69)
301 TRAP(trap70, 70)
302 TRAP(trap71, 71)
303 TRAP(trap72, 72)
304 TRAP(trap73, 73)
305 TRAP(trap74, 74)
306 TRAP(trap75, 75)
307 TRAP(trap76, 76)
308 TRAP(trap77, 77)
309 TRAP(trap78, 78)
310 TRAP(trap79, 79)
311 TRAP(trap80, 80)
312 TRAP(trap81, 81)
313 TRAP(trap82, 82)
314 TRAP(trap83, 83)
315 TRAP(trap84, 84)
316 TRAP(trap85, 85)
317 TRAP(trap86, 86)
318 TRAP(trap87, 87)
319 TRAP(trap88, 88)
320 TRAP(trap89, 89)
321 TRAP(trap90, 90)
322 TRAP(trap91, 91)
323 TRAP(trap92, 92)
324 TRAP(trap93, 93)
325 TRAP(trap94, 94)
326 TRAP(trap95, 95)
327 TRAP(trap96, 96)
328 TRAP(trap97, 97)
329 //TRAP(trap98, 98) // performance testing interrupt
330 //TRAP(trap99, 99) // syscall interrupt
331 TRAP(trap100, 100)
332 TRAP(trap101, 101)
333 TRAP(trap102, 102)
334 TRAP(trap103, 103)
335 TRAP(trap104, 104)
336 TRAP(trap105, 105)
337 TRAP(trap106, 106)
338 TRAP(trap107, 107)
339 TRAP(trap108, 108)
340 TRAP(trap109, 109)
341 TRAP(trap110, 110)
342 TRAP(trap111, 111)
343 TRAP(trap112, 112)
344 TRAP(trap113, 113)
345 TRAP(trap114, 114)
346 TRAP(trap115, 115)
347 TRAP(trap116, 116)
348 TRAP(trap117, 117)
349 TRAP(trap118, 118)
350 TRAP(trap119, 119)
351 TRAP(trap120, 120)
352 TRAP(trap121, 121)
353 TRAP(trap122, 122)
354 TRAP(trap123, 123)
355 TRAP(trap124, 124)
356 TRAP(trap125, 125)
357 TRAP(trap126, 126)
358 TRAP(trap127, 127)
359 TRAP(trap128, 128)
360 TRAP(trap129, 129)
361 TRAP(trap130, 130)
362 TRAP(trap131, 131)
363 TRAP(trap132, 132)
364 TRAP(trap133, 133)
365 TRAP(trap134, 134)
366 TRAP(trap135, 135)
367 TRAP(trap136, 136)
368 TRAP(trap137, 137)
369 TRAP(trap138, 138)
370 TRAP(trap139, 139)
371 TRAP(trap140, 140)
372 TRAP(trap141, 141)
373 TRAP(trap142, 142)
374 TRAP(trap143, 143)
375 TRAP(trap144, 144)
376 TRAP(trap145, 145)
377 TRAP(trap146, 146)
378 TRAP(trap147, 147)
379 TRAP(trap148, 148)
380 TRAP(trap149, 149)
381 TRAP(trap150, 150)
382 TRAP(trap151, 151)
383 TRAP(trap152, 152)
384 TRAP(trap153, 153)
385 TRAP(trap154, 154)
386 TRAP(trap155, 155)
387 TRAP(trap156, 156)
388 TRAP(trap157, 157)
389 TRAP(trap158, 158)
390 TRAP(trap159, 159)
391 TRAP(trap160, 160)
392 TRAP(trap161, 161)
393 TRAP(trap162, 162)
394 TRAP(trap163, 163)
395 TRAP(trap164, 164)
396 TRAP(trap165, 165)
397 TRAP(trap166, 166)
398 TRAP(trap167, 167)
399 TRAP(trap168, 168)
400 TRAP(trap169, 169)
401 TRAP(trap170, 170)
402 TRAP(trap171, 171)
403 TRAP(trap172, 172)
404 TRAP(trap173, 173)
405 TRAP(trap174, 174)
406 TRAP(trap175, 175)
407 TRAP(trap176, 176)
408 TRAP(trap177, 177)
409 TRAP(trap178, 178)
410 TRAP(trap179, 179)
411 TRAP(trap180, 180)
412 TRAP(trap181, 181)
413 TRAP(trap182, 182)
414 TRAP(trap183, 183)
415 TRAP(trap184, 184)
416 TRAP(trap185, 185)
417 TRAP(trap186, 186)
418 TRAP(trap187, 187)
419 TRAP(trap188, 188)
420 TRAP(trap189, 189)
421 TRAP(trap190, 190)
422 TRAP(trap191, 191)
423 TRAP(trap192, 192)
424 TRAP(trap193, 193)
425 TRAP(trap194, 194)
426 TRAP(trap195, 195)
427 TRAP(trap196, 196)
428 TRAP(trap197, 197)
429 TRAP(trap198, 198)
430 TRAP(trap199, 199)
431 TRAP(trap200, 200)
432 TRAP(trap201, 201)
433 TRAP(trap202, 202)
434 TRAP(trap203, 203)
435 TRAP(trap204, 204)
436 TRAP(trap205, 205)
437 TRAP(trap206, 206)
438 TRAP(trap207, 207)
439 TRAP(trap208, 208)
440 TRAP(trap209, 209)
441 TRAP(trap210, 210)
442 TRAP(trap211, 211)
443 TRAP(trap212, 212)
444 TRAP(trap213, 213)
445 TRAP(trap214, 214)
446 TRAP(trap215, 215)
447 TRAP(trap216, 216)
448 TRAP(trap217, 217)
449 TRAP(trap218, 218)
450 TRAP(trap219, 219)
451 TRAP(trap220, 220)
452 TRAP(trap221, 221)
453 TRAP(trap222, 222)
454 TRAP(trap223, 223)
455 TRAP(trap224, 224)
456 TRAP(trap225, 225)
457 TRAP(trap226, 226)
458 TRAP(trap227, 227)
459 TRAP(trap228, 228)
460 TRAP(trap229, 229)
461 TRAP(trap230, 230)
462 TRAP(trap231, 231)
463 TRAP(trap232, 232)
464 TRAP(trap233, 233)
465 TRAP(trap234, 234)
466 TRAP(trap235, 235)
467 TRAP(trap236, 236)
468 TRAP(trap237, 237)
469 TRAP(trap238, 238)
470 TRAP(trap239, 239)
471 TRAP(trap240, 240)
472 TRAP(trap241, 241)
473 TRAP(trap242, 242)
474 TRAP(trap243, 243)
475 TRAP(trap244, 244)
476 TRAP(trap245, 245)
477 TRAP(trap246, 246)
478 TRAP(trap247, 247)
479 TRAP(trap248, 248)
480 TRAP(trap249, 249)
481 TRAP(trap250, 250)
483 // smp / apic local interrupts
484 TRAP(trap251, 251)
485 TRAP(trap252, 252)
486 TRAP(trap253, 253)
487 TRAP(trap254, 254)
488 TRAP(trap255, 255)
491 .align 8;
492 FUNCTION(trap14_double_fault):
493         pushl   $14
494         pushl   $-1
495         pushl   $-1
497         PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
499         movl    %esp, %ebp              // frame pointer is the iframe
501         pushl   %ebp
502         call    x86_page_fault_exception_double_fault
504         POP_IFRAME_AND_RETURN()
505 FUNCTION_END(trap14_double_fault)
508 .align 16
509 STATIC_FUNCTION(int_bottom):
510         PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
512         movl    $KERNEL_TLS_SELECTOR, %edx
513         movw    %dx, %gs
515         movl    %esp, %ebp              // frame pointer is the iframe
517         // Set the RF (resume flag) in EFLAGS. This prevents an instruction
518         // breakpoint on the instruction we're returning to to trigger a debug
519         // exception.
520         orl             $0x10000, IFRAME_flags(%ebp);
522         cmpw    $USER_CODE_SELECTOR, IFRAME_cs(%ebp)    // user mode
523         je              int_bottom_user
525         // We need to recheck user mode using the thread's in_kernel flag, since
526         // sysexit introduces a raced condition: It doesn't reenable interrupts,
527         // so that we have to do it in the instruction before, thus opening a
528         // window for an interrupt while still being in the kernel, but having set
529         // up everything for userland already.
530         movl    %gs:0, %edi                                             // thread pointer
531         cmpb    $0, THREAD_in_kernel(%edi)
532         je              int_bottom_user
534         // disable interrupts -- the handler will enable them, if necessary
535         cli
537         pushl   %ebp
538         movl    IFRAME_vector(%ebp), %eax
539         call    *gInterruptHandlerTable(, %eax, 4)
541         POP_IFRAME_AND_RETURN()
542 FUNCTION_END(int_bottom)
545 STATIC_FUNCTION(int_bottom_user):
546         movl    $KERNEL_DATA_SELECTOR, %eax
547         cld
548         movl    %eax,%ds
549         movl    %eax,%es
551         // disable breakpoints, if installed
552         movl    %gs:0, %edi                             // thread pointer
553         cli                                                             // disable interrupts
554         STOP_USER_DEBUGGING()
556         // update the thread's user time
557         UPDATE_THREAD_USER_TIME()
559         // leave interrupts disabled -- the handler will enable them, if
560         // necessary
562         pushl   %ebp
563         movl    IFRAME_vector(%ebp), %eax
564         call    *gInterruptHandlerTable(, %eax, 4)
566         // Don't do any kernel exit work, if we actually came from the kernel (but
567         // were already/still prepared for userland), since the iframe in this case
568         // will be a kernel iframe and e.g. trying to set up a signal stack will not
569         // be a very healthy endeavor.
570         cmpw    $USER_CODE_SELECTOR, IFRAME_cs(%ebp)
571         jne             1f
573         testl   $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
574                         | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
575                         | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
576                         , THREAD_flags(%edi)
577         jnz             kernel_exit_work
580         cli                                                             // disable interrupts
582         // update the thread's kernel time and return
583         UPDATE_THREAD_KERNEL_TIME()
584         POP_IFRAME_AND_RETURN()
585 FUNCTION_END(int_bottom_user)
588 // test interrupt handler for performance measurements
589 .align 16
590 FUNCTION(trap98):
591         iret
592 FUNCTION_END(trap98)
595 .align 16
596 FUNCTION(trap99):
597         // push error, vector, orig_edx, orig_eax, and other registers
598         PUSH_IFRAME_BOTTOM_SYSCALL()
600         call    handle_syscall
602         POP_IFRAME_AND_RETURN()
603 FUNCTION_END(trap99)
606 STATIC_FUNCTION(handle_syscall):
607         movl    $KERNEL_TLS_SELECTOR, %edx
608         movw    %dx, %gs
610         // save %eax, the number of the syscall
611         movl    %eax, %esi
613         movl    $KERNEL_DATA_SELECTOR, %eax
614         cld
615         movl    %eax,%ds
616         movl    %eax,%es
618         lea             4(%esp), %ebp                   // skipping the return address, the stack
619                                                                         // frame pointer is the iframe
620         movl    %gs:0, %edi                             // thread pointer
622         // disable breakpoints, if installed
623         cli                                                             // disable interrupts
624         STOP_USER_DEBUGGING()
626         // update the thread's user time
627         UPDATE_THREAD_USER_TIME_PUSH_TIME()
628                 // leave the time on the stack (needed for post syscall debugging)
630         sti                                                             // enable interrupts
632         cmp             $SYSCALL_COUNT, %esi    // check syscall number
633         jae             bad_syscall_number
634         movl    $kSyscallInfos, %eax    // get syscall info
635         lea             (%eax, %esi, SYSCALL_INFO_sizeof), %edx
637         // copy parameters onto this stack
638         COPY_SYSCALL_PARAMETERS()
640         // pre syscall debugging
641         TRACE_PRE_SYSCALL()
642         testl   $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
643         jnz             do_pre_syscall_debug
644   pre_syscall_debug_done:
646         // call the syscall function
647         call    *SYSCALL_INFO_function(%esi)
649         // overwrite the values of %eax and %edx on the stack (the syscall return
650         // value)
651         movl    %edx, IFRAME_dx(%ebp)
652         movl    %eax, IFRAME_ax(%ebp)
654         TRACE_POST_SYSCALL()
656         testl   $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
657                         | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
658                         | THREAD_FLAGS_TRAP_FOR_CORE_DUMP \
659                         | THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
660                         | THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \
661                         , THREAD_flags(%edi)
662         jnz             post_syscall_work
664         cli                                                             // disable interrupts
666         // update the thread's kernel time
667         UPDATE_THREAD_KERNEL_TIME()
669         lea             -4(%ebp), %esp                  // remove all parameters from the stack
671         ret
672 FUNCTION_END(handle_syscall)
674   STATIC_FUNCTION(do_pre_syscall_debug):
675         movl    %esp, %eax                              // syscall parameters
676         push    %eax
677         movl    IFRAME_orig_eax(%ebp), %eax             // syscall number
678         push    %eax
679         call    user_debug_pre_syscall
680         addl    $8, %esp
681         jmp             pre_syscall_debug_done
682   FUNCTION_END(do_pre_syscall_debug)
684   STATIC_FUNCTION(post_syscall_work):
685         // clear the 64 bit return value and syscall restarted bits
686         testl   $(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
687                                 | THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi)
688         jz              2f
689   1:
690     movl        THREAD_flags(%edi), %eax
691         movl    %eax, %edx
692     andl        $~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
693                                 | THREAD_FLAGS_SYSCALL_RESTARTED), %edx
694     lock
695     cmpxchgl    %edx, THREAD_flags(%edi)
696     jnz         1b
697   2:
699         // post syscall debugging
700         testl   $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
701         jz              1f
702         pushl   -8(%ebp)                                // syscall start time
703         pushl   -12(%ebp)
704         movl    IFRAME_dx(%ebp), %edx   // syscall return value
705         movl    IFRAME_ax(%ebp), %eax
706         push    %edx
707         push    %eax
708         lea             16(%esp), %eax                  // syscall parameters
709         push    %eax
710         movl    IFRAME_orig_eax(%ebp), %eax             // syscall number
711         push    %eax
712         call    user_debug_post_syscall
713         addl    $24, %esp
714   1:
715   FUNCTION_END(post_syscall_work)
717   bad_syscall_number:
718   STATIC_FUNCTION(kernel_exit_work):
719         // if no signals are pending and the thread shall not be debugged or stopped
720         // for a core dump, we can use the quick kernel exit function
721         testl   $(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD \
722                         | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
723                         , THREAD_flags(%edi)
724         jnz             kernel_exit_handle_signals
725         cli                                                             // disable interrupts
726         call    thread_at_kernel_exit_no_signals
727   kernel_exit_work_done:
729         // syscall restart
730         // TODO: this only needs to be done for syscalls!
731         testl   $THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi)
732         jz              1f
733         push    %ebp
734         call    x86_restart_syscall
735         addl    $4, %esp
736   1:
738         // install breakpoints, if defined
739         testl   $THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi)
740         jz              1f
741         push    %ebp
742         call    x86_init_user_debug_at_kernel_exit
743   1:
744         POP_IFRAME_AND_RETURN()
745   FUNCTION_END(kernel_exit_work)
747   STATIC_FUNCTION(kernel_exit_handle_signals):
748         // make sure interrupts are enabled (they are, when coming from a syscall
749         // but otherwise they might be disabled)
750         sti
751         call    thread_at_kernel_exit   // also disables interrupts
752         jmp             kernel_exit_work_done
753   FUNCTION_END(kernel_exit_handle_signals)
755   STATIC_FUNCTION(bad_syscall_params):
756         // clear the fault handler and exit normally
757         movl    %gs:0, %edi
758         movl    $0, THREAD_fault_handler(%edi)
759         jmp             kernel_exit_work
760   FUNCTION_END(bad_syscall_params)
763 /*!     Handler called by the sysenter instruction
764         ecx - user esp
766 FUNCTION(x86_sysenter):
767         // get the thread
768         push    %gs
769         movl    $KERNEL_TLS_SELECTOR, %edx
770         movw    %dx, %gs
771         movl    %gs:0, %edx
772         pop             %gs
774         // push the iframe
775         pushl   $USER_DATA_SELECTOR             // user_ss
776         pushl   %ecx                                    // user_esp
777         pushfl                                                  // eflags
778         orl             $(1 << 9), (%esp)               // set the IF (interrupts) bit
779         pushl   $USER_CODE_SELECTOR             // user cs
781         // user_eip
782         movl    THREAD_team(%edx), %edx
783         movl    TEAM_commpage_address(%edx), %edx
784         addl    4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx
785         addl    $4, %edx                                // sysenter is at offset 2, 2 bytes long
786         pushl   %edx
788         PUSH_IFRAME_BOTTOM_SYSCALL()
790         call    handle_syscall
792         // pop the bottom of the iframe
793         lea             4(%ebp), %esp   // skip iframe type
795         pop             %gs
796         addl    $4, %esp        /* we skip %fs, as this contains the CPU
797                                                    dependent TLS segment */
798         pop             %es
799         pop             %ds
801         popa
803         // ecx already contains the user esp -- load edx with the return address
804         movl    16(%esp), %edx
806         // pop eflags, which also reenables interrupts
807         addl    $24, %esp       // skip, orig_eax/edx, vector, error_code, eip, cs
808         popfl
810         sysexit
811 FUNCTION_END(x86_sysenter)
814 /*!     \fn void x86_return_to_userland(iframe* frame)
815         \brief Returns to the userland environment given by \a frame.
817         Before returning to userland all potentially necessary kernel exit work is
818         done.
820         \a frame must point to a location somewhere on the caller's stack (e.g. a
821         local variable).
822         The function must be called with interrupts disabled.
824         \param frame The iframe defining the userland environment.
826 FUNCTION(x86_return_to_userland):
827         // get the iframe* parameter
828         movl    4(%esp), %ebp
829         movl    %ebp, %esp
831         // check, if any kernel exit work has to be done
832         movl    %gs:0, %edi
833         testl   $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
834                         | THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
835                         | THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
836                         , THREAD_flags(%edi)
837         jnz             kernel_exit_work
839         // update the thread's kernel time and return
840         UPDATE_THREAD_KERNEL_TIME()
841         POP_IFRAME_AND_RETURN()
842 FUNCTION_END(x86_return_to_userland)