18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#ifndef __ASM_UACCESS_ASM_H__
48c2ecf20Sopenharmony_ci#define __ASM_UACCESS_ASM_H__
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
78c2ecf20Sopenharmony_ci#include <asm/domain.h>
88c2ecf20Sopenharmony_ci#include <asm/memory.h>
98c2ecf20Sopenharmony_ci#include <asm/thread_info.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci	.macro	csdb
128c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL
138c2ecf20Sopenharmony_ci	.inst.w	0xf3af8014
148c2ecf20Sopenharmony_ci#else
158c2ecf20Sopenharmony_ci	.inst	0xe320f014
168c2ecf20Sopenharmony_ci#endif
178c2ecf20Sopenharmony_ci	.endm
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	.macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
208c2ecf20Sopenharmony_ci#ifndef CONFIG_CPU_USE_DOMAINS
218c2ecf20Sopenharmony_ci	adds	\tmp, \addr, #\size - 1
228c2ecf20Sopenharmony_ci	sbcscc	\tmp, \tmp, \limit
238c2ecf20Sopenharmony_ci	bcs	\bad
248c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE
258c2ecf20Sopenharmony_ci	movcs	\addr, #0
268c2ecf20Sopenharmony_ci	csdb
278c2ecf20Sopenharmony_ci#endif
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci	.endm
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	.macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req
328c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE
338c2ecf20Sopenharmony_ci	sub	\tmp, \limit, #1
348c2ecf20Sopenharmony_ci	subs	\tmp, \tmp, \addr	@ tmp = limit - 1 - addr
358c2ecf20Sopenharmony_ci	addhs	\tmp, \tmp, #1		@ if (tmp >= 0) {
368c2ecf20Sopenharmony_ci	subshs	\tmp, \tmp, \size	@ tmp = limit - (addr + size) }
378c2ecf20Sopenharmony_ci	movlo	\addr, #0		@ if (tmp < 0) addr = NULL
388c2ecf20Sopenharmony_ci	csdb
398c2ecf20Sopenharmony_ci#endif
408c2ecf20Sopenharmony_ci	.endm
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	.macro	uaccess_disable, tmp, isb=1
438c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN
448c2ecf20Sopenharmony_ci	/*
458c2ecf20Sopenharmony_ci	 * Whenever we re-enter userspace, the domains should always be
468c2ecf20Sopenharmony_ci	 * set appropriately.
478c2ecf20Sopenharmony_ci	 */
488c2ecf20Sopenharmony_ci	mov	\tmp, #DACR_UACCESS_DISABLE
498c2ecf20Sopenharmony_ci	mcr	p15, 0, \tmp, c3, c0, 0		@ Set domain register
508c2ecf20Sopenharmony_ci	.if	\isb
518c2ecf20Sopenharmony_ci	instr_sync
528c2ecf20Sopenharmony_ci	.endif
538c2ecf20Sopenharmony_ci#endif
548c2ecf20Sopenharmony_ci	.endm
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	.macro	uaccess_enable, tmp, isb=1
578c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN
588c2ecf20Sopenharmony_ci	/*
598c2ecf20Sopenharmony_ci	 * Whenever we re-enter userspace, the domains should always be
608c2ecf20Sopenharmony_ci	 * set appropriately.
618c2ecf20Sopenharmony_ci	 */
628c2ecf20Sopenharmony_ci	mov	\tmp, #DACR_UACCESS_ENABLE
638c2ecf20Sopenharmony_ci	mcr	p15, 0, \tmp, c3, c0, 0
648c2ecf20Sopenharmony_ci	.if	\isb
658c2ecf20Sopenharmony_ci	instr_sync
668c2ecf20Sopenharmony_ci	.endif
678c2ecf20Sopenharmony_ci#endif
688c2ecf20Sopenharmony_ci	.endm
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#if defined(CONFIG_CPU_SW_DOMAIN_PAN) || defined(CONFIG_CPU_USE_DOMAINS)
718c2ecf20Sopenharmony_ci#define DACR(x...)	x
728c2ecf20Sopenharmony_ci#else
738c2ecf20Sopenharmony_ci#define DACR(x...)
748c2ecf20Sopenharmony_ci#endif
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/*
778c2ecf20Sopenharmony_ci	 * Save the address limit on entry to a privileged exception.
788c2ecf20Sopenharmony_ci	 *
798c2ecf20Sopenharmony_ci	 * If we are using the DACR for kernel access by the user accessors
808c2ecf20Sopenharmony_ci	 * (CONFIG_CPU_USE_DOMAINS=y), always reset the DACR kernel domain
818c2ecf20Sopenharmony_ci	 * back to client mode, whether or not \disable is set.
828c2ecf20Sopenharmony_ci	 *
838c2ecf20Sopenharmony_ci	 * If we are using SW PAN, set the DACR user domain to no access
848c2ecf20Sopenharmony_ci	 * if \disable is set.
858c2ecf20Sopenharmony_ci	 */
868c2ecf20Sopenharmony_ci	.macro	uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
878c2ecf20Sopenharmony_ci	ldr	\tmp1, [\tsk, #TI_ADDR_LIMIT]
888c2ecf20Sopenharmony_ci	ldr	\tmp2, =TASK_SIZE
898c2ecf20Sopenharmony_ci	str	\tmp2, [\tsk, #TI_ADDR_LIMIT]
908c2ecf20Sopenharmony_ci DACR(	mrc	p15, 0, \tmp0, c3, c0, 0)
918c2ecf20Sopenharmony_ci DACR(	str	\tmp0, [sp, #SVC_DACR])
928c2ecf20Sopenharmony_ci	str	\tmp1, [sp, #SVC_ADDR_LIMIT]
938c2ecf20Sopenharmony_ci	.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
948c2ecf20Sopenharmony_ci	/* kernel=client, user=no access */
958c2ecf20Sopenharmony_ci	mov	\tmp2, #DACR_UACCESS_DISABLE
968c2ecf20Sopenharmony_ci	mcr	p15, 0, \tmp2, c3, c0, 0
978c2ecf20Sopenharmony_ci	instr_sync
988c2ecf20Sopenharmony_ci	.elseif IS_ENABLED(CONFIG_CPU_USE_DOMAINS)
998c2ecf20Sopenharmony_ci	/* kernel=client */
1008c2ecf20Sopenharmony_ci	bic	\tmp2, \tmp0, #domain_mask(DOMAIN_KERNEL)
1018c2ecf20Sopenharmony_ci	orr	\tmp2, \tmp2, #domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT)
1028c2ecf20Sopenharmony_ci	mcr	p15, 0, \tmp2, c3, c0, 0
1038c2ecf20Sopenharmony_ci	instr_sync
1048c2ecf20Sopenharmony_ci	.endif
1058c2ecf20Sopenharmony_ci	.endm
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Restore the user access state previously saved by uaccess_entry */
1088c2ecf20Sopenharmony_ci	.macro	uaccess_exit, tsk, tmp0, tmp1
1098c2ecf20Sopenharmony_ci	ldr	\tmp1, [sp, #SVC_ADDR_LIMIT]
1108c2ecf20Sopenharmony_ci DACR(	ldr	\tmp0, [sp, #SVC_DACR])
1118c2ecf20Sopenharmony_ci	str	\tmp1, [\tsk, #TI_ADDR_LIMIT]
1128c2ecf20Sopenharmony_ci DACR(	mcr	p15, 0, \tmp0, c3, c0, 0)
1138c2ecf20Sopenharmony_ci	.endm
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#undef DACR
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#endif /* __ASM_UACCESS_ASM_H__ */
118