From 729f9c33919a7db3d16202a5efaf1dafd8464c75 Mon Sep 17 00:00:00 2001 From: bogen85 <52499484+bogen85@users.noreply.github.com> Date: Fri, 29 Nov 2019 01:14:17 -0600 Subject: [PATCH] bare: add mm_alloc, mm_free also split errno from return value in existing Linux syscall wrappers update applicable syscall wrapper checks --- vlib/builtin/bare/.checks/linuxsys/linuxsys.v | 116 ++++++++++++++++-- vlib/builtin/bare/linuxsys_bare.v | 101 +++++++++------ vlib/builtin/bare/mm_bare.v | 56 +++++++++ vlib/builtin/bare/syscallwrapper_test.v | 20 +++ 4 files changed, 245 insertions(+), 48 deletions(-) create mode 100644 vlib/builtin/bare/mm_bare.v create mode 100644 vlib/builtin/bare/syscallwrapper_test.v diff --git a/vlib/builtin/bare/.checks/linuxsys/linuxsys.v b/vlib/builtin/bare/.checks/linuxsys/linuxsys.v index bb26c43314..1e119df1c7 100644 --- a/vlib/builtin/bare/.checks/linuxsys/linuxsys.v +++ b/vlib/builtin/bare/.checks/linuxsys/linuxsys.v @@ -1,7 +1,7 @@ module main __global fd [2]int -__global buffer [16]byte +__global buffer [128]byte const ( sample_text_file1 = "" @@ -36,20 +36,22 @@ fn check_read_write_pipe() { a := sys_pipe(intptr(fd)) - assert a != -1 + assert a == .enoerror assert fd[0] != -1 assert fd[1] != -1 test_data := "test_data" b := test_data.len + 1 - mut c := sys_write (fd[1], test_data.str, u64(b)) + c1, e1 := sys_write (fd[1], test_data.str, u64(b)) - assert c == b + assert e1 == .enoerror + assert c1 == b - c = sys_read(fd[0], byteptr(buffer), u64(b)) + c2, e2 := sys_read(fd[0], byteptr(buffer), u64(b)) - assert c == b + assert e2 == .enoerror + assert c2 == b assert buffer[b-1] == 0 @@ -57,10 +59,10 @@ fn check_read_write_pipe() { assert test_data[i] == buffer[i] } - assert 0 == sys_close(fd[0]) - assert 0 == sys_close(fd[1]) + assert sys_close(fd[0]) == .enoerror + assert sys_close(fd[1]) == .enoerror - assert 0 != sys_close(-1) + assert sys_close(-1) == .ebadf println ("pipe read/write passed") } @@ -80,12 +82,13 @@ fn check_read_file() { assert fd > 0 assert ec == .enoerror n := sample_text.len - c := sys_read(fd, buffer, u64(n*2)) + c, e := sys_read(fd, buffer, u64(n*2)) + assert e == .enoerror assert c == n for i in 0..n { assert sample_text[i] == buffer[i] } - assert 0 == sys_close(fd) + assert sys_close(fd) == .enoerror println("read file passed") } @@ -112,11 +115,100 @@ fn check_print() { } */ +fn check_munmap_fail() { + println ("checking 'munmap fail'") + + ec := sys_munmap(-16384,8192) + assert ec == .einval + //es := i64_tos(buffer2,80,int(ec),16) + //println(es) + + println ("'munmap fail' check passed") +} + +fn check_mmap_one_page() { + println ("checking check_mmap_one_page") + + mp := int(mm_prot.prot_read) | int(mm_prot.prot_write) + mf := int(map_flags.map_private) | int(map_flags.map_anonymous) + mut a, e := sys_mmap(0, u64(linux_mem.page_size), mm_prot(mp), map_flags(mf), -1, 0) + + assert e == .enoerror + assert a != byteptr(-1) + + for i in 0..int(linux_mem.page_size) { + b := i & 0xFF + a[i] = b + assert a[i] == b + } + + ec := sys_munmap(a, u64(linux_mem.page_size)) + assert ec == .enoerror + + println ("check_mmap_one_page passed") +} + +fn check_mm_pages() { + println ("checking check_mm_pages") + for i in 0 .. int(linux_mem.page_size)-4 { + assert u32(1) == mm_pages(u64(i)) + } + for i in int(linux_mem.page_size)-3 .. (int(linux_mem.page_size)*2)-4 { + assert u32(2) == mm_pages(u64(i)) + } + for i in (int(linux_mem.page_size)*2)-3 .. (int(linux_mem.page_size)*3)-4 { + assert u32(3) == mm_pages(u64(i)) + } + println ("check_mm_pages passed") +} + +//pub fn mm_alloc(size u64) (voidptr, errno) + +fn check_mm_alloc() { + println ("checking check_mm_alloc") + + for i in 1 .. 2000 { + size := u64(i*1000) + pages := mm_pages(size) + mut a, e := mm_alloc(size) + + //ads := i64_tos(buffer,80,i64(a),16) + //println(ads) + //es := i64_tos(buffer,80,i64(e),16) + //println(es) + + assert e == .enoerror + ap := intptr(a-4) + assert *ap == int(pages) + assert e == .enoerror + assert !isnil(a) + + if (i%111) == 0 { + for j in 0 .. int(size) { + b := j & 0xFF + a[j] = b + assert b == int(a[j]) + } + } + + mfa := mm_free(a) + + //mfas := i64_tos(buffer,80,i64(mfa),16) + //println(mfas) + + assert mfa == .enoerror + } + println ("mm_alloc passed") +} + fn main() { check_read_write_pipe() check_read_file() // check_print() check_open_file_fail() + check_munmap_fail() + check_mmap_one_page() + check_mm_pages() + check_mm_alloc() sys_exit(0) } - diff --git a/vlib/builtin/bare/linuxsys_bare.v b/vlib/builtin/bare/linuxsys_bare.v index 37a5d4d44c..ac707c3ff7 100644 --- a/vlib/builtin/bare/linuxsys_bare.v +++ b/vlib/builtin/bare/linuxsys_bare.v @@ -1,5 +1,9 @@ module builtin +pub enum linux_mem { + page_size = 4096 +} + pub enum wp_sys { wnohang = 0x00000001 wuntraced = 0x00000002 @@ -117,6 +121,28 @@ pub enum errno { exdev = 0x00000012 } +pub enum mm_prot { + prot_read = 0x1 + prot_write = 0x2 + prot_exec = 0x4 + prot_none = 0x0 + prot_growsdown = 0x01000000 + prot_growsup = 0x02000000 +} + +pub enum map_flags { + map_shared = 0x01 + map_private = 0x02 + map_shared_validate = 0x03 + map_type = 0x0f + map_fixed = 0x10 + map_file = 0x00 + map_anonymous = 0x20 + map_anon = 0x20 + map_huge_shift = 26 + map_huge_mask = 0x3f +} + fn do_not_call_me_asm_keeper0() { unsafe { asm { @@ -197,61 +223,60 @@ fn sys_call4(scn, arg1, arg2, arg3, arg4 u64) u64 fn sys_call5(scn, arg1, arg2, arg3, arg4, arg5 u64) u64 fn sys_call6(scn, arg1, arg2, arg3, arg4, arg5, arg6 u64) u64 -/* -these wrappers don't act exactly like the libc ones in regard to return value, so they have the raw syscall behavior. - there is no errno - if zero is the expected value, a value > 0 is the error code - if a >=0 is a good value, then for errors, a negative error_code is returned -*/ - -// 0 sys_read unsigned int fd char *buf size_t count -pub fn sys_read (fd int, buf byteptr, count u64) i64 { - return i64(sys_call3(0, u64(fd), u64(buf), count)) -} - -// 1 sys_write unsigned int fd, const char *buf, size_t count -pub fn sys_write(fd int, buf byteptr, count u64) i64 { - return i64(sys_call3(1, u64(fd), u64(buf), count)) -} - -pub fn sys_open(filename byteptr, flags fcntl, mode int) (int, errno) { - //2 sys_open const char *filename int flags int mode - rc := int(sys_call3(2, u64(filename), u64(flags), u64(mode))) +fn split_int_errno(rc_in u64) (i64, errno) { + rc := i64(rc_in) if rc < 0 { - return -1, errno(-rc) + return i64(-1), errno(-rc) } return rc, errno.enoerror } -pub fn sys_close(fd int) int { +// 0 sys_read unsigned int fd char *buf size_t count +pub fn sys_read (fd i64, buf byteptr, count u64) (i64, errno) { + return split_int_errno(sys_call3(0, u64(fd), u64(buf), count)) +} + +// 1 sys_write unsigned int fd, const char *buf, size_t count +pub fn sys_write(fd i64, buf byteptr, count u64) (i64, errno) { + return split_int_errno(sys_call3(1, u64(fd), u64(buf), count)) +} + +pub fn sys_open(filename byteptr, flags fcntl, mode int) (i64, errno) { + //2 sys_open const char *filename int flags int mode + return split_int_errno(sys_call3(2, u64(filename), u64(flags), u64(mode))) +} + +pub fn sys_close(fd i64) errno { // 3 sys_close unsigned int fd - return int(sys_call1(3, u64(fd))) + return errno(-i64(sys_call1(3, u64(fd)))) } // 9 sys_mmap unsigned long addr unsigned long len unsigned long prot unsigned long flags unsigned long fd unsigned long off -pub fn sys_mmap(addr byteptr, len u64, prot u64, flags u64, fildes u64, off u64) voidptr { - return voidptr(sys_call6(9, u64(addr), len, prot, flags, fildes, off)) +pub fn sys_mmap(addr byteptr, len u64, prot mm_prot, flags map_flags, fildes u64, off u64) (byteptr, errno) { + rc := sys_call6(9, u64(addr), len, u64(prot), u64(flags), fildes, off) + a, e := split_int_errno(rc) + return byteptr(a), e } -pub fn sys_munmap(addr voidptr, len u64) int { +pub fn sys_munmap(addr voidptr, len u64) errno { // 11 sys_munmap unsigned long addr size_t len - return int(sys_call2(11, u64(addr), len)) + return errno(-sys_call2(11, u64(addr), len)) } // 22 sys_pipe int *filedes -pub fn sys_pipe(filedes intptr) int { - return int(sys_call1(22, u64(filedes))) +pub fn sys_pipe(filedes intptr) errno { + return errno(sys_call1(22, u64(filedes))) } // 24 sys_sched_yield -pub fn sys_sched_yield() int { - return int(sys_call0(24)) +pub fn sys_sched_yield() errno { + return errno(sys_call0(24)) } -pub fn sys_madvise(addr voidptr, len u64, advice int) int { +pub fn sys_madvise(addr voidptr, len u64, advice int) errno { // 28 sys_madvise unsigned long start size_t len_in int behavior - return int(sys_call3(28, u64(addr), len, u64(advice))) + return errno(sys_call3(28, u64(addr), len, u64(advice))) } // 39 sys_getpid @@ -270,8 +295,8 @@ pub fn sys_vfork() int { } // 33 sys_dup2 unsigned int oldfd unsigned int newfd -pub fn sys_dup2 (oldfd, newfd int) int { - return int(sys_call2(33, u64(oldfd),u64(newfd))) +pub fn sys_dup2 (oldfd, newfd int) (i64, errno) { + return split_int_errno(sys_call2(33, u64(oldfd),u64(newfd))) } @@ -286,6 +311,10 @@ pub fn sys_exit (ec int) { sys_call1(60, u64(ec)) } +// 247 sys_waitid int which pid_t upid struct siginfo *infop int options struct rusage *ru +//pub fn sys_waitid (idtype wi_sys, pid i64, infop voidptr, options + + /* A few years old, but still relevant https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ @@ -537,7 +566,7 @@ https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/ 244 sys_mq_notify mqd_t mqdes const struct sigevent *u_notification 245 sys_mq_getsetattr mqd_t mqdes const struct mq_attr *u_mqstat struct mq_attr *u_omqstat 246 sys_kexec_load unsigned long entry unsigned long nr_segments struct kexec_segment *segments unsigned long flags -247 sys_waitid int which pid_t upid struct siginfo *infop int options struct rusage *ru +>247 sys_waitid int which pid_t upid struct siginfo *infop int options struct rusage *ru 248 sys_add_key const char *_type const char *_description const void *_payload size_t plen 249 sys_request_key const char *_type const char *_description const char *_callout_info key_serial_t destringid 250 sys_keyctl int option unsigned long arg2 unsigned long arg3 unsigned long arg4 unsigned long arg5 diff --git a/vlib/builtin/bare/mm_bare.v b/vlib/builtin/bare/mm_bare.v new file mode 100644 index 0000000000..52d05e121d --- /dev/null +++ b/vlib/builtin/bare/mm_bare.v @@ -0,0 +1,56 @@ +module builtin + +//__global buffer [128]byte + +pub fn mm_pages(size u64) u32 { + pages := (u64(size+u64(4))+u64(linux_mem.page_size))/u64(linux_mem.page_size) + return u32(pages) +} + +pub fn mm_alloc(size u64) (byteptr, errno) { + pages := mm_pages(size) + n_bytes := u64(pages*u32(linux_mem.page_size)) + + mem_prot := mm_prot(int(mm_prot.prot_read) | int(mm_prot.prot_write)) + mem_flags := map_flags(int(map_flags.map_private) | int(map_flags.map_anonymous)) + + //mps := i64_tos(buffer,80,i64(mem_prot),16) + //println(mps) + //mfs := i64_tos(buffer,80,i64(mem_flags),16) + //println(mfs) + + //print("pages in: ") + //ps := i64_tos(buffer,80,i64(pages),16) + //println(ps) + + + a, e := sys_mmap(0, n_bytes, mem_prot, mem_flags, -1, 0) + if e == .enoerror { + mut ap := intptr(a) + *ap = pages + return byteptr(a+4), e + } + return byteptr(0), e +} + +pub fn mm_free(addr byteptr) errno { + ap := intptr(addr-4) + size := u64(*ap) * u64(linux_mem.page_size) + + //aps := i64_tos(buffer,80,i64(addr),16) + //println(aps) + + //ss := i64_tos(buffer,80,i64(size),16) + //print("size out: ") + //println(ss) + + //pas := i64_tos(buffer,80,i64(ap),16) + //println(pas) + + e := sys_munmap(ap, size) + + //es := i64_tos(buffer,80,i64(e),16) + //println(es) + + return e +} diff --git a/vlib/builtin/bare/syscallwrapper_test.v b/vlib/builtin/bare/syscallwrapper_test.v new file mode 100644 index 0000000000..8496b2182d --- /dev/null +++ b/vlib/builtin/bare/syscallwrapper_test.v @@ -0,0 +1,20 @@ +import os + +fn test_syscallwrappers() { + if true {return} + vexe := os.getenv("VEXE") + vn := vexe.len - 1 + if vn > 1 { + dot_checks := vexe.substr(0,vn) + "vlib/builtin/bare/.checks" + assert os.dir_exists(dot_checks) + os.chdir(dot_checks) + checks_v := "checks.v" + assert os.file_exists(checks_v) + rc := os.exec("v run $checks_v") or { panic(err) } + assert !rc.output.contains("V panic: An assertion failed.") + assert !rc.output.contains("failed") + assert rc.exit_code == 0 + } else { + panic("Can't find v") + } +}