1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * __put_user functions. 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * (C) Copyright 2005 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#include <linux/linkage.h> 15*4882a593Smuzhiyun#include <asm/thread_info.h> 16*4882a593Smuzhiyun#include <asm/errno.h> 17*4882a593Smuzhiyun#include <asm/asm.h> 18*4882a593Smuzhiyun#include <asm/smap.h> 19*4882a593Smuzhiyun#include <asm/export.h> 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun/* 23*4882a593Smuzhiyun * __put_user_X 24*4882a593Smuzhiyun * 25*4882a593Smuzhiyun * Inputs: %eax[:%edx] contains the data 26*4882a593Smuzhiyun * %ecx contains the address 27*4882a593Smuzhiyun * 28*4882a593Smuzhiyun * Outputs: %ecx is error code (0 or -EFAULT) 29*4882a593Smuzhiyun * 30*4882a593Smuzhiyun * Clobbers: %ebx needed for task pointer 31*4882a593Smuzhiyun * 32*4882a593Smuzhiyun * These functions should not modify any other registers, 33*4882a593Smuzhiyun * as they get called from within inline assembly. 34*4882a593Smuzhiyun */ 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun#ifdef CONFIG_X86_5LEVEL 37*4882a593Smuzhiyun#define LOAD_TASK_SIZE_MINUS_N(n) \ 38*4882a593Smuzhiyun ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rbx), \ 39*4882a593Smuzhiyun __stringify(mov $((1 << 56) - 4096 - (n)),%rbx), X86_FEATURE_LA57 40*4882a593Smuzhiyun#else 41*4882a593Smuzhiyun#define LOAD_TASK_SIZE_MINUS_N(n) \ 42*4882a593Smuzhiyun mov $(TASK_SIZE_MAX - (n)),%_ASM_BX 43*4882a593Smuzhiyun#endif 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun.text 46*4882a593SmuzhiyunSYM_FUNC_START(__put_user_1) 47*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(0) 48*4882a593Smuzhiyun cmp %_ASM_BX,%_ASM_CX 49*4882a593Smuzhiyun jae .Lbad_put_user 50*4882a593SmuzhiyunSYM_INNER_LABEL(__put_user_nocheck_1, SYM_L_GLOBAL) 51*4882a593Smuzhiyun ASM_STAC 52*4882a593Smuzhiyun1: movb %al,(%_ASM_CX) 53*4882a593Smuzhiyun xor %ecx,%ecx 54*4882a593Smuzhiyun ASM_CLAC 55*4882a593Smuzhiyun RET 56*4882a593SmuzhiyunSYM_FUNC_END(__put_user_1) 57*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_1) 58*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_nocheck_1) 59*4882a593Smuzhiyun 60*4882a593SmuzhiyunSYM_FUNC_START(__put_user_2) 61*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(1) 62*4882a593Smuzhiyun cmp %_ASM_BX,%_ASM_CX 63*4882a593Smuzhiyun jae .Lbad_put_user 64*4882a593SmuzhiyunSYM_INNER_LABEL(__put_user_nocheck_2, SYM_L_GLOBAL) 65*4882a593Smuzhiyun ASM_STAC 66*4882a593Smuzhiyun2: movw %ax,(%_ASM_CX) 67*4882a593Smuzhiyun xor %ecx,%ecx 68*4882a593Smuzhiyun ASM_CLAC 69*4882a593Smuzhiyun RET 70*4882a593SmuzhiyunSYM_FUNC_END(__put_user_2) 71*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_2) 72*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_nocheck_2) 73*4882a593Smuzhiyun 74*4882a593SmuzhiyunSYM_FUNC_START(__put_user_4) 75*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(3) 76*4882a593Smuzhiyun cmp %_ASM_BX,%_ASM_CX 77*4882a593Smuzhiyun jae .Lbad_put_user 78*4882a593SmuzhiyunSYM_INNER_LABEL(__put_user_nocheck_4, SYM_L_GLOBAL) 79*4882a593Smuzhiyun ASM_STAC 80*4882a593Smuzhiyun3: movl %eax,(%_ASM_CX) 81*4882a593Smuzhiyun xor %ecx,%ecx 82*4882a593Smuzhiyun ASM_CLAC 83*4882a593Smuzhiyun RET 84*4882a593SmuzhiyunSYM_FUNC_END(__put_user_4) 85*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_4) 86*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_nocheck_4) 87*4882a593Smuzhiyun 88*4882a593SmuzhiyunSYM_FUNC_START(__put_user_8) 89*4882a593Smuzhiyun LOAD_TASK_SIZE_MINUS_N(7) 90*4882a593Smuzhiyun cmp %_ASM_BX,%_ASM_CX 91*4882a593Smuzhiyun jae .Lbad_put_user 92*4882a593SmuzhiyunSYM_INNER_LABEL(__put_user_nocheck_8, SYM_L_GLOBAL) 93*4882a593Smuzhiyun ASM_STAC 94*4882a593Smuzhiyun4: mov %_ASM_AX,(%_ASM_CX) 95*4882a593Smuzhiyun#ifdef CONFIG_X86_32 96*4882a593Smuzhiyun5: movl %edx,4(%_ASM_CX) 97*4882a593Smuzhiyun#endif 98*4882a593Smuzhiyun xor %ecx,%ecx 99*4882a593Smuzhiyun ASM_CLAC 100*4882a593Smuzhiyun RET 101*4882a593SmuzhiyunSYM_FUNC_END(__put_user_8) 102*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_8) 103*4882a593SmuzhiyunEXPORT_SYMBOL(__put_user_nocheck_8) 104*4882a593Smuzhiyun 105*4882a593SmuzhiyunSYM_CODE_START_LOCAL(.Lbad_put_user_clac) 106*4882a593Smuzhiyun ASM_CLAC 107*4882a593Smuzhiyun.Lbad_put_user: 108*4882a593Smuzhiyun movl $-EFAULT,%ecx 109*4882a593Smuzhiyun RET 110*4882a593SmuzhiyunSYM_CODE_END(.Lbad_put_user_clac) 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun _ASM_EXTABLE_UA(1b, .Lbad_put_user_clac) 113*4882a593Smuzhiyun _ASM_EXTABLE_UA(2b, .Lbad_put_user_clac) 114*4882a593Smuzhiyun _ASM_EXTABLE_UA(3b, .Lbad_put_user_clac) 115*4882a593Smuzhiyun _ASM_EXTABLE_UA(4b, .Lbad_put_user_clac) 116*4882a593Smuzhiyun#ifdef CONFIG_X86_32 117*4882a593Smuzhiyun _ASM_EXTABLE_UA(5b, .Lbad_put_user_clac) 118*4882a593Smuzhiyun#endif 119