Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] Make user-copy operations run-time configurable.

Introduces a struct uaccess_ops which allows setting user-copy
operations at run-time.

Signed-off-by: Gerald Schaefer <geraldsc@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Gerald Schaefer and committed by
Martin Schwidefsky
d02765d1 6837a8c3

+411 -621
-6
arch/s390/kernel/s390_ksyms.c
··· 25 25 EXPORT_SYMBOL(_ni_bitmap); 26 26 EXPORT_SYMBOL(_zb_findmap); 27 27 EXPORT_SYMBOL(_sb_findmap); 28 - EXPORT_SYMBOL(__copy_from_user_asm); 29 - EXPORT_SYMBOL(__copy_to_user_asm); 30 - EXPORT_SYMBOL(__copy_in_user_asm); 31 - EXPORT_SYMBOL(__clear_user_asm); 32 - EXPORT_SYMBOL(__strncpy_from_user_asm); 33 - EXPORT_SYMBOL(__strnlen_user_asm); 34 28 EXPORT_SYMBOL(diag10); 35 29 36 30 /*
+7
arch/s390/kernel/setup.c
··· 51 51 #include <asm/sections.h> 52 52 53 53 /* 54 + * User copy operations. 55 + */ 56 + struct uaccess_ops uaccess; 57 + EXPORT_SYMBOL_GPL(uaccess); 58 + 59 + /* 54 60 * Machine setup.. 55 61 */ 56 62 unsigned int console_mode = 0; ··· 647 641 648 642 memory_end = memory_size; 649 643 644 + memcpy(&uaccess, &uaccess_std, sizeof(uaccess)); 650 645 parse_early_param(); 651 646 652 647 #ifndef CONFIG_64BIT
+1 -2
arch/s390/lib/Makefile
··· 4 4 5 5 EXTRA_AFLAGS := -traditional 6 6 7 - lib-y += delay.o string.o 8 - lib-y += $(if $(CONFIG_64BIT),uaccess64.o,uaccess.o) 7 + lib-y += delay.o string.o uaccess_std.o 9 8 lib-$(CONFIG_SMP) += spinlock.o
-211
arch/s390/lib/uaccess.S
··· 1 - /* 2 - * arch/s390/lib/uaccess.S 3 - * __copy_{from|to}_user functions. 4 - * 5 - * s390 6 - * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation 7 - * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 8 - * 9 - * These functions have standard call interface 10 - */ 11 - 12 - #include <linux/errno.h> 13 - #include <asm/lowcore.h> 14 - #include <asm/asm-offsets.h> 15 - 16 - .text 17 - .align 4 18 - .globl __copy_from_user_asm 19 - # %r2 = to, %r3 = n, %r4 = from 20 - __copy_from_user_asm: 21 - slr %r0,%r0 22 - 0: mvcp 0(%r3,%r2),0(%r4),%r0 23 - jnz 1f 24 - slr %r2,%r2 25 - br %r14 26 - 1: la %r2,256(%r2) 27 - la %r4,256(%r4) 28 - ahi %r3,-256 29 - 2: mvcp 0(%r3,%r2),0(%r4),%r0 30 - jnz 1b 31 - 3: slr %r2,%r2 32 - br %r14 33 - 4: lhi %r0,-4096 34 - lr %r5,%r4 35 - slr %r5,%r0 36 - nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 37 - slr %r5,%r4 # %r5 = #bytes to next user page boundary 38 - clr %r3,%r5 # copy crosses next page boundary ? 39 - jnh 6f # no, the current page faulted 40 - # move with the reduced length which is < 256 41 - 5: mvcp 0(%r5,%r2),0(%r4),%r0 42 - slr %r3,%r5 43 - 6: lr %r2,%r3 44 - br %r14 45 - .section __ex_table,"a" 46 - .long 0b,4b 47 - .long 2b,4b 48 - .long 5b,6b 49 - .previous 50 - 51 - .align 4 52 - .text 53 - .globl __copy_to_user_asm 54 - # %r2 = from, %r3 = n, %r4 = to 55 - __copy_to_user_asm: 56 - slr %r0,%r0 57 - 0: mvcs 0(%r3,%r4),0(%r2),%r0 58 - jnz 1f 59 - slr %r2,%r2 60 - br %r14 61 - 1: la %r2,256(%r2) 62 - la %r4,256(%r4) 63 - ahi %r3,-256 64 - 2: mvcs 0(%r3,%r4),0(%r2),%r0 65 - jnz 1b 66 - 3: slr %r2,%r2 67 - br %r14 68 - 4: lhi %r0,-4096 69 - lr %r5,%r4 70 - slr %r5,%r0 71 - nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 72 - slr %r5,%r4 # %r5 = #bytes to next user page boundary 73 - clr %r3,%r5 # copy crosses next page boundary ? 74 - jnh 6f # no, the current page faulted 75 - # move with the reduced length which is < 256 76 - 5: mvcs 0(%r5,%r4),0(%r2),%r0 77 - slr %r3,%r5 78 - 6: lr %r2,%r3 79 - br %r14 80 - .section __ex_table,"a" 81 - .long 0b,4b 82 - .long 2b,4b 83 - .long 5b,6b 84 - .previous 85 - 86 - .align 4 87 - .text 88 - .globl __copy_in_user_asm 89 - # %r2 = from, %r3 = n, %r4 = to 90 - __copy_in_user_asm: 91 - ahi %r3,-1 92 - jo 6f 93 - sacf 256 94 - bras %r1,4f 95 - 0: ahi %r3,257 96 - 1: mvc 0(1,%r4),0(%r2) 97 - la %r2,1(%r2) 98 - la %r4,1(%r4) 99 - ahi %r3,-1 100 - jnz 1b 101 - 2: lr %r2,%r3 102 - br %r14 103 - 3: mvc 0(256,%r4),0(%r2) 104 - la %r2,256(%r2) 105 - la %r4,256(%r4) 106 - 4: ahi %r3,-256 107 - jnm 3b 108 - 5: ex %r3,4(%r1) 109 - sacf 0 110 - 6: slr %r2,%r2 111 - br %r14 112 - .section __ex_table,"a" 113 - .long 1b,2b 114 - .long 3b,0b 115 - .long 5b,0b 116 - .previous 117 - 118 - .align 4 119 - .text 120 - .globl __clear_user_asm 121 - # %r2 = to, %r3 = n 122 - __clear_user_asm: 123 - bras %r5,0f 124 - .long empty_zero_page 125 - 0: l %r5,0(%r5) 126 - slr %r0,%r0 127 - 1: mvcs 0(%r3,%r2),0(%r5),%r0 128 - jnz 2f 129 - slr %r2,%r2 130 - br %r14 131 - 2: la %r2,256(%r2) 132 - ahi %r3,-256 133 - 3: mvcs 0(%r3,%r2),0(%r5),%r0 134 - jnz 2b 135 - 4: slr %r2,%r2 136 - br %r14 137 - 5: lhi %r0,-4096 138 - lr %r4,%r2 139 - slr %r4,%r0 140 - nr %r4,%r0 # %r4 = (%r2 + 4096) & -4096 141 - slr %r4,%r2 # %r4 = #bytes to next user page boundary 142 - clr %r3,%r4 # clear crosses next page boundary ? 143 - jnh 7f # no, the current page faulted 144 - # clear with the reduced length which is < 256 145 - 6: mvcs 0(%r4,%r2),0(%r5),%r0 146 - slr %r3,%r4 147 - 7: lr %r2,%r3 148 - br %r14 149 - .section __ex_table,"a" 150 - .long 1b,5b 151 - .long 3b,5b 152 - .long 6b,7b 153 - .previous 154 - 155 - .align 4 156 - .text 157 - .globl __strncpy_from_user_asm 158 - # %r2 = count, %r3 = dst, %r4 = src 159 - __strncpy_from_user_asm: 160 - lhi %r0,0 161 - lr %r1,%r4 162 - la %r4,0(%r4) # clear high order bit from %r4 163 - la %r2,0(%r2,%r4) # %r2 points to first byte after string 164 - sacf 256 165 - 0: srst %r2,%r1 166 - jo 0b 167 - sacf 0 168 - lr %r1,%r2 169 - jh 1f # \0 found in string ? 170 - ahi %r1,1 # include \0 in copy 171 - 1: slr %r1,%r4 # %r1 = copy length (without \0) 172 - slr %r2,%r4 # %r2 = return length (including \0) 173 - 2: mvcp 0(%r1,%r3),0(%r4),%r0 174 - jnz 3f 175 - br %r14 176 - 3: la %r3,256(%r3) 177 - la %r4,256(%r4) 178 - ahi %r1,-256 179 - mvcp 0(%r1,%r3),0(%r4),%r0 180 - jnz 3b 181 - br %r14 182 - 4: sacf 0 183 - lhi %r2,-EFAULT 184 - br %r14 185 - .section __ex_table,"a" 186 - .long 0b,4b 187 - .previous 188 - 189 - .align 4 190 - .text 191 - .globl __strnlen_user_asm 192 - # %r2 = count, %r3 = src 193 - __strnlen_user_asm: 194 - lhi %r0,0 195 - lr %r1,%r3 196 - la %r3,0(%r3) # clear high order bit from %r4 197 - la %r2,0(%r2,%r3) # %r2 points to first byte after string 198 - sacf 256 199 - 0: srst %r2,%r1 200 - jo 0b 201 - sacf 0 202 - ahi %r2,1 # strnlen_user result includes the \0 203 - # or return count+1 if \0 not found 204 - slr %r2,%r3 205 - br %r14 206 - 2: sacf 0 207 - slr %r2,%r2 # return 0 on exception 208 - br %r14 209 - .section __ex_table,"a" 210 - .long 0b,2b 211 - .previous
-207
arch/s390/lib/uaccess64.S
··· 1 - /* 2 - * arch/s390x/lib/uaccess.S 3 - * __copy_{from|to}_user functions. 4 - * 5 - * s390 6 - * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation 7 - * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 8 - * 9 - * These functions have standard call interface 10 - */ 11 - 12 - #include <linux/errno.h> 13 - #include <asm/lowcore.h> 14 - #include <asm/asm-offsets.h> 15 - 16 - .text 17 - .align 4 18 - .globl __copy_from_user_asm 19 - # %r2 = to, %r3 = n, %r4 = from 20 - __copy_from_user_asm: 21 - slgr %r0,%r0 22 - 0: mvcp 0(%r3,%r2),0(%r4),%r0 23 - jnz 1f 24 - slgr %r2,%r2 25 - br %r14 26 - 1: la %r2,256(%r2) 27 - la %r4,256(%r4) 28 - aghi %r3,-256 29 - 2: mvcp 0(%r3,%r2),0(%r4),%r0 30 - jnz 1b 31 - 3: slgr %r2,%r2 32 - br %r14 33 - 4: lghi %r0,-4096 34 - lgr %r5,%r4 35 - slgr %r5,%r0 36 - ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 37 - slgr %r5,%r4 # %r5 = #bytes to next user page boundary 38 - clgr %r3,%r5 # copy crosses next page boundary ? 39 - jnh 6f # no, the current page faulted 40 - # move with the reduced length which is < 256 41 - 5: mvcp 0(%r5,%r2),0(%r4),%r0 42 - slgr %r3,%r5 43 - 6: lgr %r2,%r3 44 - br %r14 45 - .section __ex_table,"a" 46 - .quad 0b,4b 47 - .quad 2b,4b 48 - .quad 5b,6b 49 - .previous 50 - 51 - .align 4 52 - .text 53 - .globl __copy_to_user_asm 54 - # %r2 = from, %r3 = n, %r4 = to 55 - __copy_to_user_asm: 56 - slgr %r0,%r0 57 - 0: mvcs 0(%r3,%r4),0(%r2),%r0 58 - jnz 1f 59 - slgr %r2,%r2 60 - br %r14 61 - 1: la %r2,256(%r2) 62 - la %r4,256(%r4) 63 - aghi %r3,-256 64 - 2: mvcs 0(%r3,%r4),0(%r2),%r0 65 - jnz 1b 66 - 3: slgr %r2,%r2 67 - br %r14 68 - 4: lghi %r0,-4096 69 - lgr %r5,%r4 70 - slgr %r5,%r0 71 - ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 72 - slgr %r5,%r4 # %r5 = #bytes to next user page boundary 73 - clgr %r3,%r5 # copy crosses next page boundary ? 74 - jnh 6f # no, the current page faulted 75 - # move with the reduced length which is < 256 76 - 5: mvcs 0(%r5,%r4),0(%r2),%r0 77 - slgr %r3,%r5 78 - 6: lgr %r2,%r3 79 - br %r14 80 - .section __ex_table,"a" 81 - .quad 0b,4b 82 - .quad 2b,4b 83 - .quad 5b,6b 84 - .previous 85 - 86 - .align 4 87 - .text 88 - .globl __copy_in_user_asm 89 - # %r2 = from, %r3 = n, %r4 = to 90 - __copy_in_user_asm: 91 - aghi %r3,-1 92 - jo 6f 93 - sacf 256 94 - bras %r1,4f 95 - 0: aghi %r3,257 96 - 1: mvc 0(1,%r4),0(%r2) 97 - la %r2,1(%r2) 98 - la %r4,1(%r4) 99 - aghi %r3,-1 100 - jnz 1b 101 - 2: lgr %r2,%r3 102 - br %r14 103 - 3: mvc 0(256,%r4),0(%r2) 104 - la %r2,256(%r2) 105 - la %r4,256(%r4) 106 - 4: aghi %r3,-256 107 - jnm 3b 108 - 5: ex %r3,4(%r1) 109 - sacf 0 110 - 6: slgr %r2,%r2 111 - br 14 112 - .section __ex_table,"a" 113 - .quad 1b,2b 114 - .quad 3b,0b 115 - .quad 5b,0b 116 - .previous 117 - 118 - .align 4 119 - .text 120 - .globl __clear_user_asm 121 - # %r2 = to, %r3 = n 122 - __clear_user_asm: 123 - slgr %r0,%r0 124 - larl %r5,empty_zero_page 125 - 1: mvcs 0(%r3,%r2),0(%r5),%r0 126 - jnz 2f 127 - slgr %r2,%r2 128 - br %r14 129 - 2: la %r2,256(%r2) 130 - aghi %r3,-256 131 - 3: mvcs 0(%r3,%r2),0(%r5),%r0 132 - jnz 2b 133 - 4: slgr %r2,%r2 134 - br %r14 135 - 5: lghi %r0,-4096 136 - lgr %r4,%r2 137 - slgr %r4,%r0 138 - ngr %r4,%r0 # %r4 = (%r2 + 4096) & -4096 139 - slgr %r4,%r2 # %r4 = #bytes to next user page boundary 140 - clgr %r3,%r4 # clear crosses next page boundary ? 141 - jnh 7f # no, the current page faulted 142 - # clear with the reduced length which is < 256 143 - 6: mvcs 0(%r4,%r2),0(%r5),%r0 144 - slgr %r3,%r4 145 - 7: lgr %r2,%r3 146 - br %r14 147 - .section __ex_table,"a" 148 - .quad 1b,5b 149 - .quad 3b,5b 150 - .quad 6b,7b 151 - .previous 152 - 153 - .align 4 154 - .text 155 - .globl __strncpy_from_user_asm 156 - # %r2 = count, %r3 = dst, %r4 = src 157 - __strncpy_from_user_asm: 158 - lghi %r0,0 159 - lgr %r1,%r4 160 - la %r2,0(%r2,%r4) # %r2 points to first byte after string 161 - sacf 256 162 - 0: srst %r2,%r1 163 - jo 0b 164 - sacf 0 165 - lgr %r1,%r2 166 - jh 1f # \0 found in string ? 167 - aghi %r1,1 # include \0 in copy 168 - 1: slgr %r1,%r4 # %r1 = copy length (without \0) 169 - slgr %r2,%r4 # %r2 = return length (including \0) 170 - 2: mvcp 0(%r1,%r3),0(%r4),%r0 171 - jnz 3f 172 - br %r14 173 - 3: la %r3,256(%r3) 174 - la %r4,256(%r4) 175 - aghi %r1,-256 176 - mvcp 0(%r1,%r3),0(%r4),%r0 177 - jnz 3b 178 - br %r14 179 - 4: sacf 0 180 - lghi %r2,-EFAULT 181 - br %r14 182 - .section __ex_table,"a" 183 - .quad 0b,4b 184 - .previous 185 - 186 - .align 4 187 - .text 188 - .globl __strnlen_user_asm 189 - # %r2 = count, %r3 = src 190 - __strnlen_user_asm: 191 - lghi %r0,0 192 - lgr %r1,%r3 193 - la %r2,0(%r2,%r3) # %r2 points to first byte after string 194 - sacf 256 195 - 0: srst %r2,%r1 196 - jo 0b 197 - sacf 0 198 - aghi %r2,1 # strnlen_user result includes the \0 199 - # or return count+1 if \0 not found 200 - slgr %r2,%r3 201 - br %r14 202 - 2: sacf 0 203 - slgr %r2,%r2 # return 0 on exception 204 - br %r14 205 - .section __ex_table,"a" 206 - .quad 0b,2b 207 - .previous
+340
arch/s390/lib/uaccess_std.c
··· 1 + /* 2 + * arch/s390/lib/uaccess_std.c 3 + * 4 + * Standard user space access functions based on mvcp/mvcs and doing 5 + * interesting things in the secondary space mode. 6 + * 7 + * Copyright (C) IBM Corp. 2006 8 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), 9 + * Gerald Schaefer (gerald.schaefer@de.ibm.com) 10 + */ 11 + 12 + #include <linux/errno.h> 13 + #include <linux/mm.h> 14 + #include <asm/uaccess.h> 15 + #include <asm/futex.h> 16 + 17 + #ifndef __s390x__ 18 + #define AHI "ahi" 19 + #define ALR "alr" 20 + #define CLR "clr" 21 + #define LHI "lhi" 22 + #define SLR "slr" 23 + #else 24 + #define AHI "aghi" 25 + #define ALR "algr" 26 + #define CLR "clgr" 27 + #define LHI "lghi" 28 + #define SLR "slgr" 29 + #endif 30 + 31 + size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) 32 + { 33 + unsigned long tmp1, tmp2; 34 + 35 + tmp1 = -256UL; 36 + asm volatile( 37 + "0: mvcp 0(%0,%2),0(%1),%3\n" 38 + " jz 5f\n" 39 + "1:"ALR" %0,%3\n" 40 + " la %1,256(%1)\n" 41 + " la %2,256(%2)\n" 42 + "2: mvcp 0(%0,%2),0(%1),%3\n" 43 + " jnz 1b\n" 44 + " j 5f\n" 45 + "3: la %4,255(%1)\n" /* %4 = ptr + 255 */ 46 + " "LHI" %3,-4096\n" 47 + " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ 48 + " "SLR" %4,%1\n" 49 + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ 50 + " jnh 6f\n" 51 + "4: mvcp 0(%4,%2),0(%1),%3\n" 52 + " "SLR" %0,%4\n" 53 + " j 6f\n" 54 + "5:"SLR" %0,%0\n" 55 + "6: \n" 56 + EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b) 57 + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) 58 + : : "cc", "memory"); 59 + return size; 60 + } 61 + 62 + size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x) 63 + { 64 + unsigned long tmp1, tmp2; 65 + 66 + tmp1 = 0UL; 67 + asm volatile( 68 + "0: mvcp 0(%0,%2),0(%1),%3\n" 69 + " "SLR" %0,%0\n" 70 + " j 3f\n" 71 + "1: la %4,255(%1)\n" /* %4 = ptr + 255 */ 72 + " "LHI" %3,-4096\n" 73 + " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ 74 + " "SLR" %4,%1\n" 75 + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ 76 + " jnh 3f\n" 77 + "2: mvcp 0(%4,%2),0(%1),%3\n" 78 + " "SLR" %0,%4\n" 79 + "3:\n" 80 + EX_TABLE(0b,1b) EX_TABLE(2b,3b) 81 + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) 82 + : : "cc", "memory"); 83 + return size; 84 + } 85 + 86 + size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) 87 + { 88 + unsigned long tmp1, tmp2; 89 + 90 + tmp1 = -256UL; 91 + asm volatile( 92 + "0: mvcs 0(%0,%1),0(%2),%3\n" 93 + " jz 5f\n" 94 + "1:"ALR" %0,%3\n" 95 + " la %1,256(%1)\n" 96 + " la %2,256(%2)\n" 97 + "2: mvcs 0(%0,%1),0(%2),%3\n" 98 + " jnz 1b\n" 99 + " j 5f\n" 100 + "3: la %4,255(%1)\n" /* %4 = ptr + 255 */ 101 + " "LHI" %3,-4096\n" 102 + " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ 103 + " "SLR" %4,%1\n" 104 + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ 105 + " jnh 6f\n" 106 + "4: mvcs 0(%4,%1),0(%2),%3\n" 107 + " "SLR" %0,%4\n" 108 + " j 6f\n" 109 + "5:"SLR" %0,%0\n" 110 + "6: \n" 111 + EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b) 112 + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) 113 + : : "cc", "memory"); 114 + return size; 115 + } 116 + 117 + size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x) 118 + { 119 + unsigned long tmp1, tmp2; 120 + 121 + tmp1 = 0UL; 122 + asm volatile( 123 + "0: mvcs 0(%0,%1),0(%2),%3\n" 124 + " "SLR" %0,%0\n" 125 + " j 3f\n" 126 + "1: la %4,255(%1)\n" /* ptr + 255 */ 127 + " "LHI" %3,-4096\n" 128 + " nr %4,%3\n" /* (ptr + 255) & -4096UL */ 129 + " "SLR" %4,%1\n" 130 + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ 131 + " jnh 3f\n" 132 + "2: mvcs 0(%4,%1),0(%2),%3\n" 133 + " "SLR" %0,%4\n" 134 + "3:\n" 135 + EX_TABLE(0b,1b) EX_TABLE(2b,3b) 136 + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) 137 + : : "cc", "memory"); 138 + return size; 139 + } 140 + 141 + size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) 142 + { 143 + unsigned long tmp1; 144 + 145 + asm volatile( 146 + " "AHI" %0,-1\n" 147 + " jo 5f\n" 148 + " sacf 256\n" 149 + " bras %3,3f\n" 150 + "0:"AHI" %0,257\n" 151 + "1: mvc 0(1,%1),0(%2)\n" 152 + " la %1,1(%1)\n" 153 + " la %2,1(%2)\n" 154 + " "AHI" %0,-1\n" 155 + " jnz 1b\n" 156 + " j 5f\n" 157 + "2: mvc 0(256,%1),0(%2)\n" 158 + " la %1,256(%1)\n" 159 + " la %2,256(%2)\n" 160 + "3:"AHI" %0,-256\n" 161 + " jnm 2b\n" 162 + "4: ex %0,1b-0b(%3)\n" 163 + " sacf 0\n" 164 + "5: "SLR" %0,%0\n" 165 + "6:\n" 166 + EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b) 167 + : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1) 168 + : : "cc", "memory"); 169 + return size; 170 + } 171 + 172 + size_t clear_user_std(size_t size, void __user *to) 173 + { 174 + unsigned long tmp1, tmp2; 175 + 176 + asm volatile( 177 + " "AHI" %0,-1\n" 178 + " jo 5f\n" 179 + " sacf 256\n" 180 + " bras %3,3f\n" 181 + " xc 0(1,%1),0(%1)\n" 182 + "0:"AHI" %0,257\n" 183 + " la %2,255(%1)\n" /* %2 = ptr + 255 */ 184 + " srl %2,12\n" 185 + " sll %2,12\n" /* %2 = (ptr + 255) & -4096 */ 186 + " "SLR" %2,%1\n" 187 + " "CLR" %0,%2\n" /* clear crosses next page boundary? */ 188 + " jnh 5f\n" 189 + " "AHI" %2,-1\n" 190 + "1: ex %2,0(%3)\n" 191 + " "AHI" %2,1\n" 192 + " "SLR" %0,%2\n" 193 + " j 5f\n" 194 + "2: xc 0(256,%1),0(%1)\n" 195 + " la %1,256(%1)\n" 196 + "3:"AHI" %0,-256\n" 197 + " jnm 2b\n" 198 + "4: ex %0,0(%3)\n" 199 + " sacf 0\n" 200 + "5: "SLR" %0,%0\n" 201 + "6:\n" 202 + EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b) 203 + : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2) 204 + : : "cc", "memory"); 205 + return size; 206 + } 207 + 208 + size_t strnlen_user_std(size_t size, const char __user *src) 209 + { 210 + register unsigned long reg0 asm("0") = 0UL; 211 + unsigned long tmp1, tmp2; 212 + 213 + asm volatile( 214 + " la %2,0(%1)\n" 215 + " la %3,0(%0,%1)\n" 216 + " "SLR" %0,%0\n" 217 + " sacf 256\n" 218 + "0: srst %3,%2\n" 219 + " jo 0b\n" 220 + " la %0,1(%3)\n" /* strnlen_user results includes \0 */ 221 + " "SLR" %0,%1\n" 222 + "1: sacf 0\n" 223 + EX_TABLE(0b,1b) 224 + : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2) 225 + : "d" (reg0) : "cc", "memory"); 226 + return size; 227 + } 228 + 229 + size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst) 230 + { 231 + register unsigned long reg0 asm("0") = 0UL; 232 + unsigned long tmp1, tmp2; 233 + 234 + asm volatile( 235 + " la %3,0(%1)\n" 236 + " la %4,0(%0,%1)\n" 237 + " sacf 256\n" 238 + "0: srst %4,%3\n" 239 + " jo 0b\n" 240 + " sacf 0\n" 241 + " la %0,0(%4)\n" 242 + " jh 1f\n" /* found \0 in string ? */ 243 + " "AHI" %4,1\n" /* include \0 in copy */ 244 + "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */ 245 + " "SLR" %4,%1\n" /* %4 = copy length (including \0) */ 246 + "2: mvcp 0(%4,%2),0(%1),%5\n" 247 + " jz 9f\n" 248 + "3:"AHI" %4,-256\n" 249 + " la %1,256(%1)\n" 250 + " la %2,256(%2)\n" 251 + "4: mvcp 0(%4,%2),0(%1),%5\n" 252 + " jnz 3b\n" 253 + " j 9f\n" 254 + "7: sacf 0\n" 255 + "8:"LHI" %0,%6\n" 256 + "9:\n" 257 + EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b) 258 + : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2) 259 + : "d" (reg0), "K" (-EFAULT) : "cc", "memory"); 260 + return size; 261 + } 262 + 263 + #define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ 264 + asm volatile( \ 265 + " sacf 256\n" \ 266 + "0: l %1,0(%6)\n" \ 267 + "1:"insn \ 268 + "2: cs %1,%2,0(%6)\n" \ 269 + "3: jl 1b\n" \ 270 + " lhi %0,0\n" \ 271 + "4: sacf 0\n" \ 272 + EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \ 273 + : "=d" (ret), "=&d" (oldval), "=&d" (newval), \ 274 + "=m" (*uaddr) \ 275 + : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ 276 + "m" (*uaddr) : "cc"); 277 + 278 + int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) 279 + { 280 + int oldval = 0, newval, ret; 281 + 282 + inc_preempt_count(); 283 + 284 + switch (op) { 285 + case FUTEX_OP_SET: 286 + __futex_atomic_op("lr %2,%5\n", 287 + ret, oldval, newval, uaddr, oparg); 288 + break; 289 + case FUTEX_OP_ADD: 290 + __futex_atomic_op("lr %2,%1\nar %2,%5\n", 291 + ret, oldval, newval, uaddr, oparg); 292 + break; 293 + case FUTEX_OP_OR: 294 + __futex_atomic_op("lr %2,%1\nor %2,%5\n", 295 + ret, oldval, newval, uaddr, oparg); 296 + break; 297 + case FUTEX_OP_ANDN: 298 + __futex_atomic_op("lr %2,%1\nnr %2,%5\n", 299 + ret, oldval, newval, uaddr, oparg); 300 + break; 301 + case FUTEX_OP_XOR: 302 + __futex_atomic_op("lr %2,%1\nxr %2,%5\n", 303 + ret, oldval, newval, uaddr, oparg); 304 + break; 305 + default: 306 + ret = -ENOSYS; 307 + } 308 + dec_preempt_count(); 309 + *old = oldval; 310 + return ret; 311 + } 312 + 313 + int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) 314 + { 315 + int ret; 316 + 317 + asm volatile( 318 + " sacf 256\n" 319 + " cs %1,%4,0(%5)\n" 320 + "0: lr %0,%1\n" 321 + "1: sacf 0\n" 322 + EX_TABLE(0b,1b) 323 + : "=d" (ret), "+d" (oldval), "=m" (*uaddr) 324 + : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) 325 + : "cc", "memory" ); 326 + return ret; 327 + } 328 + 329 + struct uaccess_ops uaccess_std = { 330 + .copy_from_user = copy_from_user_std, 331 + .copy_from_user_small = copy_from_user_std_small, 332 + .copy_to_user = copy_to_user_std, 333 + .copy_to_user_small = copy_to_user_std_small, 334 + .copy_in_user = copy_in_user_std, 335 + .clear_user = clear_user_std, 336 + .strnlen_user = strnlen_user_std, 337 + .strncpy_from_user = strncpy_from_user_std, 338 + .futex_atomic_op = futex_atomic_op, 339 + .futex_atomic_cmpxchg = futex_atomic_cmpxchg, 340 + };
+7 -80
include/asm-s390/futex.h
··· 7 7 #include <asm/errno.h> 8 8 #include <asm/uaccess.h> 9 9 10 - #ifndef __s390x__ 11 - #define __futex_atomic_fixup \ 12 - ".section __ex_table,\"a\"\n" \ 13 - " .align 4\n" \ 14 - " .long 0b,4b,2b,4b,3b,4b\n" \ 15 - ".previous" 16 - #else /* __s390x__ */ 17 - #define __futex_atomic_fixup \ 18 - ".section __ex_table,\"a\"\n" \ 19 - " .align 8\n" \ 20 - " .quad 0b,4b,2b,4b,3b,4b\n" \ 21 - ".previous" 22 - #endif /* __s390x__ */ 23 - 24 - #define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ 25 - asm volatile(" sacf 256\n" \ 26 - "0: l %1,0(%6)\n" \ 27 - "1: " insn \ 28 - "2: cs %1,%2,0(%6)\n" \ 29 - "3: jl 1b\n" \ 30 - " lhi %0,0\n" \ 31 - "4: sacf 0\n" \ 32 - __futex_atomic_fixup \ 33 - : "=d" (ret), "=&d" (oldval), "=&d" (newval), \ 34 - "=m" (*uaddr) \ 35 - : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ 36 - "m" (*uaddr) : "cc" ); 37 - 38 10 static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr) 39 11 { 40 12 int op = (encoded_op >> 28) & 7; 41 13 int cmp = (encoded_op >> 24) & 15; 42 14 int oparg = (encoded_op << 8) >> 20; 43 15 int cmparg = (encoded_op << 20) >> 20; 44 - int oldval = 0, newval, ret; 16 + int oldval, ret; 17 + 45 18 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) 46 19 oparg = 1 << oparg; 47 20 48 21 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) 49 22 return -EFAULT; 50 23 51 - inc_preempt_count(); 52 - 53 - switch (op) { 54 - case FUTEX_OP_SET: 55 - __futex_atomic_op("lr %2,%5\n", 56 - ret, oldval, newval, uaddr, oparg); 57 - break; 58 - case FUTEX_OP_ADD: 59 - __futex_atomic_op("lr %2,%1\nar %2,%5\n", 60 - ret, oldval, newval, uaddr, oparg); 61 - break; 62 - case FUTEX_OP_OR: 63 - __futex_atomic_op("lr %2,%1\nor %2,%5\n", 64 - ret, oldval, newval, uaddr, oparg); 65 - break; 66 - case FUTEX_OP_ANDN: 67 - __futex_atomic_op("lr %2,%1\nnr %2,%5\n", 68 - ret, oldval, newval, uaddr, oparg); 69 - break; 70 - case FUTEX_OP_XOR: 71 - __futex_atomic_op("lr %2,%1\nxr %2,%5\n", 72 - ret, oldval, newval, uaddr, oparg); 73 - break; 74 - default: 75 - ret = -ENOSYS; 76 - } 77 - 78 - dec_preempt_count(); 24 + ret = uaccess.futex_atomic_op(op, uaddr, oparg, &oldval); 79 25 80 26 if (!ret) { 81 27 switch (cmp) { ··· 37 91 return ret; 38 92 } 39 93 40 - static inline int 41 - futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) 94 + static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, 95 + int oldval, int newval) 42 96 { 43 - int ret; 44 - 45 97 if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) 46 98 return -EFAULT; 47 - asm volatile(" sacf 256\n" 48 - " cs %1,%4,0(%5)\n" 49 - "0: lr %0,%1\n" 50 - "1: sacf 0\n" 51 - #ifndef __s390x__ 52 - ".section __ex_table,\"a\"\n" 53 - " .align 4\n" 54 - " .long 0b,1b\n" 55 - ".previous" 56 - #else /* __s390x__ */ 57 - ".section __ex_table,\"a\"\n" 58 - " .align 8\n" 59 - " .quad 0b,1b\n" 60 - ".previous" 61 - #endif /* __s390x__ */ 62 - : "=d" (ret), "+d" (oldval), "=m" (*uaddr) 63 - : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) 64 - : "cc", "memory" ); 65 - return oldval; 99 + 100 + return uaccess.futex_atomic_cmpxchg(uaddr, oldval, newval); 66 101 } 67 102 68 103 #endif /* __KERNEL__ */
+56 -115
include/asm-s390/uaccess.h
··· 47 47 S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ 48 48 asm volatile ("lctlg 7,7,%0" : : "m" (__pto) ); \ 49 49 }) 50 - #else 50 + #else /* __s390x__ */ 51 51 #define set_fs(x) \ 52 52 ({ \ 53 53 unsigned long __pto; \ ··· 56 56 S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ 57 57 asm volatile ("lctl 7,7,%0" : : "m" (__pto) ); \ 58 58 }) 59 - #endif 59 + #endif /* __s390x__ */ 60 60 61 61 #define segment_eq(a,b) ((a).ar4 == (b).ar4) 62 62 ··· 85 85 unsigned long insn, fixup; 86 86 }; 87 87 88 - #ifndef __s390x__ 89 - #define __uaccess_fixup \ 90 - ".section .fixup,\"ax\"\n" \ 91 - "2: lhi %0,%4\n" \ 92 - " bras 1,3f\n" \ 93 - " .long 1b\n" \ 94 - "3: l 1,0(1)\n" \ 95 - " br 1\n" \ 96 - ".previous\n" \ 97 - ".section __ex_table,\"a\"\n" \ 98 - " .align 4\n" \ 99 - " .long 0b,2b\n" \ 100 - ".previous" 101 - #define __uaccess_clobber "cc", "1" 102 - #else /* __s390x__ */ 103 - #define __uaccess_fixup \ 104 - ".section .fixup,\"ax\"\n" \ 105 - "2: lghi %0,%4\n" \ 106 - " jg 1b\n" \ 107 - ".previous\n" \ 108 - ".section __ex_table,\"a\"\n" \ 109 - " .align 8\n" \ 110 - " .quad 0b,2b\n" \ 111 - ".previous" 112 - #define __uaccess_clobber "cc" 113 - #endif /* __s390x__ */ 88 + struct uaccess_ops { 89 + size_t (*copy_from_user)(size_t, const void __user *, void *); 90 + size_t (*copy_from_user_small)(size_t, const void __user *, void *); 91 + size_t (*copy_to_user)(size_t, void __user *, const void *); 92 + size_t (*copy_to_user_small)(size_t, void __user *, const void *); 93 + size_t (*copy_in_user)(size_t, void __user *, const void __user *); 94 + size_t (*clear_user)(size_t, void __user *); 95 + size_t (*strnlen_user)(size_t, const char __user *); 96 + size_t (*strncpy_from_user)(size_t, const char __user *, char *); 97 + int (*futex_atomic_op)(int op, int __user *, int oparg, int *old); 98 + int (*futex_atomic_cmpxchg)(int __user *, int old, int new); 99 + }; 100 + 101 + extern struct uaccess_ops uaccess; 102 + extern struct uaccess_ops uaccess_std; 103 + 104 + static inline int __put_user_fn(size_t size, void __user *ptr, void *x) 105 + { 106 + size = uaccess.copy_to_user_small(size, ptr, x); 107 + return size ? -EFAULT : size; 108 + } 109 + 110 + static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) 111 + { 112 + size = uaccess.copy_from_user_small(size, ptr, x); 113 + return size ? -EFAULT : size; 114 + } 114 115 115 116 /* 116 117 * These are the main single-value transfer routines. They automatically 117 118 * use the right size if we just have the right pointer type. 118 119 */ 119 - #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) 120 - #define __put_user_asm(x, ptr, err) \ 121 - ({ \ 122 - err = 0; \ 123 - asm volatile( \ 124 - "0: mvcs 0(%1,%2),%3,%0\n" \ 125 - "1:\n" \ 126 - __uaccess_fixup \ 127 - : "+&d" (err) \ 128 - : "d" (sizeof(*(ptr))), "a" (ptr), "Q" (x), \ 129 - "K" (-EFAULT) \ 130 - : __uaccess_clobber ); \ 131 - }) 132 - #else 133 - #define __put_user_asm(x, ptr, err) \ 134 - ({ \ 135 - err = 0; \ 136 - asm volatile( \ 137 - "0: mvcs 0(%1,%2),0(%3),%0\n" \ 138 - "1:\n" \ 139 - __uaccess_fixup \ 140 - : "+&d" (err) \ 141 - : "d" (sizeof(*(ptr))), "a" (ptr), "a" (&(x)), \ 142 - "K" (-EFAULT), "m" (x) \ 143 - : __uaccess_clobber ); \ 144 - }) 145 - #endif 146 - 147 120 #define __put_user(x, ptr) \ 148 121 ({ \ 149 122 __typeof__(*(ptr)) __x = (x); \ 150 - int __pu_err; \ 123 + int __pu_err = -EFAULT; \ 151 124 __chk_user_ptr(ptr); \ 152 125 switch (sizeof (*(ptr))) { \ 153 126 case 1: \ 154 127 case 2: \ 155 128 case 4: \ 156 129 case 8: \ 157 - __put_user_asm(__x, ptr, __pu_err); \ 130 + __pu_err = __put_user_fn(sizeof (*(ptr)), \ 131 + ptr, &__x); \ 158 132 break; \ 159 133 default: \ 160 134 __put_user_bad(); \ ··· 146 172 147 173 extern int __put_user_bad(void) __attribute__((noreturn)); 148 174 149 - #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) 150 - #define __get_user_asm(x, ptr, err) \ 151 - ({ \ 152 - err = 0; \ 153 - asm volatile ( \ 154 - "0: mvcp %O1(%2,%R1),0(%3),%0\n" \ 155 - "1:\n" \ 156 - __uaccess_fixup \ 157 - : "+&d" (err), "=Q" (x) \ 158 - : "d" (sizeof(*(ptr))), "a" (ptr), \ 159 - "K" (-EFAULT) \ 160 - : __uaccess_clobber ); \ 161 - }) 162 - #else 163 - #define __get_user_asm(x, ptr, err) \ 164 - ({ \ 165 - err = 0; \ 166 - asm volatile ( \ 167 - "0: mvcp 0(%2,%5),0(%3),%0\n" \ 168 - "1:\n" \ 169 - __uaccess_fixup \ 170 - : "+&d" (err), "=m" (x) \ 171 - : "d" (sizeof(*(ptr))), "a" (ptr), \ 172 - "K" (-EFAULT), "a" (&(x)) \ 173 - : __uaccess_clobber ); \ 174 - }) 175 - #endif 176 - 177 175 #define __get_user(x, ptr) \ 178 176 ({ \ 179 - int __gu_err; \ 180 - __chk_user_ptr(ptr); \ 177 + int __gu_err = -EFAULT; \ 178 + __chk_user_ptr(ptr); \ 181 179 switch (sizeof(*(ptr))) { \ 182 180 case 1: { \ 183 181 unsigned char __x; \ 184 - __get_user_asm(__x, ptr, __gu_err); \ 182 + __gu_err = __get_user_fn(sizeof (*(ptr)), \ 183 + ptr, &__x); \ 185 184 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 186 185 break; \ 187 186 }; \ 188 187 case 2: { \ 189 188 unsigned short __x; \ 190 - __get_user_asm(__x, ptr, __gu_err); \ 189 + __gu_err = __get_user_fn(sizeof (*(ptr)), \ 190 + ptr, &__x); \ 191 191 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 192 192 break; \ 193 193 }; \ 194 194 case 4: { \ 195 195 unsigned int __x; \ 196 - __get_user_asm(__x, ptr, __gu_err); \ 196 + __gu_err = __get_user_fn(sizeof (*(ptr)), \ 197 + ptr, &__x); \ 197 198 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 198 199 break; \ 199 200 }; \ 200 201 case 8: { \ 201 202 unsigned long long __x; \ 202 - __get_user_asm(__x, ptr, __gu_err); \ 203 + __gu_err = __get_user_fn(sizeof (*(ptr)), \ 204 + ptr, &__x); \ 203 205 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 204 206 break; \ 205 207 }; \ ··· 197 247 #define __put_user_unaligned __put_user 198 248 #define __get_user_unaligned __get_user 199 249 200 - extern long __copy_to_user_asm(const void *from, long n, void __user *to); 201 - 202 250 /** 203 251 * __copy_to_user: - Copy a block of data into user space, with less checking. 204 252 * @to: Destination address, in user space. ··· 214 266 static inline unsigned long 215 267 __copy_to_user(void __user *to, const void *from, unsigned long n) 216 268 { 217 - return __copy_to_user_asm(from, n, to); 269 + if (__builtin_constant_p(n) && (n <= 256)) 270 + return uaccess.copy_to_user_small(n, to, from); 271 + else 272 + return uaccess.copy_to_user(n, to, from); 218 273 } 219 274 220 275 #define __copy_to_user_inatomic __copy_to_user ··· 245 294 return n; 246 295 } 247 296 248 - extern long __copy_from_user_asm(void *to, long n, const void __user *from); 249 - 250 297 /** 251 298 * __copy_from_user: - Copy a block of data from user space, with less checking. 252 299 * @to: Destination address, in kernel space. ··· 265 316 static inline unsigned long 266 317 __copy_from_user(void *to, const void __user *from, unsigned long n) 267 318 { 268 - return __copy_from_user_asm(to, n, from); 319 + if (__builtin_constant_p(n) && (n <= 256)) 320 + return uaccess.copy_from_user_small(n, from, to); 321 + else 322 + return uaccess.copy_from_user(n, from, to); 269 323 } 270 324 271 325 /** ··· 298 346 return n; 299 347 } 300 348 301 - extern unsigned long __copy_in_user_asm(const void __user *from, long n, 302 - void __user *to); 303 - 304 349 static inline unsigned long 305 350 __copy_in_user(void __user *to, const void __user *from, unsigned long n) 306 351 { 307 - return __copy_in_user_asm(from, n, to); 352 + return uaccess.copy_in_user(n, to, from); 308 353 } 309 354 310 355 static inline unsigned long ··· 309 360 { 310 361 might_sleep(); 311 362 if (__access_ok(from,n) && __access_ok(to,n)) 312 - n = __copy_in_user_asm(from, n, to); 363 + n = __copy_in_user(to, from, n); 313 364 return n; 314 365 } 315 366 316 367 /* 317 368 * Copy a null terminated string from userspace. 318 369 */ 319 - extern long __strncpy_from_user_asm(long count, char *dst, 320 - const char __user *src); 321 - 322 370 static inline long 323 371 strncpy_from_user(char *dst, const char __user *src, long count) 324 372 { 325 373 long res = -EFAULT; 326 374 might_sleep(); 327 375 if (access_ok(VERIFY_READ, src, 1)) 328 - res = __strncpy_from_user_asm(count, dst, src); 376 + res = uaccess.strncpy_from_user(count, src, dst); 329 377 return res; 330 378 } 331 - 332 - 333 - extern long __strnlen_user_asm(long count, const char __user *src); 334 379 335 380 static inline unsigned long 336 381 strnlen_user(const char __user * src, unsigned long n) 337 382 { 338 383 might_sleep(); 339 - return __strnlen_user_asm(n, src); 384 + return uaccess.strnlen_user(n, src); 340 385 } 341 386 342 387 /** ··· 353 410 * Zero Userspace 354 411 */ 355 412 356 - extern long __clear_user_asm(void __user *to, long n); 357 - 358 413 static inline unsigned long 359 414 __clear_user(void __user *to, unsigned long n) 360 415 { 361 - return __clear_user_asm(to, n); 416 + return uaccess.clear_user(n, to); 362 417 } 363 418 364 419 static inline unsigned long ··· 364 423 { 365 424 might_sleep(); 366 425 if (access_ok(VERIFY_WRITE, to, n)) 367 - n = __clear_user_asm(to, n); 426 + n = uaccess.clear_user(n, to); 368 427 return n; 369 428 } 370 429