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.
112 lines
2.0 KiB
ArmAsm
112 lines
2.0 KiB
ArmAsm
%include "tasking.inc"
|
|
|
|
; 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: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]
|
|
|
|
push rcx
|
|
push rbp
|
|
mov rbp, rsp
|
|
|
|
; account for the hole in the sysv abi
|
|
; argument list since SYSCALL uses rcx.
|
|
; r10 is non-preserved but not part of
|
|
; the function call ABI, so the rcx arg
|
|
; was stashed there.
|
|
mov rcx, r10
|
|
|
|
push rbx
|
|
push r11
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push r15
|
|
|
|
inc qword [rel __counter_syscall_enter]
|
|
|
|
and rax, 0xff ; Only 256 possible syscall values
|
|
lea r11, [rel syscall_registry]
|
|
mov r11, [r11 + rax * 8]
|
|
cmp r11, 0
|
|
je .bad_syscall
|
|
|
|
call r11
|
|
|
|
inc qword [rel __counter_syscall_sysret]
|
|
jmp 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
|
|
pop r13
|
|
pop r12
|
|
pop r11
|
|
pop rbx
|
|
|
|
pop rbp
|
|
pop rcx
|
|
|
|
mov [gs:CPU_DATA.rsp0], rsp
|
|
mov rsp, [gs:CPU_DATA.rsp3]
|
|
|
|
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:
|