; kcore/syscall.fn.x86.lin.64.s
; ~ lexi hale <lexi@hale.su>
;
; this function performs a syscall and stores its
; results in the variables provided. this makes it
; possible to bypass the hideous errno mechanism
; altogether and access the error value of a
; syscall directly. invoke as:
;
; void k_platform_syscall_raw(s64* result, u64* errno,
; syscall, u8 valency, s64[] args)
bits 64
%include "../arch/x86.lin.64.s"
%include "../arch/x86.cdecl.64.s"
; vim: ft=nasm
%macro handle_arg 1
%assign v %1+1
mov sys.reg. %+ v, [ccall.reg.4 + 8 * %1]
dec ccall.reg.3
jz .perform_call
%endmacro
global k_platform_syscall_raw:function
k_platform_syscall_raw:
; locals: rbx = s64* result
; r12 = u64* errno
; arg 0 = s64* result
; arg 1 = errno ptr
; arg 2 = syscall num
; arg 3 = valency
; arg 4 = args ptr
; store the locals in registers that
; are guaranteed not to be clobbered,
; saving us some cycles pushing to
; and popping back from the stack
mov rbx, ccall.reg.0
mov r12, ccall.reg.1
; this needs to go before the loop
; or it'll get clobbered
mov sys.reg.0, ccall.reg.2
; automatically generate the code
; needed to move the arguments into
; their correct registers. see above
%assign i 0
%rep 6
handle_arg i
%assign i i+1
%endrep
; valency >= 7. this is not valid, so
; we set our return value to 0 and the
; error number to its maximum value in
; order to indicate that the syscall
; was invalid
mov qword [rbx], 0
mov qword [r12], -1
ret
; we have a valency match - perform the
; requested syscall already store in rax
.perform_call: sys.call
; move our return values into place and
; return to the caller (which should
; always be k_platform_syscall, btw)
mov [rbx], sys.reg.ret
mov [r12], sys.reg.err
ret