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
650	// 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