162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * __put_user functions. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright 2005 Linus Torvalds 662306a36Sopenharmony_ci * (C) Copyright 2005 Andi Kleen 762306a36Sopenharmony_ci * (C) Copyright 2008 Glauber Costa 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * These functions have a non-standard call interface 1062306a36Sopenharmony_ci * to make them more efficient, especially as they 1162306a36Sopenharmony_ci * return an error value in addition to the "real" 1262306a36Sopenharmony_ci * return value. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <linux/linkage.h> 1562306a36Sopenharmony_ci#include <asm/thread_info.h> 1662306a36Sopenharmony_ci#include <asm/errno.h> 1762306a36Sopenharmony_ci#include <asm/asm.h> 1862306a36Sopenharmony_ci#include <asm/smap.h> 1962306a36Sopenharmony_ci#include <asm/export.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * __put_user_X 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Inputs: %eax[:%edx] contains the data 2662306a36Sopenharmony_ci * %ecx contains the address 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Outputs: %ecx is error code (0 or -EFAULT) 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Clobbers: %ebx needed for task pointer 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * These functions should not modify any other registers, 3362306a36Sopenharmony_ci * as they get called from within inline assembly. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci.macro check_range size:req 3762306a36Sopenharmony_ci.if IS_ENABLED(CONFIG_X86_64) 3862306a36Sopenharmony_ci mov %rcx, %rbx 3962306a36Sopenharmony_ci sar $63, %rbx 4062306a36Sopenharmony_ci or %rbx, %rcx 4162306a36Sopenharmony_ci.else 4262306a36Sopenharmony_ci cmp $TASK_SIZE_MAX-\size+1, %ecx 4362306a36Sopenharmony_ci jae .Lbad_put_user 4462306a36Sopenharmony_ci.endif 4562306a36Sopenharmony_ci.endm 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci.text 4862306a36Sopenharmony_ciSYM_FUNC_START(__put_user_1) 4962306a36Sopenharmony_ci check_range size=1 5062306a36Sopenharmony_ci ASM_STAC 5162306a36Sopenharmony_ci1: movb %al,(%_ASM_CX) 5262306a36Sopenharmony_ci xor %ecx,%ecx 5362306a36Sopenharmony_ci ASM_CLAC 5462306a36Sopenharmony_ci RET 5562306a36Sopenharmony_ciSYM_FUNC_END(__put_user_1) 5662306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_1) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciSYM_FUNC_START(__put_user_nocheck_1) 5962306a36Sopenharmony_ci ASM_STAC 6062306a36Sopenharmony_ci2: movb %al,(%_ASM_CX) 6162306a36Sopenharmony_ci xor %ecx,%ecx 6262306a36Sopenharmony_ci ASM_CLAC 6362306a36Sopenharmony_ci RET 6462306a36Sopenharmony_ciSYM_FUNC_END(__put_user_nocheck_1) 6562306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_nocheck_1) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciSYM_FUNC_START(__put_user_2) 6862306a36Sopenharmony_ci check_range size=2 6962306a36Sopenharmony_ci ASM_STAC 7062306a36Sopenharmony_ci3: movw %ax,(%_ASM_CX) 7162306a36Sopenharmony_ci xor %ecx,%ecx 7262306a36Sopenharmony_ci ASM_CLAC 7362306a36Sopenharmony_ci RET 7462306a36Sopenharmony_ciSYM_FUNC_END(__put_user_2) 7562306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_2) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciSYM_FUNC_START(__put_user_nocheck_2) 7862306a36Sopenharmony_ci ASM_STAC 7962306a36Sopenharmony_ci4: movw %ax,(%_ASM_CX) 8062306a36Sopenharmony_ci xor %ecx,%ecx 8162306a36Sopenharmony_ci ASM_CLAC 8262306a36Sopenharmony_ci RET 8362306a36Sopenharmony_ciSYM_FUNC_END(__put_user_nocheck_2) 8462306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_nocheck_2) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciSYM_FUNC_START(__put_user_4) 8762306a36Sopenharmony_ci check_range size=4 8862306a36Sopenharmony_ci ASM_STAC 8962306a36Sopenharmony_ci5: movl %eax,(%_ASM_CX) 9062306a36Sopenharmony_ci xor %ecx,%ecx 9162306a36Sopenharmony_ci ASM_CLAC 9262306a36Sopenharmony_ci RET 9362306a36Sopenharmony_ciSYM_FUNC_END(__put_user_4) 9462306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_4) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ciSYM_FUNC_START(__put_user_nocheck_4) 9762306a36Sopenharmony_ci ASM_STAC 9862306a36Sopenharmony_ci6: movl %eax,(%_ASM_CX) 9962306a36Sopenharmony_ci xor %ecx,%ecx 10062306a36Sopenharmony_ci ASM_CLAC 10162306a36Sopenharmony_ci RET 10262306a36Sopenharmony_ciSYM_FUNC_END(__put_user_nocheck_4) 10362306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_nocheck_4) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ciSYM_FUNC_START(__put_user_8) 10662306a36Sopenharmony_ci check_range size=8 10762306a36Sopenharmony_ci ASM_STAC 10862306a36Sopenharmony_ci7: mov %_ASM_AX,(%_ASM_CX) 10962306a36Sopenharmony_ci#ifdef CONFIG_X86_32 11062306a36Sopenharmony_ci8: movl %edx,4(%_ASM_CX) 11162306a36Sopenharmony_ci#endif 11262306a36Sopenharmony_ci xor %ecx,%ecx 11362306a36Sopenharmony_ci ASM_CLAC 11462306a36Sopenharmony_ci RET 11562306a36Sopenharmony_ciSYM_FUNC_END(__put_user_8) 11662306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_8) 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciSYM_FUNC_START(__put_user_nocheck_8) 11962306a36Sopenharmony_ci ASM_STAC 12062306a36Sopenharmony_ci9: mov %_ASM_AX,(%_ASM_CX) 12162306a36Sopenharmony_ci#ifdef CONFIG_X86_32 12262306a36Sopenharmony_ci10: movl %edx,4(%_ASM_CX) 12362306a36Sopenharmony_ci#endif 12462306a36Sopenharmony_ci xor %ecx,%ecx 12562306a36Sopenharmony_ci ASM_CLAC 12662306a36Sopenharmony_ci RET 12762306a36Sopenharmony_ciSYM_FUNC_END(__put_user_nocheck_8) 12862306a36Sopenharmony_ciEXPORT_SYMBOL(__put_user_nocheck_8) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciSYM_CODE_START_LOCAL(__put_user_handle_exception) 13162306a36Sopenharmony_ci ASM_CLAC 13262306a36Sopenharmony_ci.Lbad_put_user: 13362306a36Sopenharmony_ci movl $-EFAULT,%ecx 13462306a36Sopenharmony_ci RET 13562306a36Sopenharmony_ciSYM_CODE_END(__put_user_handle_exception) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci _ASM_EXTABLE_UA(1b, __put_user_handle_exception) 13862306a36Sopenharmony_ci _ASM_EXTABLE_UA(2b, __put_user_handle_exception) 13962306a36Sopenharmony_ci _ASM_EXTABLE_UA(3b, __put_user_handle_exception) 14062306a36Sopenharmony_ci _ASM_EXTABLE_UA(4b, __put_user_handle_exception) 14162306a36Sopenharmony_ci _ASM_EXTABLE_UA(5b, __put_user_handle_exception) 14262306a36Sopenharmony_ci _ASM_EXTABLE_UA(6b, __put_user_handle_exception) 14362306a36Sopenharmony_ci _ASM_EXTABLE_UA(7b, __put_user_handle_exception) 14462306a36Sopenharmony_ci _ASM_EXTABLE_UA(9b, __put_user_handle_exception) 14562306a36Sopenharmony_ci#ifdef CONFIG_X86_32 14662306a36Sopenharmony_ci _ASM_EXTABLE_UA(8b, __put_user_handle_exception) 14762306a36Sopenharmony_ci _ASM_EXTABLE_UA(10b, __put_user_handle_exception) 14862306a36Sopenharmony_ci#endif 149