; 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
; which file is included is selected via the value
; of the target tuple - arch/$target is passed to
; the assembler as an include directory
%include 'syscall.s'
%include 'cdecl.s'
; vim: ft=nasm
%macro handle_arg 1
%assign v %1+1
mov sys.reg. %+ v, [r15 + 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
; we use two registers that are supposed
; to be callee-saved, so we need to
; push them to the stack and then pop
; them back off just before the fn rets.
push rbx
push r12
; 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
; the fourth argument is in %r8, which
; is also a syscall register, so we
; need to move it to a safe register
; to keep it from getting clobbered
; before we begin the "loop"
mov r15, ccall.reg.4
; 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 -1 and the
; error number to its maximum value in
; order to indicate that the syscall
; was invalid
mov qword [rbx], -1
mov qword [r12], -1
ret
; we have a valency match - perform the
; requested syscall already store in rax
.perform_call: sys.call
; check for an error - on x86, error is
; returned as a negative value in %rax
test sys.reg.ret, sys.reg.ret
js .error ; jump if sign flag set
; 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 qword [r12], 0 ; no error
jmp .return
; an error was returned - we need to set
; the errno to its positive equivalent,
; and store -1 in the return variable
.error: neg sys.reg.ret
mov qword [rbx], -1
mov [r12], sys.reg.ret
jmp .return
.return: pop r12
pop rbx
ret