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