getuser.S 3.0 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
L
Linus Torvalds 已提交
2 3 4 5 6
/*
 * __get_user functions.
 *
 * (C) Copyright 1998 Linus Torvalds
 * (C) Copyright 2005 Andi Kleen
7
 * (C) Copyright 2008 Glauber Costa
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17
 *
 * 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
 *
18
 * Inputs:	%[r|e]ax contains the address.
L
Linus Torvalds 已提交
19
 *
20 21
 * Outputs:	%[r|e]ax is error code (0 or -EFAULT)
 *		%[r|e]dx contains zero-extended value
22
 *		%ecx contains the high half for 32-bit __get_user_8
23
 *
L
Linus Torvalds 已提交
24 25 26 27 28 29
 *
 * These functions should not modify any other registers,
 * as they get called from within inline assembly.
 */

#include <linux/linkage.h>
30
#include <asm/page_types.h>
L
Linus Torvalds 已提交
31
#include <asm/errno.h>
32
#include <asm/asm-offsets.h>
L
Linus Torvalds 已提交
33
#include <asm/thread_info.h>
G
Glauber Costa 已提交
34
#include <asm/asm.h>
35
#include <asm/smap.h>
36
#include <asm/export.h>
L
Linus Torvalds 已提交
37 38

	.text
39
ENTRY(__get_user_1)
40 41
	mov PER_CPU_VAR(current_task), %_ASM_DX
	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
L
Linus Torvalds 已提交
42
	jae bad_get_user
43 44
	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
	and %_ASM_DX, %_ASM_AX
45
	ASM_STAC
46
1:	movzbl (%_ASM_AX),%edx
47
	xor %eax,%eax
48
	ASM_CLAC
L
Linus Torvalds 已提交
49
	ret
50
ENDPROC(__get_user_1)
51
EXPORT_SYMBOL(__get_user_1)
L
Linus Torvalds 已提交
52

53
ENTRY(__get_user_2)
G
Glauber Costa 已提交
54
	add $1,%_ASM_AX
55
	jc bad_get_user
56 57
	mov PER_CPU_VAR(current_task), %_ASM_DX
	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
58
	jae bad_get_user
59 60
	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
	and %_ASM_DX, %_ASM_AX
61
	ASM_STAC
G
Glauber Costa 已提交
62
2:	movzwl -1(%_ASM_AX),%edx
63
	xor %eax,%eax
64
	ASM_CLAC
L
Linus Torvalds 已提交
65
	ret
66
ENDPROC(__get_user_2)
67
EXPORT_SYMBOL(__get_user_2)
L
Linus Torvalds 已提交
68

69
ENTRY(__get_user_4)
G
Glauber Costa 已提交
70
	add $3,%_ASM_AX
71
	jc bad_get_user
72 73
	mov PER_CPU_VAR(current_task), %_ASM_DX
	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
74
	jae bad_get_user
75 76
	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
	and %_ASM_DX, %_ASM_AX
77
	ASM_STAC
78
3:	movl -3(%_ASM_AX),%edx
79
	xor %eax,%eax
80
	ASM_CLAC
L
Linus Torvalds 已提交
81
	ret
82
ENDPROC(__get_user_4)
83
EXPORT_SYMBOL(__get_user_4)
L
Linus Torvalds 已提交
84

85
ENTRY(__get_user_8)
86
#ifdef CONFIG_X86_64
G
Glauber Costa 已提交
87
	add $7,%_ASM_AX
88
	jc bad_get_user
89 90
	mov PER_CPU_VAR(current_task), %_ASM_DX
	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
91
	jae bad_get_user
92 93
	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
	and %_ASM_DX, %_ASM_AX
94
	ASM_STAC
95
4:	movq -7(%_ASM_AX),%rdx
96
	xor %eax,%eax
97
	ASM_CLAC
L
Linus Torvalds 已提交
98
	ret
99 100 101
#else
	add $7,%_ASM_AX
	jc bad_get_user_8
102 103
	mov PER_CPU_VAR(current_task), %_ASM_DX
	cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
104
	jae bad_get_user_8
105 106
	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
	and %_ASM_DX, %_ASM_AX
107
	ASM_STAC
108 109
4:	movl -7(%_ASM_AX),%edx
5:	movl -3(%_ASM_AX),%ecx
110 111 112 113
	xor %eax,%eax
	ASM_CLAC
	ret
#endif
114
ENDPROC(__get_user_8)
115
EXPORT_SYMBOL(__get_user_8)
116

L
Linus Torvalds 已提交
117 118

bad_get_user:
119
	xor %edx,%edx
G
Glauber Costa 已提交
120
	mov $(-EFAULT),%_ASM_AX
121
	ASM_CLAC
L
Linus Torvalds 已提交
122
	ret
123
END(bad_get_user)
L
Linus Torvalds 已提交
124

125 126 127 128 129 130 131 132 133 134
#ifdef CONFIG_X86_32
bad_get_user_8:
	xor %edx,%edx
	xor %ecx,%ecx
	mov $(-EFAULT),%_ASM_AX
	ASM_CLAC
	ret
END(bad_get_user_8)
#endif

135 136 137
	_ASM_EXTABLE(1b,bad_get_user)
	_ASM_EXTABLE(2b,bad_get_user)
	_ASM_EXTABLE(3b,bad_get_user)
138
#ifdef CONFIG_X86_64
139
	_ASM_EXTABLE(4b,bad_get_user)
140 141 142
#else
	_ASM_EXTABLE(4b,bad_get_user_8)
	_ASM_EXTABLE(5b,bad_get_user_8)
143
#endif