162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/lib/getuser.S 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2001 Russell King 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Idea from x86 version, (C) Copyright 1998 Linus Torvalds 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * These functions have a non-standard call interface to make them more 1062306a36Sopenharmony_ci * efficient, especially as they return an error value in addition to 1162306a36Sopenharmony_ci * the "real" return value. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * __get_user_X 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Inputs: r0 contains the address 1662306a36Sopenharmony_ci * r1 contains the address limit, which must be preserved 1762306a36Sopenharmony_ci * Outputs: r0 is the error code 1862306a36Sopenharmony_ci * r2, r3 contains the zero-extended value 1962306a36Sopenharmony_ci * lr corrupted 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * No other registers must be altered. (see <asm/uaccess.h> 2262306a36Sopenharmony_ci * for specific ASM register usage). 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Note that ADDR_LIMIT is either 0 or 0xc0000000. 2562306a36Sopenharmony_ci * Note also that it is intended that __get_user_bad is not global. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci#include <linux/linkage.h> 2862306a36Sopenharmony_ci#include <asm/assembler.h> 2962306a36Sopenharmony_ci#include <asm/errno.h> 3062306a36Sopenharmony_ci#include <asm/domain.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciENTRY(__get_user_1) 3362306a36Sopenharmony_ci check_uaccess r0, 1, r1, r2, __get_user_bad 3462306a36Sopenharmony_ci1: TUSER(ldrb) r2, [r0] 3562306a36Sopenharmony_ci mov r0, #0 3662306a36Sopenharmony_ci ret lr 3762306a36Sopenharmony_ciENDPROC(__get_user_1) 3862306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_1) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ciENTRY(__get_user_2) 4162306a36Sopenharmony_ci check_uaccess r0, 2, r1, r2, __get_user_bad 4262306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci2: TUSER(ldrh) r2, [r0] 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#else 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 4962306a36Sopenharmony_cirb .req ip 5062306a36Sopenharmony_ci2: ldrbt r2, [r0], #1 5162306a36Sopenharmony_ci3: ldrbt rb, [r0], #0 5262306a36Sopenharmony_ci#else 5362306a36Sopenharmony_cirb .req r0 5462306a36Sopenharmony_ci2: ldrb r2, [r0] 5562306a36Sopenharmony_ci3: ldrb rb, [r0, #1] 5662306a36Sopenharmony_ci#endif 5762306a36Sopenharmony_ci#ifndef __ARMEB__ 5862306a36Sopenharmony_ci orr r2, r2, rb, lsl #8 5962306a36Sopenharmony_ci#else 6062306a36Sopenharmony_ci orr r2, rb, r2, lsl #8 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ >= 6 */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci mov r0, #0 6662306a36Sopenharmony_ci ret lr 6762306a36Sopenharmony_ciENDPROC(__get_user_2) 6862306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_2) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciENTRY(__get_user_4) 7162306a36Sopenharmony_ci check_uaccess r0, 4, r1, r2, __get_user_bad 7262306a36Sopenharmony_ci4: TUSER(ldr) r2, [r0] 7362306a36Sopenharmony_ci mov r0, #0 7462306a36Sopenharmony_ci ret lr 7562306a36Sopenharmony_ciENDPROC(__get_user_4) 7662306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_4) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciENTRY(__get_user_8) 7962306a36Sopenharmony_ci check_uaccess r0, 8, r1, r2, __get_user_bad8 8062306a36Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL 8162306a36Sopenharmony_ci5: TUSER(ldr) r2, [r0] 8262306a36Sopenharmony_ci6: TUSER(ldr) r3, [r0, #4] 8362306a36Sopenharmony_ci#else 8462306a36Sopenharmony_ci5: TUSER(ldr) r2, [r0], #4 8562306a36Sopenharmony_ci6: TUSER(ldr) r3, [r0] 8662306a36Sopenharmony_ci#endif 8762306a36Sopenharmony_ci mov r0, #0 8862306a36Sopenharmony_ci ret lr 8962306a36Sopenharmony_ciENDPROC(__get_user_8) 9062306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_8) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#ifdef __ARMEB__ 9362306a36Sopenharmony_ciENTRY(__get_user_32t_8) 9462306a36Sopenharmony_ci check_uaccess r0, 8, r1, r2, __get_user_bad 9562306a36Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 9662306a36Sopenharmony_ci add r0, r0, #4 9762306a36Sopenharmony_ci7: ldrt r2, [r0] 9862306a36Sopenharmony_ci#else 9962306a36Sopenharmony_ci7: ldr r2, [r0, #4] 10062306a36Sopenharmony_ci#endif 10162306a36Sopenharmony_ci mov r0, #0 10262306a36Sopenharmony_ci ret lr 10362306a36Sopenharmony_ciENDPROC(__get_user_32t_8) 10462306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_32t_8) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciENTRY(__get_user_64t_1) 10762306a36Sopenharmony_ci check_uaccess r0, 1, r1, r2, __get_user_bad8 10862306a36Sopenharmony_ci8: TUSER(ldrb) r3, [r0] 10962306a36Sopenharmony_ci mov r0, #0 11062306a36Sopenharmony_ci ret lr 11162306a36Sopenharmony_ciENDPROC(__get_user_64t_1) 11262306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_64t_1) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciENTRY(__get_user_64t_2) 11562306a36Sopenharmony_ci check_uaccess r0, 2, r1, r2, __get_user_bad8 11662306a36Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 11762306a36Sopenharmony_cirb .req ip 11862306a36Sopenharmony_ci9: ldrbt r3, [r0], #1 11962306a36Sopenharmony_ci10: ldrbt rb, [r0], #0 12062306a36Sopenharmony_ci#else 12162306a36Sopenharmony_cirb .req r0 12262306a36Sopenharmony_ci9: ldrb r3, [r0] 12362306a36Sopenharmony_ci10: ldrb rb, [r0, #1] 12462306a36Sopenharmony_ci#endif 12562306a36Sopenharmony_ci orr r3, rb, r3, lsl #8 12662306a36Sopenharmony_ci mov r0, #0 12762306a36Sopenharmony_ci ret lr 12862306a36Sopenharmony_ciENDPROC(__get_user_64t_2) 12962306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_64t_2) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciENTRY(__get_user_64t_4) 13262306a36Sopenharmony_ci check_uaccess r0, 4, r1, r2, __get_user_bad8 13362306a36Sopenharmony_ci11: TUSER(ldr) r3, [r0] 13462306a36Sopenharmony_ci mov r0, #0 13562306a36Sopenharmony_ci ret lr 13662306a36Sopenharmony_ciENDPROC(__get_user_64t_4) 13762306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_64t_4) 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci__get_user_bad8: 14162306a36Sopenharmony_ci mov r3, #0 14262306a36Sopenharmony_ci__get_user_bad: 14362306a36Sopenharmony_ci mov r2, #0 14462306a36Sopenharmony_ci mov r0, #-EFAULT 14562306a36Sopenharmony_ci ret lr 14662306a36Sopenharmony_ciENDPROC(__get_user_bad) 14762306a36Sopenharmony_ciENDPROC(__get_user_bad8) 14862306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_bad) 14962306a36Sopenharmony_ci_ASM_NOKPROBE(__get_user_bad8) 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci.pushsection __ex_table, "a" 15262306a36Sopenharmony_ci .long 1b, __get_user_bad 15362306a36Sopenharmony_ci .long 2b, __get_user_bad 15462306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6 15562306a36Sopenharmony_ci .long 3b, __get_user_bad 15662306a36Sopenharmony_ci#endif 15762306a36Sopenharmony_ci .long 4b, __get_user_bad 15862306a36Sopenharmony_ci .long 5b, __get_user_bad8 15962306a36Sopenharmony_ci .long 6b, __get_user_bad8 16062306a36Sopenharmony_ci#ifdef __ARMEB__ 16162306a36Sopenharmony_ci .long 7b, __get_user_bad 16262306a36Sopenharmony_ci .long 8b, __get_user_bad8 16362306a36Sopenharmony_ci .long 9b, __get_user_bad8 16462306a36Sopenharmony_ci .long 10b, __get_user_bad8 16562306a36Sopenharmony_ci .long 11b, __get_user_bad8 16662306a36Sopenharmony_ci#endif 16762306a36Sopenharmony_ci.popsection 168