1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * linux/arch/arm/lib/getuser.S |
4 | * |
5 | * Copyright (C) 2001 Russell King |
6 | * |
7 | * Idea from x86 version, (C) Copyright 1998 Linus Torvalds |
8 | * |
9 | * These functions have a non-standard call interface to make them more |
10 | * efficient, especially as they return an error value in addition to |
11 | * the "real" return value. |
12 | * |
13 | * __get_user_X |
14 | * |
15 | * Inputs: r0 contains the address |
16 | * r1 contains the address limit, which must be preserved |
17 | * Outputs: r0 is the error code |
18 | * r2, r3 contains the zero-extended value |
19 | * lr corrupted |
20 | * |
21 | * No other registers must be altered. (see <asm/uaccess.h> |
22 | * for specific ASM register usage). |
23 | * |
24 | * Note that ADDR_LIMIT is either 0 or 0xc0000000. |
25 | * Note also that it is intended that __get_user_bad is not global. |
26 | */ |
27 | #include <linux/linkage.h> |
28 | #include <asm/assembler.h> |
29 | #include <asm/errno.h> |
30 | #include <asm/domain.h> |
31 | |
32 | ENTRY(__get_user_1) |
33 | check_uaccess r0, 1, r1, r2, __get_user_bad |
34 | 1: TUSER(ldrb) r2, [r0] |
35 | mov r0, #0 |
36 | ret lr |
37 | ENDPROC(__get_user_1) |
38 | _ASM_NOKPROBE(__get_user_1) |
39 | |
40 | ENTRY(__get_user_2) |
41 | check_uaccess r0, 2, r1, r2, __get_user_bad |
42 | #if __LINUX_ARM_ARCH__ >= 6 |
43 | |
44 | 2: TUSER(ldrh) r2, [r0] |
45 | |
46 | #else |
47 | |
48 | #ifdef CONFIG_CPU_USE_DOMAINS |
49 | rb .req ip |
50 | 2: ldrbt r2, [r0], #1 |
51 | 3: ldrbt rb, [r0], #0 |
52 | #else |
53 | rb .req r0 |
54 | 2: ldrb r2, [r0] |
55 | 3: ldrb rb, [r0, #1] |
56 | #endif |
57 | #ifndef __ARMEB__ |
58 | orr r2, r2, rb, lsl #8 |
59 | #else |
60 | orr r2, rb, r2, lsl #8 |
61 | #endif |
62 | |
63 | #endif /* __LINUX_ARM_ARCH__ >= 6 */ |
64 | |
65 | mov r0, #0 |
66 | ret lr |
67 | ENDPROC(__get_user_2) |
68 | _ASM_NOKPROBE(__get_user_2) |
69 | |
70 | ENTRY(__get_user_4) |
71 | check_uaccess r0, 4, r1, r2, __get_user_bad |
72 | 4: TUSER(ldr) r2, [r0] |
73 | mov r0, #0 |
74 | ret lr |
75 | ENDPROC(__get_user_4) |
76 | _ASM_NOKPROBE(__get_user_4) |
77 | |
78 | ENTRY(__get_user_8) |
79 | check_uaccess r0, 8, r1, r2, __get_user_bad8 |
80 | #ifdef CONFIG_THUMB2_KERNEL |
81 | 5: TUSER(ldr) r2, [r0] |
82 | 6: TUSER(ldr) r3, [r0, #4] |
83 | #else |
84 | 5: TUSER(ldr) r2, [r0], #4 |
85 | 6: TUSER(ldr) r3, [r0] |
86 | #endif |
87 | mov r0, #0 |
88 | ret lr |
89 | ENDPROC(__get_user_8) |
90 | _ASM_NOKPROBE(__get_user_8) |
91 | |
92 | #ifdef __ARMEB__ |
93 | ENTRY(__get_user_32t_8) |
94 | check_uaccess r0, 8, r1, r2, __get_user_bad |
95 | #ifdef CONFIG_CPU_USE_DOMAINS |
96 | add r0, r0, #4 |
97 | 7: ldrt r2, [r0] |
98 | #else |
99 | 7: ldr r2, [r0, #4] |
100 | #endif |
101 | mov r0, #0 |
102 | ret lr |
103 | ENDPROC(__get_user_32t_8) |
104 | _ASM_NOKPROBE(__get_user_32t_8) |
105 | |
106 | ENTRY(__get_user_64t_1) |
107 | check_uaccess r0, 1, r1, r2, __get_user_bad8 |
108 | 8: TUSER(ldrb) r3, [r0] |
109 | mov r0, #0 |
110 | ret lr |
111 | ENDPROC(__get_user_64t_1) |
112 | _ASM_NOKPROBE(__get_user_64t_1) |
113 | |
114 | ENTRY(__get_user_64t_2) |
115 | check_uaccess r0, 2, r1, r2, __get_user_bad8 |
116 | #ifdef CONFIG_CPU_USE_DOMAINS |
117 | rb .req ip |
118 | 9: ldrbt r3, [r0], #1 |
119 | 10: ldrbt rb, [r0], #0 |
120 | #else |
121 | rb .req r0 |
122 | 9: ldrb r3, [r0] |
123 | 10: ldrb rb, [r0, #1] |
124 | #endif |
125 | orr r3, rb, r3, lsl #8 |
126 | mov r0, #0 |
127 | ret lr |
128 | ENDPROC(__get_user_64t_2) |
129 | _ASM_NOKPROBE(__get_user_64t_2) |
130 | |
131 | ENTRY(__get_user_64t_4) |
132 | check_uaccess r0, 4, r1, r2, __get_user_bad8 |
133 | 11: TUSER(ldr) r3, [r0] |
134 | mov r0, #0 |
135 | ret lr |
136 | ENDPROC(__get_user_64t_4) |
137 | _ASM_NOKPROBE(__get_user_64t_4) |
138 | #endif |
139 | |
140 | __get_user_bad8: |
141 | mov r3, #0 |
142 | __get_user_bad: |
143 | mov r2, #0 |
144 | mov r0, #-EFAULT |
145 | ret lr |
146 | ENDPROC(__get_user_bad) |
147 | ENDPROC(__get_user_bad8) |
148 | _ASM_NOKPROBE(__get_user_bad) |
149 | _ASM_NOKPROBE(__get_user_bad8) |
150 | |
151 | .pushsection __ex_table, "a" |
152 | .long 1b, __get_user_bad |
153 | .long 2b, __get_user_bad |
154 | #if __LINUX_ARM_ARCH__ < 6 |
155 | .long 3b, __get_user_bad |
156 | #endif |
157 | .long 4b, __get_user_bad |
158 | .long 5b, __get_user_bad8 |
159 | .long 6b, __get_user_bad8 |
160 | #ifdef __ARMEB__ |
161 | .long 7b, __get_user_bad |
162 | .long 8b, __get_user_bad8 |
163 | .long 9b, __get_user_bad8 |
164 | .long 10b, __get_user_bad8 |
165 | .long 11b, __get_user_bad8 |
166 | #endif |
167 | .popsection |
168 | |