1/*
2 * __put_user functions.
3 *
4 * (C) Copyright 2005 Linus Torvalds
5 *
6 * These functions have a non-standard call interface
7 * to make them more efficient, especially as they
8 * return an error value in addition to the "real"
9 * return value.
10 */
11#include <linux/linkage.h>
12#include <asm/dwarf2.h>
13#include <asm/thread_info.h>
14
15
16/*
17 * __put_user_X
18 *
19 * Inputs:	%eax[:%edx] contains the data
20 *		%ecx contains the address
21 *
22 * Outputs:	%eax is error code (0 or -EFAULT)
23 *
24 * These functions should not modify any other registers,
25 * as they get called from within inline assembly.
26 */
27
28#define ENTER	CFI_STARTPROC ; \
29		pushl %ebx ; \
30		CFI_ADJUST_CFA_OFFSET 4 ; \
31		CFI_REL_OFFSET ebx, 0 ; \
32		GET_THREAD_INFO(%ebx)
33#define EXIT	popl %ebx ; \
34		CFI_ADJUST_CFA_OFFSET -4 ; \
35		CFI_RESTORE ebx ; \
36		ret ; \
37		CFI_ENDPROC
38
39.text
40ENTRY(__put_user_1)
41	ENTER
42	cmpl TI_addr_limit(%ebx),%ecx
43	jae bad_put_user
441:	movb %al,(%ecx)
45	xorl %eax,%eax
46	EXIT
47ENDPROC(__put_user_1)
48
49ENTRY(__put_user_2)
50	ENTER
51	movl TI_addr_limit(%ebx),%ebx
52	subl $1,%ebx
53	cmpl %ebx,%ecx
54	jae bad_put_user
552:	movw %ax,(%ecx)
56	xorl %eax,%eax
57	EXIT
58ENDPROC(__put_user_2)
59
60ENTRY(__put_user_4)
61	ENTER
62	movl TI_addr_limit(%ebx),%ebx
63	subl $3,%ebx
64	cmpl %ebx,%ecx
65	jae bad_put_user
663:	movl %eax,(%ecx)
67	xorl %eax,%eax
68	EXIT
69ENDPROC(__put_user_4)
70
71ENTRY(__put_user_8)
72	ENTER
73	movl TI_addr_limit(%ebx),%ebx
74	subl $7,%ebx
75	cmpl %ebx,%ecx
76	jae bad_put_user
774:	movl %eax,(%ecx)
785:	movl %edx,4(%ecx)
79	xorl %eax,%eax
80	EXIT
81ENDPROC(__put_user_8)
82
83bad_put_user:
84	CFI_STARTPROC simple
85	CFI_DEF_CFA esp, 2*4
86	CFI_OFFSET eip, -1*4
87	CFI_OFFSET ebx, -2*4
88	movl $-14,%eax
89	EXIT
90END(bad_put_user)
91
92.section __ex_table,"a"
93	.long 1b,bad_put_user
94	.long 2b,bad_put_user
95	.long 3b,bad_put_user
96	.long 4b,bad_put_user
97	.long 5b,bad_put_user
98.previous
99