fault handler problem of user space access fucntions in sh3/Locore.c

Izumi Tsutsui <[email protected]>
Newsgroups gmane.os.netbsd.ports.sh3
Message-ID <[email protected]>
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
[email protected]

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 *):
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.