1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * linux/arch/arm/lib/getuser.S 4 * 5 * Copyright (C) 2001 Russell King 6 * 7 * Idea from x86 version, (C) Copyright 1998 Linus Torvalds 8 * 9 * These functions have a non-standard call interface to make them more 10 * efficient, especially as they return an error value in addition to 11 * the "real" return value. 12 * 13 * __get_user_X 14 * 15 * Inputs: r0 contains the address 16 * r1 contains the address limit, which must be preserved 17 * Outputs: r0 is the error code 18 * r2, r3 contains the zero-extended value 19 * lr corrupted 20 * 21 * No other registers must be altered. (see <asm/uaccess.h> 22 * for specific ASM register usage). 23 * 24 * Note that ADDR_LIMIT is either 0 or 0xc0000000. 25 * Note also that it is intended that __get_user_bad is not global. 26 */ 27 #include <linux/linkage.h> 28 #include <asm/assembler.h> 29 #include <asm/errno.h> 30 #include <asm/extable.h> 31 #include <asm/domain.h> 32 33 ENTRY(__get_user_1) 34 check_uaccess r0, 1, r1, r2, __get_user_bad 35 1: TUSER(ldrb) r2, [r0] 36 mov r0, #0 37 ret lr 38 ENDPROC(__get_user_1) 39 _ASM_NOKPROBE(__get_user_1) 40 41 ENTRY(__get_user_2) 42 check_uaccess r0, 2, r1, r2, __get_user_bad 43 #if __LINUX_ARM_ARCH__ >= 6 44 45 2: TUSER(ldrh) r2, [r0] 46 47 #else 48 49 #ifdef CONFIG_CPU_USE_DOMAINS 50 rb .req ip 51 2: ldrbt r2, [r0], #1 52 3: ldrbt rb, [r0], #0 53 #else 54 rb .req r0 55 2: ldrb r2, [r0] 56 3: ldrb rb, [r0, #1] 57 #endif 58 #ifndef __ARMEB__ 59 orr r2, r2, rb, lsl #8 60 #else 61 orr r2, rb, r2, lsl #8 62 #endif 63 64 #endif /* __LINUX_ARM_ARCH__ >= 6 */ 65 66 mov r0, #0 67 ret lr 68 ENDPROC(__get_user_2) 69 _ASM_NOKPROBE(__get_user_2) 70 71 ENTRY(__get_user_4) 72 check_uaccess r0, 4, r1, r2, __get_user_bad 73 4: TUSER(ldr) r2, [r0] 74 mov r0, #0 75 ret lr 76 ENDPROC(__get_user_4) 77 _ASM_NOKPROBE(__get_user_4) 78 79 ENTRY(__get_user_8) 80 check_uaccess r0, 8, r1, r2, __get_user_bad8 81 #ifdef CONFIG_THUMB2_KERNEL 82 5: TUSER(ldr) r2, [r0] 83 6: TUSER(ldr) r3, [r0, #4] 84 #else 85 5: TUSER(ldr) r2, [r0], #4 86 6: TUSER(ldr) r3, [r0] 87 #endif 88 mov r0, #0 89 ret lr 90 ENDPROC(__get_user_8) 91 _ASM_NOKPROBE(__get_user_8) 92 93 #ifdef __ARMEB__ 94 ENTRY(__get_user_32t_8) 95 check_uaccess r0, 8, r1, r2, __get_user_bad 96 #ifdef CONFIG_CPU_USE_DOMAINS 97 add r0, r0, #4 98 7: ldrt r2, [r0] 99 #else 100 7: ldr r2, [r0, #4] 101 #endif 102 mov r0, #0 103 ret lr 104 ENDPROC(__get_user_32t_8) 105 _ASM_NOKPROBE(__get_user_32t_8) 106 107 ENTRY(__get_user_64t_1) 108 check_uaccess r0, 1, r1, r2, __get_user_bad8 109 8: TUSER(ldrb) r3, [r0] 110 mov r0, #0 111 ret lr 112 ENDPROC(__get_user_64t_1) 113 _ASM_NOKPROBE(__get_user_64t_1) 114 115 ENTRY(__get_user_64t_2) 116 check_uaccess r0, 2, r1, r2, __get_user_bad8 117 #ifdef CONFIG_CPU_USE_DOMAINS 118 rb .req ip 119 9: ldrbt r3, [r0], #1 120 10: ldrbt rb, [r0], #0 121 #else 122 rb .req r0 123 9: ldrb r3, [r0] 124 10: ldrb rb, [r0, #1] 125 #endif 126 orr r3, rb, r3, lsl #8 127 mov r0, #0 128 ret lr 129 ENDPROC(__get_user_64t_2) 130 _ASM_NOKPROBE(__get_user_64t_2) 131 132 ENTRY(__get_user_64t_4) 133 check_uaccess r0, 4, r1, r2, __get_user_bad8 134 11: TUSER(ldr) r3, [r0] 135 mov r0, #0 136 ret lr 137 ENDPROC(__get_user_64t_4) 138 _ASM_NOKPROBE(__get_user_64t_4) 139 #endif 140 141 __get_user_bad8: 142 mov r3, #0 143 __get_user_bad: 144 mov r2, #0 145 mov r0, #-EFAULT 146 ret lr 147 ENDPROC(__get_user_bad) 148 ENDPROC(__get_user_bad8) 149 _ASM_NOKPROBE(__get_user_bad) 150 _ASM_NOKPROBE(__get_user_bad8) 151 152 .pushsection __ex_table, "a" 153 ex_entry 1b, __get_user_bad 154 ex_entry 2b, __get_user_bad 155 #if __LINUX_ARM_ARCH__ < 6 156 ex_entry 3b, __get_user_bad 157 #endif 158 ex_entry 4b, __get_user_bad 159 ex_entry 5b, __get_user_bad8 160 ex_entry 6b, __get_user_bad8 161 #ifdef __ARMEB__ 162 ex_entry 7b, __get_user_bad 163 ex_entry 8b, __get_user_bad8 164 ex_entry 9b, __get_user_bad8 165 ex_entry 10b, __get_user_bad8 166 ex_entry 11b, __get_user_bad8 167 #endif 168