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
6
7
8
9
10
11






ENOSPC
EDQUOT
EIO
EAGAIN
EFBIG
EINTR
EDESTADDRREQ













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

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

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







|







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

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

57
58
59
60
61
62
63

64







fi

# the following function is called to report a command invocation
# the person compiling the library. the first argument should be
# an ansi format string; this is used to color-code the tool being
# launched and thus should be different for each one.


report() { announce $@; $@; }














>
|
>
>
>
>
>
>
>
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
fi

# the following function is called to report a command invocation
# the person compiling the library. the first argument should be
# an ansi format string; this is used to color-code the tool being
# launched and thus should be different for each one.

report() {
	announce $@; $@;
	status=$?
	if test $status -ne 0; then
		args=($@)
		say "process ${args[0]} failed with status code $status"
		exit $status
	fi
}

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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
38
39
40
41
42
43
44







45
46
47
48
49
50
51
; 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/posix/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
................................................................................
	; 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







|
|




|







 







>
>
>
>
>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
; 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/posix/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, [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
................................................................................
	; 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

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

18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33

	if (kiosend(e.std, ptr, null) == kiocond_ok) {
		/* great, continue */
	} else {
		return kbad_io;
	}

	void* region = kmheapa(2048);

	if (region == null) return kbad_mem;

	kmzero(region,2048);

	if (kmheapf(region) >= kmcond_fail) return kbad_mem;

	return kbad_ok;
}







|
>
|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

	if (kiosend(e.std, ptr, null) == kiocond_ok) {
		/* great, continue */
	} else {
		return kbad_io;
	}

	void* region;
	kmcond alloc = kmheapa(&region, 2048);
	if (alloc != kmcond_ok) return kbad_mem;

	kmzero(region,2048);

	if (kmheapf(region) >= kmcond_fail) return kbad_mem;

	return kbad_ok;
}

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

8
9
10
11
12
13
14


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
49
50
51
52
53
54
55




















56
57
58

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

77
 * see also: kmheapf() "heap free"
 */

/* arch specific headers */
#ifdef KFenv_posix
#	include <posix/posix.h>
#endif



/* we define all our platform functions here, whether or not
 * they're for the correct platform - only the ones that are
 * called by the preprocessed form of the code will actually
 * be linked, linker errors are our friend here! */
extern void* kmem_platform_mmap(void* addr,
		unsigned long sz, unsigned long prot, unsigned long flags,
		unsigned long fd, unsigned long off);

void* kmheapa(sz len) {
	/* allocate an object on the heap and return
	 * a pointer, or NULL if the allocation failed. */
	union {
		void* raw;
		ubyte* byte;
		kmbox* header;
	} region;
................................................................................
		/* because munmap needs to be informed of the size of
		 * the region we are going to unmap, we need to store
		 * that information in the region that we are mapping.
		 * the user will receive an adjusted pointer that can
		 * be adjusted to point a field of type size_t that
		 * contains the size of the allocated space.*/





















		region.byte = kmem_platform_mmap(null, region_size,
				posix_prot_read | posix_prot_write,
				posix_flag_anonymous | posix_map_shared, -1, 0);

		/* impl note: while per manpage fd is "ignored"
		 * for MAP_ANONYMOUS, "some implementations" require
		 * a value of -1 */

		if (region.raw == (void*) -1) return null;
		/* worth retrieving errno? discuss */

#	else
 	   Knoimpl(kmheapa,KVos);
#		error missing implementation
#	endif
	
	void* const object = (region.byte + sizeof (kmbox));

	region.header -> kind = kmkind_heap;
	region.header -> size = len;

	return object;

}







>
>









|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
>




<
<
<










|
>

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85



86
87
88
89
90
91
92
93
94
95
96
97
98
 * see also: kmheapf() "heap free"
 */

/* arch specific headers */
#ifdef KFenv_posix
#	include <posix/posix.h>
#endif

#include <error_table.h>

/* we define all our platform functions here, whether or not
 * they're for the correct platform - only the ones that are
 * called by the preprocessed form of the code will actually
 * be linked, linker errors are our friend here! */
extern void* kmem_platform_mmap(void* addr,
		unsigned long sz, unsigned long prot, unsigned long flags,
		unsigned long fd, unsigned long off);

kmcond kmheapa(void** where, sz len) {
	/* allocate an object on the heap and return
	 * a pointer, or NULL if the allocation failed. */
	union {
		void* raw;
		ubyte* byte;
		kmbox* header;
	} region;
................................................................................
		/* because munmap needs to be informed of the size of
		 * the region we are going to unmap, we need to store
		 * that information in the region that we are mapping.
		 * the user will receive an adjusted pointer that can
		 * be adjusted to point a field of type size_t that
		 * contains the size of the allocated space.*/

		k_platform_syscall_arg args[] = {
			null, region_size, 
			posix_prot_read | posix_prot_write,
			posix_flag_anonymous | posix_map_shared,
			-1, 0
		};

		struct k_platform_syscall_answer r = k_platform_syscall
			(k_platform_syscall_mmap, Kmsz(args), args);

		if (r.error == 0) region.byte = (ubyte*)r.ret; else {
			switch (r.error) {
				case k_platform_error_EAGAIN: return kmcond_bad_lock;
				case k_platform_error_EINVAL: return kmcond_bad_size;
				case k_platform_error_EMFILE: return kmcond_too_many;
				case k_platform_error_ENOMEM: return kmcond_no_room;
				default: return kmcond_fail_assert;
			}
		}

		/* region.byte = kmem_platform_mmap(null, region_size, */
		/* 		posix_prot_read | posix_prot_write, */
		/* 		posix_flag_anonymous | posix_map_shared, -1, 0); */

		/* impl note: while per manpage fd is "ignored"
		 * for MAP_ANONYMOUS, "some implementations" require
		 * a value of -1 */




#	else
 	   Knoimpl(kmheapa,KVos);
#		error missing implementation
#	endif
	
	void* const object = (region.byte + sizeof (kmbox));

	region.header -> kind = kmkind_heap;
	region.header -> size = len;

	*where = object;
	return kmcond_ok;
}

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

3
4
5
6
7
8
9
10
11


12
13
14
15


16
17
/* heapao.fn.c - kmheapao() "allocate heap object"
 * ~ lexi hale <lexi@hale.su>
 * kmheapao() allocates a region in heap memory
 * and returns a kmptr struct referencing that
 * newly allocated region.
 */

kmptr kmheapao(sz size) {
	void* ptr = kmheapa(size);


	kmptr p = {
		.kind = (ptr != null ? kmkind_heap : kmkind_fail),
		.ref = ptr,
		.shred = false,


	}; return p;
}







|
|
>
>




>
>
|

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* heapao.fn.c - kmheapao() "allocate heap object"
 * ~ lexi hale <lexi@hale.su>
 * kmheapao() allocates a region in heap memory
 * and returns a kmptr struct referencing that
 * newly allocated region.
 */

kmcond kmheapao(kmptr* where, sz size) {
	void* ptr;
	kmcond e = kmheapa(&ptr, size);
	if (e != kmcond_ok) return e;
	kmptr p = {
		.kind = (ptr != null ? kmkind_heap : kmkind_fail),
		.ref = ptr,
		.shred = false,
	};
	*where = p;
	return kmcond_ok;
}

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

1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20








21
22
23
24
25
26
27
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#ifndef KImem
#define KImem
#include <k/type.h>


#ifndef KFclean
#	define Kmsz(e) ( sizeof (e) / sizeof (e) [0] )
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef enum kmcond {
	kmcond_ok,
	kmcond_unnecessary,

	kmcond_fail,
	kmcond_unhandled,
	kmcond_mismatch,
	kmcond_bad_address,








} kmcond;

typedef enum kmkind {
	kmkind_none,
	kmkind_fail,
	kmkind_linear,
	kmkind_heap,
................................................................................
	kmkind kind;
	kmshred shred;
	void* ref;
} kmptr;

/* heap functions */

void*  kmheapa(sz);
kmptr  kmheapao(sz);
kmcond kmheapf(void*);

/* generic functions */

kmcond kmfree(kmptr);
kmkind kmtell(void*);
void kmzero(void*,sz);
void kmozero(kmptr);



>










|






>
>
>
>
>
>
>
>







 







|
|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#ifndef KImem
#define KImem
#include <k/type.h>
#include <k/internal.egroup.h>

#ifndef KFclean
#	define Kmsz(e) ( sizeof (e) / sizeof (e) [0] )
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef enum kmcond {
	kmcond_ok = kmcond_id,
	kmcond_unnecessary,

	kmcond_fail,
	kmcond_unhandled,
	kmcond_mismatch,
	kmcond_bad_address,
	kmcond_bad_lock,
	kmcond_bad_size,
	kmcond_no_room,
	kmcond_too_many,

	/* when something truly should
	 * never happen: */
	kmcond_fail_assert,
} kmcond;

typedef enum kmkind {
	kmkind_none,
	kmkind_fail,
	kmkind_linear,
	kmkind_heap,
................................................................................
	kmkind kind;
	kmshred shred;
	void* ref;
} kmptr;

/* heap functions */

kmcond kmheapa (void**, sz);
kmcond kmheapao(kmptr*, sz);
kmcond kmheapf (void*);

/* generic functions */

kmcond kmfree(kmptr);
kmkind kmtell(void*);
void kmzero(void*,sz);
void kmozero(kmptr);