| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *    User Space Access Routines | 
|  | 3 | * | 
|  | 4 | *    Copyright (C) 2000-2002 Hewlett-Packard (John Marvin) | 
|  | 5 | *    Copyright (C) 2000 Richard Hirst <rhirst with parisc-linux.org> | 
|  | 6 | *    Copyright (C) 2001 Matthieu Delahaye <delahaym at esiee.fr> | 
|  | 7 | *    Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org> | 
|  | 8 | * | 
|  | 9 | * | 
|  | 10 | *    This program is free software; you can redistribute it and/or modify | 
|  | 11 | *    it under the terms of the GNU General Public License as published by | 
|  | 12 | *    the Free Software Foundation; either version 2, or (at your option) | 
|  | 13 | *    any later version. | 
|  | 14 | * | 
|  | 15 | *    This program is distributed in the hope that it will be useful, | 
|  | 16 | *    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 17 | *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 18 | *    GNU General Public License for more details. | 
|  | 19 | * | 
|  | 20 | *    You should have received a copy of the GNU General Public License | 
|  | 21 | *    along with this program; if not, write to the Free Software | 
|  | 22 | *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | 23 | */ | 
|  | 24 |  | 
|  | 25 | /* | 
|  | 26 | * These routines still have plenty of room for optimization | 
|  | 27 | * (word & doubleword load/store, dual issue, store hints, etc.). | 
|  | 28 | */ | 
|  | 29 |  | 
|  | 30 | /* | 
|  | 31 | * The following routines assume that space register 3 (sr3) contains | 
|  | 32 | * the space id associated with the current users address space. | 
|  | 33 | */ | 
|  | 34 |  | 
|  | 35 |  | 
| Kyle McMartin | dfcf753 | 2008-05-22 14:36:31 -0400 | [diff] [blame] | 36 | .text | 
|  | 37 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 | #include <asm/assembly.h> | 
|  | 39 | #include <asm/errno.h> | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 40 | #include <linux/linkage.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 41 |  | 
|  | 42 | /* | 
|  | 43 | * get_sr gets the appropriate space value into | 
|  | 44 | * sr1 for kernel/user space access, depending | 
|  | 45 | * on the flag stored in the task structure. | 
|  | 46 | */ | 
|  | 47 |  | 
|  | 48 | .macro  get_sr | 
|  | 49 | mfctl       %cr30,%r1 | 
|  | 50 | ldw         TI_SEGMENT(%r1),%r22 | 
|  | 51 | mfsp        %sr3,%r1 | 
|  | 52 | or,<>       %r22,%r0,%r0 | 
|  | 53 | copy        %r0,%r1 | 
|  | 54 | mtsp        %r1,%sr1 | 
|  | 55 | .endm | 
|  | 56 |  | 
|  | 57 | .macro fixup_branch lbl | 
|  | 58 | ldil	    L%\lbl, %r1 | 
|  | 59 | ldo	    R%\lbl(%r1), %r1 | 
|  | 60 | bv          %r0(%r1) | 
|  | 61 | .endm | 
|  | 62 |  | 
|  | 63 | /* | 
|  | 64 | * long lstrncpy_from_user(char *dst, const char *src, long n) | 
|  | 65 | * | 
|  | 66 | * Returns -EFAULT if exception before terminator, | 
|  | 67 | *         N if the entire buffer filled, | 
|  | 68 | *         otherwise strlen (i.e. excludes zero byte) | 
|  | 69 | */ | 
|  | 70 |  | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 71 | ENTRY(lstrncpy_from_user) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | .proc | 
|  | 73 | .callinfo NO_CALLS | 
|  | 74 | .entry | 
|  | 75 | comib,=     0,%r24,$lsfu_done | 
|  | 76 | copy        %r24,%r23 | 
|  | 77 | get_sr | 
|  | 78 | 1:      ldbs,ma     1(%sr1,%r25),%r1 | 
|  | 79 | $lsfu_loop: | 
|  | 80 | stbs,ma     %r1,1(%r26) | 
|  | 81 | comib,=,n   0,%r1,$lsfu_done | 
|  | 82 | addib,<>,n  -1,%r24,$lsfu_loop | 
|  | 83 | 2:      ldbs,ma     1(%sr1,%r25),%r1 | 
|  | 84 | $lsfu_done: | 
|  | 85 | sub         %r23,%r24,%r28 | 
|  | 86 | $lsfu_exit: | 
|  | 87 | bv          %r0(%r2) | 
|  | 88 | nop | 
|  | 89 | .exit | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 90 | ENDPROC(lstrncpy_from_user) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 |  | 
|  | 92 | .section .fixup,"ax" | 
|  | 93 | 3:      fixup_branch $lsfu_exit | 
|  | 94 | ldi         -EFAULT,%r28 | 
|  | 95 | .previous | 
|  | 96 |  | 
|  | 97 | .section __ex_table,"aw" | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 98 | ASM_ULONG_INSN 1b,3b | 
|  | 99 | ASM_ULONG_INSN 2b,3b | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | .previous | 
|  | 101 |  | 
|  | 102 | .procend | 
|  | 103 |  | 
|  | 104 | /* | 
|  | 105 | * unsigned long lclear_user(void *to, unsigned long n) | 
|  | 106 | * | 
|  | 107 | * Returns 0 for success. | 
|  | 108 | * otherwise, returns number of bytes not transferred. | 
|  | 109 | */ | 
|  | 110 |  | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 111 | ENTRY(lclear_user) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 | .proc | 
|  | 113 | .callinfo NO_CALLS | 
|  | 114 | .entry | 
|  | 115 | comib,=,n   0,%r25,$lclu_done | 
|  | 116 | get_sr | 
|  | 117 | $lclu_loop: | 
|  | 118 | addib,<>    -1,%r25,$lclu_loop | 
|  | 119 | 1:      stbs,ma     %r0,1(%sr1,%r26) | 
|  | 120 |  | 
|  | 121 | $lclu_done: | 
|  | 122 | bv          %r0(%r2) | 
|  | 123 | copy        %r25,%r28 | 
|  | 124 | .exit | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 125 | ENDPROC(lclear_user) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 |  | 
|  | 127 | .section .fixup,"ax" | 
|  | 128 | 2:      fixup_branch $lclu_done | 
|  | 129 | ldo        1(%r25),%r25 | 
|  | 130 | .previous | 
|  | 131 |  | 
|  | 132 | .section __ex_table,"aw" | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 133 | ASM_ULONG_INSN 1b,2b | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 | .previous | 
|  | 135 |  | 
|  | 136 | .procend | 
|  | 137 |  | 
|  | 138 | /* | 
|  | 139 | * long lstrnlen_user(char *s, long n) | 
|  | 140 | * | 
|  | 141 | * Returns 0 if exception before zero byte or reaching N, | 
|  | 142 | *         N+1 if N would be exceeded, | 
|  | 143 | *         else strlen + 1 (i.e. includes zero byte). | 
|  | 144 | */ | 
|  | 145 |  | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 146 | ENTRY(lstrnlen_user) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | .proc | 
|  | 148 | .callinfo NO_CALLS | 
|  | 149 | .entry | 
|  | 150 | comib,=     0,%r25,$lslen_nzero | 
|  | 151 | copy	    %r26,%r24 | 
|  | 152 | get_sr | 
|  | 153 | 1:      ldbs,ma     1(%sr1,%r26),%r1 | 
|  | 154 | $lslen_loop: | 
|  | 155 | comib,=,n   0,%r1,$lslen_done | 
|  | 156 | addib,<>    -1,%r25,$lslen_loop | 
|  | 157 | 2:      ldbs,ma     1(%sr1,%r26),%r1 | 
|  | 158 | $lslen_done: | 
|  | 159 | bv          %r0(%r2) | 
|  | 160 | sub	    %r26,%r24,%r28 | 
|  | 161 | .exit | 
|  | 162 |  | 
|  | 163 | $lslen_nzero: | 
|  | 164 | b           $lslen_done | 
|  | 165 | ldo         1(%r26),%r26 /* special case for N == 0 */ | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 166 | ENDPROC(lstrnlen_user) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 |  | 
|  | 168 | .section .fixup,"ax" | 
|  | 169 | 3:      fixup_branch $lslen_done | 
|  | 170 | copy        %r24,%r26    /* reset r26 so 0 is returned on fault */ | 
|  | 171 | .previous | 
|  | 172 |  | 
|  | 173 | .section __ex_table,"aw" | 
| Helge Deller | 0b3d643 | 2007-01-28 14:52:57 +0100 | [diff] [blame] | 174 | ASM_ULONG_INSN 1b,3b | 
|  | 175 | ASM_ULONG_INSN 2b,3b | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 176 | .previous | 
|  | 177 |  | 
|  | 178 | .procend | 
|  | 179 |  | 
|  | 180 | .end |