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