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