Root/
1 | /* |
2 | * Copyright 2011 Tilera Corporation. All Rights Reserved. |
3 | * |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation, version 2. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, but |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or |
11 | * NON INFRINGEMENT. See the GNU General Public License for |
12 | * more details. |
13 | */ |
14 | |
15 | #include <linux/linkage.h> |
16 | #include <asm/errno.h> |
17 | #include <asm/cache.h> |
18 | #include <arch/chip.h> |
19 | |
20 | /* Access user memory, but use MMU to avoid propagating kernel exceptions. */ |
21 | |
22 | /* |
23 | * strnlen_user_asm takes the pointer in r0, and the length bound in r1. |
24 | * It returns the length, including the terminating NUL, or zero on exception. |
25 | * If length is greater than the bound, returns one plus the bound. |
26 | */ |
27 | STD_ENTRY(strnlen_user_asm) |
28 | { beqz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */ |
29 | 1: { ld1u r4, r0; addi r1, r1, -1 } |
30 | beqz r4, 2f |
31 | { bnezt r1, 1b; addi r0, r0, 1 } |
32 | 2: { sub r0, r0, r3; jrp lr } |
33 | STD_ENDPROC(strnlen_user_asm) |
34 | .pushsection .fixup,"ax" |
35 | strnlen_user_fault: |
36 | { move r0, zero; jrp lr } |
37 | ENDPROC(strnlen_user_fault) |
38 | .section __ex_table,"a" |
39 | .quad 1b, strnlen_user_fault |
40 | .popsection |
41 | |
42 | /* |
43 | * strncpy_from_user_asm takes the kernel target pointer in r0, |
44 | * the userspace source pointer in r1, and the length bound (including |
45 | * the trailing NUL) in r2. On success, it returns the string length |
46 | * (not including the trailing NUL), or -EFAULT on failure. |
47 | */ |
48 | STD_ENTRY(strncpy_from_user_asm) |
49 | { beqz r2, 2f; move r3, r0 } |
50 | 1: { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } |
51 | { st1 r0, r4; addi r0, r0, 1 } |
52 | beqz r2, 2f |
53 | bnezt r4, 1b |
54 | addi r0, r0, -1 /* don't count the trailing NUL */ |
55 | 2: { sub r0, r0, r3; jrp lr } |
56 | STD_ENDPROC(strncpy_from_user_asm) |
57 | .pushsection .fixup,"ax" |
58 | strncpy_from_user_fault: |
59 | { movei r0, -EFAULT; jrp lr } |
60 | ENDPROC(strncpy_from_user_fault) |
61 | .section __ex_table,"a" |
62 | .quad 1b, strncpy_from_user_fault |
63 | .popsection |
64 | |
65 | /* |
66 | * clear_user_asm takes the user target address in r0 and the |
67 | * number of bytes to zero in r1. |
68 | * It returns the number of uncopiable bytes (hopefully zero) in r0. |
69 | * Note that we don't use a separate .fixup section here since we fall |
70 | * through into the "fixup" code as the last straight-line bundle anyway. |
71 | */ |
72 | STD_ENTRY(clear_user_asm) |
73 | { beqz r1, 2f; or r2, r0, r1 } |
74 | andi r2, r2, 7 |
75 | beqzt r2, .Lclear_aligned_user_asm |
76 | 1: { st1 r0, zero; addi r0, r0, 1; addi r1, r1, -1 } |
77 | bnezt r1, 1b |
78 | 2: { move r0, r1; jrp lr } |
79 | .pushsection __ex_table,"a" |
80 | .quad 1b, 2b |
81 | .popsection |
82 | |
83 | .Lclear_aligned_user_asm: |
84 | 1: { st r0, zero; addi r0, r0, 8; addi r1, r1, -8 } |
85 | bnezt r1, 1b |
86 | 2: { move r0, r1; jrp lr } |
87 | STD_ENDPROC(clear_user_asm) |
88 | .pushsection __ex_table,"a" |
89 | .quad 1b, 2b |
90 | .popsection |
91 | |
92 | /* |
93 | * flush_user_asm takes the user target address in r0 and the |
94 | * number of bytes to flush in r1. |
95 | * It returns the number of unflushable bytes (hopefully zero) in r0. |
96 | */ |
97 | STD_ENTRY(flush_user_asm) |
98 | beqz r1, 2f |
99 | { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } |
100 | { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } |
101 | { and r0, r0, r2; and r1, r1, r2 } |
102 | { sub r1, r1, r0 } |
103 | 1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() } |
104 | { addi r0, r0, CHIP_FLUSH_STRIDE(); bnezt r1, 1b } |
105 | 2: { move r0, r1; jrp lr } |
106 | STD_ENDPROC(flush_user_asm) |
107 | .pushsection __ex_table,"a" |
108 | .quad 1b, 2b |
109 | .popsection |
110 | |
111 | /* |
112 | * inv_user_asm takes the user target address in r0 and the |
113 | * number of bytes to invalidate in r1. |
114 | * It returns the number of not inv'able bytes (hopefully zero) in r0. |
115 | */ |
116 | STD_ENTRY(inv_user_asm) |
117 | beqz r1, 2f |
118 | { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } |
119 | { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } |
120 | { and r0, r0, r2; and r1, r1, r2 } |
121 | { sub r1, r1, r0 } |
122 | 1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() } |
123 | { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b } |
124 | 2: { move r0, r1; jrp lr } |
125 | STD_ENDPROC(inv_user_asm) |
126 | .pushsection __ex_table,"a" |
127 | .quad 1b, 2b |
128 | .popsection |
129 | |
130 | /* |
131 | * finv_user_asm takes the user target address in r0 and the |
132 | * number of bytes to flush-invalidate in r1. |
133 | * It returns the number of not finv'able bytes (hopefully zero) in r0. |
134 | */ |
135 | STD_ENTRY(finv_user_asm) |
136 | beqz r1, 2f |
137 | { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } |
138 | { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } |
139 | { and r0, r0, r2; and r1, r1, r2 } |
140 | { sub r1, r1, r0 } |
141 | 1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() } |
142 | { addi r0, r0, CHIP_FINV_STRIDE(); bnezt r1, 1b } |
143 | 2: { move r0, r1; jrp lr } |
144 | STD_ENDPROC(finv_user_asm) |
145 | .pushsection __ex_table,"a" |
146 | .quad 1b, 2b |
147 | .popsection |
148 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9