1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * __get_user functions. 4 * 5 * (C) Copyright 1998 Linus Torvalds 6 * (C) Copyright 2005 Andi Kleen 7 * (C) Copyright 2008 Glauber Costa 8 * 9 * These functions have a non-standard call interface 10 * to make them more efficient, especially as they 11 * return an error value in addition to the "real" 12 * return value. 13 */ 14 15 /* 16 * __get_user_X 17 * 18 * Inputs: %[r|e]ax contains the address. 19 * 20 * Outputs: %[r|e]ax is error code (0 or -EFAULT) 21 * %[r|e]dx contains zero-extended value 22 * %ecx contains the high half for 32-bit __get_user_8 23 * 24 * 25 * These functions should not modify any other registers, 26 * as they get called from within inline assembly. 27 */ 28 29 #include <linux/export.h> 30 #include <linux/linkage.h> 31 #include <asm/page_types.h> 32 #include <asm/errno.h> 33 #include <asm/asm-offsets.h> 34 #include <asm/thread_info.h> 35 #include <asm/asm.h> 36 #include <asm/smap.h> 37 38 #define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC 39 40 .macro check_range size:req 41 .if IS_ENABLED(CONFIG_X86_64) 42 movq $0x0123456789abcdef,%rdx 43 1: 44 .pushsection runtime_ptr_USER_PTR_MAX,"a" 45 .long 1b - 8 - . 46 .popsection 47 cmp %rax, %rdx 48 sbb %rdx, %rdx 49 or %rdx, %rax 50 .else 51 cmp $TASK_SIZE_MAX-\size+1, %eax 52 jae .Lbad_get_user 53 sbb %edx, %edx /* array_index_mask_nospec() */ 54 and %edx, %eax 55 .endif 56 .endm 57 58 .macro UACCESS op src dst 59 1: \op \src,\dst 60 _ASM_EXTABLE_UA(1b, __get_user_handle_exception) 61 .endm 62 63 64 .text 65 SYM_FUNC_START(__get_user_1) 66 check_range size=1 67 ASM_STAC 68 UACCESS movzbl (%_ASM_AX),%edx 69 xor %eax,%eax 70 ASM_CLAC 71 RET 72 SYM_FUNC_END(__get_user_1) 73 EXPORT_SYMBOL(__get_user_1) 74 75 SYM_FUNC_START(__get_user_2) 76 check_range size=2 77 ASM_STAC 78 UACCESS movzwl (%_ASM_AX),%edx 79 xor %eax,%eax 80 ASM_CLAC 81 RET 82 SYM_FUNC_END(__get_user_2) 83 EXPORT_SYMBOL(__get_user_2) 84 85 SYM_FUNC_START(__get_user_4) 86 check_range size=4 87 ASM_STAC 88 UACCESS movl (%_ASM_AX),%edx 89 xor %eax,%eax 90 ASM_CLAC 91 RET 92 SYM_FUNC_END(__get_user_4) 93 EXPORT_SYMBOL(__get_user_4) 94 95 SYM_FUNC_START(__get_user_8) 96 #ifndef CONFIG_X86_64 97 xor %ecx,%ecx 98 #endif 99 check_range size=8 100 ASM_STAC 101 #ifdef CONFIG_X86_64 102 UACCESS movq (%_ASM_AX),%rdx 103 #else 104 UACCESS movl (%_ASM_AX),%edx 105 UACCESS movl 4(%_ASM_AX),%ecx 106 #endif 107 xor %eax,%eax 108 ASM_CLAC 109 RET 110 SYM_FUNC_END(__get_user_8) 111 EXPORT_SYMBOL(__get_user_8) 112 113 /* .. and the same for __get_user, just without the range checks */ 114 SYM_FUNC_START(__get_user_nocheck_1) 115 ASM_STAC 116 ASM_BARRIER_NOSPEC 117 UACCESS movzbl (%_ASM_AX),%edx 118 xor %eax,%eax 119 ASM_CLAC 120 RET 121 SYM_FUNC_END(__get_user_nocheck_1) 122 EXPORT_SYMBOL(__get_user_nocheck_1) 123 124 SYM_FUNC_START(__get_user_nocheck_2) 125 ASM_STAC 126 ASM_BARRIER_NOSPEC 127 UACCESS movzwl (%_ASM_AX),%edx 128 xor %eax,%eax 129 ASM_CLAC 130 RET 131 SYM_FUNC_END(__get_user_nocheck_2) 132 EXPORT_SYMBOL(__get_user_nocheck_2) 133 134 SYM_FUNC_START(__get_user_nocheck_4) 135 ASM_STAC 136 ASM_BARRIER_NOSPEC 137 UACCESS movl (%_ASM_AX),%edx 138 xor %eax,%eax 139 ASM_CLAC 140 RET 141 SYM_FUNC_END(__get_user_nocheck_4) 142 EXPORT_SYMBOL(__get_user_nocheck_4) 143 144 SYM_FUNC_START(__get_user_nocheck_8) 145 ASM_STAC 146 ASM_BARRIER_NOSPEC 147 #ifdef CONFIG_X86_64 148 UACCESS movq (%_ASM_AX),%rdx 149 #else 150 xor %ecx,%ecx 151 UACCESS movl (%_ASM_AX),%edx 152 UACCESS movl 4(%_ASM_AX),%ecx 153 #endif 154 xor %eax,%eax 155 ASM_CLAC 156 RET 157 SYM_FUNC_END(__get_user_nocheck_8) 158 EXPORT_SYMBOL(__get_user_nocheck_8) 159 160 161 SYM_CODE_START_LOCAL(__get_user_handle_exception) 162 ASM_CLAC 163 .Lbad_get_user: 164 xor %edx,%edx 165 mov $(-EFAULT),%_ASM_AX 166 RET 167 SYM_CODE_END(__get_user_handle_exception)
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.