#include <arch/user_debugger.h>
#include <arch/x86/arch_cpu.h>
#include <arch/x86/arch_kernel.h>
#include <arch/x86/descriptors.h>
#include <asm_defs.h>
#include <commpage_defs.h>
#include <thread_types.h>
#include "tracing_config.h"
#include "asm_offsets.h"
#include "syscall_numbers.h"
#include "syscall_table.h"
#define LOCK_THREAD_TIME() \
lea THREAD_time_lock(%edi), %eax; \
pushl %eax; \
call acquire_spinlock;
#define UNLOCK_THREAD_TIME() \
\
\
call release_spinlock; \
addl $4, %esp;
#define UPDATE_THREAD_USER_TIME_COMMON() \
movl %eax, %ebx; \
movl %edx, %ecx; \
\
\
sub THREAD_last_time(%edi), %eax; \
sbb (THREAD_last_time + 4)(%edi), %edx; \
add %eax, THREAD_user_time(%edi); \
adc %edx, (THREAD_user_time + 4)(%edi); \
\
\
movl %ebx, THREAD_last_time(%edi); \
movl %ecx, (THREAD_last_time + 4)(%edi); \
\
\
movb $1, THREAD_in_kernel(%edi);
#define UPDATE_THREAD_USER_TIME() \
LOCK_THREAD_TIME() \
call system_time; \
UPDATE_THREAD_USER_TIME_COMMON() \
UNLOCK_THREAD_TIME()
#define UPDATE_THREAD_KERNEL_TIME() \
LOCK_THREAD_TIME() \
\
call system_time; \
\
movl %eax, %ebx; \
movl %edx, %ecx; \
\
\
sub THREAD_last_time(%edi), %eax; \
sbb (THREAD_last_time + 4)(%edi), %edx; \
add %eax, THREAD_kernel_time(%edi); \
adc %edx, (THREAD_kernel_time + 4)(%edi); \
\
\
movl %ebx, THREAD_last_time(%edi); \
movl %ecx, (THREAD_last_time + 4)(%edi); \
\
\
movb $0, THREAD_in_kernel(%edi); \
\
UNLOCK_THREAD_TIME() \
#define PUSH_IFRAME_BOTTOM(iframeType) \
pusha; \
push %ds; \
push %es; \
push %fs; \
push %gs; \
pushl $iframeType
#define PUSH_IFRAME_BOTTOM_SYSCALL() \
pushl $0; \
pushl $99; \
pushl %edx; \
pushl %eax; \
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_SYSCALL)
#define POP_IFRAME_AND_RETURN() \
\
lea 4(%ebp), %esp; \
\
pop %gs; \
addl $4, %esp;
\
pop %es; \
pop %ds; \
\
popa; \
addl $16,%esp;
\
iret
#define STOP_USER_DEBUGGING() \
testl $(THREAD_FLAGS_BREAKPOINTS_INSTALLED \
| THREAD_FLAGS_SINGLE_STEP), THREAD_flags(%edi); \
jz 1f; \
call x86_exit_user_debug_at_kernel_entry; \
1:
#define COPY_SYSCALL_PARAMETERS() \
\
subl $80, %esp; \
\
\
movl IFRAME_user_sp(%ebp), %esi; \
addl $4, %esi; \
cmp $KERNEL_BASE, %esi; \
jae bad_syscall_params; \
\
\
movl $bad_syscall_params, THREAD_fault_handler(%edi); \
\
\
movl %esp, %edi; \
\
\
movl SYSCALL_INFO_parameter_size(%edx), %ecx; \
shrl $2, %ecx; \
\
\
cld; \
rep movsl; \
\
\
movl %edx, %esi; \
movl %gs:0, %edi; \
movl $0, THREAD_fault_handler(%edi)
#if SYSCALL_TRACING
# define TRACE_PRE_SYSCALL() \
movl %esp, %eax; \
push %eax; \
movl IFRAME_orig_eax(%ebp), %eax; \
push %eax; \
call trace_pre_syscall; \
addl $8, %esp;
# define TRACE_POST_SYSCALL() \
testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi); \
jnz 1f; \
xor %edx, %edx; \
1: \
push %edx; \
push %eax; \
movl IFRAME_orig_eax(%ebp), %eax; \
push %eax; \
call trace_post_syscall; \
addl $12, %esp
#else
# define TRACE_PRE_SYSCALL()
# define TRACE_POST_SYSCALL()
#endif
.text
#define TRAP_ERRC(name, vector) \
.align 8; \
FUNCTION(name): \
pushl $vector; \
pushl %edx; \
pushl %eax; \
jmp intr_bottom; \
FUNCTION_END(name)
#define TRAP(name, vector) \
.align 8; \
FUNCTION(name): \
pushl $0; \
pushl $vector; \
pushl %edx; \
pushl %eax; \
jmp intr_bottom; \
FUNCTION_END(name)
TRAP(trap0, 0)
TRAP(trap1, 1)
TRAP(trap2, 2)
TRAP(trap3, 3)
TRAP(trap4, 4)
TRAP(trap5, 5)
TRAP(trap6, 6)
TRAP(trap7, 7)
.align 8;
FUNCTION(double_fault):
pushl $-1;
pushl $-1;
pushl $-1;
pushl $KERNEL_CODE_SELECTOR
pushl $-1;
pushl $0;
pushl $8;
pushl $-1;
pushl $-1;
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
movl %esp, %ebp
pushl %ebp
call x86_double_fault_exception
POP_IFRAME_AND_RETURN()
FUNCTION_END(double_fault)
TRAP(trap9, 9)
TRAP_ERRC(trap10, 10)
TRAP_ERRC(trap11, 11)
TRAP_ERRC(trap12, 12)
TRAP_ERRC(trap13, 13)
TRAP_ERRC(trap14, 14)
TRAP(trap16, 16)
TRAP_ERRC(trap17, 17)
TRAP(trap18, 18)
TRAP(trap19, 19)
TRAP(trap32, 32)
TRAP(trap33, 33)
TRAP(trap34, 34)
TRAP(trap35, 35)
TRAP(trap36, 36)
TRAP(trap37, 37)
TRAP(trap38, 38)
TRAP(trap39, 39)
TRAP(trap40, 40)
TRAP(trap41, 41)
TRAP(trap42, 42)
TRAP(trap43, 43)
TRAP(trap44, 44)
TRAP(trap45, 45)
TRAP(trap46, 46)
TRAP(trap47, 47)
TRAP(trap48, 48)
TRAP(trap49, 49)
TRAP(trap50, 50)
TRAP(trap51, 51)
TRAP(trap52, 52)
TRAP(trap53, 53)
TRAP(trap54, 54)
TRAP(trap55, 55)
TRAP(trap56, 56)
TRAP(trap57, 57)
TRAP(trap58, 58)
TRAP(trap59, 59)
TRAP(trap60, 60)
TRAP(trap61, 61)
TRAP(trap62, 62)
TRAP(trap63, 63)
TRAP(trap64, 64)
TRAP(trap65, 65)
TRAP(trap66, 66)
TRAP(trap67, 67)
TRAP(trap68, 68)
TRAP(trap69, 69)
TRAP(trap70, 70)
TRAP(trap71, 71)
TRAP(trap72, 72)
TRAP(trap73, 73)
TRAP(trap74, 74)
TRAP(trap75, 75)
TRAP(trap76, 76)
TRAP(trap77, 77)
TRAP(trap78, 78)
TRAP(trap79, 79)
TRAP(trap80, 80)
TRAP(trap81, 81)
TRAP(trap82, 82)
TRAP(trap83, 83)
TRAP(trap84, 84)
TRAP(trap85, 85)
TRAP(trap86, 86)
TRAP(trap87, 87)
TRAP(trap88, 88)
TRAP(trap89, 89)
TRAP(trap90, 90)
TRAP(trap91, 91)
TRAP(trap92, 92)
TRAP(trap93, 93)
TRAP(trap94, 94)
TRAP(trap95, 95)
TRAP(trap96, 96)
TRAP(trap97, 97)
TRAP(trap100, 100)
TRAP(trap101, 101)
TRAP(trap102, 102)
TRAP(trap103, 103)
TRAP(trap104, 104)
TRAP(trap105, 105)
TRAP(trap106, 106)
TRAP(trap107, 107)
TRAP(trap108, 108)
TRAP(trap109, 109)
TRAP(trap110, 110)
TRAP(trap111, 111)
TRAP(trap112, 112)
TRAP(trap113, 113)
TRAP(trap114, 114)
TRAP(trap115, 115)
TRAP(trap116, 116)
TRAP(trap117, 117)
TRAP(trap118, 118)
TRAP(trap119, 119)
TRAP(trap120, 120)
TRAP(trap121, 121)
TRAP(trap122, 122)
TRAP(trap123, 123)
TRAP(trap124, 124)
TRAP(trap125, 125)
TRAP(trap126, 126)
TRAP(trap127, 127)
TRAP(trap128, 128)
TRAP(trap129, 129)
TRAP(trap130, 130)
TRAP(trap131, 131)
TRAP(trap132, 132)
TRAP(trap133, 133)
TRAP(trap134, 134)
TRAP(trap135, 135)
TRAP(trap136, 136)
TRAP(trap137, 137)
TRAP(trap138, 138)
TRAP(trap139, 139)
TRAP(trap140, 140)
TRAP(trap141, 141)
TRAP(trap142, 142)
TRAP(trap143, 143)
TRAP(trap144, 144)
TRAP(trap145, 145)
TRAP(trap146, 146)
TRAP(trap147, 147)
TRAP(trap148, 148)
TRAP(trap149, 149)
TRAP(trap150, 150)
TRAP(trap151, 151)
TRAP(trap152, 152)
TRAP(trap153, 153)
TRAP(trap154, 154)
TRAP(trap155, 155)
TRAP(trap156, 156)
TRAP(trap157, 157)
TRAP(trap158, 158)
TRAP(trap159, 159)
TRAP(trap160, 160)
TRAP(trap161, 161)
TRAP(trap162, 162)
TRAP(trap163, 163)
TRAP(trap164, 164)
TRAP(trap165, 165)
TRAP(trap166, 166)
TRAP(trap167, 167)
TRAP(trap168, 168)
TRAP(trap169, 169)
TRAP(trap170, 170)
TRAP(trap171, 171)
TRAP(trap172, 172)
TRAP(trap173, 173)
TRAP(trap174, 174)
TRAP(trap175, 175)
TRAP(trap176, 176)
TRAP(trap177, 177)
TRAP(trap178, 178)
TRAP(trap179, 179)
TRAP(trap180, 180)
TRAP(trap181, 181)
TRAP(trap182, 182)
TRAP(trap183, 183)
TRAP(trap184, 184)
TRAP(trap185, 185)
TRAP(trap186, 186)
TRAP(trap187, 187)
TRAP(trap188, 188)
TRAP(trap189, 189)
TRAP(trap190, 190)
TRAP(trap191, 191)
TRAP(trap192, 192)
TRAP(trap193, 193)
TRAP(trap194, 194)
TRAP(trap195, 195)
TRAP(trap196, 196)
TRAP(trap197, 197)
TRAP(trap198, 198)
TRAP(trap199, 199)
TRAP(trap200, 200)
TRAP(trap201, 201)
TRAP(trap202, 202)
TRAP(trap203, 203)
TRAP(trap204, 204)
TRAP(trap205, 205)
TRAP(trap206, 206)
TRAP(trap207, 207)
TRAP(trap208, 208)
TRAP(trap209, 209)
TRAP(trap210, 210)
TRAP(trap211, 211)
TRAP(trap212, 212)
TRAP(trap213, 213)
TRAP(trap214, 214)
TRAP(trap215, 215)
TRAP(trap216, 216)
TRAP(trap217, 217)
TRAP(trap218, 218)
TRAP(trap219, 219)
TRAP(trap220, 220)
TRAP(trap221, 221)
TRAP(trap222, 222)
TRAP(trap223, 223)
TRAP(trap224, 224)
TRAP(trap225, 225)
TRAP(trap226, 226)
TRAP(trap227, 227)
TRAP(trap228, 228)
TRAP(trap229, 229)
TRAP(trap230, 230)
TRAP(trap231, 231)
TRAP(trap232, 232)
TRAP(trap233, 233)
TRAP(trap234, 234)
TRAP(trap235, 235)
TRAP(trap236, 236)
TRAP(trap237, 237)
TRAP(trap238, 238)
TRAP(trap239, 239)
TRAP(trap240, 240)
TRAP(trap241, 241)
TRAP(trap242, 242)
TRAP(trap243, 243)
TRAP(trap244, 244)
TRAP(trap245, 245)
TRAP(trap246, 246)
TRAP(trap247, 247)
TRAP(trap248, 248)
TRAP(trap249, 249)
TRAP(trap250, 250)
TRAP(trap251, 251)
TRAP(trap252, 252)
TRAP(trap253, 253)
TRAP(trap254, 254)
TRAP(trap255, 255)
.align 8;
FUNCTION(trap14_double_fault):
pushl $14
pushl $-1
pushl $-1
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
movl %esp, %ebp
pushl %ebp
call x86_page_fault_exception_double_fault
POP_IFRAME_AND_RETURN()
FUNCTION_END(trap14_double_fault)
.align 16
STATIC_FUNCTION(intr_bottom):
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
movl $KERNEL_TLS_SELECTOR, %edx
movw %dx, %gs
movl %esp, %ebp
orl $0x10000, IFRAME_flags(%ebp);
cmpw $USER_CODE_SELECTOR, IFRAME_cs(%ebp)
je intr_bottom_user
movl %gs:0, %edi
cmpb $0, THREAD_in_kernel(%edi)
je intr_bottom_user
cli
pushl %ebp
movl IFRAME_vector(%ebp), %eax
call *gInterruptHandlerTable(, %eax, 4)
POP_IFRAME_AND_RETURN()
FUNCTION_END(intr_bottom)
STATIC_FUNCTION(intr_bottom_user):
movl $KERNEL_DATA_SELECTOR, %eax
cld
movl %eax,%ds
movl %eax,%es
movl %gs:0, %edi
cli
STOP_USER_DEBUGGING()
UPDATE_THREAD_USER_TIME()
pushl %ebp
movl IFRAME_vector(%ebp), %eax
call *gInterruptHandlerTable(, %eax, 4)
cmpw $USER_CODE_SELECTOR, IFRAME_cs(%ebp)
jne 1f
testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
| THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
, THREAD_flags(%edi)
jnz kernel_exit_work
1:
cli
UPDATE_THREAD_KERNEL_TIME()
POP_IFRAME_AND_RETURN()
FUNCTION_END(intr_bottom_user)
.align 16
FUNCTION(trap98):
iret
FUNCTION_END(trap98)
.align 16
FUNCTION(trap99):
PUSH_IFRAME_BOTTOM_SYSCALL()
call handle_syscall
POP_IFRAME_AND_RETURN()
FUNCTION_END(trap99)
STATIC_FUNCTION(handle_syscall):
movl $KERNEL_TLS_SELECTOR, %edx
movw %dx, %gs
movl %eax, %esi
movl $KERNEL_DATA_SELECTOR, %eax
cld
movl %eax,%ds
movl %eax,%es
lea 4(%esp), %ebp
movl %gs:0, %edi
cli
STOP_USER_DEBUGGING()
UPDATE_THREAD_USER_TIME()
sti
cmp $SYSCALL_COUNT, %esi
jae bad_syscall_number
movl $kSyscallInfos, %eax
lea (%eax, %esi, SYSCALL_INFO_sizeof), %edx
COPY_SYSCALL_PARAMETERS()
TRACE_PRE_SYSCALL()
testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
jnz do_pre_syscall_debug
pre_syscall_debug_done:
call *SYSCALL_INFO_function(%esi)
testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi)
jz 1f
movl %edx, IFRAME_dx(%ebp)
1:
movl %eax, IFRAME_ax(%ebp)
TRACE_POST_SYSCALL()
testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
| THREAD_FLAGS_TRAP_FOR_CORE_DUMP \
| THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
| THREAD_FLAGS_RESTART_SYSCALL | THREAD_FLAGS_SYSCALL_RESTARTED) \
, THREAD_flags(%edi)
jnz post_syscall_work
cli
UPDATE_THREAD_KERNEL_TIME()
lea -4(%ebp), %esp
ret
FUNCTION_END(handle_syscall)
STATIC_FUNCTION(do_pre_syscall_debug):
movl %esp, %eax
push %eax
movl IFRAME_orig_eax(%ebp), %eax
push %eax
call user_debug_pre_syscall
addl $8, %esp
jmp pre_syscall_debug_done
FUNCTION_END(do_pre_syscall_debug)
STATIC_FUNCTION(post_syscall_work):
testl $THREAD_FLAGS_DEBUGGER_INSTALLED, THREAD_flags(%edi)
jz 2f
xor %edx, %edx
testl $THREAD_FLAGS_64_BIT_SYSCALL_RETURN, THREAD_flags(%edi)
jz 1f
movl IFRAME_dx(%ebp), %edx
1:
movl IFRAME_ax(%ebp), %eax
push %edx
push %eax
lea 8(%esp), %eax
push %eax
movl IFRAME_orig_eax(%ebp), %eax
push %eax
call user_debug_post_syscall
addl $16, %esp
2:
testl $(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
| THREAD_FLAGS_SYSCALL_RESTARTED), THREAD_flags(%edi)
jz 2f
1:
movl THREAD_flags(%edi), %eax
movl %eax, %edx
andl $~(THREAD_FLAGS_64_BIT_SYSCALL_RETURN \
| THREAD_FLAGS_SYSCALL_RESTARTED), %edx
lock
cmpxchgl %edx, THREAD_flags(%edi)
jnz 1b
2:
FUNCTION_END(post_syscall_work)
bad_syscall_number:
STATIC_FUNCTION(kernel_exit_work):
testl $(THREAD_FLAGS_SIGNALS_PENDING | THREAD_FLAGS_DEBUG_THREAD \
| THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
, THREAD_flags(%edi)
jnz kernel_exit_handle_signals
cli
call thread_at_kernel_exit_no_signals
kernel_exit_work_done:
testl $THREAD_FLAGS_RESTART_SYSCALL, THREAD_flags(%edi)
jz 1f
push %ebp
call x86_restart_syscall
addl $4, %esp
1:
testl $THREAD_FLAGS_BREAKPOINTS_DEFINED, THREAD_flags(%edi)
jz 1f
push %ebp
call x86_init_user_debug_at_kernel_exit
1:
POP_IFRAME_AND_RETURN()
FUNCTION_END(kernel_exit_work)
STATIC_FUNCTION(kernel_exit_handle_signals):
sti
call thread_at_kernel_exit
jmp kernel_exit_work_done
FUNCTION_END(kernel_exit_handle_signals)
STATIC_FUNCTION(bad_syscall_params):
movl %gs:0, %edi
movl $0, THREAD_fault_handler(%edi)
jmp kernel_exit_work
FUNCTION_END(bad_syscall_params)
FUNCTION(x86_sysenter):
push %gs
movl $KERNEL_TLS_SELECTOR, %edx
movw %dx, %gs
movl %gs:0, %edx
pop %gs
pushl $USER_DATA_SELECTOR
pushl %ecx
pushfl
orl $(1 << 9), (%esp)
pushl $USER_CODE_SELECTOR
movl THREAD_team(%edx), %edx
movl TEAM_commpage_address(%edx), %edx
addl 4 * COMMPAGE_ENTRY_X86_SYSCALL(%edx), %edx
addl $4, %edx
pushl %edx
PUSH_IFRAME_BOTTOM_SYSCALL()
call handle_syscall
lea 4(%ebp), %esp
pop %gs
addl $4, %esp
pop %es
pop %ds
popa
movl 16(%esp), %edx
addl $24, %esp
popfl
sysexit
FUNCTION_END(x86_sysenter)
FUNCTION(x86_return_to_userland):
movl 4(%esp), %ebp
movl %ebp, %esp
movl %gs:0, %edi
testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED \
| THREAD_FLAGS_TRAP_FOR_CORE_DUMP) \
, THREAD_flags(%edi)
jnz kernel_exit_work
UPDATE_THREAD_KERNEL_TIME()
POP_IFRAME_AND_RETURN()
FUNCTION_END(x86_return_to_userland)