xref: /haiku/src/system/kernel/arch/x86/32/interrupts.S (revision eea5774f46bba925156498abf9cb1a1165647bf7)
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 */
9
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>
17
18#include "tracing_config.h"
19
20#include "asm_offsets.h"
21#include "syscall_numbers.h"
22#include "syscall_table.h"
23
24
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() */
30
31#define UNLOCK_THREAD_TIME()								\
32	/* spinlock address still on stack from */				\
33	/* LOCK_THREAD_TIME() */								\
34	call	release_spinlock;								\
35	addl	$4, %esp;
36
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);
53
54#define UPDATE_THREAD_USER_TIME()							\
55	LOCK_THREAD_TIME()										\
56	call	system_time;									\
57	UPDATE_THREAD_USER_TIME_COMMON()						\
58	UNLOCK_THREAD_TIME()
59
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()
75
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()									\
98
99#define PUSH_IFRAME_BOTTOM(iframeType)	\
100	pusha;								\
101	push	%ds;						\
102	push	%es;						\
103	push	%fs;						\
104	push	%gs;						\
105	pushl	$iframeType
106
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)
113
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
128
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:
135
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)
164
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;
173
174#	define TRACE_POST_SYSCALL()	\
175		push	%edx;							/* syscall return value */	\
176		push	%eax;														\
177		movl	IFRAME_orig_eax(%ebp), %eax;	/* syscall number */		\
178		push	%eax;														\
179		call	trace_post_syscall;											\
180		addl	$12, %esp
181#else
182#	define TRACE_PRE_SYSCALL()
183#	define TRACE_POST_SYSCALL()
184#endif
185
186
187.text
188
189#define TRAP_ERRC(name, vector) \
190.align 8; \
191FUNCTION(name): \
192	pushl	$vector; \
193	pushl	%edx; \
194	pushl	%eax; \
195	jmp		int_bottom;	\
196FUNCTION_END(name)
197
198#define TRAP(name, vector) \
199.align 8; \
200FUNCTION(name): \
201	pushl	$0; \
202	pushl	$vector; \
203	pushl	%edx; \
204	pushl	%eax; \
205	jmp		int_bottom; \
206FUNCTION_END(name)
207
208TRAP(trap0, 0)
209TRAP(trap1, 1)
210TRAP(trap2, 2)
211TRAP(trap3, 3)
212TRAP(trap4, 4)
213TRAP(trap5, 5)
214TRAP(trap6, 6)
215TRAP(trap7, 7)
216
217.align 8;
218FUNCTION(double_fault):
219	pushl	$-1;	// user-ss
220	pushl	$-1;	// user-esp
221	pushl	$-1;	// flags
222	pushl	$KERNEL_CODE_SELECTOR	// cs
223	pushl	$-1;	// eip
224	pushl	$0;		// error-code
225	pushl	$8;
226	pushl	$-1;
227	pushl	$-1;
228
229	PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
230
231	movl	%esp, %ebp		// frame pointer is the iframe
232
233	pushl	%ebp
234	call	x86_double_fault_exception
235
236	// Well, there's no returning from a double fault, but maybe a real hacker
237	// can repair things in KDL.
238	POP_IFRAME_AND_RETURN()
239FUNCTION_END(double_fault)
240
241
242TRAP(trap9, 9)
243TRAP_ERRC(trap10, 10)
244TRAP_ERRC(trap11, 11)
245TRAP_ERRC(trap12, 12)
246TRAP_ERRC(trap13, 13)
247TRAP_ERRC(trap14, 14)
248/*TRAP(trap15, 15)*/
249TRAP(trap16, 16)
250TRAP_ERRC(trap17, 17)
251TRAP(trap18, 18)
252TRAP(trap19, 19)
253
254// legacy or ioapic interrupts
255TRAP(trap32, 32)
256TRAP(trap33, 33)
257TRAP(trap34, 34)
258TRAP(trap35, 35)
259TRAP(trap36, 36)
260TRAP(trap37, 37)
261TRAP(trap38, 38)
262TRAP(trap39, 39)
263TRAP(trap40, 40)
264TRAP(trap41, 41)
265TRAP(trap42, 42)
266TRAP(trap43, 43)
267TRAP(trap44, 44)
268TRAP(trap45, 45)
269TRAP(trap46, 46)
270TRAP(trap47, 47)
271
272// additional ioapic interrupts
273TRAP(trap48, 48)
274TRAP(trap49, 49)
275TRAP(trap50, 50)
276TRAP(trap51, 51)
277TRAP(trap52, 52)
278TRAP(trap53, 53)
279TRAP(trap54, 54)
280TRAP(trap55, 55)
281
282// configurable msi or msi-x interrupts
283TRAP(trap56, 56)
284TRAP(trap57, 57)
285TRAP(trap58, 58)
286TRAP(trap59, 59)
287TRAP(trap60, 60)
288TRAP(trap61, 61)
289TRAP(trap62, 62)
290TRAP(trap63, 63)
291TRAP(trap64, 64)
292TRAP(trap65, 65)
293TRAP(trap66, 66)
294TRAP(trap67, 67)
295TRAP(trap68, 68)
296TRAP(trap69, 69)
297TRAP(trap70, 70)
298TRAP(trap71, 71)
299TRAP(trap72, 72)
300TRAP(trap73, 73)
301TRAP(trap74, 74)
302TRAP(trap75, 75)
303TRAP(trap76, 76)
304TRAP(trap77, 77)
305TRAP(trap78, 78)
306TRAP(trap79, 79)
307TRAP(trap80, 80)
308TRAP(trap81, 81)
309TRAP(trap82, 82)
310TRAP(trap83, 83)
311TRAP(trap84, 84)
312TRAP(trap85, 85)
313TRAP(trap86, 86)
314TRAP(trap87, 87)
315TRAP(trap88, 88)
316TRAP(trap89, 89)
317TRAP(trap90, 90)
318TRAP(trap91, 91)
319TRAP(trap92, 92)
320TRAP(trap93, 93)
321TRAP(trap94, 94)
322TRAP(trap95, 95)
323TRAP(trap96, 96)
324TRAP(trap97, 97)
325//TRAP(trap98, 98) // performance testing interrupt
326//TRAP(trap99, 99) // syscall interrupt
327TRAP(trap100, 100)
328TRAP(trap101, 101)
329TRAP(trap102, 102)
330TRAP(trap103, 103)
331TRAP(trap104, 104)
332TRAP(trap105, 105)
333TRAP(trap106, 106)
334TRAP(trap107, 107)
335TRAP(trap108, 108)
336TRAP(trap109, 109)
337TRAP(trap110, 110)
338TRAP(trap111, 111)
339TRAP(trap112, 112)
340TRAP(trap113, 113)
341TRAP(trap114, 114)
342TRAP(trap115, 115)
343TRAP(trap116, 116)
344TRAP(trap117, 117)
345TRAP(trap118, 118)
346TRAP(trap119, 119)
347TRAP(trap120, 120)
348TRAP(trap121, 121)
349TRAP(trap122, 122)
350TRAP(trap123, 123)
351TRAP(trap124, 124)
352TRAP(trap125, 125)
353TRAP(trap126, 126)
354TRAP(trap127, 127)
355TRAP(trap128, 128)
356TRAP(trap129, 129)
357TRAP(trap130, 130)
358TRAP(trap131, 131)
359TRAP(trap132, 132)
360TRAP(trap133, 133)
361TRAP(trap134, 134)
362TRAP(trap135, 135)
363TRAP(trap136, 136)
364TRAP(trap137, 137)
365TRAP(trap138, 138)
366TRAP(trap139, 139)
367TRAP(trap140, 140)
368TRAP(trap141, 141)
369TRAP(trap142, 142)
370TRAP(trap143, 143)
371TRAP(trap144, 144)
372TRAP(trap145, 145)
373TRAP(trap146, 146)
374TRAP(trap147, 147)
375TRAP(trap148, 148)
376TRAP(trap149, 149)
377TRAP(trap150, 150)
378TRAP(trap151, 151)
379TRAP(trap152, 152)
380TRAP(trap153, 153)
381TRAP(trap154, 154)
382TRAP(trap155, 155)
383TRAP(trap156, 156)
384TRAP(trap157, 157)
385TRAP(trap158, 158)
386TRAP(trap159, 159)
387TRAP(trap160, 160)
388TRAP(trap161, 161)
389TRAP(trap162, 162)
390TRAP(trap163, 163)
391TRAP(trap164, 164)
392TRAP(trap165, 165)
393TRAP(trap166, 166)
394TRAP(trap167, 167)
395TRAP(trap168, 168)
396TRAP(trap169, 169)
397TRAP(trap170, 170)
398TRAP(trap171, 171)
399TRAP(trap172, 172)
400TRAP(trap173, 173)
401TRAP(trap174, 174)
402TRAP(trap175, 175)
403TRAP(trap176, 176)
404TRAP(trap177, 177)
405TRAP(trap178, 178)
406TRAP(trap179, 179)
407TRAP(trap180, 180)
408TRAP(trap181, 181)
409TRAP(trap182, 182)
410TRAP(trap183, 183)
411TRAP(trap184, 184)
412TRAP(trap185, 185)
413TRAP(trap186, 186)
414TRAP(trap187, 187)
415TRAP(trap188, 188)
416TRAP(trap189, 189)
417TRAP(trap190, 190)
418TRAP(trap191, 191)
419TRAP(trap192, 192)
420TRAP(trap193, 193)
421TRAP(trap194, 194)
422TRAP(trap195, 195)
423TRAP(trap196, 196)
424TRAP(trap197, 197)
425TRAP(trap198, 198)
426TRAP(trap199, 199)
427TRAP(trap200, 200)
428TRAP(trap201, 201)
429TRAP(trap202, 202)
430TRAP(trap203, 203)
431TRAP(trap204, 204)
432TRAP(trap205, 205)
433TRAP(trap206, 206)
434TRAP(trap207, 207)
435TRAP(trap208, 208)
436TRAP(trap209, 209)
437TRAP(trap210, 210)
438TRAP(trap211, 211)
439TRAP(trap212, 212)
440TRAP(trap213, 213)
441TRAP(trap214, 214)
442TRAP(trap215, 215)
443TRAP(trap216, 216)
444TRAP(trap217, 217)
445TRAP(trap218, 218)
446TRAP(trap219, 219)
447TRAP(trap220, 220)
448TRAP(trap221, 221)
449TRAP(trap222, 222)
450TRAP(trap223, 223)
451TRAP(trap224, 224)
452TRAP(trap225, 225)
453TRAP(trap226, 226)
454TRAP(trap227, 227)
455TRAP(trap228, 228)
456TRAP(trap229, 229)
457TRAP(trap230, 230)
458TRAP(trap231, 231)
459TRAP(trap232, 232)
460TRAP(trap233, 233)
461TRAP(trap234, 234)
462TRAP(trap235, 235)
463TRAP(trap236, 236)
464TRAP(trap237, 237)
465TRAP(trap238, 238)
466TRAP(trap239, 239)
467TRAP(trap240, 240)
468TRAP(trap241, 241)
469TRAP(trap242, 242)
470TRAP(trap243, 243)
471TRAP(trap244, 244)
472TRAP(trap245, 245)
473TRAP(trap246, 246)
474TRAP(trap247, 247)
475TRAP(trap248, 248)
476TRAP(trap249, 249)
477TRAP(trap250, 250)
478
479// smp / apic local interrupts
480TRAP(trap251, 251)
481TRAP(trap252, 252)
482TRAP(trap253, 253)
483TRAP(trap254, 254)
484TRAP(trap255, 255)
485
486
487.align 8;
488FUNCTION(trap14_double_fault):
489	pushl	$14
490	pushl	$-1
491	pushl	$-1
492
493	PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
494
495	movl	%esp, %ebp		// frame pointer is the iframe
496
497	pushl	%ebp
498	call	x86_page_fault_exception_double_fault
499
500	POP_IFRAME_AND_RETURN()
501FUNCTION_END(trap14_double_fault)
502
503
504.align 16
505STATIC_FUNCTION(int_bottom):
506	PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
507
508	movl	$KERNEL_TLS_SELECTOR, %edx
509	movw	%dx, %gs
510
511	movl	%esp, %ebp		// frame pointer is the iframe
512
513	// Set the RF (resume flag) in EFLAGS. This prevents an instruction
514	// breakpoint on the instruction we're returning to to trigger a debug
515	// exception.
516	orl		$0x10000, IFRAME_flags(%ebp);
517
518	cmpw	$USER_CODE_SELECTOR, IFRAME_cs(%ebp)	// user mode
519	je		int_bottom_user
520
521	// We need to recheck user mode using the thread's in_kernel flag, since
522	// sysexit introduces a raced condition: It doesn't reenable interrupts,
523	// so that we have to do it in the instruction before, thus opening a
524	// window for an interrupt while still being in the kernel, but having set
525	// up everything for userland already.
526	movl	%gs:0, %edi						// thread pointer
527	cmpb	$0, THREAD_in_kernel(%edi)
528	je		int_bottom_user
529
530	// disable interrupts -- the handler will enable them, if necessary
531	cli
532
533	pushl	%ebp
534	movl	IFRAME_vector(%ebp), %eax
535	call	*gInterruptHandlerTable(, %eax, 4)
536
537	POP_IFRAME_AND_RETURN()
538FUNCTION_END(int_bottom)
539
540
541STATIC_FUNCTION(int_bottom_user):
542	movl	$KERNEL_DATA_SELECTOR, %eax
543	cld
544	movl	%eax,%ds
545	movl	%eax,%es
546
547	// disable breakpoints, if installed
548	movl	%gs:0, %edi				// thread pointer
549	cli								// disable interrupts
550	STOP_USER_DEBUGGING()
551
552	// update the thread's user time
553	UPDATE_THREAD_USER_TIME()
554
555	// leave interrupts disabled -- the handler will enable them, if
556	// necessary
557
558	pushl	%ebp
559	movl	IFRAME_vector(%ebp), %eax
560	call	*gInterruptHandlerTable(, %eax, 4)
561
562	// Don't do any kernel exit work, if we actually came from the kernel (but
563	// were already/still prepared for userland), since the iframe in this case
564	// will be a kernel iframe and e.g. trying to set up a signal stack will not
565	// be a very healthy endeavor.
566	cmpw	$USER_CODE_SELECTOR, IFRAME_cs(%ebp)
567	jne		1f
568
569	testl	$(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
570			| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
571			| THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
572			, THREAD_flags(%edi)
573	jnz		kernel_exit_work
5741:
575
576	cli								// disable interrupts
577
578	// update the thread's kernel time and return
579	UPDATE_THREAD_KERNEL_TIME()
580	POP_IFRAME_AND_RETURN()
581FUNCTION_END(int_bottom_user)
582
583
584// test interrupt handler for performance measurements
585.align 16
586FUNCTION(trap98):
587	iret
588FUNCTION_END(trap98)
589
590
591.align 16
592FUNCTION(trap99):
593	// push error, vector, orig_edx, orig_eax, and other registers
594	PUSH_IFRAME_BOTTOM_SYSCALL()
595
596	call	handle_syscall
597
598	POP_IFRAME_AND_RETURN()
599FUNCTION_END(trap99)
600
601
602STATIC_FUNCTION(handle_syscall):
603	movl	$KERNEL_TLS_SELECTOR, %edx
604	movw	%dx, %gs
605
606	// save %eax, the number of the syscall
607	movl	%eax, %esi
608
609	movl	$KERNEL_DATA_SELECTOR, %eax
610	cld
611	movl	%eax,%ds
612	movl	%eax,%es
613
614	lea		4(%esp), %ebp			// skipping the return address, the stack
615									// frame pointer is the iframe
616	movl	%gs:0, %edi				// thread pointer
617
618	// disable breakpoints, if installed
619	cli								// disable interrupts
620	STOP_USER_DEBUGGING()
621
622	// update the thread's user time
623	UPDATE_THREAD_USER_TIME_PUSH_TIME()
624		// leave the time on the stack (needed for post syscall debugging)
625
626	sti								// enable interrupts
627
628	cmp		$SYSCALL_COUNT, %esi	// check syscall number
629	jae		bad_syscall_number
630	movl	$kSyscallInfos, %eax	// get syscall info
631	lea		(%eax, %esi, SYSCALL_INFO_sizeof), %edx
632
633	// copy parameters onto this stack
634	COPY_SYSCALL_PARAMETERS()
635
636	// pre syscall debugging
637	TRACE_PRE_SYSCALL()
638	testl	$THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
639	jnz		do_pre_syscall_debug
640  pre_syscall_debug_done:
641
642	// call the syscall function
643	call	*SYSCALL_INFO_function(%esi)
644
645	testl	$THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi)
646	jnz		1f
647	xor		%edx, %edx
648  1:
649
650	// overwrite the values of %eax and %edx on the stack (the syscall return value)
651	movl	%edx, IFRAME_dx(%ebp)
652	movl	%eax, IFRAME_ax(%ebp)
653
654	TRACE_POST_SYSCALL()
655
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
663
664	cli								// disable interrupts
665
666	// update the thread's kernel time
667	UPDATE_THREAD_KERNEL_TIME()
668
669	lea		-4(%ebp), %esp			// remove all parameters from the stack
670
671	ret
672FUNCTION_END(handle_syscall)
673
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)
683
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:
698
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)
716
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:
728
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:
737
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)
746
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)
754
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)
761
762
763/*!	Handler called by the sysenter instruction
764	ecx - user esp
765*/
766FUNCTION(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
773
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
780
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
787
788	PUSH_IFRAME_BOTTOM_SYSCALL()
789
790	call	handle_syscall
791
792	// pop the bottom of the iframe
793	lea		4(%ebp), %esp	// skip iframe type
794
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
800
801	popa
802
803	// ecx already contains the user esp -- load edx with the return address
804	movl	16(%esp), %edx
805
806	// pop eflags, which also reenables interrupts
807	addl	$24, %esp	// skip, orig_eax/edx, vector, error_code, eip, cs
808	popfl
809
810	sysexit
811FUNCTION_END(x86_sysenter)
812
813
814/*!	\fn void x86_return_to_userland(iframe* frame)
815	\brief Returns to the userland environment given by \a frame.
816
817	Before returning to userland all potentially necessary kernel exit work is
818	done.
819
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.
823
824	\param frame The iframe defining the userland environment.
825*/
826FUNCTION(x86_return_to_userland):
827	// get the iframe* parameter
828	movl	4(%esp), %ebp
829	movl	%ebp, %esp
830
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
838
839	// update the thread's kernel time and return
840	UPDATE_THREAD_KERNEL_TIME()
841	POP_IFRAME_AND_RETURN()
842FUNCTION_END(x86_return_to_userland)
843