1194676Sthompsa/* SPDX-License-Identifier: GPL-2.0-only */
2194676Sthompsa/*
3194676Sthompsa *  linux/arch/arm/lib/putuser.S
4194676Sthompsa *
5194676Sthompsa *  Copyright (C) 2001 Russell King
6194676Sthompsa *
7194676Sthompsa *  Idea from x86 version, (C) Copyright 1998 Linus Torvalds
8194676Sthompsa *
9194676Sthompsa * These functions have a non-standard call interface to make
10194676Sthompsa * them more efficient, especially as they return an error
11194676Sthompsa * value in addition to the "real" return value.
12194676Sthompsa *
13194676Sthompsa * __put_user_X
14194676Sthompsa *
15194676Sthompsa * Inputs:	r0 contains the address
16194676Sthompsa *		r1 contains the address limit, which must be preserved
17194676Sthompsa *		r2, r3 contains the value
18194676Sthompsa * Outputs:	r0 is the error code
19194676Sthompsa *		lr corrupted
20194676Sthompsa *
21194676Sthompsa * No other registers must be altered.  (see <asm/uaccess.h>
22194676Sthompsa * for specific ASM register usage).
23194676Sthompsa *
24194676Sthompsa * Note that ADDR_LIMIT is either 0 or 0xc0000000
25194676Sthompsa * Note also that it is intended that __put_user_bad is not global.
26194676Sthompsa */
27194676Sthompsa#include <linux/linkage.h>
28194676Sthompsa#include <asm/assembler.h>
29194676Sthompsa#include <asm/errno.h>
30194676Sthompsa#include <asm/domain.h>
31194676Sthompsa
32194676SthompsaENTRY(__put_user_1)
33194676Sthompsa	check_uaccess r0, 1, r1, ip, __put_user_bad
34194676Sthompsa1: TUSER(strb)	r2, [r0]
35194676Sthompsa	mov	r0, #0
36194676Sthompsa	ret	lr
37194676SthompsaENDPROC(__put_user_1)
38194676Sthompsa
39194676SthompsaENTRY(__put_user_2)
40194676Sthompsa	check_uaccess r0, 2, r1, ip, __put_user_bad
41194676Sthompsa#if __LINUX_ARM_ARCH__ >= 6
42194676Sthompsa
43194676Sthompsa2: TUSER(strh)	r2, [r0]
44194676Sthompsa
45194676Sthompsa#else
46194676Sthompsa
47194676Sthompsa	mov	ip, r2, lsr #8
48194676Sthompsa#ifndef __ARMEB__
49194676Sthompsa2: TUSER(strb)	r2, [r0], #1
50194676Sthompsa3: TUSER(strb)	ip, [r0]
51194676Sthompsa#else
52194676Sthompsa2: TUSER(strb)	ip, [r0], #1
53194676Sthompsa3: TUSER(strb)	r2, [r0]
54194676Sthompsa#endif
55194676Sthompsa
56194676Sthompsa#endif /* __LINUX_ARM_ARCH__ >= 6 */
57194676Sthompsa	mov	r0, #0
58194676Sthompsa	ret	lr
59194676SthompsaENDPROC(__put_user_2)
60194676Sthompsa
61194676SthompsaENTRY(__put_user_4)
62194676Sthompsa	check_uaccess r0, 4, r1, ip, __put_user_bad
63194676Sthompsa4: TUSER(str)	r2, [r0]
64194676Sthompsa	mov	r0, #0
65194676Sthompsa	ret	lr
66194676SthompsaENDPROC(__put_user_4)
67194676Sthompsa
68194676SthompsaENTRY(__put_user_8)
69194676Sthompsa	check_uaccess r0, 8, r1, ip, __put_user_bad
70194676Sthompsa#ifdef CONFIG_THUMB2_KERNEL
71194676Sthompsa5: TUSER(str)	r2, [r0]
72194676Sthompsa6: TUSER(str)	r3, [r0, #4]
73194676Sthompsa#else
74194676Sthompsa5: TUSER(str)	r2, [r0], #4
75194676Sthompsa6: TUSER(str)	r3, [r0]
76194676Sthompsa#endif
77194676Sthompsa	mov	r0, #0
78194676Sthompsa	ret	lr
79194676SthompsaENDPROC(__put_user_8)
80194676Sthompsa
81194676Sthompsa__put_user_bad:
82194676Sthompsa	mov	r0, #-EFAULT
83194676Sthompsa	ret	lr
84194676SthompsaENDPROC(__put_user_bad)
85194676Sthompsa
86194676Sthompsa.pushsection __ex_table, "a"
87194676Sthompsa	.long	1b, __put_user_bad
88194676Sthompsa	.long	2b, __put_user_bad
89194676Sthompsa#if __LINUX_ARM_ARCH__ < 6
90194676Sthompsa	.long	3b, __put_user_bad
91194676Sthompsa#endif
92194676Sthompsa	.long	4b, __put_user_bad
93194676Sthompsa	.long	5b, __put_user_bad
94194676Sthompsa	.long	6b, __put_user_bad
95194676Sthompsa.popsection
96194676Sthompsa