11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * __put_user functions.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2005 Linus Torvalds
55cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa * (C) Copyright 2005 Andi Kleen
65cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa * (C) Copyright 2008 Glauber Costa
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These functions have a non-standard call interface
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to make them more efficient, especially as they
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return an error value in addition to the "real"
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return value.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1300e065ea587363e538d9624eea8cacad12cb7397Jan Beulich#include <linux/linkage.h>
1400e065ea587363e538d9624eea8cacad12cb7397Jan Beulich#include <asm/dwarf2.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/thread_info.h>
165cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa#include <asm/errno.h>
172528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa#include <asm/asm.h>
1863bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin#include <asm/smap.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * __put_user_X
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Inputs:	%eax[:%edx] contains the data
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		%ecx contains the address
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Outputs:	%eax is error code (0 or -EFAULT)
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These functions should not modify any other registers,
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as they get called from within inline assembly.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3300e065ea587363e538d9624eea8cacad12cb7397Jan Beulich#define ENTER	CFI_STARTPROC ; \
342528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa		GET_THREAD_INFO(%_ASM_BX)
3563bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin#define EXIT	ASM_CLAC ;	\
3663bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin		ret ;		\
3700e065ea587363e538d9624eea8cacad12cb7397Jan Beulich		CFI_ENDPROC
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds.text
4000e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENTRY(__put_user_1)
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ENTER
422528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	cmp TI_addr_limit(%_ASM_BX),%_ASM_CX
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jae bad_put_user
4463bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin	ASM_STAC
452528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa1:	movb %al,(%_ASM_CX)
46efea505d83873cfc8a7cdbb8a2a11d2c67467843Glauber Costa	xor %eax,%eax
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXIT
4800e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENDPROC(__put_user_1)
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5000e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENTRY(__put_user_2)
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ENTER
522528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	mov TI_addr_limit(%_ASM_BX),%_ASM_BX
532528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	sub $1,%_ASM_BX
542528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	cmp %_ASM_BX,%_ASM_CX
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jae bad_put_user
5663bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin	ASM_STAC
572528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa2:	movw %ax,(%_ASM_CX)
58efea505d83873cfc8a7cdbb8a2a11d2c67467843Glauber Costa	xor %eax,%eax
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXIT
6000e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENDPROC(__put_user_2)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6200e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENTRY(__put_user_4)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ENTER
642528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	mov TI_addr_limit(%_ASM_BX),%_ASM_BX
652528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	sub $3,%_ASM_BX
662528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	cmp %_ASM_BX,%_ASM_CX
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jae bad_put_user
6863bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin	ASM_STAC
692528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa3:	movl %eax,(%_ASM_CX)
70efea505d83873cfc8a7cdbb8a2a11d2c67467843Glauber Costa	xor %eax,%eax
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXIT
7200e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENDPROC(__put_user_4)
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7400e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENTRY(__put_user_8)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ENTER
762528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	mov TI_addr_limit(%_ASM_BX),%_ASM_BX
772528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	sub $7,%_ASM_BX
782528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa	cmp %_ASM_BX,%_ASM_CX
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	jae bad_put_user
8063bcff2a307b9bcc712a8251eb27df8b2e117967H. Peter Anvin	ASM_STAC
815cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa4:	mov %_ASM_AX,(%_ASM_CX)
825cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa#ifdef CONFIG_X86_32
832528de431ddb200653d1dc6ca90074bad9520f09Glauber Costa5:	movl %edx,4(%_ASM_CX)
845cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa#endif
85efea505d83873cfc8a7cdbb8a2a11d2c67467843Glauber Costa	xor %eax,%eax
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXIT
8700e065ea587363e538d9624eea8cacad12cb7397Jan BeulichENDPROC(__put_user_8)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbad_put_user:
90268cf048c890d10bd3a86bd87922ed8a722d502fGlauber Costa	CFI_STARTPROC
915cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa	movl $-EFAULT,%eax
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	EXIT
9300e065ea587363e538d9624eea8cacad12cb7397Jan BeulichEND(bad_put_user)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95a53a96e5413d3639ed75d202bbfe68aa0a56c091H. Peter Anvin	_ASM_EXTABLE(1b,bad_put_user)
96a53a96e5413d3639ed75d202bbfe68aa0a56c091H. Peter Anvin	_ASM_EXTABLE(2b,bad_put_user)
97a53a96e5413d3639ed75d202bbfe68aa0a56c091H. Peter Anvin	_ASM_EXTABLE(3b,bad_put_user)
98a53a96e5413d3639ed75d202bbfe68aa0a56c091H. Peter Anvin	_ASM_EXTABLE(4b,bad_put_user)
995cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa#ifdef CONFIG_X86_32
100a53a96e5413d3639ed75d202bbfe68aa0a56c091H. Peter Anvin	_ASM_EXTABLE(5b,bad_put_user)
1015cbbc3b1eb37bdc72eefd2de03b39f5e784400c2Glauber Costa#endif
102