Index: arch/makefile ================================================================== --- arch/makefile +++ arch/makefile @@ -1,19 +1,44 @@ +ifeq (${OS},lin) + p-headers-syscall ?= /usr/include/asm/unistd_${BITS}.h + p-headers-errno ?= /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h +else ifeq (${OS},fbsd) + p-headers-syscall ?= /usr/include/sys/syscall.h + p-headers-errno ?= /usr/include/errno.h +else + $(info we don’t know where to find your magic number headers.) + $(info to compile libk, please provide the following variables \ +to the make command line:) + $(info --- p-headers-syscall=(location of syscall header)) + $(info --- p-headers-errno=(location of your errno values header)) + $(info note that /usr/include/errno.h or your system’s equivalent \ +may not be sufficient. make sure the file you pass actually contains \ +individual #define statements for each possible value of errno!) + $(error table generation failed due to missing primaries) +endif + ${TMP}: mkdir -p ${TMP} -${TMP}/calls.x86.lin.32.tbl: ${lin-headers}/unistd_32.h ${TMP} - grep "#define __NR_" $< | sed 's;^#define __NR_;;' > $@ -${TMP}/calls.x86.lin.64.tbl: ${lin-headers}/unistd_64.h ${TMP} - grep "#define __NR_" $< | sed 's;^#define __NR_;;' > $@ -${TMP}/calls.x86.fbsd.%.tbl: ${fbsd-headers}/syscall.h ${TMP} - grep "#define SYS_" $< | sed 's;^#define SYS_;;' | sed 's;[\t ]\+; ;' > $@ +${TMP}/calls.lin@x86.%.tbl: $(p-headers-syscall) + mkdir -p ${TMP} + grep -h "#define __NR_" $^ | sed 's;^#define __NR_;;' > $@ +${TMP}/calls.fbsd@%.tbl: $(p-headers-syscall) + mkdir -p ${TMP} + grep -h "#define SYS_" $^ | sed 's;^#define SYS_;;' | sed 's;[\t ]\+; ;' > $@ + +${TMP}/system_calls.%: ${TMP}/calls.${OS}@${ARCH}.${BITS}.tbl ${TMP} + awk -f syscall.awk -v out=$* <$< >$@ + +${TMP}/error_names.tbl: $(p-headers-errno) + mkdir -p ${TMP} + grep -h "#[ ]*define[ ]\+E" $^ | sed 's;^#[\t ]*define[\t ]\+\(E[A-Z0-9]\+\).*$$;k_platform_error_\1 \1;' > $@ +${TMP}/error_numbers.tbl: $(p-headers-errno) ${TMP}/error_names.tbl + cat $^ | cpp -P >$@ -${TMP}/calls.s: ${TMP}/calls.${TARGET}.tbl - awk -f syscall.awk -v out=asm <$< >$@ -${TMP}/calls.h: ${TMP}/calls.${TARGET}.tbl - awk -f syscall.awk -v out=header <$< >$@ +${TMP}/error_table.h: ${TMP}/error_numbers.tbl ${TMP} + awk -f errtbl.awk <$< >$@ -${TMP}/typesize: typesize.c +${TMP}/typesize: typesize.c ${TMP} $(CC) -std=c11 $< -o $@ -${TMP}/typesize.def: ${TMP}/typesize +${TMP}/typesize.def: ${TMP}/typesize ${TMP} $< > $@ Index: arch/posix.h ================================================================== --- arch/posix.h +++ arch/posix.h @@ -3,10 +3,12 @@ * needed in syscalls, both cross-platform * ones and os-dependent ones. note that * the values may change depending on the * OS specified! */ +#ifndef KIplatform_posix +#define KIplatform_posix #include #include enum posix_prot { posix_prot_none = 0, @@ -30,8 +32,34 @@ /* platform flags */ posix_flag_linux_hugetlb = 0x40000 }; -struct kposix_syscall_result { long ret, error; } +/* platform types */ + +typedef s64 k_platform_syscall_return; +typedef u64 k_platform_syscall_error; + +#if KVos == KA_os_lin + typedef long k_platform_syscall_arg; +#elif KVos == KA_os_fbsd + typedef u64 k_platform_syscall_arg; +#else + /* we're going to just pick a sane + * fallback that's reasonably likely + * to work with most systems one way + * or another */ + typedef unsigned long long k_platform_syscall_arg; +#endif + +struct k_platform_syscall_answer { + k_platform_syscall_return ret; + k_platform_syscall_error error; +}; + +#include + +extern struct k_platform_syscall_answer +k_platform_syscall(enum k_platform_syscall call, u8 valency, + k_platform_syscall_arg args[]); -kposix_syscall(enum kposix_syscall syscall, sz argct, long args[]); +#endif Index: arch/syscall.awk ================================================================== --- arch/syscall.awk +++ arch/syscall.awk @@ -1,17 +1,17 @@ BEGIN { - if (out == "header") { + if (out == "h") { print "#ifndef KIplatform_syscalls" print "#define KIplatform_syscalls" - print "enum /* syscall numbers */ {" + print "enum k_platform_syscall {" } } -out == "header" { print "\tk_platform_syscall_"$1" = "$2"," } -out == "asm" { print "%define sys."$1" "$2 } +out == "h" { print "\tk_platform_syscall_"$1" = "$2"," } # c header +out == "s" { print "%define sys."$1" "$2 } # assembly END { - if (out == "header") { - print "}" + if (out == "h") { + print "};" print "#endif" } } Index: arch/x86.fbsd.32.s ================================================================== --- arch/x86.fbsd.32.s +++ arch/x86.fbsd.32.s @@ -1,10 +1,10 @@ ;; abi definition file for x86 linux 64-bit ; vim: ft=nasm ; syscall numbers - syscall table must be created first! -%include "calls.s" +%include "system_calls.s" ; extremely stupid freebsd-ism: expects the syscall to ; come from a function _syscall: int 0x80 ret Index: arch/x86.fbsd.64.s ================================================================== --- arch/x86.fbsd.64.s +++ arch/x86.fbsd.64.s @@ -1,8 +1,8 @@ ;; abi definition file for x86 linux 64-bit ; vim: ft=nasm ; syscall numbers - syscall table must be created first! -%include "calls.x86.fbsd.64.s" +%include "system_calls.s" ; freebsd uses the common x86-64 ABI %include "x86.syscall.64.s" Index: arch/x86.lin.32.s ================================================================== --- arch/x86.lin.32.s +++ arch/x86.lin.32.s @@ -1,10 +1,10 @@ ;; abi definition file for x86 linux 32-bit ; vim: ft=nasm ; syscall32 numbers - syscall table must be created first! -%include "calls.s" +%include "system_calls.s" ; syscall32 registers %define sys.reg.n 6 %define sys.reg.0 eax %define sys.reg.1 ebx Index: arch/x86.lin.64.s ================================================================== --- arch/x86.lin.64.s +++ arch/x86.lin.64.s @@ -1,9 +1,9 @@ ;; abi definition file for x86 linux 64-bit ; vim: ft=nasm ; syscall64 numbers - syscall table must be created first! -%include "calls.s" +%include "system_calls.s" ; linux uses the common x86-64 ABI %include "x86.syscall.64.s" Index: arch/x86.syscall.64.s ================================================================== --- arch/x86.syscall.64.s +++ arch/x86.syscall.64.s @@ -27,13 +27,14 @@ %define sys.call syscall ; register order for syscall convention %define sys.reg.n 7 %define sys.reg.ret rax +%define sys.reg.err rbx %define sys.reg.0 rax %define sys.reg.1 rdi %define sys.reg.2 rsi %define sys.reg.3 rdx %define sys.reg.4 r10 %define sys.reg.5 r8 %define sys.reg.6 r9 Index: kcore/exit.fn.x86.lin.64.s ================================================================== --- kcore/exit.fn.x86.lin.64.s +++ kcore/exit.fn.x86.lin.64.s @@ -1,11 +1,11 @@ bits 64 %include "../arch/x86.lin.64.s" %include "../arch/x86.cdecl.64.s" ; vim: ft=nasm -global kio_posix_exit +global kio_posix_exit:function kio_posix_exit: mov sys.reg.1, ccall.reg.0 ;nop - rdi → rdi mov sys.reg.0, sys.exit sys.call ; no return ADDED kcore/platform.syscall.fn.c Index: kcore/platform.syscall.fn.c ================================================================== --- kcore/platform.syscall.fn.c +++ kcore/platform.syscall.fn.c @@ -0,0 +1,36 @@ +/* platform.syscall.fn.c + * ~ lexi hale + * this file provides a unified interface + * to the host operating system's syscalls. + * its function signature may vary across + * OSes, as the details of each's syscall + * implementation may vary drastically. + */ + +#include +#include + +#ifdef KFenv_posix +# include +#else + Knoimpl(k_platform_syscall) +#endif + +extern void k_platform_syscall_raw ( + k_platform_syscall_return* return_slot, + k_platform_syscall_error* error_no_slot, + enum k_platform_syscall syscall_no, + u8 valency, + s64* args); + +struct k_platform_syscall_answer +k_platform_syscall(enum k_platform_syscall call, u8 valency, s64 args[]) { + struct k_platform_syscall_answer answer; + + k_platform_syscall_raw + (&answer.ret, + &answer.error, + call, valency, args); + + return answer; +} ADDED kcore/syscall.fn.x86.lin.64.s Index: kcore/syscall.fn.x86.lin.64.s ================================================================== --- kcore/syscall.fn.x86.lin.64.s +++ kcore/syscall.fn.x86.lin.64.s @@ -0,0 +1,73 @@ +; kcore/syscall.fn.x86.lin.64.s +; ~ lexi hale +; +; 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 Index: kio/send.fn.c ================================================================== --- kio/send.fn.c +++ kio/send.fn.c @@ -8,17 +8,26 @@ /* we define all platform functions here, * whether or not they're for the correct * platform - only the ones actually called * by the generated code will be linked */ -extern sz kio_posix_fd_write(int fd, const char* buf, sz len); +#include kiocond kiosend(kiochan target, ksraw string, sz* len) { if (target.out.kind == kiostream_closed) return kiocond_fail_closed_stream; # ifdef KFenv_posix - sz size = kio_posix_fd_write(target.out.platform_fd, string.ptr, string.size); + /* issue the write syscall here and now so we can + * retrieve errno and report it if necessary */ + + k_platform_syscall_arg args[] = { + target.out.platform_fd, (k_platform_syscall_arg)string.ptr, string.size }; + + struct k_platform_syscall_answer a = k_platform_syscall + (k_platform_syscall_write,3,args); + + sz size = a.ret; if (size == -1) return kiocond_fail; //TODO: retrieve errno and offer more specific errors # else # if KVos == win # error windows IO send function not yet defined # else Index: makefile ================================================================== --- makefile +++ makefile @@ -12,12 +12,10 @@ else export TARGET = $(ARCH).$(OS) endif export m4 = m4 -export lin-headers = /usr/include/asm -export fbsd-headers = /usr/include/sys moddirs = $(wildcard k*) binaries = $(wildcard k*/*.exe.c) functions = $(wildcard k*/*.fn.c) assemblies = $(wildcard k*/*.fn.$(TARGET).s) @@ -94,11 +92,11 @@ lists = moddirs functions assemblies fnobjects rtobjects binaries binmods POSIX dbg: @echo -e lists: $(foreach var, $(lists), "\\n - \\e[1m$(var)\\e[m = $($(var))") -%.obj: %/makefile $(TMP)/calls.h $(TMP)/calls.s $(OUT) +%.obj: %/makefile $(TMP)/system_calls.h $(TMP)/system_calls.s $(OUT) cd $* && $(MAKE) obj %.tool: %/makefile $(OUT) cd $* && $(MAKE) tool @@ -106,12 +104,12 @@ cd $* && $(MAKE) dbg %.def: %/makefile $(TMP)/typesize.def $(OUT) $(OUT)/k cd $* && $(MAKE) def -.PRECIOUS: $(TMP)/calls.% -$(TMP)/calls.%: arch/makefile +.PRECIOUS: $(TMP)/system_calls.% +$(TMP)/system_calls.%: arch/makefile $(MAKE) -C arch $@ $(TMP)/typesize.def: arch/makefile $(TMP) $(MAKE) -C arch $@ Index: modmake ================================================================== --- modmake +++ modmake @@ -11,11 +11,11 @@ tools = $(filter %.exe.c, $(src)) nontools = $(filter-out %.exe.c, $(src)) cobjects = $(filter %.c, $(nontools)) sobjects = $(filter %.${TARGET}.s, $(nontools)) -cflags = -std=c11 -isystem ${OUT} -isystem ${ROOT}/arch -fPIC -nostdlib ${COMPLIB} -L${OUT} +cflags = -std=c11 -isystem ${OUT} -isystem ${TMP} -isystem ${ROOT}/arch -fPIC -nostdlib ${COMPLIB} -L${OUT} m-env = atom_target_arch=${ARCH} m-env += atom_target_os=${OS} ifneq (${BITS},) #!!! ifdef does NOT work with environment variables m-env += atom_target_bits=${BITS}