xref: /haiku/src/system/kernel/arch/x86/32/interrupts.S (revision a6a15d5e711ca9fd0fd2ad171ea2a327137f9383)
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		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_TRAP_FOR_CORE_DUMP) \
576			, THREAD_flags(%edi)
577	jnz		kernel_exit_work
5781:
579
580	cli								// disable interrupts
581
582	// update the thread's kernel time and return
583	UPDATE_THREAD_KERNEL_TIME()
584	POP_IFRAME_AND_RETURN()
585FUNCTION_END(int_bottom_user)
586
587
588// test interrupt handler for performance measurements
589.align 16
590FUNCTION(trap98):
591	iret
592FUNCTION_END(trap98)
593
594
595.align 16
596FUNCTION(trap99):
597	// push error, vector, orig_edx, orig_eax, and other registers
598	PUSH_IFRAME_BOTTOM_SYSCALL()
599
600	call	handle_syscall
601
602	POP_IFRAME_AND_RETURN()
603FUNCTION_END(trap99)
604
605
606STATIC_FUNCTION(handle_syscall):
607	movl	$KERNEL_TLS_SELECTOR, %edx
608	movw	%dx, %gs
609
610	// save %eax, the number of the syscall
611	movl	%eax, %esi
612
613	movl	$KERNEL_DATA_SELECTOR, %eax
614	cld
615	movl	%eax,%ds
616	movl	%eax,%es
617
618	lea		4(%esp), %ebp			// skipping the return address, the stack
619									// frame pointer is the iframe
620	movl	%gs:0, %edi				// thread pointer
621
622	// disable breakpoints, if installed
623	cli								// disable interrupts
624	STOP_USER_DEBUGGING()
625
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)
629
630	sti								// enable interrupts
631
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
636
637	// copy parameters onto this stack
638	COPY_SYSCALL_PARAMETERS()
639
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:
645
646	// call the syscall function
647	call	*SYSCALL_INFO_function(%esi)
648
649	// overwrite the values of %eax and %edx on the stack (the syscall return value)
650	testl	$THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi)
651	jz		1f
652	movl	%edx, IFRAME_dx(%ebp)
653  1:
654	movl	%eax, IFRAME_ax(%ebp)
655
656	TRACE_POST_SYSCALL()
657
658	testl	$(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
659			| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
660			| THREAD_FLAGS_TRAP_FOR_CORE_DUMP \
661			| THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
662			| THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \
663			, THREAD_flags(%edi)
664	jnz		post_syscall_work
665
666	cli								// disable interrupts
667
668	// update the thread's kernel time
669	UPDATE_THREAD_KERNEL_TIME()
670
671	lea		-4(%ebp), %esp			// remove all parameters from the stack
672
673	ret
674FUNCTION_END(handle_syscall)
675
676  STATIC_FUNCTION(do_pre_syscall_debug):
677	movl	%esp, %eax				// syscall parameters
678	push	%eax
679	movl	IFRAME_orig_eax(%ebp), %eax		// syscall number
680	push	%eax
681	call	user_debug_pre_syscall
682	addl	$8, %esp
683	jmp		pre_syscall_debug_done
684  FUNCTION_END(do_pre_syscall_debug)
685
686  STATIC_FUNCTION(post_syscall_work):
687	// post syscall debugging
688	testl	$THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
689	jz		2f
690	pushl	-8(%ebp)				// syscall start time
691	pushl	-12(%ebp)
692	xor		%edx, %edx
693	testl	$THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi)
694	jz		1f
695	movl	IFRAME_dx(%ebp), %edx	// syscall return value
696  1:
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
707  2:
708	// clear the 64 bit return value and syscall restarted bits
709	testl	$(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
710				| THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi)
711	jz		2f
712  1:
713	movl	THREAD_flags(%edi), %eax
714	movl	%eax, %edx
715	andl	$~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
716				| THREAD_FLAGS_SYSCALL_RESTARTED), %edx
717	lock
718	cmpxchgl	%edx, THREAD_flags(%edi)
719	jnz		1b
720  2:
721  FUNCTION_END(post_syscall_work)
722
723  bad_syscall_number:
724  STATIC_FUNCTION(kernel_exit_work):
725	// if no signals are pending and the thread shall not be debugged or stopped
726	// for a core dump, we can use the quick kernel exit function
727	testl	$(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD \
728			| THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
729			, THREAD_flags(%edi)
730	jnz		kernel_exit_handle_signals
731	cli								// disable interrupts
732	call	thread_at_kernel_exit_no_signals
733  kernel_exit_work_done:
734
735	// syscall restart
736	// TODO: this only needs to be done for syscalls!
737	testl	$THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi)
738	jz		1f
739	push	%ebp
740	call	x86_restart_syscall
741	addl	$4, %esp
742  1:
743
744	// install breakpoints, if defined
745	testl	$THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi)
746	jz		1f
747	push	%ebp
748	call	x86_init_user_debug_at_kernel_exit
749  1:
750	POP_IFRAME_AND_RETURN()
751  FUNCTION_END(kernel_exit_work)
752
753  STATIC_FUNCTION(kernel_exit_handle_signals):
754	// make sure interrupts are enabled (they are, when coming from a syscall
755	// but otherwise they might be disabled)
756	sti
757	call	thread_at_kernel_exit	// also disables interrupts
758	jmp		kernel_exit_work_done
759  FUNCTION_END(kernel_exit_handle_signals)
760
761  STATIC_FUNCTION(bad_syscall_params):
762	// clear the fault handler and exit normally
763	movl	%gs:0, %edi
764	movl	$0, THREAD_fault_handler(%edi)
765	jmp		kernel_exit_work
766  FUNCTION_END(bad_syscall_params)
767
768
769/*!	Handler called by the sysenter instruction
770	ecx - user esp
771*/
772FUNCTION(x86_sysenter):
773	// get the thread
774	push	%gs
775	movl	$KERNEL_TLS_SELECTOR, %edx
776	movw	%dx, %gs
777	movl	%gs:0, %edx
778	pop		%gs
779
780	// push the iframe
781	pushl	$USER_DATA_SELECTOR		// user_ss
782	pushl	%ecx					// user_esp
783	pushfl							// eflags
784	orl		$(1 << 9), (%esp)		// set the IF (interrupts) bit
785	pushl	$USER_CODE_SELECTOR		// user cs
786
787	// user_eip
788	movl	THREAD_team(%edx), %edx
789	movl	TEAM_commpage_address(%edx), %edx
790	addl	4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx
791	addl	$4, %edx				// sysenter is at offset 2, 2 bytes long
792	pushl	%edx
793
794	PUSH_IFRAME_BOTTOM_SYSCALL()
795
796	call	handle_syscall
797
798	// pop the bottom of the iframe
799	lea		4(%ebp), %esp	// skip iframe type
800
801	pop		%gs
802	addl	$4, %esp	/* we skip %fs, as this contains the CPU
803						   dependent TLS segment */
804	pop		%es
805	pop		%ds
806
807	popa
808
809	// ecx already contains the user esp -- load edx with the return address
810	movl	16(%esp), %edx
811
812	// pop eflags, which also reenables interrupts
813	addl	$24, %esp	// skip, orig_eax/edx, vector, error_code, eip, cs
814	popfl
815
816	sysexit
817FUNCTION_END(x86_sysenter)
818
819
820/*!	\fn void x86_return_to_userland(iframe* frame)
821	\brief Returns to the userland environment given by \a frame.
822
823	Before returning to userland all potentially necessary kernel exit work is
824	done.
825
826	\a frame must point to a location somewhere on the caller's stack (e.g. a
827	local variable).
828	The function must be called with interrupts disabled.
829
830	\param frame The iframe defining the userland environment.
831*/
832FUNCTION(x86_return_to_userland):
833	// get the iframe* parameter
834	movl	4(%esp), %ebp
835	movl	%ebp, %esp
836
837	// check, if any kernel exit work has to be done
838	movl	%gs:0, %edi
839	testl	$(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
840			| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
841			| THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
842			, THREAD_flags(%edi)
843	jnz		kernel_exit_work
844
845	// update the thread's kernel time and return
846	UPDATE_THREAD_KERNEL_TIME()
847	POP_IFRAME_AND_RETURN()
848FUNCTION_END(x86_return_to_userland)
849