libk  Check-in [e50a476efe]

Overview
Comment:removed sneaky segfault in x86-64 syscall fn where %r8 (the register that contains the pointer to the syscall arguments from the C syscall wrapper, which need to be copied into the correct registers before the kernel is invoked) gets overwritten if the syscall valency > 5, because of overlapping ccall and syscall ABI argument registers - r8 is clobbered by argument 5 and any further attempts to use it as a ptr segfault at best. also modified the report function so that it immediate cancels compilation if a sub-process reports failure. changed allocator function signatures so they can return a condition code if the kernel reports an error; updated example code so it compiles and runs without fault.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e50a476efef720ed926f519a291311b560264f46d8deb86a3b7cf4f76d997c9c
User & Date: lexi on 2019-08-22 02:52:20
Other Links: manifest | tags
Context
2019-08-22
04:31
finish moving heap allocation/free functions to the posix syscall apparatus and deprecate the direct assembly implementations of platform_mmap; update the kmem docs to match new function signatures (and remove typos) check-in: 709ffb094d user: lexi tags: trunk
02:52
removed sneaky segfault in x86-64 syscall fn where %r8 (the register that contains the pointer to the syscall arguments from the C syscall wrapper, which need to be copied into the correct registers before the kernel is invoked) gets overwritten if the syscall valency > 5, because of overlapping ccall and syscall ABI argument registers - r8 is clobbered by argument 5 and any further attempts to use it as a ptr segfault at best. also modified the report function so that it immediate cancels compilation if a sub-process reports failure. changed allocator function signatures so they can return a condition code if the kernel reports an error; updated example code so it compiles and runs without fault. check-in: e50a476efe user: lexi tags: trunk
01:37
add first iteration of knum header check-in: 5560c2725b user: lexi tags: trunk
Changes

Modified arch/posix/errnos from [cc3bf9e501] to [1054d9a4df].

     5      5   ENOSPC
     6      6   EDQUOT
     7      7   EIO
     8      8   EAGAIN
     9      9   EFBIG
    10     10   EINTR
    11     11   EDESTADDRREQ
           12  +EACCES
           13  +EMFILE
           14  +ENODEV
           15  +ENOMEM
           16  +ENXIO
           17  +EOVERFLOW

Modified build.sh from [d7b4907031] to [b5a70ac75f].

   146    146   		if test ! "$output" -ot "$src"; then
   147    147   			return
   148    148   		fi
   149    149   	fi
   150    150   	if test "$debug" = yes; then
   151    151   		local dflag="-g dwarf2"
   152    152   	fi
   153         -	report $asm $flags $dflag "-f$bin_fmt" -i "$gen" "$src" -o "$output";
          153  +	report $asm $flags $dflag "-f$bin_fmt" -i "$gen" -i "$PWD" "$src" -o "$output";
   154    154   }
   155    155   comp_co()  { comp_c $1 $2 "-c -fPIC"; }
   156    156   comp_c(){
   157    157   	local src=$1
   158    158   	local output=$2
   159    159   	local flags=$3
   160    160   	if test -e "$output"; then

Modified global/common.sh from [e60df5a627] to [582c735deb].

    57     57   fi
    58     58   
    59     59   # the following function is called to report a command invocation
    60     60   # the person compiling the library. the first argument should be
    61     61   # an ansi format string; this is used to color-code the tool being
    62     62   # launched and thus should be different for each one.
    63     63   
    64         -report() { announce $@; $@; }
           64  +report() {
           65  +	announce $@; $@;
           66  +	status=$?
           67  +	if test $status -ne 0; then
           68  +		args=($@)
           69  +		say "process ${args[0]} failed with status code $status"
           70  +		exit $status
           71  +	fi
           72  +}

Modified mod/kcore/syscall.fn.x86.lin.64.s from [472ad3a7d3] to [9bf0ba9bf3].

     7      7   ; altogether and access the error value of a
     8      8   ; syscall directly. invoke as:
     9      9   ;
    10     10   ; 	void k_platform_syscall_raw(s64* result, u64* errno,
    11     11   ;		syscall, u8 valency, s64[] args)
    12     12   
    13     13   bits 64
    14         -%include "../arch/posix/x86.lin.64.s"
    15         -%include "../arch/x86.cdecl.64.s"
           14  +%include "arch/posix/x86.lin.64.s"
           15  +%include "arch/x86.cdecl.64.s"
    16     16   ; vim: ft=nasm
    17     17   
    18     18   %macro handle_arg 1
    19     19   	%assign v %1+1
    20         -	mov sys.reg. %+ v, [ccall.reg.4 + 8 * %1]
           20  +	mov sys.reg. %+ v, [r15 + 8 * %1]
    21     21   	dec ccall.reg.3
    22     22   	jz .perform_call
    23     23   %endmacro
    24     24   
    25     25   global k_platform_syscall_raw:function
    26     26   k_platform_syscall_raw:
    27     27   	; locals: rbx = s64* result
................................................................................
    38     38   	; and popping back from the stack
    39     39   	mov rbx, ccall.reg.0
    40     40   	mov r12, ccall.reg.1
    41     41   
    42     42   	; this needs to go before the loop
    43     43   	; or it'll get clobbered
    44     44   	mov sys.reg.0, ccall.reg.2
           45  +
           46  +	; the fourth argument is in %r8, which
           47  +	; is also a syscall register, so we 
           48  +	; need to move it to a safe register
           49  +	; to keep it from getting clobbered
           50  +	; before we begin the "loop"
           51  +	mov r15, ccall.reg.4
    45     52   
    46     53   	; automatically generate the code
    47     54   	; needed to move the arguments into
    48     55   	; their correct registers. see above
    49     56   	%assign i 0
    50     57   	%rep 6
    51     58   		handle_arg i

Modified mod/kcore/testbin.exe.c from [c4d82c1a4a] to [ae0ed8cd11].

    18     18   
    19     19   	if (kiosend(e.std, ptr, null) == kiocond_ok) {
    20     20   		/* great, continue */
    21     21   	} else {
    22     22   		return kbad_io;
    23     23   	}
    24     24   
    25         -	void* region = kmheapa(2048);
    26         -	if (region == null) return kbad_mem;
           25  +	void* region;
           26  +	kmcond alloc = kmheapa(&region, 2048);
           27  +	if (alloc != kmcond_ok) return kbad_mem;
    27     28   
    28     29   	kmzero(region,2048);
    29     30   
    30     31   	if (kmheapf(region) >= kmcond_fail) return kbad_mem;
    31     32   
    32     33   	return kbad_ok;
    33     34   }

Modified mod/kmem/heapa.fn.c from [641176b71f] to [e093792a2c].

     8      8    * see also: kmheapf() "heap free"
     9      9    */
    10     10   
    11     11   /* arch specific headers */
    12     12   #ifdef KFenv_posix
    13     13   #	include <posix/posix.h>
    14     14   #endif
           15  +
           16  +#include <error_table.h>
    15     17   
    16     18   /* we define all our platform functions here, whether or not
    17     19    * they're for the correct platform - only the ones that are
    18     20    * called by the preprocessed form of the code will actually
    19     21    * be linked, linker errors are our friend here! */
    20     22   extern void* kmem_platform_mmap(void* addr,
    21     23   		unsigned long sz, unsigned long prot, unsigned long flags,
    22     24   		unsigned long fd, unsigned long off);
    23     25   
    24         -void* kmheapa(sz len) {
           26  +kmcond kmheapa(void** where, sz len) {
    25     27   	/* allocate an object on the heap and return
    26     28   	 * a pointer, or NULL if the allocation failed. */
    27     29   	union {
    28     30   		void* raw;
    29     31   		ubyte* byte;
    30     32   		kmbox* header;
    31     33   	} region;
................................................................................
    49     51   		/* because munmap needs to be informed of the size of
    50     52   		 * the region we are going to unmap, we need to store
    51     53   		 * that information in the region that we are mapping.
    52     54   		 * the user will receive an adjusted pointer that can
    53     55   		 * be adjusted to point a field of type size_t that
    54     56   		 * contains the size of the allocated space.*/
    55     57   
    56         -		region.byte = kmem_platform_mmap(null, region_size,
    57         -				posix_prot_read | posix_prot_write,
    58         -				posix_flag_anonymous | posix_map_shared, -1, 0);
           58  +		k_platform_syscall_arg args[] = {
           59  +			null, region_size, 
           60  +			posix_prot_read | posix_prot_write,
           61  +			posix_flag_anonymous | posix_map_shared,
           62  +			-1, 0
           63  +		};
           64  +
           65  +		struct k_platform_syscall_answer r = k_platform_syscall
           66  +			(k_platform_syscall_mmap, Kmsz(args), args);
           67  +
           68  +		if (r.error == 0) region.byte = (ubyte*)r.ret; else {
           69  +			switch (r.error) {
           70  +				case k_platform_error_EAGAIN: return kmcond_bad_lock;
           71  +				case k_platform_error_EINVAL: return kmcond_bad_size;
           72  +				case k_platform_error_EMFILE: return kmcond_too_many;
           73  +				case k_platform_error_ENOMEM: return kmcond_no_room;
           74  +				default: return kmcond_fail_assert;
           75  +			}
           76  +		}
           77  +
           78  +		/* region.byte = kmem_platform_mmap(null, region_size, */
           79  +		/* 		posix_prot_read | posix_prot_write, */
           80  +		/* 		posix_flag_anonymous | posix_map_shared, -1, 0); */
           81  +
    59     82   		/* impl note: while per manpage fd is "ignored"
    60     83   		 * for MAP_ANONYMOUS, "some implementations" require
    61     84   		 * a value of -1 */
    62     85   
    63         -		if (region.raw == (void*) -1) return null;
    64         -		/* worth retrieving errno? discuss */
    65         -
    66     86   #	else
    67     87    	   Knoimpl(kmheapa,KVos);
    68     88   #		error missing implementation
    69     89   #	endif
    70     90   	
    71     91   	void* const object = (region.byte + sizeof (kmbox));
    72     92   
    73     93   	region.header -> kind = kmkind_heap;
    74     94   	region.header -> size = len;
    75     95   
    76         -	return object;
           96  +	*where = object;
           97  +	return kmcond_ok;
    77     98   }

Modified mod/kmem/heapao.fn.c from [930b5d7379] to [e98ef79662].

     3      3   /* heapao.fn.c - kmheapao() "allocate heap object"
     4      4    * ~ lexi hale <lexi@hale.su>
     5      5    * kmheapao() allocates a region in heap memory
     6      6    * and returns a kmptr struct referencing that
     7      7    * newly allocated region.
     8      8    */
     9      9   
    10         -kmptr kmheapao(sz size) {
    11         -	void* ptr = kmheapa(size);
           10  +kmcond kmheapao(kmptr* where, sz size) {
           11  +	void* ptr;
           12  +	kmcond e = kmheapa(&ptr, size);
           13  +	if (e != kmcond_ok) return e;
    12     14   	kmptr p = {
    13     15   		.kind = (ptr != null ? kmkind_heap : kmkind_fail),
    14     16   		.ref = ptr,
    15     17   		.shred = false,
    16         -	}; return p;
           18  +	};
           19  +	*where = p;
           20  +	return kmcond_ok;
    17     21   }

Modified mod/kmem/mem.h from [bec7e80543] to [d8d36f64f5].

     1      1   #ifndef KImem
     2      2   #define KImem
     3      3   #include <k/type.h>
            4  +#include <k/internal.egroup.h>
     4      5   
     5      6   #ifndef KFclean
     6      7   #	define Kmsz(e) ( sizeof (e) / sizeof (e) [0] )
     7      8   #endif
     8      9   
     9     10   #ifdef __cplusplus
    10     11   extern "C" {
    11     12   #endif
    12     13   
    13     14   typedef enum kmcond {
    14         -	kmcond_ok,
           15  +	kmcond_ok = kmcond_id,
    15     16   	kmcond_unnecessary,
    16     17   
    17     18   	kmcond_fail,
    18     19   	kmcond_unhandled,
    19     20   	kmcond_mismatch,
    20     21   	kmcond_bad_address,
           22  +	kmcond_bad_lock,
           23  +	kmcond_bad_size,
           24  +	kmcond_no_room,
           25  +	kmcond_too_many,
           26  +
           27  +	/* when something truly should
           28  +	 * never happen: */
           29  +	kmcond_fail_assert,
    21     30   } kmcond;
    22     31   
    23     32   typedef enum kmkind {
    24     33   	kmkind_none,
    25     34   	kmkind_fail,
    26     35   	kmkind_linear,
    27     36   	kmkind_heap,
................................................................................
    59     68   	kmkind kind;
    60     69   	kmshred shred;
    61     70   	void* ref;
    62     71   } kmptr;
    63     72   
    64     73   /* heap functions */
    65     74   
    66         -void*  kmheapa(sz);
    67         -kmptr  kmheapao(sz);
    68         -kmcond kmheapf(void*);
           75  +kmcond kmheapa (void**, sz);
           76  +kmcond kmheapao(kmptr*, sz);
           77  +kmcond kmheapf (void*);
    69     78   
    70     79   /* generic functions */
    71     80   
    72     81   kmcond kmfree(kmptr);
    73     82   kmkind kmtell(void*);
    74     83   void kmzero(void*,sz);
    75     84   void kmozero(kmptr);