diff options
author | Andrew Waterman <andrew@sifive.com> | 2021-02-10 17:03:03 -0800 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2021-03-25 22:21:06 -0700 |
commit | 817e7d0dfea820a369a5b5c2d5d729942b7daf42 (patch) | |
tree | a725081a6966d928cb9ddacdd2172251ef1691f9 /pk | |
parent | b7f64fe5584094a6fe65d94d5e2382ff9289cbda (diff) | |
download | pk-817e7d0dfea820a369a5b5c2d5d729942b7daf42.zip pk-817e7d0dfea820a369a5b5c2d5d729942b7daf42.tar.gz pk-817e7d0dfea820a369a5b5c2d5d729942b7daf42.tar.bz2 |
pk: only access user memory through explicit accessors
Enforced with sstatus.SUM.
Diffstat (limited to 'pk')
-rw-r--r-- | pk/elf.c | 3 | ||||
-rw-r--r-- | pk/file.c | 14 | ||||
-rw-r--r-- | pk/mmap.c | 3 | ||||
-rw-r--r-- | pk/mmap.h | 5 | ||||
-rw-r--r-- | pk/pk.c | 14 | ||||
-rw-r--r-- | pk/pk.mk.in | 2 | ||||
-rw-r--r-- | pk/syscall.c | 234 | ||||
-rw-r--r-- | pk/usermem.c | 66 | ||||
-rw-r--r-- | pk/usermem.h | 14 |
9 files changed, 278 insertions, 77 deletions
@@ -5,6 +5,7 @@ #include "boot.h" #include "bits.h" #include "elf.h" +#include "usermem.h" #include <sys/stat.h> #include <fcntl.h> #include <string.h> @@ -83,7 +84,7 @@ void load_elf(const char* fn, elf_info* info) int prot = get_prot(ph[i].p_flags); if (__do_mmap(vaddr - prepad, ph[i].p_filesz + prepad, prot | PROT_WRITE, flags2, file, ph[i].p_offset - prepad) != vaddr - prepad) goto fail; - memset((void*)vaddr - prepad, 0, prepad); + memset_user((void*)vaddr - prepad, 0, prepad); if (!(prot & PROT_WRITE)) if (do_mprotect(vaddr - prepad, ph[i].p_filesz + prepad, prot)) goto fail; @@ -105,7 +105,7 @@ file_t* file_openat(int dirfd, const char* fn, int flags, int mode) return ERR_PTR(-ENOMEM); size_t fn_size = strlen(fn)+1; - long ret = frontend_syscall(SYS_openat, dirfd, va2pa(fn), fn_size, flags, mode, 0, 0); + long ret = frontend_syscall(SYS_openat, dirfd, kva2pa(fn), fn_size, flags, mode, 0, 0); if (ret >= 0) { f->kfd = ret; @@ -133,26 +133,22 @@ int fd_close(int fd) ssize_t file_read(file_t* f, void* buf, size_t size) { - populate_mapping(buf, size, PROT_WRITE); - return frontend_syscall(SYS_read, f->kfd, va2pa(buf), size, 0, 0, 0, 0); + return frontend_syscall(SYS_read, f->kfd, kva2pa(buf), size, 0, 0, 0, 0); } ssize_t file_pread(file_t* f, void* buf, size_t size, off_t offset) { - populate_mapping(buf, size, PROT_WRITE); - return frontend_syscall(SYS_pread, f->kfd, va2pa(buf), size, offset, 0, 0, 0); + return frontend_syscall(SYS_pread, f->kfd, kva2pa(buf), size, offset, 0, 0, 0); } ssize_t file_write(file_t* f, const void* buf, size_t size) { - populate_mapping(buf, size, PROT_READ); - return frontend_syscall(SYS_write, f->kfd, va2pa(buf), size, 0, 0, 0, 0); + return frontend_syscall(SYS_write, f->kfd, kva2pa(buf), size, 0, 0, 0, 0); } ssize_t file_pwrite(file_t* f, const void* buf, size_t size, off_t offset) { - populate_mapping(buf, size, PROT_READ); - return frontend_syscall(SYS_pwrite, f->kfd, va2pa(buf), size, offset, 0, 0, 0); + return frontend_syscall(SYS_pwrite, f->kfd, kva2pa(buf), size, offset, 0, 0, 0); } int file_truncate(file_t* f, off_t len) @@ -175,6 +175,7 @@ static int __handle_page_fault(uintptr_t vaddr, int prot) else if (!(*pte & PTE_V)) { uintptr_t ppn = vpn + (first_free_paddr / RISCV_PGSIZE); + uintptr_t kva = ppn * RISCV_PGSIZE; vmr_t* v = (vmr_t*)*pte; *pte = pte_create(ppn, prot_to_type(PROT_READ|PROT_WRITE, 0)); @@ -182,7 +183,7 @@ static int __handle_page_fault(uintptr_t vaddr, int prot) if (v->file) { size_t flen = MIN(RISCV_PGSIZE, v->length - (vaddr - v->addr)); - ssize_t ret = file_pread(v->file, (void*)vaddr, flen, vaddr - v->addr + v->offset); + ssize_t ret = file_pread(v->file, (void*)kva, flen, vaddr - v->addr + v->offset); kassert(ret > 0); if (ret < RISCV_PGSIZE) memset((void*)vaddr + ret, 0, RISCV_PGSIZE - ret); @@ -34,8 +34,7 @@ uintptr_t do_mremap(uintptr_t addr, size_t old_size, size_t new_size, int flags) uintptr_t do_mprotect(uintptr_t addr, size_t length, int prot); uintptr_t do_brk(uintptr_t addr); -#define va2pa(va) ({ uintptr_t __va = (uintptr_t)(va); \ - extern uintptr_t first_free_paddr; \ - __va >= MEM_START ? __va : __va + first_free_paddr; }) +#define kva2pa(va) ((uintptr_t)(va)) +#define is_uva(va) ((uintptr_t)(va) < MEM_START) #endif @@ -6,6 +6,7 @@ #include "elf.h" #include "mtrap.h" #include "frontend.h" +#include "usermem.h" #include <stdbool.h> elf_info current; @@ -58,7 +59,7 @@ typedef union { static size_t parse_args(arg_buf* args) { - long r = frontend_syscall(SYS_getmainvars, va2pa(args), sizeof(*args), 0, 0, 0, 0, 0); + long r = frontend_syscall(SYS_getmainvars, kva2pa(args), sizeof(*args), 0, 0, 0, 0, 0); if (r != 0) panic("args must not exceed %d bytes", (int)sizeof(arg_buf)); @@ -86,14 +87,14 @@ static void run_loaded_program(size_t argc, char** argv, uintptr_t kstack_top) { // copy phdrs to user stack size_t stack_top = current.stack_top - current.phdr_size; - memcpy((void*)stack_top, (void*)current.phdr, current.phdr_size); + memcpy_to_user((void*)stack_top, (void*)current.phdr, current.phdr_size); current.phdr = stack_top; // copy argv to user stack for (size_t i = 0; i < argc; i++) { size_t len = strlen((char*)(uintptr_t)argv[i])+1; stack_top -= len; - memcpy((void*)stack_top, (void*)(uintptr_t)argv[i], len); + memcpy_to_user((void*)stack_top, (void*)(uintptr_t)argv[i], len); argv[i] = (void*)stack_top; } @@ -105,7 +106,7 @@ static void run_loaded_program(size_t argc, char** argv, uintptr_t kstack_top) for (size_t i = 0; i < envc; i++) { size_t len = strlen(envp[i]) + 1; stack_top -= len; - memcpy((void*)stack_top, envp[i], len); + memcpy_to_user((void*)stack_top, envp[i], len); envp[i] = (void*)stack_top; } @@ -128,7 +129,8 @@ static void run_loaded_program(size_t argc, char** argv, uintptr_t kstack_top) // place argc, argv, envp, auxp on stack #define PUSH_ARG(type, value) do { \ - *((type*)sp) = (type)value; \ + type __tmp = (type)(value); \ + memcpy_to_user(sp, &__tmp, sizeof(type)); \ sp ++; \ } while (0) @@ -187,7 +189,7 @@ void boot_loader(uintptr_t dtb) write_csr(stvec, &trap_entry); write_csr(sscratch, 0); write_csr(sie, 0); - set_csr(sstatus, SSTATUS_SUM | SSTATUS_FS | SSTATUS_VS); + set_csr(sstatus, SSTATUS_FS | SSTATUS_VS); file_init(); enter_supervisor_mode(rest_of_boot_loader, pk_vm_init(), 0); diff --git a/pk/pk.mk.in b/pk/pk.mk.in index 281b1d9..3eb858d 100644 --- a/pk/pk.mk.in +++ b/pk/pk.mk.in @@ -13,6 +13,7 @@ pk_hdrs = \ mmap.h \ pk.h \ syscall.h \ + usermem.h \ pk_c_srcs = \ file.c \ @@ -22,6 +23,7 @@ pk_c_srcs = \ elf.c \ console.c \ mmap.c \ + usermem.c \ pk_asm_srcs = \ entry.S \ diff --git a/pk/syscall.c b/pk/syscall.c index e6916a2..bfc95ec 100644 --- a/pk/syscall.c +++ b/pk/syscall.c @@ -3,9 +3,11 @@ #include "syscall.h" #include "pk.h" #include "file.h" +#include "bits.h" #include "frontend.h" #include "mmap.h" #include "boot.h" +#include "usermem.h" #include <string.h> #include <errno.h> @@ -13,6 +15,8 @@ typedef long (*syscall_t)(long, long, long, long, long, long, long); #define CLOCK_FREQ 1000000000 +#define MAX_BUF 512 + void sys_exit(int code) { if (current.cycle0) { @@ -33,10 +37,25 @@ ssize_t sys_read(int fd, char* buf, size_t n) { ssize_t r = -EBADF; file_t* f = file_get(fd); + char kbuf[MAX_BUF]; + + if (f) { + for (size_t total = 0; ; ) { + size_t cur = MIN(n - total, MAX_BUF); + r = file_read(f, kbuf, cur); + if (r < 0) + break; + + memcpy_to_user(buf, kbuf, r); + + total += r; + buf += r; + if (r < cur || total == n) { + r = total; + break; + } + } - if (f) - { - r = file_read(f, buf, n); file_decref(f); } @@ -47,10 +66,26 @@ ssize_t sys_pread(int fd, char* buf, size_t n, off_t offset) { ssize_t r = -EBADF; file_t* f = file_get(fd); + char kbuf[MAX_BUF]; + + if (f) { + for (size_t total = 0; ; ) { + size_t cur = MIN(n - total, MAX_BUF); + r = file_pread(f, kbuf, cur, offset); + if (r < 0) + break; + + memcpy_to_user(buf, kbuf, r); + + total += r; + buf += r; + offset += r; + if (r < cur || total == n) { + r = total; + break; + } + } - if (f) - { - r = file_pread(f, buf, n, offset); file_decref(f); } @@ -61,10 +96,26 @@ ssize_t sys_write(int fd, const char* buf, size_t n) { ssize_t r = -EBADF; file_t* f = file_get(fd); + char kbuf[MAX_BUF]; + + if (f) { + for (size_t total = 0; ; ) { + size_t cur = MIN(n - total, MAX_BUF); + memcpy_from_user(kbuf, buf, cur); + + r = file_write(f, kbuf, cur); + + if (r < 0) + break; + + total += r; + buf += r; + if (r < cur || total == n) { + r = total; + break; + } + } - if (f) - { - r = file_write(f, buf, n); file_decref(f); } @@ -85,7 +136,11 @@ int sys_openat(int dirfd, const char* name, int flags, int mode) { int kfd = at_kfd(dirfd); if (kfd != -1) { - file_t* file = file_openat(kfd, name, flags, mode); + char kname[MAX_BUF]; + if (!strcpy_from_user(kname, name, MAX_BUF)) + return -ENAMETOOLONG; + + file_t* file = file_openat(kfd, kname, flags, mode); if (IS_ERR_VALUE(file)) return PTR_ERR(file); @@ -114,13 +169,19 @@ int sys_close(int fd) } int sys_renameat(int old_fd, const char *old_path, int new_fd, const char *new_path) { + int old_kfd = at_kfd(old_fd); int new_kfd = at_kfd(new_fd); if(old_kfd != -1 && new_kfd != -1) { - size_t old_size = strlen(old_path)+1; - size_t new_size = strlen(new_path)+1; - return frontend_syscall(SYS_renameat, old_kfd, va2pa(old_path), old_size, - new_kfd, va2pa(new_path), new_size, 0); + char kold_path[MAX_BUF], knew_path[MAX_BUF]; + if (!strcpy_from_user(kold_path, old_path, MAX_BUF) || !strcpy_from_user(knew_path, new_path, MAX_BUF)) + return -ENAMETOOLONG; + + size_t old_size = strlen(kold_path)+1; + size_t new_size = strlen(knew_path)+1; + + return frontend_syscall(SYS_renameat, old_kfd, kva2pa(kold_path), old_size, + new_kfd, kva2pa(knew_path), new_size, 0); } return -EBADF; } @@ -133,8 +194,8 @@ int sys_fstat(int fd, void* st) if (f) { struct frontend_stat buf; - r = frontend_syscall(SYS_fstat, f->kfd, va2pa(&buf), 0, 0, 0, 0, 0); - memcpy(st, &buf, sizeof(buf)); + r = frontend_syscall(SYS_fstat, f->kfd, kva2pa(&buf), 0, 0, 0, 0, 0); + memcpy_to_user(st, &buf, sizeof(buf)); file_decref(f); } @@ -215,8 +276,14 @@ ssize_t sys_lseek(int fd, size_t ptr, int dir) long sys_lstat(const char* name, void* st) { struct frontend_stat buf; - size_t name_size = strlen(name)+1; - long ret = frontend_syscall(SYS_lstat, va2pa(name), name_size, va2pa(&buf), 0, 0, 0, 0); + + char kname[MAX_BUF]; + if (!strcpy_from_user(kname, name, MAX_BUF)) + return -ENAMETOOLONG; + + size_t name_size = strlen(kname)+1; + + long ret = frontend_syscall(SYS_lstat, kva2pa(kname), name_size, kva2pa(&buf), 0, 0, 0, 0); memcpy(st, &buf, sizeof(buf)); return ret; } @@ -226,9 +293,15 @@ long sys_fstatat(int dirfd, const char* name, void* st, int flags) int kfd = at_kfd(dirfd); if (kfd != -1) { struct frontend_stat buf; - size_t name_size = strlen(name)+1; - long ret = frontend_syscall(SYS_fstatat, kfd, va2pa(name), name_size, va2pa(&buf), flags, 0, 0); - memcpy(st, &buf, sizeof(buf)); + + char kname[MAX_BUF]; + if (!strcpy_from_user(kname, name, MAX_BUF)) + return -ENAMETOOLONG; + + size_t name_size = strlen(kname)+1; + + long ret = frontend_syscall(SYS_fstatat, kfd, kva2pa(kname), name_size, kva2pa(&buf), flags, 0, 0); + memcpy_to_user(st, &buf, sizeof(buf)); return ret; } return -EBADF; @@ -262,8 +335,13 @@ long sys_faccessat(int dirfd, const char *name, int mode) { int kfd = at_kfd(dirfd); if (kfd != -1) { - size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_faccessat, kfd, va2pa(name), name_size, mode, 0, 0, 0); + char kname[MAX_BUF]; + if (!strcpy_from_user(kname, name, MAX_BUF)) + return -ENAMETOOLONG; + + size_t name_size = strlen(kname)+1; + + return frontend_syscall(SYS_faccessat, kfd, kva2pa(kname), name_size, mode, 0, 0, 0); } return -EBADF; } @@ -278,10 +356,16 @@ long sys_linkat(int old_dirfd, const char* old_name, int new_dirfd, const char* int old_kfd = at_kfd(old_dirfd); int new_kfd = at_kfd(new_dirfd); if (old_kfd != -1 && new_kfd != -1) { - size_t old_size = strlen(old_name)+1; - size_t new_size = strlen(new_name)+1; - return frontend_syscall(SYS_linkat, old_kfd, va2pa(old_name), old_size, - new_kfd, va2pa(new_name), new_size, + + char kold_name[MAX_BUF], knew_name[MAX_BUF]; + if (!strcpy_from_user(kold_name, old_name, MAX_BUF) || !strcpy_from_user(knew_name, new_name, MAX_BUF)) + return -ENAMETOOLONG; + + size_t old_size = strlen(kold_name)+1; + size_t new_size = strlen(knew_name)+1; + + return frontend_syscall(SYS_linkat, old_kfd, kva2pa(kold_name), old_size, + new_kfd, kva2pa(knew_name), new_size, flags); } return -EBADF; @@ -296,8 +380,13 @@ long sys_unlinkat(int dirfd, const char* name, int flags) { int kfd = at_kfd(dirfd); if (kfd != -1) { - size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_unlinkat, kfd, va2pa(name), name_size, flags, 0, 0, 0); + char kname[MAX_BUF]; + if (!strcpy_from_user(kname, name, MAX_BUF)) + return -ENAMETOOLONG; + + size_t name_size = strlen(kname)+1; + + return frontend_syscall(SYS_unlinkat, kfd, kva2pa(kname), name_size, flags, 0, 0, 0); } return -EBADF; } @@ -311,8 +400,13 @@ long sys_mkdirat(int dirfd, const char* name, int mode) { int kfd = at_kfd(dirfd); if (kfd != -1) { - size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_mkdirat, kfd, va2pa(name), name_size, mode, 0, 0, 0); + char kname[MAX_BUF]; + if (!strcpy_from_user(kname, name, MAX_BUF)) + return -ENAMETOOLONG; + + size_t name_size = strlen(kname)+1; + + return frontend_syscall(SYS_mkdirat, kfd, kva2pa(kname), name_size, mode, 0, 0, 0); } return -EBADF; } @@ -322,10 +416,13 @@ long sys_mkdir(const char* name, int mode) return sys_mkdirat(AT_FDCWD, name, mode); } -long sys_getcwd(const char* buf, size_t size) +long sys_getcwd(char* buf, size_t size) { - populate_mapping(buf, size, PROT_WRITE); - return frontend_syscall(SYS_getcwd, va2pa(buf), size, 0, 0, 0, 0, 0); + char kbuf[MAX_BUF]; + long ret = frontend_syscall(SYS_getcwd, kva2pa(kbuf), MIN(size, MAX_BUF), 0, 0, 0, 0, 0); + if (ret == 0) + memcpy_to_user(buf, kbuf, strlen(kbuf) + 1); + return ret; } size_t sys_brk(size_t pos) @@ -335,13 +432,19 @@ size_t sys_brk(size_t pos) int sys_uname(void* buf) { - const int sz = 65; - strcpy(buf + 0*sz, "Proxy Kernel"); - strcpy(buf + 1*sz, ""); - strcpy(buf + 2*sz, "4.15.0"); - strcpy(buf + 3*sz, ""); - strcpy(buf + 4*sz, ""); - strcpy(buf + 5*sz, ""); + const int sz = 65, sz_total = sz * 6; + char kbuf[sz_total]; + memset(kbuf, 0, sz_total); + + strcpy(kbuf + 0*sz, "Proxy Kernel"); + strcpy(kbuf + 1*sz, ""); + strcpy(kbuf + 2*sz, "4.15.0"); + strcpy(kbuf + 3*sz, ""); + strcpy(kbuf + 4*sz, ""); + strcpy(kbuf + 5*sz, ""); + + memcpy_to_user(buf, kbuf, sz_total); + return 0; } @@ -382,17 +485,19 @@ uintptr_t sys_mprotect(uintptr_t addr, size_t length, int prot) int sys_rt_sigaction(int sig, const void* act, void* oact, size_t sssz) { - if (oact) - memset(oact, 0, sizeof(long) * 3); + if (oact) { + long koact[3] = {0}; + memcpy_to_user(oact, koact, sizeof(koact)); + } return 0; } long sys_time(long* loc) { - uint64_t t = rdcycle64() / CLOCK_FREQ; + long t = (long)(rdcycle64() / CLOCK_FREQ); if (loc) - *loc = t; + memcpy_to_user(loc, &t, sizeof(t)); return t; } @@ -400,10 +505,11 @@ int sys_times(long* loc) { uint64_t t = rdcycle64(); kassert(CLOCK_FREQ % 1000000 == 0); - loc[0] = t / (CLOCK_FREQ / 1000000); - loc[1] = 0; - loc[2] = 0; - loc[3] = 0; + + long kloc[4] = {0}; + kloc[0] = t / (CLOCK_FREQ / 1000000); + + memcpy_to_user(loc, kloc, sizeof(kloc)); return 0; } @@ -411,8 +517,12 @@ int sys_times(long* loc) int sys_gettimeofday(long* loc) { uint64_t t = rdcycle64(); - loc[0] = t / CLOCK_FREQ; - loc[1] = (t % CLOCK_FREQ) / (CLOCK_FREQ / 1000000); + + long kloc[2]; + kloc[0] = t / CLOCK_FREQ; + kloc[1] = (t % CLOCK_FREQ) / (CLOCK_FREQ / 1000000); + + memcpy_to_user(loc, kloc, sizeof(kloc)); return 0; } @@ -420,8 +530,12 @@ int sys_gettimeofday(long* loc) long sys_clock_gettime(int clk_id, long *loc) { uint64_t t = rdcycle64(); - loc[0] = t / CLOCK_FREQ; - loc[1] = (t % CLOCK_FREQ) / (CLOCK_FREQ / 1000000000); + + long kloc[2]; + kloc[0] = t / CLOCK_FREQ; + kloc[1] = (t % CLOCK_FREQ) / (CLOCK_FREQ / 1000000000); + + memcpy_to_user(loc, kloc, sizeof(kloc)); return 0; } @@ -429,9 +543,11 @@ long sys_clock_gettime(int clk_id, long *loc) ssize_t sys_writev(int fd, const long* iov, int cnt) { ssize_t ret = 0; - for (int i = 0; i < cnt; i++) - { - ssize_t r = sys_write(fd, (void*)iov[2*i], iov[2*i+1]); + for (int i = 0; i < cnt; i++) { + long kiov[2]; + memcpy_from_user(kiov, iov + 2*i, 2*sizeof(long)); + + ssize_t r = sys_write(fd, (void*)kiov[0], kiov[1]); if (r < 0) return r; ret += r; @@ -441,7 +557,11 @@ ssize_t sys_writev(int fd, const long* iov, int cnt) int sys_chdir(const char *path) { - return frontend_syscall(SYS_chdir, va2pa(path), 0, 0, 0, 0, 0, 0); + char kbuf[MAX_BUF]; + if (!strcpy_from_user(kbuf, path, MAX_BUF)) + return -ENAMETOOLONG; + + return frontend_syscall(SYS_chdir, kva2pa(kbuf), 0, 0, 0, 0, 0, 0); } int sys_getdents(int fd, void* dirbuf, int count) diff --git a/pk/usermem.c b/pk/usermem.c new file mode 100644 index 0000000..b65e515 --- /dev/null +++ b/pk/usermem.c @@ -0,0 +1,66 @@ +// See LICENSE for license details. + +#include "usermem.h" +#include "mmap.h" +#include <string.h> +#include <stdint.h> + +void memset_user(void* dst, int ch, size_t n) +{ + if ((uintptr_t)dst + n < (uintptr_t)dst || !is_uva(dst + n - 1)) + handle_page_fault((uintptr_t)dst, PROT_WRITE); + + uintptr_t sstatus = set_csr(sstatus, SSTATUS_SUM); + + memset(dst, ch, n); + + write_csr(sstatus, sstatus); +} + +void memcpy_to_user(void* dst, const void* src, size_t n) +{ + if ((uintptr_t)dst + n < (uintptr_t)dst || !is_uva(dst + n - 1)) + handle_page_fault((uintptr_t)dst, PROT_WRITE); + + uintptr_t sstatus = set_csr(sstatus, SSTATUS_SUM); + + memcpy(dst, src, n); + + write_csr(sstatus, sstatus); +} + +void memcpy_from_user(void* dst, const void* src, size_t n) +{ + if ((uintptr_t)src + n < (uintptr_t)src || !is_uva(src + n - 1)) + handle_page_fault((uintptr_t)src, PROT_READ); + + uintptr_t sstatus = set_csr(sstatus, SSTATUS_SUM); + + memcpy(dst, src, n); + + write_csr(sstatus, sstatus); +} + +bool strcpy_from_user(char* dst, const char* src, size_t n) +{ + uintptr_t sstatus = set_csr(sstatus, SSTATUS_SUM); + + while (n > 0) { + if (!is_uva(src)) + handle_page_fault((uintptr_t)src, PROT_READ); + + char ch = *(volatile const char*)src; + *dst = ch; + + if (ch == 0) + return true; + + src++; + dst++; + n--; + } + + write_csr(sstatus, sstatus); + + return false; +} diff --git a/pk/usermem.h b/pk/usermem.h new file mode 100644 index 0000000..3cb3ed0 --- /dev/null +++ b/pk/usermem.h @@ -0,0 +1,14 @@ +// See LICENSE for license details. + +#ifndef _PK_USERMEM_H +#define _PK_USERMEM_H + +#include <stdbool.h> +#include <stddef.h> + +void memset_user(void* dst, int ch, size_t n); +void memcpy_to_user(void* dst, const void* src, size_t n); +void memcpy_from_user(void* dst, const void* src, size_t n); +bool strcpy_from_user(char* dst, const char* src, size_t n); + +#endif |