xref: /haiku/src/system/kernel/arch/x86/32/interrupts.S (revision a085e81e62d7a860f809b4fb7c7bf5654c396985)
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	%dr3, %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_SEG;	// 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	%esp, %ebp		// frame pointer is the iframe
513
514	// Set the RF (resume flag) in EFLAGS. This prevents an instruction
515	// breakpoint on the instruction we're returning to to trigger a debug
516	// exception.
517	orl		$0x10000, IFRAME_flags(%ebp);
518
519	cmp		$USER_CODE_SEG, IFRAME_cs(%ebp)	// user mode
520	je		int_bottom_user
521
522	// We need to recheck user mode using the thread's in_kernel flag, since
523	// sysexit introduces a raced condition: It doesn't reenable interrupts,
524	// so that we have to do it in the instruction before, thus opening a
525	// window for an interrupt while still being in the kernel, but having set
526	// up everything for userland already.
527	movl	%dr3, %edi						// thread pointer
528	cmpb	$0, THREAD_in_kernel(%edi)
529	je		int_bottom_user
530
531	// disable interrupts -- the handler will enable them, if necessary
532	cli
533
534	pushl	%ebp
535	movl	IFRAME_vector(%ebp), %eax
536	call	*gInterruptHandlerTable(, %eax, 4)
537
538	POP_IFRAME_AND_RETURN()
539FUNCTION_END(int_bottom)
540
541
542STATIC_FUNCTION(int_bottom_user):
543	movl	$KERNEL_DATA_SEG,%eax
544	cld
545	movl	%eax,%ds
546	movl	%eax,%es
547
548	// disable breakpoints, if installed
549	movl	%dr3, %edi				// thread pointer
550	cli								// disable interrupts
551	STOP_USER_DEBUGGING()
552
553	// update the thread's user time
554	UPDATE_THREAD_USER_TIME()
555
556	// leave interrupts disabled -- the handler will enable them, if
557	// necessary
558
559	pushl	%ebp
560	movl	IFRAME_vector(%ebp), %eax
561	call	*gInterruptHandlerTable(, %eax, 4)
562
563	// Don't do any kernel exit work, if we actually came from the kernel (but
564	// were already/still prepared for userland), since the iframe in this case
565	// will be a kernel iframe and e.g. trying to set up a signal stack will not
566	// be a very healthy endeavor.
567	cmp		$USER_CODE_SEG, IFRAME_cs(%ebp)
568	jne		1f
569
570	testl	$(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
571			| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \
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	// save %eax, the number of the syscall
604	movl	%eax, %esi
605
606	movl	$KERNEL_DATA_SEG,%eax
607	cld
608	movl	%eax,%ds
609	movl	%eax,%es
610
611	lea		4(%esp), %ebp			// skipping the return address, the stack
612									// frame pointer is the iframe
613	movl	%dr3, %edi				// thread pointer
614
615	// disable breakpoints, if installed
616	cli								// disable interrupts
617	STOP_USER_DEBUGGING()
618
619	// update the thread's user time
620	UPDATE_THREAD_USER_TIME_PUSH_TIME()
621		// leave the time on the stack (needed for post syscall debugging)
622
623	sti								// enable interrupts
624
625	cmp		$SYSCALL_COUNT, %esi	// check syscall number
626	jae		bad_syscall_number
627	movl	$kSyscallInfos, %eax	// get syscall info
628	lea		(%eax, %esi, SYSCALL_INFO_sizeof), %edx
629
630	// copy parameters onto this stack
631	COPY_SYSCALL_PARAMETERS()
632
633	// pre syscall debugging
634	TRACE_PRE_SYSCALL()
635	testl	$THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
636	jnz		do_pre_syscall_debug
637  pre_syscall_debug_done:
638
639	// call the syscall function
640	call	*SYSCALL_INFO_function(%esi)
641
642	// overwrite the values of %eax and %edx on the stack (the syscall return
643	// value)
644	movl	%edx, IFRAME_dx(%ebp)
645	movl	%eax, IFRAME_ax(%ebp)
646
647	TRACE_POST_SYSCALL()
648
649	testl	$(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
650			| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
651			| THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
652			| THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \
653			, THREAD_flags(%edi)
654	jnz		post_syscall_work
655
656	cli								// disable interrupts
657
658	// update the thread's kernel time
659	UPDATE_THREAD_KERNEL_TIME()
660
661	lea		-4(%ebp), %esp			// remove all parameters from the stack
662
663	ret
664FUNCTION_END(handle_syscall)
665
666  STATIC_FUNCTION(do_pre_syscall_debug):
667	movl	%esp, %eax				// syscall parameters
668	push	%eax
669	movl	IFRAME_orig_eax(%ebp), %eax		// syscall number
670	push	%eax
671	call	user_debug_pre_syscall
672	addl	$8, %esp
673	jmp		pre_syscall_debug_done
674  FUNCTION_END(do_pre_syscall_debug)
675
676  STATIC_FUNCTION(post_syscall_work):
677	// clear the 64 bit return value and syscall restarted bits
678	testl	$(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
679				| THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi)
680	jz		2f
681  1:
682    movl	THREAD_flags(%edi), %eax
683	movl	%eax, %edx
684    andl	$~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
685				| THREAD_FLAGS_SYSCALL_RESTARTED), %edx
686    lock
687    cmpxchgl	%edx, THREAD_flags(%edi)
688    jnz		1b
689  2:
690
691	// post syscall debugging
692	testl	$THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
693	jz		1f
694	pushl	-8(%ebp)				// syscall start time
695	pushl	-12(%ebp)
696	movl	IFRAME_dx(%ebp), %edx	// syscall return value
697	movl	IFRAME_ax(%ebp), %eax
698	push	%edx
699	push	%eax
700	lea		16(%esp), %eax			// syscall parameters
701	push	%eax
702	movl	IFRAME_orig_eax(%ebp), %eax		// syscall number
703	push	%eax
704	call	user_debug_post_syscall
705	addl	$24, %esp
706  1:
707  FUNCTION_END(post_syscall_work)
708
709  bad_syscall_number:
710  STATIC_FUNCTION(kernel_exit_work):
711	// if no signals are pending and the thread shall not be debugged, we can
712	// use the quick kernel exit function
713	testl	$(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD) \
714			, THREAD_flags(%edi)
715	jnz		kernel_exit_handle_signals
716	cli								// disable interrupts
717	call	thread_at_kernel_exit_no_signals
718  kernel_exit_work_done:
719
720	// syscall restart
721	// TODO: this only needs to be done for syscalls!
722	testl	$THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi)
723	jz		1f
724	push	%ebp
725	call	x86_restart_syscall
726	addl	$4, %esp
727  1:
728
729	// install breakpoints, if defined
730	testl	$THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi)
731	jz		1f
732	push	%ebp
733	call	x86_init_user_debug_at_kernel_exit
734  1:
735	POP_IFRAME_AND_RETURN()
736  FUNCTION_END(kernel_exit_work)
737
738  STATIC_FUNCTION(kernel_exit_handle_signals):
739	// make sure interrupts are enabled (they are, when coming from a syscall
740	// but otherwise they might be disabled)
741	sti
742	call	thread_at_kernel_exit	// also disables interrupts
743	jmp		kernel_exit_work_done
744  FUNCTION_END(kernel_exit_handle_signals)
745
746  STATIC_FUNCTION(bad_syscall_params):
747	// clear the fault handler and exit normally
748	movl	%dr3, %edi
749	movl	$0, THREAD_fault_handler(%edi)
750	jmp		kernel_exit_work
751  FUNCTION_END(bad_syscall_params)
752
753
754/*!	Handler called by the sysenter instruction
755	ecx - user esp
756*/
757FUNCTION(x86_sysenter):
758	// get the thread
759	movl	%dr3, %edx
760
761	// push the iframe
762	pushl	$USER_DATA_SEG			// user_ss
763	pushl	%ecx					// user_esp
764	pushfl							// eflags
765	orl		$(1 << 9), (%esp)		// set the IF (interrupts) bit
766	pushl	$USER_CODE_SEG			// user cs
767
768	// user_eip
769	movl	THREAD_team(%edx), %edx
770	movl	TEAM_commpage_address(%edx), %edx
771	addl	4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx
772	addl	$4, %edx				// sysenter is at offset 2, 2 bytes long
773	pushl	%edx
774
775	PUSH_IFRAME_BOTTOM_SYSCALL()
776
777	call	handle_syscall
778
779	// pop the bottom of the iframe
780	lea		4(%ebp), %esp	// skip iframe type
781
782	pop		%gs
783	addl	$4, %esp	/* we skip %fs, as this contains the CPU
784						   dependent TLS segment */
785	pop		%es
786	pop		%ds
787
788	popa
789
790	// ecx already contains the user esp -- load edx with the return address
791	movl	16(%esp), %edx
792
793	// pop eflags, which also reenables interrupts
794	addl	$24, %esp	// skip, orig_eax/edx, vector, error_code, eip, cs
795	popfl
796
797	sysexit
798FUNCTION_END(x86_sysenter)
799
800
801/*!	\fn void x86_return_to_userland(iframe* frame)
802	\brief Returns to the userland environment given by \a frame.
803
804	Before returning to userland all potentially necessary kernel exit work is
805	done.
806
807	\a frame must point to a location somewhere on the caller's stack (e.g. a
808	local variable).
809	The function must be called with interrupts disabled.
810
811	\param frame The iframe defining the userland environment.
812*/
813FUNCTION(x86_return_to_userland):
814	// get the iframe* parameter
815	movl	4(%esp), %ebp
816	movl	%ebp, %esp
817
818	// check, if any kernel exit work has to be done
819	movl	%dr3, %edi
820	testl	$(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
821			| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \
822			, THREAD_flags(%edi)
823	jnz		kernel_exit_work
824
825	// update the thread's kernel time and return
826	UPDATE_THREAD_KERNEL_TIME()
827	POP_IFRAME_AND_RETURN()
828FUNCTION_END(x86_return_to_userland)
829