1/* 2 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 3 * 4 * Assembly Language User Access Routines 5 * Copyright (C) 2000 Hewlett-Packard (John Marvin) 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22/* 23 * These routines still have plenty of room for optimization 24 * (word & doubleword load/store, dual issue, store hints, etc.). 25 */ 26 27/* 28 * The following routines assume that space register 3 (sr3) contains 29 * the space id associated with the current users address space. 30 */ 31 32 33 .text 34 35#include <asm/assembly.h> 36#include <asm/errno.h> 37 38 /* 39 * get_sr gets the appropriate space value into 40 * sr1 for kernel/user space access, depending 41 * on the flag stored in the task structure. 42 */ 43 44 .macro get_sr 45 mfctl %cr30,%r1 46 ldw TASK_SEGMENT(%r1),%r22 47 mfsp %sr3,%r1 48 or,<> %r22,%r0,%r0 49 copy %r0,%r1 50 mtsp %r1,%sr1 51 .endm 52 53 /* 54 * unsigned long 55 * lcopy_to_user(void *to, const void *from, unsigned long n) 56 * 57 * Returns 0 for success. 58 * otherwise, returns number of bytes not transferred. 59 */ 60 61 .export lcopy_to_user,code 62lcopy_to_user: 63 .proc 64 .callinfo NO_CALLS 65 .entry 66 comib,=,n 0,%r24,$lctu_done 67 get_sr 68$lctu_loop: 69 ldbs,ma 1(%r25),%r1 70 addib,<> -1,%r24,$lctu_loop 711: stbs,ma %r1,1(%sr1,%r26) 72$lctu_done: 73 bv %r0(%r2) 74 copy %r24,%r28 75 .exit 76 772: b $lctu_done 78 ldo 1(%r24),%r24 79 80 .section __ex_table,"a" 81#ifdef __LP64__ 82 .dword 1b,(2b-1b) 83#else 84 .word 1b,(2b-1b) 85#endif 86 .previous 87 88 .procend 89 90 /* 91 * unsigned long 92 * lcopy_from_user(void *to, const void *from, unsigned long n) 93 * 94 * Returns 0 for success. 95 * otherwise, returns number of bytes not transferred. 96 * 97 * NOTE: This routine will also zero any bytes in the 98 * destination that were not copied due to a fault. 99 * 100 */ 101 102 .export lcopy_from_user,code 103lcopy_from_user: 104 .proc 105 .callinfo NO_CALLS 106 .entry 107 comib,=,n 0,%r24,$lcfu_done 108 get_sr 109$lcfu_loop: 1101: ldbs,ma 1(%sr1,%r25),%r1 111 addib,<> -1,%r24,$lcfu_loop 112 stbs,ma %r1,1(%r26) 113$lcfu_done: 114 bv %r0(%r2) 115 copy %r24,%r28 116 .exit 117 1182: copy %r24,%r23 119$lcfu_zero_loop: 120 addib,<> -1,%r23,$lcfu_zero_loop 121 stbs,ma %r0,1(%r26) 122 b $lcfu_done 123 nop 124 125 .section __ex_table,"a" 126#ifdef __LP64__ 127 .dword 1b,(2b-1b) 128#else 129 .word 1b,(2b-1b) 130#endif 131 .previous 132 133 .procend 134 135 /* 136 * long lstrncpy_from_user(char *dst, const char *src, long n) 137 * 138 * Returns -EFAULT if exception before terminator, 139 * N if the entire buffer filled, 140 * otherwise strlen (i.e. excludes zero byte) 141 */ 142 143 .export lstrncpy_from_user,code 144lstrncpy_from_user: 145 .proc 146 .callinfo NO_CALLS 147 .entry 148 comib,= 0,%r24,$lsfu_done 149 copy %r24,%r23 150 get_sr 1511: ldbs,ma 1(%sr1,%r25),%r1 152$lsfu_loop: 153 stbs,ma %r1,1(%r26) 154 comib,=,n 0,%r1,$lsfu_done 155 addib,<>,n -1,%r24,$lsfu_loop 1562: ldbs,ma 1(%sr1,%r25),%r1 157$lsfu_done: 158 sub %r23,%r24,%r28 159$lsfu_exit: 160 bv %r0(%r2) 161 nop 162 .exit 163 1643: b $lsfu_exit 165 ldi -EFAULT,%r28 166 167 .section __ex_table,"a" 168#ifdef __LP64__ 169 .dword 1b,(3b-1b) 170 .dword 2b,(3b-2b) 171#else 172 .word 1b,(3b-1b) 173 .word 2b,(3b-2b) 174#endif 175 .previous 176 177 .procend 178 179 /* 180 * unsigned long lclear_user(void *to, unsigned long n) 181 * 182 * Returns 0 for success. 183 * otherwise, returns number of bytes not transferred. 184 */ 185 186 .export lclear_user,code 187lclear_user: 188 .proc 189 .callinfo NO_CALLS 190 .entry 191 comib,=,n 0,%r25,$lclu_done 192 get_sr 193$lclu_loop: 194 addib,<> -1,%r25,$lclu_loop 1951: stbs,ma %r0,1(%sr1,%r26) 196 197$lclu_done: 198 bv %r0(%r2) 199 copy %r25,%r28 200 .exit 201 2022: b $lclu_done 203 ldo 1(%r25),%r25 204 205 .section __ex_table,"a" 206#ifdef __LP64__ 207 .dword 1b,(2b-1b) 208#else 209 .word 1b,(2b-1b) 210#endif 211 .previous 212 213 .procend 214 215 /* 216 * long lstrnlen_user(char *s, long n) 217 * 218 * Returns 0 if exception before zero byte or reaching N, 219 * N+1 if N would be exceeded, 220 * else strlen + 1 (i.e. includes zero byte). 221 */ 222 223 .export lstrnlen_user,code 224lstrnlen_user: 225 .proc 226 .callinfo NO_CALLS 227 .entry 228 comib,= 0,%r25,$lslen_nzero 229 copy %r26,%r24 230 get_sr 2311: ldbs,ma 1(%sr1,%r26),%r1 232$lslen_loop: 233 comib,=,n 0,%r1,$lslen_done 234 addib,<> -1,%r25,$lslen_loop 2352: ldbs,ma 1(%sr1,%r26),%r1 236$lslen_done: 237 bv %r0(%r2) 238 sub %r26,%r24,%r28 239 .exit 240 241$lslen_nzero: 242 b $lslen_done 243 ldo 1(%r26),%r26 /* special case for N == 0 */ 244 2453: b $lslen_done 246 copy %r24,%r26 /* reset r26 so 0 is returned on fault */ 247 248 .section __ex_table,"a" 249#ifdef __LP64__ 250 .dword 1b,(3b-1b) 251 .dword 2b,(3b-2b) 252#else 253 .word 1b,(3b-1b) 254 .word 2b,(3b-2b) 255#endif 256 .previous 257 258 .procend 259 260 .end 261