162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#ifndef __ASM_UACCESS_ASM_H__
462306a36Sopenharmony_ci#define __ASM_UACCESS_ASM_H__
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <asm/asm-offsets.h>
762306a36Sopenharmony_ci#include <asm/domain.h>
862306a36Sopenharmony_ci#include <asm/page.h>
962306a36Sopenharmony_ci#include <asm/thread_info.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci	.macro	csdb
1262306a36Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL
1362306a36Sopenharmony_ci	.inst.w	0xf3af8014
1462306a36Sopenharmony_ci#else
1562306a36Sopenharmony_ci	.inst	0xe320f014
1662306a36Sopenharmony_ci#endif
1762306a36Sopenharmony_ci	.endm
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	.macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
2062306a36Sopenharmony_ci#ifndef CONFIG_CPU_USE_DOMAINS
2162306a36Sopenharmony_ci	adds	\tmp, \addr, #\size - 1
2262306a36Sopenharmony_ci	sbcscc	\tmp, \tmp, \limit
2362306a36Sopenharmony_ci	bcs	\bad
2462306a36Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE
2562306a36Sopenharmony_ci	movcs	\addr, #0
2662306a36Sopenharmony_ci	csdb
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci	.endm
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	.macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req
3262306a36Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE
3362306a36Sopenharmony_ci	sub	\tmp, \limit, #1
3462306a36Sopenharmony_ci	subs	\tmp, \tmp, \addr	@ tmp = limit - 1 - addr
3562306a36Sopenharmony_ci	addhs	\tmp, \tmp, #1		@ if (tmp >= 0) {
3662306a36Sopenharmony_ci	subshs	\tmp, \tmp, \size	@ tmp = limit - (addr + size) }
3762306a36Sopenharmony_ci	movlo	\addr, #0		@ if (tmp < 0) addr = NULL
3862306a36Sopenharmony_ci	csdb
3962306a36Sopenharmony_ci#endif
4062306a36Sopenharmony_ci	.endm
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	.macro	uaccess_disable, tmp, isb=1
4362306a36Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * Whenever we re-enter userspace, the domains should always be
4662306a36Sopenharmony_ci	 * set appropriately.
4762306a36Sopenharmony_ci	 */
4862306a36Sopenharmony_ci	mov	\tmp, #DACR_UACCESS_DISABLE
4962306a36Sopenharmony_ci	mcr	p15, 0, \tmp, c3, c0, 0		@ Set domain register
5062306a36Sopenharmony_ci	.if	\isb
5162306a36Sopenharmony_ci	instr_sync
5262306a36Sopenharmony_ci	.endif
5362306a36Sopenharmony_ci#endif
5462306a36Sopenharmony_ci	.endm
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	.macro	uaccess_enable, tmp, isb=1
5762306a36Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN
5862306a36Sopenharmony_ci	/*
5962306a36Sopenharmony_ci	 * Whenever we re-enter userspace, the domains should always be
6062306a36Sopenharmony_ci	 * set appropriately.
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	mov	\tmp, #DACR_UACCESS_ENABLE
6362306a36Sopenharmony_ci	mcr	p15, 0, \tmp, c3, c0, 0
6462306a36Sopenharmony_ci	.if	\isb
6562306a36Sopenharmony_ci	instr_sync
6662306a36Sopenharmony_ci	.endif
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci	.endm
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#if defined(CONFIG_CPU_SW_DOMAIN_PAN) || defined(CONFIG_CPU_USE_DOMAINS)
7162306a36Sopenharmony_ci#define DACR(x...)	x
7262306a36Sopenharmony_ci#else
7362306a36Sopenharmony_ci#define DACR(x...)
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	/*
7762306a36Sopenharmony_ci	 * Save the address limit on entry to a privileged exception.
7862306a36Sopenharmony_ci	 *
7962306a36Sopenharmony_ci	 * If we are using the DACR for kernel access by the user accessors
8062306a36Sopenharmony_ci	 * (CONFIG_CPU_USE_DOMAINS=y), always reset the DACR kernel domain
8162306a36Sopenharmony_ci	 * back to client mode, whether or not \disable is set.
8262306a36Sopenharmony_ci	 *
8362306a36Sopenharmony_ci	 * If we are using SW PAN, set the DACR user domain to no access
8462306a36Sopenharmony_ci	 * if \disable is set.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	.macro	uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
8762306a36Sopenharmony_ci DACR(	mrc	p15, 0, \tmp0, c3, c0, 0)
8862306a36Sopenharmony_ci DACR(	str	\tmp0, [sp, #SVC_DACR])
8962306a36Sopenharmony_ci	.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
9062306a36Sopenharmony_ci	/* kernel=client, user=no access */
9162306a36Sopenharmony_ci	mov	\tmp2, #DACR_UACCESS_DISABLE
9262306a36Sopenharmony_ci	mcr	p15, 0, \tmp2, c3, c0, 0
9362306a36Sopenharmony_ci	instr_sync
9462306a36Sopenharmony_ci	.elseif IS_ENABLED(CONFIG_CPU_USE_DOMAINS)
9562306a36Sopenharmony_ci	/* kernel=client */
9662306a36Sopenharmony_ci	bic	\tmp2, \tmp0, #domain_mask(DOMAIN_KERNEL)
9762306a36Sopenharmony_ci	orr	\tmp2, \tmp2, #domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT)
9862306a36Sopenharmony_ci	mcr	p15, 0, \tmp2, c3, c0, 0
9962306a36Sopenharmony_ci	instr_sync
10062306a36Sopenharmony_ci	.endif
10162306a36Sopenharmony_ci	.endm
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Restore the user access state previously saved by uaccess_entry */
10462306a36Sopenharmony_ci	.macro	uaccess_exit, tsk, tmp0, tmp1
10562306a36Sopenharmony_ci DACR(	ldr	\tmp0, [sp, #SVC_DACR])
10662306a36Sopenharmony_ci DACR(	mcr	p15, 0, \tmp0, c3, c0, 0)
10762306a36Sopenharmony_ci	.endm
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#undef DACR
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#endif /* __ASM_UACCESS_ASM_H__ */
112