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