18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/lib/getuser.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001 Russell King 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Idea from x86 version, (C) Copyright 1998 Linus Torvalds 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * These functions have a non-standard call interface to make them more 108c2ecf20Sopenharmony_ci * efficient, especially as they return an error value in addition to 118c2ecf20Sopenharmony_ci * the "real" return value. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * __get_user_X 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Inputs: r0 contains the address 168c2ecf20Sopenharmony_ci * r1 contains the address limit, which must be preserved 178c2ecf20Sopenharmony_ci * Outputs: r0 is the error code 188c2ecf20Sopenharmony_ci * r2, r3 contains the zero-extended value 198c2ecf20Sopenharmony_ci * lr corrupted 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * No other registers must be altered. (see <asm/uaccess.h> 228c2ecf20Sopenharmony_ci * for specific ASM register usage). 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Note that ADDR_LIMIT is either 0 or 0xc0000000. 258c2ecf20Sopenharmony_ci * Note also that it is intended that __get_user_bad is not global. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci#include <linux/linkage.h> 288c2ecf20Sopenharmony_ci#include <asm/assembler.h> 298c2ecf20Sopenharmony_ci#include <asm/errno.h> 308c2ecf20Sopenharmony_ci#include <asm/extable.h> 318c2ecf20Sopenharmony_ci#include <asm/domain.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciENTRY(__get_user_1) 348c2ecf20Sopenharmony_ci check_uaccess r0, 1, r1, r2, __get_user_bad 358c2ecf20Sopenharmony_ci1: TUSER(ldrb) r2, [r0] 368c2ecf20Sopenharmony_ci mov r0, #0 378c2ecf20Sopenharmony_ci ret lr 388c2ecf20Sopenharmony_ciENDPROC(__get_user_1) 398c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_1) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciENTRY(__get_user_2) 428c2ecf20Sopenharmony_ci check_uaccess r0, 2, r1, r2, __get_user_bad 438c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci2: TUSER(ldrh) r2, [r0] 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#else 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 508c2ecf20Sopenharmony_cirb .req ip 518c2ecf20Sopenharmony_ci2: ldrbt r2, [r0], #1 528c2ecf20Sopenharmony_ci3: ldrbt rb, [r0], #0 538c2ecf20Sopenharmony_ci#else 548c2ecf20Sopenharmony_cirb .req r0 558c2ecf20Sopenharmony_ci2: ldrb r2, [r0] 568c2ecf20Sopenharmony_ci3: ldrb rb, [r0, #1] 578c2ecf20Sopenharmony_ci#endif 588c2ecf20Sopenharmony_ci#ifndef __ARMEB__ 598c2ecf20Sopenharmony_ci orr r2, r2, rb, lsl #8 608c2ecf20Sopenharmony_ci#else 618c2ecf20Sopenharmony_ci orr r2, rb, r2, lsl #8 628c2ecf20Sopenharmony_ci#endif 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ >= 6 */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mov r0, #0 678c2ecf20Sopenharmony_ci ret lr 688c2ecf20Sopenharmony_ciENDPROC(__get_user_2) 698c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_2) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciENTRY(__get_user_4) 728c2ecf20Sopenharmony_ci check_uaccess r0, 4, r1, r2, __get_user_bad 738c2ecf20Sopenharmony_ci4: TUSER(ldr) r2, [r0] 748c2ecf20Sopenharmony_ci mov r0, #0 758c2ecf20Sopenharmony_ci ret lr 768c2ecf20Sopenharmony_ciENDPROC(__get_user_4) 778c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_4) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciENTRY(__get_user_8) 808c2ecf20Sopenharmony_ci check_uaccess r0, 8, r1, r2, __get_user_bad8 818c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL 828c2ecf20Sopenharmony_ci5: TUSER(ldr) r2, [r0] 838c2ecf20Sopenharmony_ci6: TUSER(ldr) r3, [r0, #4] 848c2ecf20Sopenharmony_ci#else 858c2ecf20Sopenharmony_ci5: TUSER(ldr) r2, [r0], #4 868c2ecf20Sopenharmony_ci6: TUSER(ldr) r3, [r0] 878c2ecf20Sopenharmony_ci#endif 888c2ecf20Sopenharmony_ci mov r0, #0 898c2ecf20Sopenharmony_ci ret lr 908c2ecf20Sopenharmony_ciENDPROC(__get_user_8) 918c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_8) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 948c2ecf20Sopenharmony_ciENTRY(__get_user_32t_8) 958c2ecf20Sopenharmony_ci check_uaccess r0, 8, r1, r2, __get_user_bad 968c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 978c2ecf20Sopenharmony_ci add r0, r0, #4 988c2ecf20Sopenharmony_ci7: ldrt r2, [r0] 998c2ecf20Sopenharmony_ci#else 1008c2ecf20Sopenharmony_ci7: ldr r2, [r0, #4] 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_ci mov r0, #0 1038c2ecf20Sopenharmony_ci ret lr 1048c2ecf20Sopenharmony_ciENDPROC(__get_user_32t_8) 1058c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_32t_8) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciENTRY(__get_user_64t_1) 1088c2ecf20Sopenharmony_ci check_uaccess r0, 1, r1, r2, __get_user_bad8 1098c2ecf20Sopenharmony_ci8: TUSER(ldrb) r3, [r0] 1108c2ecf20Sopenharmony_ci mov r0, #0 1118c2ecf20Sopenharmony_ci ret lr 1128c2ecf20Sopenharmony_ciENDPROC(__get_user_64t_1) 1138c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_64t_1) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciENTRY(__get_user_64t_2) 1168c2ecf20Sopenharmony_ci check_uaccess r0, 2, r1, r2, __get_user_bad8 1178c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 1188c2ecf20Sopenharmony_cirb .req ip 1198c2ecf20Sopenharmony_ci9: ldrbt r3, [r0], #1 1208c2ecf20Sopenharmony_ci10: ldrbt rb, [r0], #0 1218c2ecf20Sopenharmony_ci#else 1228c2ecf20Sopenharmony_cirb .req r0 1238c2ecf20Sopenharmony_ci9: ldrb r3, [r0] 1248c2ecf20Sopenharmony_ci10: ldrb rb, [r0, #1] 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci orr r3, rb, r3, lsl #8 1278c2ecf20Sopenharmony_ci mov r0, #0 1288c2ecf20Sopenharmony_ci ret lr 1298c2ecf20Sopenharmony_ciENDPROC(__get_user_64t_2) 1308c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_64t_2) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciENTRY(__get_user_64t_4) 1338c2ecf20Sopenharmony_ci check_uaccess r0, 4, r1, r2, __get_user_bad8 1348c2ecf20Sopenharmony_ci11: TUSER(ldr) r3, [r0] 1358c2ecf20Sopenharmony_ci mov r0, #0 1368c2ecf20Sopenharmony_ci ret lr 1378c2ecf20Sopenharmony_ciENDPROC(__get_user_64t_4) 1388c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_64t_4) 1398c2ecf20Sopenharmony_ci#endif 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci__get_user_bad8: 1428c2ecf20Sopenharmony_ci mov r3, #0 1438c2ecf20Sopenharmony_ci__get_user_bad: 1448c2ecf20Sopenharmony_ci mov r2, #0 1458c2ecf20Sopenharmony_ci mov r0, #-EFAULT 1468c2ecf20Sopenharmony_ci ret lr 1478c2ecf20Sopenharmony_ciENDPROC(__get_user_bad) 1488c2ecf20Sopenharmony_ciENDPROC(__get_user_bad8) 1498c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_bad) 1508c2ecf20Sopenharmony_ci_ASM_NOKPROBE(__get_user_bad8) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci.pushsection __ex_table, "a" 1538c2ecf20Sopenharmony_ci ex_entry 1b, __get_user_bad 1548c2ecf20Sopenharmony_ci ex_entry 2b, __get_user_bad 1558c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6 1568c2ecf20Sopenharmony_ci ex_entry 3b, __get_user_bad 1578c2ecf20Sopenharmony_ci#endif 1588c2ecf20Sopenharmony_ci ex_entry 4b, __get_user_bad 1598c2ecf20Sopenharmony_ci ex_entry 5b, __get_user_bad8 1608c2ecf20Sopenharmony_ci ex_entry 6b, __get_user_bad8 1618c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 1628c2ecf20Sopenharmony_ci ex_entry 7b, __get_user_bad 1638c2ecf20Sopenharmony_ci ex_entry 8b, __get_user_bad8 1648c2ecf20Sopenharmony_ci ex_entry 9b, __get_user_bad8 1658c2ecf20Sopenharmony_ci ex_entry 10b, __get_user_bad8 1668c2ecf20Sopenharmony_ci ex_entry 11b, __get_user_bad8 1678c2ecf20Sopenharmony_ci#endif 168