+/*
+ * Copy a null terminated string from the user address space into
+ * the kernel address space.
+ *
+ * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
+ */
+ENTRY(copyinstr, R6)
+ movl 12(ap),r6 # r6 = max length
+ jlss 8f
+ movl 4(ap),r1 # r1 = user address
+ bicl3 $~(NBPG*CLSIZE-1),r1,r2 # r2 = bytes on first page
+ subl3 r2,$NBPG*CLSIZE,r2
+ movl 8(ap),r3 # r3 = kernel address
+1:
+ cmpl r6,r2 # r2 = min(bytes on page, length left);
+ jgeq 2f
+ movl r6,r2
+2:
+ prober $3,r2,(r1) # bytes accessible?
+ jeql 8f
+ subl2 r2,r6 # update bytes left count
+#ifdef NOSUBSINST
+ # fake the locc instr. for processors that don't have it
+ movl r2,r0
+6:
+ tstb (r1)+
+ jeql 5f
+ sobgtr r0,6b
+ jbr 7f
+5:
+ decl r1
+ jbr 3f
+7:
+#else
+ locc $0,r2,(r1) # null byte found?
+ jneq 3f
+#endif
+ subl2 r2,r1 # back up pointer updated by `locc'
+ movc3 r2,(r1),(r3) # copy in next piece
+ movl $(NBPG*CLSIZE),r2 # check next page
+ tstl r6 # run out of space?
+ jneq 1b
+ movl $ENOENT,r0 # set error code and return
+ jbr 9f
+3:
+ tstl 16(ap) # return length?
+ beql 4f
+ subl3 r6,12(ap),r6 # actual len = maxlen - unused pages
+ subl2 r0,r6 # - unused on this page
+ addl3 $1,r6,*16(ap) # + the null byte
+4:
+ subl2 r0,r2 # r2 = number of bytes to move
+ subl2 r2,r1 # back up pointer updated by `locc'
+ incl r2 # copy null byte as well
+ movc3 r2,(r1),(r3) # copy in last piece
+ clrl r0 # redundant
+ ret
+8:
+ movl $EFAULT,r0
+9:
+ tstl 16(ap)
+ beql 1f
+ subl3 r6,12(ap),*16(ap)
+1:
+ ret
+
+/*
+ * Copy a null terminated string from the kernel
+ * address space to the user address space.
+ *
+ * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
+ */
+ENTRY(copyoutstr, R6)
+ movl 12(ap),r6 # r6 = max length
+ jlss 8b
+ movl 4(ap),r1 # r1 = kernel address
+ movl 8(ap),r3 # r3 = user address
+ bicl3 $~(NBPG*CLSIZE-1),r3,r2 # r2 = bytes on first page
+ subl3 r2,$NBPG*CLSIZE,r2
+1:
+ cmpl r6,r2 # r2 = min(bytes on page, length left);
+ jgeq 2f
+ movl r6,r2
+2:
+ probew $3,r2,(r3) # bytes accessible?
+ jeql 8b
+ subl2 r2,r6 # update bytes left count
+#ifdef NOSUBSINST
+ # fake the locc instr. for processors that don't have it
+ movl r2,r0
+6:
+ tstb (r1)+
+ jeql 5f
+ sobgtr r0,6b
+ jbr 7f
+5:
+ decl r1
+ jbr 3b
+7:
+#else
+ locc $0,r2,(r1) # null byte found?
+ jneq 3b
+#endif
+ subl2 r2,r1 # back up pointer updated by `locc'
+ movc3 r2,(r1),(r3) # copy in next piece
+ movl $(NBPG*CLSIZE),r2 # check next page
+ tstl r6 # run out of space?
+ jneq 1b
+ movl $ENOENT,r0 # set error code and return
+ jbr 9b
+
+/*
+ * Copy a null terminated string from one point to another in
+ * the kernel address space.
+ *
+ * copystr(fromaddr, toaddr, maxlength, &lencopied)
+ */
+ENTRY(copystr, R6)
+ movl 12(ap),r6 # r6 = max length
+ jlss 8b
+ movl 4(ap),r1 # r1 = src address
+ movl 8(ap),r3 # r3 = dest address
+1:
+ movzwl $65535,r2 # r2 = bytes in first chunk
+ cmpl r6,r2 # r2 = min(bytes in chunk, length left);
+ jgeq 2f
+ movl r6,r2
+2:
+ subl2 r2,r6 # update bytes left count
+#ifdef NOSUBSINST
+ # fake the locc instr. for processors that don't have it
+ movl r2,r0
+6:
+ tstb (r1)+
+ jeql 5f
+ sobgtr r0,6b
+ jbr 7f
+5:
+ decl r1
+ jbr 3b
+7:
+#else
+ locc $0,r2,(r1) # null byte found?
+ jneq 3b
+#endif
+ subl2 r2,r1 # back up pointer updated by `locc'
+ movc3 r2,(r1),(r3) # copy in next piece
+ tstl r6 # run out of space?
+ jneq 1b
+ movl $ENOENT,r0 # set error code and return
+ jbr 9b
+
+/*
+ * Copy specified amount of data from user space into the kernel
+ * Copyin(from, to, len)
+ * r1 == from (user source address)
+ * r3 == to (kernel destination address)
+ * r5 == length
+ */
+ .align 1
+JSBENTRY(Copyin, R1|R3|R5)
+ cmpl r5,$(NBPG*CLSIZE) # probing one page or less ?
+ bgtru 1f # no
+ prober $3,r5,(r1) # bytes accessible ?