1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * __get_user functions. 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * (C) Copyright 1998 Linus Torvalds 6*4882a593Smuzhiyun * (C) Copyright 2005 Andi Kleen 7*4882a593Smuzhiyun * (C) Copyright 2008 Glauber Costa 8*4882a593Smuzhiyun * 9*4882a593Smuzhiyun * These functions have a non-standard call interface 10*4882a593Smuzhiyun * to make them more efficient, especially as they 11*4882a593Smuzhiyun * return an error value in addition to the "real" 12*4882a593Smuzhiyun * return value. 13*4882a593Smuzhiyun */ 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun/* 16*4882a593Smuzhiyun * __get_user_X 17*4882a593Smuzhiyun * 18*4882a593Smuzhiyun * Inputs: %[r|e]ax contains the address. 19*4882a593Smuzhiyun * 20*4882a593Smuzhiyun * Outputs: %[r|e]ax is error code (0 or -EFAULT) 21*4882a593Smuzhiyun * %[r|e]dx contains zero-extended value 22*4882a593Smuzhiyun * %ecx contains the high half for 32-bit __get_user_8 23*4882a593Smuzhiyun * 24*4882a593Smuzhiyun * 25*4882a593Smuzhiyun * These functions should not modify any other registers, 26*4882a593Smuzhiyun * as they get called from within inline assembly. 27*4882a593Smuzhiyun */ 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun#include <linux/linkage.h> 30*4882a593Smuzhiyun#include <asm/page_types.h> 31*4882a593Smuzhiyun#include <asm/errno.h> 32*4882a593Smuzhiyun#include <asm/asm-offsets.h> 33*4882a593Smuzhiyun#include <asm/thread_info.h> 34*4882a593Smuzhiyun#include <asm/asm.h> 35*4882a593Smuzhiyun#include <asm/smap.h> 36*4882a593Smuzhiyun#include <asm/export.h> 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun#ifdef CONFIG_X86_5LEVEL 41*4882a593Smuzhiyun#define LOAD_TASK_SIZE_MINUS_N(n) \ 42*4882a593Smuzhiyun ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rdx), \ 43*4882a593Smuzhiyun __stringify(mov $((1 << 56) - 4096 - (n)),%rdx), X86_FEATURE_LA57 44*4882a593Smuzhiyun#else 45*4882a593Smuzhiyun#define LOAD_TASK_SIZE_MINUS_N(n) \ 46*4882a593Smuzhiyun mov $(TASK_SIZE_MAX - (n)),%_ASM_DX 47*4882a593Smuzhiyun#endif 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun .text 50*4882a593SmuzhiyunSYM_FUNC_START(__get_user_1) 51*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(0) 52*4882a593Smuzhiyun cmp %_ASM_DX,%_ASM_AX 53*4882a593Smuzhiyun jae bad_get_user 54*4882a593Smuzhiyun sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ 55*4882a593Smuzhiyun and %_ASM_DX, %_ASM_AX 56*4882a593Smuzhiyun ASM_STAC 57*4882a593Smuzhiyun1: movzbl (%_ASM_AX),%edx 58*4882a593Smuzhiyun xor %eax,%eax 59*4882a593Smuzhiyun ASM_CLAC 60*4882a593Smuzhiyun RET 61*4882a593SmuzhiyunSYM_FUNC_END(__get_user_1) 62*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_1) 63*4882a593Smuzhiyun 64*4882a593SmuzhiyunSYM_FUNC_START(__get_user_2) 65*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(1) 66*4882a593Smuzhiyun cmp %_ASM_DX,%_ASM_AX 67*4882a593Smuzhiyun jae bad_get_user 68*4882a593Smuzhiyun sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ 69*4882a593Smuzhiyun and %_ASM_DX, %_ASM_AX 70*4882a593Smuzhiyun ASM_STAC 71*4882a593Smuzhiyun2: movzwl (%_ASM_AX),%edx 72*4882a593Smuzhiyun xor %eax,%eax 73*4882a593Smuzhiyun ASM_CLAC 74*4882a593Smuzhiyun RET 75*4882a593SmuzhiyunSYM_FUNC_END(__get_user_2) 76*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_2) 77*4882a593Smuzhiyun 78*4882a593SmuzhiyunSYM_FUNC_START(__get_user_4) 79*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(3) 80*4882a593Smuzhiyun cmp %_ASM_DX,%_ASM_AX 81*4882a593Smuzhiyun jae bad_get_user 82*4882a593Smuzhiyun sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ 83*4882a593Smuzhiyun and %_ASM_DX, %_ASM_AX 84*4882a593Smuzhiyun ASM_STAC 85*4882a593Smuzhiyun3: movl (%_ASM_AX),%edx 86*4882a593Smuzhiyun xor %eax,%eax 87*4882a593Smuzhiyun ASM_CLAC 88*4882a593Smuzhiyun RET 89*4882a593SmuzhiyunSYM_FUNC_END(__get_user_4) 90*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_4) 91*4882a593Smuzhiyun 92*4882a593SmuzhiyunSYM_FUNC_START(__get_user_8) 93*4882a593Smuzhiyun#ifdef CONFIG_X86_64 94*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(7) 95*4882a593Smuzhiyun cmp %_ASM_DX,%_ASM_AX 96*4882a593Smuzhiyun jae bad_get_user 97*4882a593Smuzhiyun sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ 98*4882a593Smuzhiyun and %_ASM_DX, %_ASM_AX 99*4882a593Smuzhiyun ASM_STAC 100*4882a593Smuzhiyun4: movq (%_ASM_AX),%rdx 101*4882a593Smuzhiyun xor %eax,%eax 102*4882a593Smuzhiyun ASM_CLAC 103*4882a593Smuzhiyun RET 104*4882a593Smuzhiyun#else 105*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(7) 106*4882a593Smuzhiyun cmp %_ASM_DX,%_ASM_AX 107*4882a593Smuzhiyun jae bad_get_user_8 108*4882a593Smuzhiyun sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */ 109*4882a593Smuzhiyun and %_ASM_DX, %_ASM_AX 110*4882a593Smuzhiyun ASM_STAC 111*4882a593Smuzhiyun4: movl (%_ASM_AX),%edx 112*4882a593Smuzhiyun5: movl 4(%_ASM_AX),%ecx 113*4882a593Smuzhiyun xor %eax,%eax 114*4882a593Smuzhiyun ASM_CLAC 115*4882a593Smuzhiyun RET 116*4882a593Smuzhiyun#endif 117*4882a593SmuzhiyunSYM_FUNC_END(__get_user_8) 118*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_8) 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun/* .. and the same for __get_user, just without the range checks */ 121*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_1) 122*4882a593Smuzhiyun ASM_STAC 123*4882a593Smuzhiyun ASM_BARRIER_NOSPEC 124*4882a593Smuzhiyun6: movzbl (%_ASM_AX),%edx 125*4882a593Smuzhiyun xor %eax,%eax 126*4882a593Smuzhiyun ASM_CLAC 127*4882a593Smuzhiyun RET 128*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_1) 129*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_1) 130*4882a593Smuzhiyun 131*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_2) 132*4882a593Smuzhiyun ASM_STAC 133*4882a593Smuzhiyun ASM_BARRIER_NOSPEC 134*4882a593Smuzhiyun7: movzwl (%_ASM_AX),%edx 135*4882a593Smuzhiyun xor %eax,%eax 136*4882a593Smuzhiyun ASM_CLAC 137*4882a593Smuzhiyun RET 138*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_2) 139*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_2) 140*4882a593Smuzhiyun 141*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_4) 142*4882a593Smuzhiyun ASM_STAC 143*4882a593Smuzhiyun ASM_BARRIER_NOSPEC 144*4882a593Smuzhiyun8: movl (%_ASM_AX),%edx 145*4882a593Smuzhiyun xor %eax,%eax 146*4882a593Smuzhiyun ASM_CLAC 147*4882a593Smuzhiyun RET 148*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_4) 149*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_4) 150*4882a593Smuzhiyun 151*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_8) 152*4882a593Smuzhiyun ASM_STAC 153*4882a593Smuzhiyun ASM_BARRIER_NOSPEC 154*4882a593Smuzhiyun#ifdef CONFIG_X86_64 155*4882a593Smuzhiyun9: movq (%_ASM_AX),%rdx 156*4882a593Smuzhiyun#else 157*4882a593Smuzhiyun9: movl (%_ASM_AX),%edx 158*4882a593Smuzhiyun10: movl 4(%_ASM_AX),%ecx 159*4882a593Smuzhiyun#endif 160*4882a593Smuzhiyun xor %eax,%eax 161*4882a593Smuzhiyun ASM_CLAC 162*4882a593Smuzhiyun RET 163*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_8) 164*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_8) 165*4882a593Smuzhiyun 166*4882a593Smuzhiyun 167*4882a593SmuzhiyunSYM_CODE_START_LOCAL(.Lbad_get_user_clac) 168*4882a593Smuzhiyun ASM_CLAC 169*4882a593Smuzhiyunbad_get_user: 170*4882a593Smuzhiyun xor %edx,%edx 171*4882a593Smuzhiyun mov $(-EFAULT),%_ASM_AX 172*4882a593Smuzhiyun RET 173*4882a593SmuzhiyunSYM_CODE_END(.Lbad_get_user_clac) 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun#ifdef CONFIG_X86_32 176*4882a593SmuzhiyunSYM_CODE_START_LOCAL(.Lbad_get_user_8_clac) 177*4882a593Smuzhiyun ASM_CLAC 178*4882a593Smuzhiyunbad_get_user_8: 179*4882a593Smuzhiyun xor %edx,%edx 180*4882a593Smuzhiyun xor %ecx,%ecx 181*4882a593Smuzhiyun mov $(-EFAULT),%_ASM_AX 182*4882a593Smuzhiyun RET 183*4882a593SmuzhiyunSYM_CODE_END(.Lbad_get_user_8_clac) 184*4882a593Smuzhiyun#endif 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun/* get_user */ 187*4882a593Smuzhiyun _ASM_EXTABLE_UA(1b, .Lbad_get_user_clac) 188*4882a593Smuzhiyun _ASM_EXTABLE_UA(2b, .Lbad_get_user_clac) 189*4882a593Smuzhiyun _ASM_EXTABLE_UA(3b, .Lbad_get_user_clac) 190*4882a593Smuzhiyun#ifdef CONFIG_X86_64 191*4882a593Smuzhiyun _ASM_EXTABLE_UA(4b, .Lbad_get_user_clac) 192*4882a593Smuzhiyun#else 193*4882a593Smuzhiyun _ASM_EXTABLE_UA(4b, .Lbad_get_user_8_clac) 194*4882a593Smuzhiyun _ASM_EXTABLE_UA(5b, .Lbad_get_user_8_clac) 195*4882a593Smuzhiyun#endif 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun/* __get_user */ 198*4882a593Smuzhiyun _ASM_EXTABLE_UA(6b, .Lbad_get_user_clac) 199*4882a593Smuzhiyun _ASM_EXTABLE_UA(7b, .Lbad_get_user_clac) 200*4882a593Smuzhiyun _ASM_EXTABLE_UA(8b, .Lbad_get_user_clac) 201*4882a593Smuzhiyun#ifdef CONFIG_X86_64 202*4882a593Smuzhiyun _ASM_EXTABLE_UA(9b, .Lbad_get_user_clac) 203*4882a593Smuzhiyun#else 204*4882a593Smuzhiyun _ASM_EXTABLE_UA(9b, .Lbad_get_user_8_clac) 205*4882a593Smuzhiyun _ASM_EXTABLE_UA(10b, .Lbad_get_user_8_clac) 206*4882a593Smuzhiyun#endif 207