libk  syscall.fn.x86.lin.64.s at [12a51d9c50]

File mod/kcore/syscall.fn.x86.lin.64.s artifact a731f1dad0 part of check-in 12a51d9c50


; 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 three 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
	push r15

	; 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 r15 
		 pop r12
	         pop rbx
			 ret