; kcore/syscall.fn.x86.lin.32.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(s32* result, u32* errno,
; syscall, u8 valency, s32[] args)
bits 32
%include "../arch/posix/x86.lin.32.s"
%include "../arch/x86.cdecl.32.s"
; vim: ft=nasm
%define result_ptr edi
%define errno_ptr ebx
%define valency ecx
%define args esi
%define opcode eax
%macro handle_arg 1
push dword [args]
sub args, 4
dec valency
jz .perform_call
%endmacro
global k_platform_syscall_raw:function
k_platform_syscall_raw:
; locals: rbx = s32* result
; r12 = u32* errno
; arg 0 = s32* 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
pop result_ptr
pop errno_ptr
pop edx ; opcode
; set up registers for the loop
pop valency
pop args ; ptr to args array
mov eax, 4
mul valency
add args, eax ; adjust args pointer to point
; at end of array, so it can be
; trivially pushed in backwards
; this needs to go before the loop
; or it'll get clobbered
mov opcode, edx ; syscall number
; 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 dword [result_ptr], -1
mov dword [errno_ptr], -1
ret
; we have a valency match - perform the
; requested syscall already stored in eax
.perform_call: sys.call
; check if an error has occurred, and
; jump to the error handling routine
; if necessary
test sys.reg.ret, sys.reg.ret
js .error
; move our return values into place and
; return to the caller (which should
; always be k_platform_syscall, btw)
mov [result_ptr], sys.reg.ret
mov dword [errno_ptr], 0
ret
.error: neg sys.reg.ret
mov dword [result_ptr], -1
mov [errno_ptr], sys.reg.ret
ret