bare: add mm_alloc, mm_free

also split errno from return value in existing Linux syscall wrappers
update applicable syscall wrapper checks
pull/2922/head
bogen85 2019-11-29 01:14:17 -06:00 committed by Alexander Medvednikov
parent 52d25336db
commit 729f9c3391
4 changed files with 245 additions and 48 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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
}

View File

@ -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")
}
}