1/* 2 * __put_user functions. 3 * 4 * (C) Copyright 2005 Linus Torvalds 5 * (C) Copyright 2005 Andi Kleen 6 * (C) Copyright 2008 Glauber Costa 7 * 8 * These functions have a non-standard call interface 9 * to make them more efficient, especially as they 10 * return an error value in addition to the "real" 11 * return value. 12 */ 13#include <linux/linkage.h> 14#include <asm/thread_info.h> 15#include <asm/errno.h> 16#include <asm/asm.h> 17#include <asm/smap.h> 18 19 20/* 21 * __put_user_X 22 * 23 * Inputs: %eax[:%edx] contains the data 24 * %ecx contains the address 25 * 26 * Outputs: %eax is error code (0 or -EFAULT) 27 * 28 * These functions should not modify any other registers, 29 * as they get called from within inline assembly. 30 */ 31 32#define ENTER GET_THREAD_INFO(%_ASM_BX) 33#define EXIT ASM_CLAC ; \ 34 ret 35 36.text 37ENTRY(__put_user_1) 38 ENTER 39 cmp TI_addr_limit(%_ASM_BX),%_ASM_CX 40 jae bad_put_user 41 ASM_STAC 421: movb %al,(%_ASM_CX) 43 xor %eax,%eax 44 EXIT 45ENDPROC(__put_user_1) 46 47ENTRY(__put_user_2) 48 ENTER 49 mov TI_addr_limit(%_ASM_BX),%_ASM_BX 50 sub $1,%_ASM_BX 51 cmp %_ASM_BX,%_ASM_CX 52 jae bad_put_user 53 ASM_STAC 542: movw %ax,(%_ASM_CX) 55 xor %eax,%eax 56 EXIT 57ENDPROC(__put_user_2) 58 59ENTRY(__put_user_4) 60 ENTER 61 mov TI_addr_limit(%_ASM_BX),%_ASM_BX 62 sub $3,%_ASM_BX 63 cmp %_ASM_BX,%_ASM_CX 64 jae bad_put_user 65 ASM_STAC 663: movl %eax,(%_ASM_CX) 67 xor %eax,%eax 68 EXIT 69ENDPROC(__put_user_4) 70 71ENTRY(__put_user_8) 72 ENTER 73 mov TI_addr_limit(%_ASM_BX),%_ASM_BX 74 sub $7,%_ASM_BX 75 cmp %_ASM_BX,%_ASM_CX 76 jae bad_put_user 77 ASM_STAC 784: mov %_ASM_AX,(%_ASM_CX) 79#ifdef CONFIG_X86_32 805: movl %edx,4(%_ASM_CX) 81#endif 82 xor %eax,%eax 83 EXIT 84ENDPROC(__put_user_8) 85 86bad_put_user: 87 movl $-EFAULT,%eax 88 EXIT 89END(bad_put_user) 90 91 _ASM_EXTABLE(1b,bad_put_user) 92 _ASM_EXTABLE(2b,bad_put_user) 93 _ASM_EXTABLE(3b,bad_put_user) 94 _ASM_EXTABLE(4b,bad_put_user) 95#ifdef CONFIG_X86_32 96 _ASM_EXTABLE(5b,bad_put_user) 97#endif 98