162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * __get_user functions. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright 1998 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 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * __get_user_X 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Inputs: %[r|e]ax contains the address. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Outputs: %[r|e]ax is error code (0 or -EFAULT) 2162306a36Sopenharmony_ci * %[r|e]dx contains zero-extended value 2262306a36Sopenharmony_ci * %ecx contains the high half for 32-bit __get_user_8 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * These functions should not modify any other registers, 2662306a36Sopenharmony_ci * as they get called from within inline assembly. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/linkage.h> 3062306a36Sopenharmony_ci#include <asm/page_types.h> 3162306a36Sopenharmony_ci#include <asm/errno.h> 3262306a36Sopenharmony_ci#include <asm/asm-offsets.h> 3362306a36Sopenharmony_ci#include <asm/thread_info.h> 3462306a36Sopenharmony_ci#include <asm/asm.h> 3562306a36Sopenharmony_ci#include <asm/smap.h> 3662306a36Sopenharmony_ci#include <asm/export.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci.macro check_range size:req 4162306a36Sopenharmony_ci.if IS_ENABLED(CONFIG_X86_64) 4262306a36Sopenharmony_ci mov %rax, %rdx 4362306a36Sopenharmony_ci sar $63, %rdx 4462306a36Sopenharmony_ci or %rdx, %rax 4562306a36Sopenharmony_ci.else 4662306a36Sopenharmony_ci cmp $TASK_SIZE_MAX-\size+1, %eax 4762306a36Sopenharmony_ci jae .Lbad_get_user 4862306a36Sopenharmony_ci sbb %edx, %edx /* array_index_mask_nospec() */ 4962306a36Sopenharmony_ci and %edx, %eax 5062306a36Sopenharmony_ci.endif 5162306a36Sopenharmony_ci.endm 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci .text 5462306a36Sopenharmony_ciSYM_FUNC_START(__get_user_1) 5562306a36Sopenharmony_ci check_range size=1 5662306a36Sopenharmony_ci ASM_STAC 5762306a36Sopenharmony_ci1: movzbl (%_ASM_AX),%edx 5862306a36Sopenharmony_ci xor %eax,%eax 5962306a36Sopenharmony_ci ASM_CLAC 6062306a36Sopenharmony_ci RET 6162306a36Sopenharmony_ciSYM_FUNC_END(__get_user_1) 6262306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_1) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciSYM_FUNC_START(__get_user_2) 6562306a36Sopenharmony_ci check_range size=2 6662306a36Sopenharmony_ci ASM_STAC 6762306a36Sopenharmony_ci2: movzwl (%_ASM_AX),%edx 6862306a36Sopenharmony_ci xor %eax,%eax 6962306a36Sopenharmony_ci ASM_CLAC 7062306a36Sopenharmony_ci RET 7162306a36Sopenharmony_ciSYM_FUNC_END(__get_user_2) 7262306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_2) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciSYM_FUNC_START(__get_user_4) 7562306a36Sopenharmony_ci check_range size=4 7662306a36Sopenharmony_ci ASM_STAC 7762306a36Sopenharmony_ci3: movl (%_ASM_AX),%edx 7862306a36Sopenharmony_ci xor %eax,%eax 7962306a36Sopenharmony_ci ASM_CLAC 8062306a36Sopenharmony_ci RET 8162306a36Sopenharmony_ciSYM_FUNC_END(__get_user_4) 8262306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_4) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciSYM_FUNC_START(__get_user_8) 8562306a36Sopenharmony_ci check_range size=8 8662306a36Sopenharmony_ci ASM_STAC 8762306a36Sopenharmony_ci#ifdef CONFIG_X86_64 8862306a36Sopenharmony_ci4: movq (%_ASM_AX),%rdx 8962306a36Sopenharmony_ci#else 9062306a36Sopenharmony_ci4: movl (%_ASM_AX),%edx 9162306a36Sopenharmony_ci5: movl 4(%_ASM_AX),%ecx 9262306a36Sopenharmony_ci#endif 9362306a36Sopenharmony_ci xor %eax,%eax 9462306a36Sopenharmony_ci ASM_CLAC 9562306a36Sopenharmony_ci RET 9662306a36Sopenharmony_ciSYM_FUNC_END(__get_user_8) 9762306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_8) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* .. and the same for __get_user, just without the range checks */ 10062306a36Sopenharmony_ciSYM_FUNC_START(__get_user_nocheck_1) 10162306a36Sopenharmony_ci ASM_STAC 10262306a36Sopenharmony_ci ASM_BARRIER_NOSPEC 10362306a36Sopenharmony_ci6: movzbl (%_ASM_AX),%edx 10462306a36Sopenharmony_ci xor %eax,%eax 10562306a36Sopenharmony_ci ASM_CLAC 10662306a36Sopenharmony_ci RET 10762306a36Sopenharmony_ciSYM_FUNC_END(__get_user_nocheck_1) 10862306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_nocheck_1) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciSYM_FUNC_START(__get_user_nocheck_2) 11162306a36Sopenharmony_ci ASM_STAC 11262306a36Sopenharmony_ci ASM_BARRIER_NOSPEC 11362306a36Sopenharmony_ci7: movzwl (%_ASM_AX),%edx 11462306a36Sopenharmony_ci xor %eax,%eax 11562306a36Sopenharmony_ci ASM_CLAC 11662306a36Sopenharmony_ci RET 11762306a36Sopenharmony_ciSYM_FUNC_END(__get_user_nocheck_2) 11862306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_nocheck_2) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ciSYM_FUNC_START(__get_user_nocheck_4) 12162306a36Sopenharmony_ci ASM_STAC 12262306a36Sopenharmony_ci ASM_BARRIER_NOSPEC 12362306a36Sopenharmony_ci8: movl (%_ASM_AX),%edx 12462306a36Sopenharmony_ci xor %eax,%eax 12562306a36Sopenharmony_ci ASM_CLAC 12662306a36Sopenharmony_ci RET 12762306a36Sopenharmony_ciSYM_FUNC_END(__get_user_nocheck_4) 12862306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_nocheck_4) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciSYM_FUNC_START(__get_user_nocheck_8) 13162306a36Sopenharmony_ci ASM_STAC 13262306a36Sopenharmony_ci ASM_BARRIER_NOSPEC 13362306a36Sopenharmony_ci#ifdef CONFIG_X86_64 13462306a36Sopenharmony_ci9: movq (%_ASM_AX),%rdx 13562306a36Sopenharmony_ci#else 13662306a36Sopenharmony_ci9: movl (%_ASM_AX),%edx 13762306a36Sopenharmony_ci10: movl 4(%_ASM_AX),%ecx 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ci xor %eax,%eax 14062306a36Sopenharmony_ci ASM_CLAC 14162306a36Sopenharmony_ci RET 14262306a36Sopenharmony_ciSYM_FUNC_END(__get_user_nocheck_8) 14362306a36Sopenharmony_ciEXPORT_SYMBOL(__get_user_nocheck_8) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciSYM_CODE_START_LOCAL(__get_user_handle_exception) 14762306a36Sopenharmony_ci ASM_CLAC 14862306a36Sopenharmony_ci.Lbad_get_user: 14962306a36Sopenharmony_ci xor %edx,%edx 15062306a36Sopenharmony_ci mov $(-EFAULT),%_ASM_AX 15162306a36Sopenharmony_ci RET 15262306a36Sopenharmony_ciSYM_CODE_END(__get_user_handle_exception) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#ifdef CONFIG_X86_32 15562306a36Sopenharmony_ciSYM_CODE_START_LOCAL(__get_user_8_handle_exception) 15662306a36Sopenharmony_ci ASM_CLAC 15762306a36Sopenharmony_cibad_get_user_8: 15862306a36Sopenharmony_ci xor %edx,%edx 15962306a36Sopenharmony_ci xor %ecx,%ecx 16062306a36Sopenharmony_ci mov $(-EFAULT),%_ASM_AX 16162306a36Sopenharmony_ci RET 16262306a36Sopenharmony_ciSYM_CODE_END(__get_user_8_handle_exception) 16362306a36Sopenharmony_ci#endif 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* get_user */ 16662306a36Sopenharmony_ci _ASM_EXTABLE_UA(1b, __get_user_handle_exception) 16762306a36Sopenharmony_ci _ASM_EXTABLE_UA(2b, __get_user_handle_exception) 16862306a36Sopenharmony_ci _ASM_EXTABLE_UA(3b, __get_user_handle_exception) 16962306a36Sopenharmony_ci#ifdef CONFIG_X86_64 17062306a36Sopenharmony_ci _ASM_EXTABLE_UA(4b, __get_user_handle_exception) 17162306a36Sopenharmony_ci#else 17262306a36Sopenharmony_ci _ASM_EXTABLE_UA(4b, __get_user_8_handle_exception) 17362306a36Sopenharmony_ci _ASM_EXTABLE_UA(5b, __get_user_8_handle_exception) 17462306a36Sopenharmony_ci#endif 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* __get_user */ 17762306a36Sopenharmony_ci _ASM_EXTABLE_UA(6b, __get_user_handle_exception) 17862306a36Sopenharmony_ci _ASM_EXTABLE_UA(7b, __get_user_handle_exception) 17962306a36Sopenharmony_ci _ASM_EXTABLE_UA(8b, __get_user_handle_exception) 18062306a36Sopenharmony_ci#ifdef CONFIG_X86_64 18162306a36Sopenharmony_ci _ASM_EXTABLE_UA(9b, __get_user_handle_exception) 18262306a36Sopenharmony_ci#else 18362306a36Sopenharmony_ci _ASM_EXTABLE_UA(9b, __get_user_8_handle_exception) 18462306a36Sopenharmony_ci _ASM_EXTABLE_UA(10b, __get_user_8_handle_exception) 18562306a36Sopenharmony_ci#endif 186