[kernel] Update syscall MSRs for all CPUs
Since SYSCALL/SYSRET rely on MSRs to control their function, split out syscall_enable() into syscall_initialize() and syscall_enable(), the latter being called on all CPUs. This affects not just syscalls but also the kernel_to_user_trampoline. Additionally, do away with the max syscalls, and just make a single page of syscall pointers and name pointers. Max syscalls was fragile and needed to be kept in sync in multiple places.
This commit is contained in:
@@ -1,17 +1,32 @@
|
||||
%include "tasking.inc"
|
||||
|
||||
; Make sure to keep MAX_SYSCALLS in sync with
|
||||
; syscall::MAX in syscall.h
|
||||
MAX_SYSCALLS equ 0x40
|
||||
; SYSCALL/SYSRET control MSRs
|
||||
MSR_STAR equ 0xc0000081
|
||||
MSR_LSTAR equ 0xc0000082
|
||||
MSR_FMASK equ 0xc0000084
|
||||
|
||||
; IA32_STAR - high 32 bits contain k+u CS
|
||||
; Kernel CS: GDT[1] ring 0 bits[47:32]
|
||||
; User CS: GDT[3] ring 3 bits[63:48]
|
||||
STAR_HIGH equ \
|
||||
(((1 << 3) | 0)) | \
|
||||
(((3 << 3) | 3) << 16)
|
||||
|
||||
; IA32_FMASK - Mask off interrupts in syscalls
|
||||
FMASK_VAL equ 0x200
|
||||
|
||||
extern __counter_syscall_enter
|
||||
extern __counter_syscall_sysret
|
||||
|
||||
extern syscall_registry
|
||||
extern syscall_invalid
|
||||
|
||||
global syscall_handler_prelude
|
||||
|
||||
global syscall_handler_prelude:function (syscall_handler_prelude.end - syscall_handler_prelude)
|
||||
syscall_handler_prelude:
|
||||
push rbp ; Never executed, fake function prelude
|
||||
mov rbp, rsp ; to calm down gdb
|
||||
|
||||
.real:
|
||||
swapgs
|
||||
mov [gs:CPU_DATA.rsp3], rsp
|
||||
mov rsp, [gs:CPU_DATA.rsp0]
|
||||
@@ -36,14 +51,7 @@ syscall_handler_prelude:
|
||||
|
||||
inc qword [rel __counter_syscall_enter]
|
||||
|
||||
cmp rax, MAX_SYSCALLS
|
||||
jle .ok_syscall
|
||||
|
||||
.bad_syscall:
|
||||
mov rdi, rax
|
||||
call syscall_invalid
|
||||
|
||||
.ok_syscall:
|
||||
and rax, 0xff ; Only 256 possible syscall values
|
||||
lea r11, [rel syscall_registry]
|
||||
mov r11, [r11 + rax * 8]
|
||||
cmp r11, 0
|
||||
@@ -52,8 +60,14 @@ syscall_handler_prelude:
|
||||
call r11
|
||||
|
||||
inc qword [rel __counter_syscall_sysret]
|
||||
jmp kernel_to_user_trampoline
|
||||
|
||||
global kernel_to_user_trampoline
|
||||
.bad_syscall:
|
||||
mov rdi, rax
|
||||
call syscall_invalid
|
||||
.end:
|
||||
|
||||
global kernel_to_user_trampoline:function (kernel_to_user_trampoline.end - kernel_to_user_trampoline)
|
||||
kernel_to_user_trampoline:
|
||||
pop r15
|
||||
pop r14
|
||||
@@ -70,3 +84,28 @@ kernel_to_user_trampoline:
|
||||
|
||||
swapgs
|
||||
o64 sysret
|
||||
.end:
|
||||
|
||||
global syscall_enable:function (syscall_enable.end - syscall_enable)
|
||||
syscall_enable:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
mov rcx, MSR_STAR
|
||||
mov rax, 0
|
||||
mov rdx, STAR_HIGH
|
||||
wrmsr
|
||||
|
||||
mov rcx, MSR_LSTAR
|
||||
mov rax, syscall_handler_prelude.real
|
||||
mov rdx, rax
|
||||
shr rdx, 32
|
||||
wrmsr
|
||||
|
||||
mov rcx, MSR_FMASK
|
||||
mov rax, FMASK_VAL
|
||||
wrmsr
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
.end:
|
||||
|
||||
Reference in New Issue
Block a user