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 <linux/objtool.h> 32#include <asm/page_types.h> 33#include <asm/errno.h> 34#include <asm/asm-offsets.h> 35#include <asm/thread_info.h> 36#include <asm/asm.h> 37#include <asm/smap.h> 38#include <asm/runtime-const.h> 39 40#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC 41 42.macro check_range size:req 43.if IS_ENABLED(CONFIG_X86_64) 44 RUNTIME_CONST_PTR USER_PTR_MAX, rdx 45 cmp %rdx, %rax 46 cmova %rdx, %rax 47.else 48 cmp $TASK_SIZE_MAX-\size+1, %eax 49 jae .Lbad_get_user 50 sbb %edx, %edx /* array_index_mask_nospec() */ 51 and %edx, %eax 52.endif 53.endm 54 55.macro UACCESS op src dst 561: \op \src,\dst 57 _ASM_EXTABLE_UA(1b, __get_user_handle_exception) 58.endm 59 60 61 .text 62SYM_FUNC_START(__get_user_1) 63 ANNOTATE_NOENDBR 64 check_range size=1 65 ASM_STAC 66 UACCESS movzbl (%_ASM_AX),%edx 67 xor %eax,%eax 68 ASM_CLAC 69 RET 70SYM_FUNC_END(__get_user_1) 71EXPORT_SYMBOL(__get_user_1) 72 73SYM_FUNC_START(__get_user_2) 74 ANNOTATE_NOENDBR 75 check_range size=2 76 ASM_STAC 77 UACCESS movzwl (%_ASM_AX),%edx 78 xor %eax,%eax 79 ASM_CLAC 80 RET 81SYM_FUNC_END(__get_user_2) 82EXPORT_SYMBOL(__get_user_2) 83 84SYM_FUNC_START(__get_user_4) 85 ANNOTATE_NOENDBR 86 check_range size=4 87 ASM_STAC 88 UACCESS movl (%_ASM_AX),%edx 89 xor %eax,%eax 90 ASM_CLAC 91 RET 92SYM_FUNC_END(__get_user_4) 93EXPORT_SYMBOL(__get_user_4) 94 95SYM_FUNC_START(__get_user_8) 96 ANNOTATE_NOENDBR 97#ifndef CONFIG_X86_64 98 xor %ecx,%ecx 99#endif 100 check_range size=8 101 ASM_STAC 102#ifdef CONFIG_X86_64 103 UACCESS movq (%_ASM_AX),%rdx 104#else 105 UACCESS movl (%_ASM_AX),%edx 106 UACCESS movl 4(%_ASM_AX),%ecx 107#endif 108 xor %eax,%eax 109 ASM_CLAC 110 RET 111SYM_FUNC_END(__get_user_8) 112EXPORT_SYMBOL(__get_user_8) 113 114/* .. and the same for __get_user, just without the range checks */ 115SYM_FUNC_START(__get_user_nocheck_1) 116 ANNOTATE_NOENDBR 117 ASM_STAC 118 ASM_BARRIER_NOSPEC 119 UACCESS movzbl (%_ASM_AX),%edx 120 xor %eax,%eax 121 ASM_CLAC 122 RET 123SYM_FUNC_END(__get_user_nocheck_1) 124EXPORT_SYMBOL(__get_user_nocheck_1) 125 126SYM_FUNC_START(__get_user_nocheck_2) 127 ANNOTATE_NOENDBR 128 ASM_STAC 129 ASM_BARRIER_NOSPEC 130 UACCESS movzwl (%_ASM_AX),%edx 131 xor %eax,%eax 132 ASM_CLAC 133 RET 134SYM_FUNC_END(__get_user_nocheck_2) 135EXPORT_SYMBOL(__get_user_nocheck_2) 136 137SYM_FUNC_START(__get_user_nocheck_4) 138 ANNOTATE_NOENDBR 139 ASM_STAC 140 ASM_BARRIER_NOSPEC 141 UACCESS movl (%_ASM_AX),%edx 142 xor %eax,%eax 143 ASM_CLAC 144 RET 145SYM_FUNC_END(__get_user_nocheck_4) 146EXPORT_SYMBOL(__get_user_nocheck_4) 147 148SYM_FUNC_START(__get_user_nocheck_8) 149 ANNOTATE_NOENDBR 150 ASM_STAC 151 ASM_BARRIER_NOSPEC 152#ifdef CONFIG_X86_64 153 UACCESS movq (%_ASM_AX),%rdx 154#else 155 xor %ecx,%ecx 156 UACCESS movl (%_ASM_AX),%edx 157 UACCESS movl 4(%_ASM_AX),%ecx 158#endif 159 xor %eax,%eax 160 ASM_CLAC 161 RET 162SYM_FUNC_END(__get_user_nocheck_8) 163EXPORT_SYMBOL(__get_user_nocheck_8) 164 165 166SYM_CODE_START_LOCAL(__get_user_handle_exception) 167 ASM_CLAC 168.Lbad_get_user: 169 xor %edx,%edx 170 mov $(-EFAULT),%_ASM_AX 171 RET 172SYM_CODE_END(__get_user_handle_exception) 173