Subject: fault handler problem of user space access fucntions in sh3/Locore.c
To: None <port-sh3@netbsd.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-sh3
Date: 03/14/2003 20:54:29
I noticed current user space access functions for sh3
(copyin*(), copyout*() and [fs]uword() etc.) didn't return
correct values if a bad address was encountered.
(They return random values.)
All these functions use "labels as values" extension of gcc
to set fault handler address:
---
{
:
curpcb->pcb_onfault = &&Err999;
memcpy(to, from, len);
curpcb->pcb_onfault = 0;
return (0);
Err999:
curpcb->pcb_onfault = 0;
return (EFAULT);
}
---
but it seems all instructions after the Err999 labels are removed
during gcc optimization:
---
1fc: 08 d8 mov.l 220 <copyout+0x44>,r8 ! 0x0 (== curpcb)
1fe: 82 62 mov.l @r8,r2
200: 08 d1 mov.l 224 <copyout+0x48>,r1 ! 0x212 (== &&Err999)
202: 1c 12 mov.l r1,@(48,r2)
curpcb->pcb_onfault = &&Err999;
204: 08 d1 mov.l 228 <copyout+0x4c>,r1 ! 0x0 (== memcpy)
206: 0b 41 jsr @r1
208: 33 65 mov r3,r5
memcpy(to, from, len);
20a: 82 62 mov.l @r8,r2
20c: 00 e1 mov #0,r1
20e: 1c 12 mov.l r1,@(48,r2)
210: 00 e0 mov #0,r0
curpcb->pcb_onfault = 0;
(&&Err999 points here)
212: e3 6f mov r14,r15
214: 26 4f lds.l @r15+,pr
216: f6 6e mov.l @r15+,r14
218: 0b 00 rts
21a: f6 68 mov.l @r15+,r8
return (0);
---
The register r0 is not preserved during tlb_exception(),
so the function returns random values on the fault.
I don't know whether this is gcc's bug or not,
(gcc-3.x won't help either) but the easiest way to fix is
to rewrite these functions in asm as some other ports do.
I'd like to commit the attached patch, but any
suggestions/comments are appreciate since I'm not
familiar with SH3 asm. (mostly taken from gcc -S output.)
---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp
Index: sh3/Locore.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/sh3/Locore.c,v
retrieving revision 1.15
diff -u -r1.15 Locore.c
--- sh3/Locore.c 2003/01/18 06:33:43 1.15
+++ sh3/Locore.c 2003/03/14 04:27:46
@@ -224,144 +224,6 @@
}
/*
- * copyout(caddr_t from, caddr_t to, size_t len);
- * Copy len bytes into the user's address space.
- */
-int
-copyout(const void *kaddr, void *uaddr, size_t len)
-{
- const void *from = kaddr;
- char *to = uaddr;
-
- if (to + len < to || to + len > (char *)VM_MAXUSER_ADDRESS)
- return (EFAULT);
-
- curpcb->pcb_onfault = &&Err999;
- memcpy(to, from, len);
- curpcb->pcb_onfault = 0;
- return (0);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (EFAULT);
-}
-
-/*
- * copyin(caddr_t from, caddr_t to, size_t len);
- * Copy len bytes from the user's address space.
- */
-int
-copyin(const void *uaddr, void *kaddr, size_t len)
-{
- const char *from = uaddr;
- void *to = kaddr;
-
- if (from + len < from || from + len > (char *)VM_MAXUSER_ADDRESS)
- return (EFAULT);
-
- curpcb->pcb_onfault = &&Err999;
- memcpy(to, from, len);
- curpcb->pcb_onfault = 0;
- return (0);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (EFAULT);
-}
-
-/*
- * copyoutstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
- * Copy a NUL-terminated string, at most maxlen characters long, into the
- * user's address space. Return the number of characters copied (including the
- * NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; else
- * return 0 or EFAULT.
- */
-int
-copyoutstr(const void *kaddr, void *uaddr, size_t maxlen, size_t *lencopied)
-{
- const char *from = kaddr;
- char *to = uaddr;
- int cnt;
- int rc = 0;
- const char *from_top = from;
-
- curpcb->pcb_onfault = &&Err999;
-
- if ((cnt = (char *)VM_MAXUSER_ADDRESS - to) > maxlen)
- cnt = maxlen;
-
- while (cnt--) {
- if ((*to++ = *from++) == 0) {
- rc = 0;
- goto out;
- }
- }
-
- if (to >= (char *)VM_MAXUSER_ADDRESS)
- rc = EFAULT;
- else
- rc = ENAMETOOLONG;
-
- out:
- if (lencopied)
- *lencopied = from - from_top;
- curpcb->pcb_onfault = 0;
- return (rc);
-
- Err999:
- if (lencopied)
- *lencopied = from - from_top;
- curpcb->pcb_onfault = 0;
- return (EFAULT);
-}
-
-/*
- * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
- * Copy a NUL-terminated string, at most maxlen characters long, from the
- * user's address space. Return the number of characters copied (including the
- * NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; else
- * return 0 or EFAULT.
- */
-int
-copyinstr(const void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied)
-{
- const char *from = uaddr;
- char *to = kaddr;
- int cnt;
- int rc = 0;
- const char *from_top = from;
-
- curpcb->pcb_onfault = &&Err999;
-
- if ((cnt = (char *)VM_MAXUSER_ADDRESS - to) > maxlen)
- cnt = maxlen;
-
- while (cnt--) {
- if ((*to++ = *from++) == 0) {
- rc = 0;
- goto out;
- }
- }
-
- if (to >= (char *)VM_MAXUSER_ADDRESS)
- rc = EFAULT;
- else
- rc = ENAMETOOLONG;
-
- out:
- if (lencopied)
- *lencopied = from - from_top;
- curpcb->pcb_onfault = 0;
- return (rc);
-
- Err999:
- if (lencopied)
- *lencopied = from - from_top;
- curpcb->pcb_onfault = 0;
- return (EFAULT);
-}
-
-/*
* copystr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
* Copy a NUL-terminated string, at most maxlen characters long. Return the
* number of characters copied (including the NUL) in *lencopied. If the
@@ -386,227 +248,4 @@
*lencopied = i;
return (ENAMETOOLONG);
-}
-
-/*
- * fuword(caddr_t uaddr);
- * Fetch an int from the user's address space.
- */
-long
-fuword(const void *base)
-{
- const char *uaddr = base;
- long rc;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(long))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
-
- rc = *(long *)uaddr;
-
- curpcb->pcb_onfault = 0;
- return (rc);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (-1);
-}
-
-/*
- * fusword(caddr_t uaddr);
- * Fetch a short from the user's address space.
- */
-int
-fusword(const void *base)
-{
- const char *uaddr = base;
- int rc;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(short))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
-
- rc = *(unsigned short *)uaddr;
-
- curpcb->pcb_onfault = 0;
- return (rc);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (-1);
-}
-
-/*
- * fuswintr(caddr_t uaddr);
- * Fetch a short from the user's address space. Can be called during an
- * interrupt.
- */
-int
-fuswintr(const void *base)
-{
- const char *uaddr = base;
- int rc;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(short))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
- curpcb->pcb_faultbail = 1;
-
- rc = *(unsigned short *)uaddr;
-
- curpcb->pcb_onfault = 0;
- curpcb->pcb_faultbail = 0;
- return (rc);
-
- Err999:
- curpcb->pcb_onfault = 0;
- curpcb->pcb_faultbail = 0;
- return (-1);
-}
-
-/*
- * fubyte(caddr_t uaddr);
- * Fetch a byte from the user's address space.
- */
-int
-fubyte(const void *base)
-{
- const char *uaddr = base;
- int rc;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(char))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
-
- rc = *(unsigned char *)uaddr;
-
- curpcb->pcb_onfault = 0;
- return (rc);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (-1);
-}
-
-/*
- * suword(caddr_t uaddr, int x);
- * Store an int in the user's address space.
- */
-int
-suword(void *base, long x)
-{
- char *uaddr = base;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(long))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
- *(int *)uaddr = x;
- curpcb->pcb_onfault = 0;
-
- return (0);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (-1);
-}
-
-/*
- * susword(void *uaddr, short x);
- * Store a short in the user's address space.
- */
-int
-susword(void *base, short x)
-{
- char *uaddr = base;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(short))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
-
- *(short *)uaddr = x;
-
- curpcb->pcb_onfault = 0;
- return (0);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (-1);
-}
-
-/*
- * suswintr(caddr_t uaddr, short x);
- * Store a short in the user's address space. Can be called during an
- * interrupt.
- */
-int
-suswintr(void *base, short x)
-{
- char *uaddr = base;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(short))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
- curpcb->pcb_faultbail = 1;
-
- *(short *)uaddr = x;
-
- curpcb->pcb_onfault = 0;
- curpcb->pcb_faultbail = 0;
- return (0);
-
- Err999:
- curpcb->pcb_onfault = 0;
- curpcb->pcb_faultbail = 0;
-
- return (-1);
-}
-
-/*
- * subyte(caddr_t uaddr, char x);
- * Store a byte in the user's address space.
- */
-int
-subyte(void *base, int x)
-{
- char *uaddr = base;
-
- if (uaddr > (char *)VM_MAXUSER_ADDRESS - sizeof(char))
- return (-1);
-
- curpcb->pcb_onfault = &&Err999;
-
- *(char *)uaddr = x;
-
- curpcb->pcb_onfault = 0;
- return (0);
-
- Err999:
- curpcb->pcb_onfault = 0;
- return (-1);
-}
-
-int
-kcopy(const void *src, void *dst, size_t len)
-{
- caddr_t oldfault;
-
- oldfault = curpcb->pcb_onfault;
-
- curpcb->pcb_onfault = &&Err999;
- memcpy(dst, src, len);
- curpcb->pcb_onfault = oldfault;
-
- return (0);
-
- Err999:
- curpcb->pcb_onfault = oldfault;
-
- return (EFAULT);
}
Index: sh3/genassym.cf
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/sh3/genassym.cf,v
retrieving revision 1.7
diff -u -r1.7 genassym.cf
--- sh3/genassym.cf 2003/01/18 06:33:43 1.7
+++ sh3/genassym.cf 2003/03/14 04:27:47
@@ -37,10 +37,11 @@
include <sys/proc.h>
include <sys/signal.h>
include <sys/mbuf.h>
+include <sys/user.h>
+include <sys/errno.h>
include <uvm/uvm_extern.h>
-include <sh3/pcb.h>
include <sh3/locore.h>
-include <sh3/proc.h>
+include <sh3/vmparam.h>
define TF_SIZE sizeof(struct trapframe)
define TF_EXPEVT offsetof(struct trapframe, tf_expevt)
@@ -95,10 +96,18 @@
define SC_EFLAGS offsetof(struct sigcontext, sc_ssr)
+define PCB_ONFAULT offsetof(struct pcb, pcb_onfault)
+define PCB_FAULTBAIL offsetof(struct pcb, pcb_faultbail)
+
define LSONPROC LSONPROC
define LSRUN LSRUN
define UVMEXP_INTRS offsetof(struct uvmexp, intrs)
+
+define VM_MAXUSER_ADDRESS VM_MAXUSER_ADDRESS
+
+define EFAULT EFAULT
+define ENAMETOOLONG ENAMETOOLONG
#
# in_cksum.S
Index: sh3/locore_subr.S
===================================================================
RCS file: /cvsroot/src/sys/arch/sh3/sh3/locore_subr.S,v
retrieving revision 1.13
diff -u -r1.13 locore_subr.S
--- sh3/locore_subr.S 2003/01/18 06:33:43 1.13
+++ sh3/locore_subr.S 2003/03/14 04:27:48
@@ -426,6 +426,596 @@
rts
nop
+/*
+ * copyout(caddr_t kaddr, caddr_t uaddr, size_t len);
+ * Copy len bytes into the user's address space.
+ */
+ENTRY(copyout)
+ mov.l r14, @-r15
+ sts.l pr, @-r15
+ mov r15, r14
+
+ mov #EFAULT, r0 /* assume there was a problem */
+ mov r4, r3
+ mov r5, r2
+ mov r5, r4
+ add r6, r2
+ cmp/hs r5, r2 /* bomb if uaddr+len wraps */
+ bf 2f
+ mov.l _Lcopyout.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r2 /* bomb if uaddr isn't in user space */
+ bt 2f
+
+ mov.l _Lcopyout.curpcb, r1 /* set fault hander */
+ mov.l @r1, r2
+ mov.l _Lcopyout.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l _Lcopyout.memcpy, r1
+ jsr @r1 /* memcpy(uaddr, kaddr, len) */
+ mov r3, r5
+
+ mov #0, r0
+1:
+ mov.l _Lcopyout.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ mov r14, r15
+ lds.l @r15+, pr
+ rts
+ mov.l @r15+, r14
+
+3:
+ bra 1b
+ mov #EFAULT, r0
+
+ .align 2
+_Lcopyout.onfault:
+ .long 3b
+_Lcopyout.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS
+_Lcopyout.curpcb:
+ .long _C_LABEL(curpcb)
+_Lcopyout.memcpy:
+ .long _C_LABEL(memcpy)
+
+/*
+ * copyin(caddr_t uaddr, caddr_t kaddr, size_t len);
+ * Copy len bytes from the user's address space.
+ */
+ENTRY(copyin)
+ mov.l r14, @-r15
+ sts.l pr, @-r15
+ mov r15, r14
+
+ mov #EFAULT, r0 /* assume there was a problem */
+ mov r4, r3
+ mov r5, r4
+ mov r3, r2
+ add r6, r2
+ cmp/hs r3, r2 /* bomb if uaddr+len wraps */
+ bf 2f
+ mov.l _Lcopyin.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r2 /* bomb if uaddr isn't in user space */
+ bt 2f
+
+ mov.l _Lcopyin.curpcb, r1 /* set fault hander */
+ mov.l @r1, r2
+ mov.l _Lcopyin.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l _Lcopyin.memcpy, r1
+ jsr @r1 /* memcpy(kaddr, uaddr, len) */
+ mov r3, r5
+
+ mov #0, r0
+1:
+ mov.l _Lcopyin.curpcb, r1 /* clear fault hander */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ mov r14, r15
+ lds.l @r15+, pr
+ rts
+ mov.l @r15+, r14
+
+3:
+ bra 1b
+ mov #EFAULT, r0
+
+ .align 2
+_Lcopyin.onfault:
+ .long 3b
+_Lcopyin.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS
+_Lcopyin.curpcb:
+ .long _C_LABEL(curpcb)
+_Lcopyin.memcpy:
+ .long _C_LABEL(memcpy)
+
+/*
+ * copyoutstr(caddr_t kaddr, caddr_t uaddr, size_t maxlen, size_t *lencopied);
+ * Copy a NUL-terminated string, at most maxlen characters long, into the
+ * user's address space. Return the number of characters copied (including the
+ * NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; else
+ * return 0 or EFAULT.
+ */
+ENTRY(copyoutstr)
+ mov.l r8, @-r15
+
+ mov #EFAULT, r3 /* assume there was a problem */
+ mov r4, r8
+ mov.l _Lcopyoutstr.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lcopyoutstr.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l _Lcopyoutstr.VM_MAXUSER_ADDRESS, r1
+ mov r1, r0
+ sub r5, r0
+ cmp/hi r6, r0 /* don't beyond user space */
+ bf 2f
+ bra 2f
+ mov r6, r0
+
+ .align 2
+1:
+ mov.b @r4+, r1 /* copy str */
+ mov.b r1, @r5
+ extu.b r1, r1
+ add #1, r5
+ tst r1, r1
+ bf 2f
+ bra 3f
+ mov #0, r3
+ .align 2
+2:
+ add #-1, r0
+ cmp/eq #-1, r0
+ bf 1b
+ mov.l _Lcopyoutstr.VM_MAXUSER_ADDRESS, r1
+ cmp/hs r1, r5
+ bt 3f
+ mov #ENAMETOOLONG, r3
+
+3:
+ tst r7, r7 /* set lencopied if needed */
+ bt 4f
+ mov r4, r1
+ sub r8, r1
+ mov.l r1, @r7
+4:
+ mov.l _Lcopyoutstr.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+
+ mov r3, r0
+ rts
+ mov.l @r15+, r8
+
+5:
+ bra 4b
+ mov #EFAULT, r0
+
+ .align 2
+_Lcopyoutstr.onfault:
+ .long 5b
+_Lcopyoutstr.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS
+_Lcopyoutstr.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
+ * Copy a NUL-terminated string, at most maxlen characters long, from the
+ * user's address space. Return the number of characters copied (including the
+ * NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; else
+ * return 0 or EFAULT.
+ */
+ENTRY(copyinstr)
+ mov.l r8, @-r15
+ mov #EFAULT, r3 /* assume there was a problem */
+ mov r4, r8
+ mov.l _Lcopyinstr.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lcopyinstr.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+
+ mov.l _Lcopyinstr.VM_MAXUSER_ADDRESS, r1
+ mov r1, r0
+ sub r5, r0
+ cmp/hi r6, r0 /* don't beyond user space */
+ bf 2f
+ bra 2f
+ mov r6, r0
+
+ .align 2
+1:
+ mov.b @r4+, r1 /* copy str */
+ mov.b r1, @r5
+ extu.b r1, r1
+ add #1, r5
+ tst r1, r1
+ bf 2f
+ bra 3f
+ mov #0, r3
+ .align 2
+2:
+ add #-1, r0
+ cmp/eq #-1, r0
+ bf 1b
+ mov.l _Lcopyinstr.VM_MAXUSER_ADDRESS, r1
+ cmp/hs r1, r5
+ bt 3f
+ mov #ENAMETOOLONG, r3
+
+3:
+ tst r7, r7 /* set lencopied if needed */
+ bt 4f
+ mov r4, r1
+ sub r8, r1
+ mov.l r1, @r7
+4:
+ mov.l _Lcopyinstr.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+
+ mov r3, r0
+ rts
+ mov.l @r15+, r8
+
+5:
+ bra 4b
+ mov #EFAULT, r0
+
+ .align 2
+_Lcopyinstr.onfault:
+ .long 5b
+_Lcopyinstr.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS
+_Lcopyinstr.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * fuword(caddr_t uaddr);
+ * Fetch an int from the user's address space.
+ */
+ENTRY(fuword)
+ mov.l _Lfuword.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't in user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lfuword.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lfuword.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l @r4, r0 /* fetch the value */
+1:
+ mov.l _Lfuword.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lfuword.onfault:
+ .long 3b
+_Lfuword.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 4 /*sizeof(long)*/
+_Lfuword.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * fusword(caddr_t uaddr);
+ * Fetch a short from the user's address space.
+ */
+ENTRY(fusword)
+ mov.l _Lfusword.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lfusword.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lfusword.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.w @r4, r1 /* fetch the value */
+ exts.w r1, r0
+1:
+ mov.l _Lfusword.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lfusword.onfault:
+ .long 3b
+_Lfusword.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 2 /*sizeof(short)*/
+_Lfusword.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * fuswintr(caddr_t uaddr);
+ * Fetch a short from the user's address space. Can be called during an
+ * interrupt.
+ */
+ENTRY(fuswintr)
+ mov.l _Lfuswintr.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lfuswintr.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lfuswintr.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov #1, r1 /* set faultbail */
+ mov.l r1, @(PCB_FAULTBAIL,r2)
+ mov.w @r4, r1 /* fetch the value */
+ exts.w r1, r0
+1:
+ mov.l _Lfuswintr.curpcb, r1 /* clear fault handler and faultbail */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l r1, @(PCB_FAULTBAIL,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lfuswintr.onfault:
+ .long 3b
+_Lfuswintr.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 2 /*sizeof(short)*/
+_Lfuswintr.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * fubyte(caddr_t uaddr);
+ * Fetch a byte from the user's address space.
+ */
+ENTRY(fubyte)
+ mov.l _Lfubyte.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't in user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lfubyte.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lfubyte.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.b @r4, r1 /* fetch the value */
+ exts.b r1, r0
+1:
+ mov.l _Lfubyte.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lfubyte.onfault:
+ .long 3b
+_Lfubyte.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 1 /*sizeof(char)*/
+_Lfubyte.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * suword(caddr_t uaddr, int x);
+ * Store an int in the user's address space.
+ */
+ENTRY(suword)
+ mov.l _Lsuword.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't in user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lsuword.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lsuword.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l r5, @r4 /* store the value */
+ mov #0, r0
+1:
+ mov.l _Lsuword.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lsuword.onfault:
+ .long 3b
+_Lsuword.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 4 /*sizeof(long)*/
+_Lsuword.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * susword(void *uaddr, short x);
+ * Store a short in the user's address space.
+ */
+ENTRY(susword)
+ mov.l _Lsusword.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't in user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lsusword.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lsusword.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.w r5, @r4 /* store the value */
+ mov #0, r0
+1:
+ mov.l _Lsusword.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lsusword.onfault:
+ .long 3b
+_Lsusword.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 2 /*sizeof(short)*/
+_Lsusword.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * suswintr(caddr_t uaddr, short x);
+ * Store a short in the user's address space. Can be called during an
+ * interrupt.
+ */
+ENTRY(suswintr)
+ mov.l _Lsuswintr.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't in user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lsuswintr.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lsuswintr.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov #1, r1 /* set faultbail */
+ mov.l r1, @(PCB_FAULTBAIL,r2)
+ mov.w r5, @r4 /* store the value */
+ mov #0, r0
+1:
+ mov.l _Lsuswintr.curpcb, r1 /* clear fault handler and faultbail */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.l r1, @(PCB_FAULTBAIL,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lsuswintr.onfault:
+ .long 3b
+_Lsuswintr.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 2 /*sizeof(short)*/
+_Lsuswintr.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * subyte(caddr_t uaddr, char x);
+ * Store a byte in the user's address space.
+ */
+ENTRY(subyte)
+ mov.l _Lsubyte.VM_MAXUSER_ADDRESS, r1
+ cmp/hi r1, r4 /* bomb if uaddr isn't in user space */
+ bt/s 2f
+ mov #-1, r0
+ mov.l _Lsubyte.curpcb, r1 /* set fault handler */
+ mov.l @r1, r2
+ mov.l _Lsubyte.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+ mov.b r5, @r4 /* store the value */
+ mov #0, r0
+1:
+ mov.l _Lsubyte.curpcb, r1 /* clear fault handler */
+ mov.l @r1, r2
+ mov #0, r1
+ mov.l r1, @(PCB_ONFAULT,r2)
+2:
+ rts
+ nop
+
+3:
+ bra 1b
+ mov #-1, r0
+
+ .align 2
+_Lsubyte.onfault:
+ .long 3b
+_Lsubyte.VM_MAXUSER_ADDRESS:
+ .long VM_MAXUSER_ADDRESS - 1 /*sizeof(char)*/
+_Lsubyte.curpcb:
+ .long _C_LABEL(curpcb)
+
+/*
+ * kcopy(const void *src, void *dst, size_t len)
+ */
+ENTRY(kcopy)
+ mov.l r8, @-r15
+ mov.l r14, @-r15
+ sts.l pr, @-r15
+ mov r15, r14
+
+ mov r4, r3
+ mov.l _Lkcopy.curpcb, r1
+ mov.l @r1, r2
+ mov.l @(PCB_ONFAULT,r2) ,r8 /* save old fault handler */
+ mov.l _Lkcopy.onfault, r1
+ mov.l r1, @(PCB_ONFAULT,r2) /* set fault handler */
+ mov.l _Lkcopy.memcpy, r1
+ mov r5, r4
+ jsr @r1 /* memcpy(dst, src, len) */
+ mov r3, r5
+ mov #0, r0
+1:
+ mov.l _Lkcopy.curpcb, r1 /* restore fault handler */
+ mov.l @r1, r2
+ mov.l r8, @(PCB_ONFAULT,r2)
+
+ mov r14, r15
+ lds.l @r15+, pr
+ mov.l @r15+, r14
+ rts
+ mov.l @r15+, r8
+
+2:
+ bra 1b
+ mov #EFAULT, r0
+
+ .align 2
+_Lkcopy.onfault:
+ .long 2b
+_Lkcopy.curpcb:
+ .long _C_LABEL(curpcb)
+_Lkcopy.memcpy:
+ .long _C_LABEL(memcpy)
+
#if defined(DDB) || defined(KGDB)
/*
* int setjmp(label_t *):