Module Name: src Committed By: nisimura Date: Wed Aug 16 22:48:11 UTC 2017
Modified Files: src/sys/arch/aarch64/aarch64: trap.c Log Message: reimplement copy/fetch/store(9). mostly copied from riscv To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/arch/aarch64/aarch64/trap.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/aarch64/aarch64/trap.c diff -u src/sys/arch/aarch64/aarch64/trap.c:1.1 src/sys/arch/aarch64/aarch64/trap.c:1.2 --- src/sys/arch/aarch64/aarch64/trap.c:1.1 Sun Aug 10 05:47:37 2014 +++ src/sys/arch/aarch64/aarch64/trap.c Wed Aug 16 22:48:11 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.1 2014/08/10 05:47:37 matt Exp $ */ +/* $NetBSD: trap.c,v 1.2 2017/08/16 22:48:11 nisimura Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.1 2014/08/10 05:47:37 matt Exp $"); +__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.2 2017/08/16 22:48:11 nisimura Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -45,3 +45,290 @@ userret(struct lwp *l, struct trapframe { mi_userret(l); } + +// XXXAARCH64 might be populated in frame.h in future + +#define FB_X19 0 +#define FB_X20 1 +#define FB_X21 2 +#define FB_X22 3 +#define FB_X23 4 +#define FB_X24 5 +#define FB_X25 6 +#define FB_X26 7 +#define FB_X27 8 +#define FB_X28 9 +#define FB_X29 10 +#define FB_SP 11 +#define FB_LR 12 +#define FB_V0 13 +#define FB_MAX 14 + +struct faultbuf { + register_t fb_reg[FB_MAX]; +}; + +int cpu_set_onfault(struct faultbuf *, register_t) __returns_twice; +void cpu_jump_onfault(struct trapframe *, const struct faultbuf *); +void cpu_unset_onfault(void); +struct faultbuf *cpu_disable_onfault(void); +void cpu_enable_onfault(struct faultbuf *); + +void +cpu_jump_onfault(struct trapframe *tf, const struct faultbuf *fb) +{ + + tf->tf_reg[19] = fb->fb_reg[FB_X19]; + tf->tf_reg[20] = fb->fb_reg[FB_X20]; + tf->tf_reg[21] = fb->fb_reg[FB_X21]; + tf->tf_reg[22] = fb->fb_reg[FB_X22]; + tf->tf_reg[23] = fb->fb_reg[FB_X23]; + tf->tf_reg[24] = fb->fb_reg[FB_X24]; + tf->tf_reg[25] = fb->fb_reg[FB_X25]; + tf->tf_reg[26] = fb->fb_reg[FB_X26]; + tf->tf_reg[27] = fb->fb_reg[FB_X27]; + tf->tf_reg[28] = fb->fb_reg[FB_X28]; + tf->tf_reg[29] = fb->fb_reg[FB_X29]; + tf->tf_reg[0] = fb->fb_reg[FB_V0]; + tf->tf_sp = fb->fb_reg[FB_SP]; + tf->tf_lr = fb->fb_reg[FB_LR]; +} + +void +cpu_unset_onfault(void) +{ + + curlwp->l_md.md_onfault = NULL; +} + +struct faultbuf * +cpu_disable_onfault(void) +{ + struct faultbuf * const fb = curlwp->l_md.md_onfault; + + curlwp->l_md.md_onfault = NULL; + return fb; +} + +void +cpu_enable_onfault(struct faultbuf *fb) +{ + + curlwp->l_md.md_onfault = NULL; +} + +/* + * kcopy(9) + * int kcopy(const void *src, void *dst, size_t len); + * + * copy(9) + * int copyin(const void *uaddr, void *kaddr, size_t len); + * int copyout(const void *kaddr, void *uaddr, size_t len); + * int copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done); + * int copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done); + * int copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done); + */ + +int +kcopy(const void *kfaddr, void *kdaddr, size_t len) +{ + struct faultbuf fb; + int error; + + if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) { + memcpy(kdaddr, kfaddr, len); + cpu_unset_onfault(); + } + return error; +} + +int +copyin(const void *uaddr, void *kaddr, size_t len) +{ + struct faultbuf fb; + int error; + + if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) { + memcpy(kaddr, uaddr, len); + cpu_unset_onfault(); + } + return error; +} + +int +copyout(const void *kaddr, void *uaddr, size_t len) +{ + struct faultbuf fb; + int error; + + if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) { + memcpy(uaddr, kaddr, len); + cpu_unset_onfault(); + } + return error; +} + +int +copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done) +{ + struct faultbuf fb; + int error; + + if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) { + len = strlcpy(kdaddr, kfaddr, len); + cpu_unset_onfault(); + if (done != NULL) { + *done = len; + } + } + return error; +} + +int +copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done) +{ + struct faultbuf fb; + int error; + + if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) { + len = strlcpy(kaddr, uaddr, len); + cpu_unset_onfault(); + if (done != NULL) { + *done = len; + } + } + return error; +} + +int +copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done) +{ + struct faultbuf fb; + int error; + + if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) { + len = strlcpy(uaddr, kaddr, len); + cpu_unset_onfault(); + if (done != NULL) { + *done = len; + } + } + return error; +} + +/* + * fetch(9) + * int fubyte(const void *base); + * int fusword(const void *base); + * int fuswintr(const void *base); + * long fuword(const void *base); + * + * store(9) + * int subyte(void *base, int c); + * int susword(void *base, short c); + * int suswintr(void *base, short c); + * int suword(void *base, long c); + */ + +union xubuf { + uint8_t b[4]; + uint16_t w[2]; + uint32_t l[1]; +}; + +static bool +fetch_user_data(union xubuf *xu, const void *base, size_t len) +{ + struct faultbuf fb; + + if (cpu_set_onfault(&fb, 1) == 0) { + memcpy(xu->b, base, len); + cpu_unset_onfault(); + return true; + } + return false; +} + +int +fubyte(const void *base) +{ + union xubuf xu; + + if (fetch_user_data(&xu, base, sizeof(xu.b[0]))) + return xu.b[0]; + return -1; +} + +int +fusword(const void *base) +{ + union xubuf xu; + + if (fetch_user_data(&xu, base, sizeof(xu.w[0]))) + return xu.w[0]; + return -1; +} + +int +fuswintr(const void *base) +{ + + return -1; +} + +long +fuword(const void *base) +{ + union xubuf xu; + + if (fetch_user_data(&xu, base, sizeof(xu.l[0]))) + return xu.l[0]; + return -1; +} + +static bool +store_user_data(void *base, const union xubuf *xu, size_t len) +{ + struct faultbuf fb; + + if (cpu_set_onfault(&fb, 1) == 0) { + memcpy(base, xu->b, len); + cpu_unset_onfault(); + return true; + } + return false; +} + +int +subyte(void *base, int c) +{ + union xubuf xu; + + xu.l[0] = 0; xu.b[0] = c; // { .b[0] = c, .b[1 ... 3] = 0 } + return store_user_data(base, &xu, sizeof(xu.b[0])) ? 0 : -1; +} + +int +susword(void *base, short c) +{ + union xubuf xu; + + xu.l[0] = 0; xu.w[0] = c; // { .w[0] = c, .w[1] = 0 } + return store_user_data(base, &xu, sizeof(xu.w[0])) ? 0 : -1; +} + +int +suswintr(void *base, short c) +{ + + return -1; +} + +int +suword(void *base, long c) +{ + union xubuf xu; + + xu.l[0] = c; // { .l[0] = c } + return store_user_data(base, &xu, sizeof(xu.l[0])) ? 0 : -1; +}