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

ENTRY(__get_user_1)
	check_uaccess r0, 1, r1, r2, __get_user_bad
1: TUSER(ldrb)	r2, [r0]
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_1)
_ASM_NOKPROBE(__get_user_1)

ENTRY(__get_user_2)
	check_uaccess r0, 2, r1, r2, __get_user_bad
#if __LINUX_ARM_ARCH__ >= 6

2: TUSER(ldrh)	r2, [r0]

#else

#ifdef CONFIG_CPU_USE_DOMAINS
rb	.req	ip
2:	ldrbt	r2, [r0], #1
3:	ldrbt	rb, [r0], #0
#else
rb	.req	r0
2:	ldrb	r2, [r0]
3:	ldrb	rb, [r0, #1]
#endif
#ifndef __ARMEB__
	orr	r2, r2, rb, lsl #8
#else
	orr	r2, rb, r2, lsl #8
#endif

#endif /* __LINUX_ARM_ARCH__ >= 6 */

	mov	r0, #0
	ret	lr
ENDPROC(__get_user_2)
_ASM_NOKPROBE(__get_user_2)

ENTRY(__get_user_4)
	check_uaccess r0, 4, r1, r2, __get_user_bad
4: TUSER(ldr)	r2, [r0]
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_4)
_ASM_NOKPROBE(__get_user_4)

ENTRY(__get_user_8)
	check_uaccess r0, 8, r1, r2, __get_user_bad8
#ifdef CONFIG_THUMB2_KERNEL
5: TUSER(ldr)	r2, [r0]
6: TUSER(ldr)	r3, [r0, #4]
#else
5: TUSER(ldr)	r2, [r0], #4
6: TUSER(ldr)	r3, [r0]
#endif
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_8)
_ASM_NOKPROBE(__get_user_8)

#ifdef __ARMEB__
ENTRY(__get_user_32t_8)
	check_uaccess r0, 8, r1, r2, __get_user_bad
#ifdef CONFIG_CPU_USE_DOMAINS
	add	r0, r0, #4
7:	ldrt	r2, [r0]
#else
7:	ldr	r2, [r0, #4]
#endif
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_32t_8)
_ASM_NOKPROBE(__get_user_32t_8)

ENTRY(__get_user_64t_1)
	check_uaccess r0, 1, r1, r2, __get_user_bad8
8: TUSER(ldrb)	r3, [r0]
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_64t_1)
_ASM_NOKPROBE(__get_user_64t_1)

ENTRY(__get_user_64t_2)
	check_uaccess r0, 2, r1, r2, __get_user_bad8
#ifdef CONFIG_CPU_USE_DOMAINS
rb	.req	ip
9:	ldrbt	r3, [r0], #1
10:	ldrbt	rb, [r0], #0
#else
rb	.req	r0
9:	ldrb	r3, [r0]
10:	ldrb	rb, [r0, #1]
#endif
	orr	r3, rb, r3, lsl #8
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_64t_2)
_ASM_NOKPROBE(__get_user_64t_2)

ENTRY(__get_user_64t_4)
	check_uaccess r0, 4, r1, r2, __get_user_bad8
11: TUSER(ldr)	r3, [r0]
	mov	r0, #0
	ret	lr
ENDPROC(__get_user_64t_4)
_ASM_NOKPROBE(__get_user_64t_4)
#endif

__get_user_bad8:
	mov	r3, #0
__get_user_bad:
	mov	r2, #0
	mov	r0, #-EFAULT
	ret	lr
ENDPROC(__get_user_bad)
ENDPROC(__get_user_bad8)
_ASM_NOKPROBE(__get_user_bad)
_ASM_NOKPROBE(__get_user_bad8)

.pushsection __ex_table, "a"
	.long	1b, __get_user_bad
	.long	2b, __get_user_bad
#if __LINUX_ARM_ARCH__ < 6
	.long	3b, __get_user_bad
#endif
	.long	4b, __get_user_bad
	.long	5b, __get_user_bad8
	.long	6b, __get_user_bad8
#ifdef __ARMEB__
	.long   7b, __get_user_bad
	.long	8b, __get_user_bad8
	.long	9b, __get_user_bad8
	.long	10b, __get_user_bad8
	.long	11b, __get_user_bad8
#endif
.popsection