1/*
2 * __get_user functions.
3 *
4 * (C) Copyright 1998 Linus Torvalds
5 * (C) Copyright 2005 Andi Kleen
6 *
7 * These functions have a non-standard call interface
8 * to make them more efficient, especially as they
9 * return an error value in addition to the "real"
10 * return value.
11 */
12
13/*
14 * __get_user_X
15 *
16 * Inputs:	%rcx contains the address.
17 *		The register is modified, but all changes are undone
18 *		before returning because the C code doesn't know about it.
19 *
20 * Outputs:	%rax is error code (0 or -EFAULT)
21 *		%rdx contains zero-extended value
22 *
23 * %r8 is destroyed.
24 *
25 * These functions should not modify any other registers,
26 * as they get called from within inline assembly.
27 */
28
29#include <linux/linkage.h>
30#include <asm/dwarf2.h>
31#include <asm/page.h>
32#include <asm/errno.h>
33#include <asm/asm-offsets.h>
34#include <asm/thread_info.h>
35
36	.text
37ENTRY(__get_user_1)
38	CFI_STARTPROC
39	GET_THREAD_INFO(%r8)
40	cmpq threadinfo_addr_limit(%r8),%rcx
41	jae bad_get_user
421:	movzb (%rcx),%edx
43	xorl %eax,%eax
44	ret
45	CFI_ENDPROC
46ENDPROC(__get_user_1)
47
48ENTRY(__get_user_2)
49	CFI_STARTPROC
50	GET_THREAD_INFO(%r8)
51	addq $1,%rcx
52	jc 20f
53	cmpq threadinfo_addr_limit(%r8),%rcx
54	jae 20f
55	decq   %rcx
562:	movzwl (%rcx),%edx
57	xorl %eax,%eax
58	ret
5920:	decq    %rcx
60	jmp	bad_get_user
61	CFI_ENDPROC
62ENDPROC(__get_user_2)
63
64ENTRY(__get_user_4)
65	CFI_STARTPROC
66	GET_THREAD_INFO(%r8)
67	addq $3,%rcx
68	jc 30f
69	cmpq threadinfo_addr_limit(%r8),%rcx
70	jae 30f
71	subq $3,%rcx
723:	movl (%rcx),%edx
73	xorl %eax,%eax
74	ret
7530:	subq $3,%rcx
76	jmp bad_get_user
77	CFI_ENDPROC
78ENDPROC(__get_user_4)
79
80ENTRY(__get_user_8)
81	CFI_STARTPROC
82	GET_THREAD_INFO(%r8)
83	addq $7,%rcx
84	jc 40f
85	cmpq threadinfo_addr_limit(%r8),%rcx
86	jae	40f
87	subq	$7,%rcx
884:	movq (%rcx),%rdx
89	xorl %eax,%eax
90	ret
9140:	subq $7,%rcx
92	jmp bad_get_user
93	CFI_ENDPROC
94ENDPROC(__get_user_8)
95
96bad_get_user:
97	CFI_STARTPROC
98	xorl %edx,%edx
99	movq $(-EFAULT),%rax
100	ret
101	CFI_ENDPROC
102END(bad_get_user)
103
104.section __ex_table,"a"
105	.quad 1b,bad_get_user
106	.quad 2b,bad_get_user
107	.quad 3b,bad_get_user
108	.quad 4b,bad_get_user
109.previous
110