summaryrefslogtreecommitdiff
path: root/kernel/traps.s
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/traps.s')
-rw-r--r--kernel/traps.s146
1 files changed, 132 insertions, 14 deletions
diff --git a/kernel/traps.s b/kernel/traps.s
index e084ac8..73e7f64 100644
--- a/kernel/traps.s
+++ b/kernel/traps.s
@@ -3,13 +3,24 @@
; as well as the system call interface.
;
+global check_signals
global syscall_init
global traps_init
extern call_table
+extern ctask
extern idt
extern panic
extern printk
extern register_isr
+extern sighandler_default
+
+; here we define offsets into task_struct.
+; if task_struct is modified, this must be
+; too.
+
+%define ts_signal 6
+%define ts_sig_handlers 10
+%define ts_tss_esp0 142
%macro SAVE 0
pusha
@@ -64,19 +75,6 @@ extern register_isr
iret
%endmacro
-%macro RESTORE_SYS 0
- ; preserve our modified EAX (return value for syscalls)
- mov [esp+30], eax
- ; restore the data segment selectors
- pop ax
- mov ds, ax
- mov es, ax
- mov fs, ax
- mov gs, ax
- popa
- iret
-%endmacro
-
traps:
dd exc_div
dd exc_debug
@@ -204,6 +202,34 @@ exc_gprot:
exc_pagef:
SAVE_ERR
+ ; here we check if the page fault was
+ ; caused by a process trying to return
+ ; from a signal handler (this should cause
+ ; a page fault for accessing page
+ ; 0xFFFFE000 during the handler's
+ ; execution).
+
+ ; check if the offending address is 0xFFFFE000
+ mov eax, cr2
+ cmp eax, 0xFFFFE000
+ jne .skip
+ ; check if we're actually handling a signal
+ mov eax, [ctask]
+ mov eax, [eax+ts_tss_esp0]
+ cmp eax, 0xFFFFFFFF
+ je .skip
+ ; final checks that a user-initiated read caused the fault
+ mov eax, ebx
+ and eax, 6
+ cmp eax, 4
+ jne .skip
+ jmp sigret
+.skip:
+
+ ; if the above conditions are false, a
+ ; signal handler was not trying to return,
+ ; so we handle the page fault normally
+
push ebx
mov ebx, cr2
push ebx
@@ -243,6 +269,9 @@ exc_reserved:
syscall_handler:
SAVE
+ ; push the arguments onto the stack, then
+ ; calculate the offset for the appropriate
+ ; handler function and call it
push edx
push ecx
push ebx
@@ -251,9 +280,98 @@ syscall_handler:
add eax, call_table
call [eax]
add esp, 12
+ ; preserve the syscall's return value
+ mov [esp+30], eax
+ mov eax, esp
+ ; check pending signals and handle them (if any)
+ push eax
+ call check_signals
+ add esp, 4
- RESTORE_SYS
+ RESTORE
+; void check_signals(void *saved_state)
+check_signals:
+ push ebp
+ mov ebp, esp
+ push ebx
+ push esi
+ ; abort if a signal is already being handled
+ mov eax, [ctask]
+ mov ebx, [eax+ts_tss_esp0]
+ cmp ebx, 0xFFFFFFFF
+ jne .end
+ ; check if there are any pending signals
+ ; if so, we'll resume at the signal
+ ; handler if a custom handler has been
+ ; defined, otherwise, we run the default
+ ; handler.
+ mov edx, [eax+ts_signal]
+ cmp edx, 0
+ je .end
+ ; find which signal has been triggered (then clear it's flag)
+ bsf ecx, edx
+ mov ebx, 1
+ shl ebx, cl
+ xor ebx, 0xFFFFFFFF
+ and dword [eax+ts_signal], ebx
+ mov ebx, ecx
+ ; calculate offset to the handler function
+ shl ecx, 2
+ add ecx, eax
+ add ecx, ts_sig_handlers
+ cmp dword [ecx], 0
+ jne .custom_handler
+ ; call the default handler
+ push ebx
+ call sighandler_default
+ add esp, 4
+ jmp .end
+.custom_handler:
+ ; save our stack pointer
+ mov esi, [ebp+8]
+ mov [eax+ts_tss_esp0], esi
+ ; here, we push the return address onto
+ ; the user's stack. we give a bogus return
+ ; address of 0xFFFFE000 (the second-last
+ ; page) to deliberately trigger a page
+ ; fault that will alert us when the signal
+ ; handler tried to return.
+ mov ebx, [ebp+8]
+ mov esi, ebx
+ add esi, 46
+ mov esi, [esi]
+ sub esi, 4
+ mov dword [esi], 0xFFFFE000
+ ; push a new state onto our stack
+ push dword [ebx+50] ; SS
+ push dword esi ; ESP
+ push dword [ebx+42] ; EFLAGS
+ push dword [ebx+38] ; CS
+ push dword [ecx] ; EIP
+ push dword 0 ; EAX
+ push dword 0 ; ECX
+ push dword 0 ; EDX
+ push dword 0 ; EBX
+ push dword 0 ; ESP
+ push dword [ebx+10] ; EBP
+ push dword 0 ; ESI
+ push dword 0 ; EDI
+ push word [ebx] ; DS
+ RESTORE
+.end:
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+sigret:
+ call check_signals
+ ; restore our original stack frame and reset the TSS's ESP0
+ mov esp, [eax+ts_tss_esp0]
+ mov dword [eax+ts_tss_esp0], 0xFFFFFFFF
+ ; finally, perform the normal syscall return
+ RESTORE
syscall_init:
push ebp