18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  arch/arm/include/asm/assembler.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1996-2000 Russell King
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  This file contains arm architecture specific defines
88c2ecf20Sopenharmony_ci *  for the different processors.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  Do not include any C declarations in this file - it is included by
118c2ecf20Sopenharmony_ci *  assembler source.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#ifndef __ASM_ASSEMBLER_H__
148c2ecf20Sopenharmony_ci#define __ASM_ASSEMBLER_H__
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
178c2ecf20Sopenharmony_ci#error "Only include this from assembly code"
188c2ecf20Sopenharmony_ci#endif
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
218c2ecf20Sopenharmony_ci#include <asm/extable.h>
228c2ecf20Sopenharmony_ci#include <asm/opcodes-virt.h>
238c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
248c2ecf20Sopenharmony_ci#include <asm/page.h>
258c2ecf20Sopenharmony_ci#include <asm/thread_info.h>
268c2ecf20Sopenharmony_ci#include <asm/uaccess-asm.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define IOMEM(x)	(x)
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * Endian independent macros for shifting bytes within registers.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci#ifndef __ARMEB__
348c2ecf20Sopenharmony_ci#define lspull          lsr
358c2ecf20Sopenharmony_ci#define lspush          lsl
368c2ecf20Sopenharmony_ci#define get_byte_0      lsl #0
378c2ecf20Sopenharmony_ci#define get_byte_1	lsr #8
388c2ecf20Sopenharmony_ci#define get_byte_2	lsr #16
398c2ecf20Sopenharmony_ci#define get_byte_3	lsr #24
408c2ecf20Sopenharmony_ci#define put_byte_0      lsl #0
418c2ecf20Sopenharmony_ci#define put_byte_1	lsl #8
428c2ecf20Sopenharmony_ci#define put_byte_2	lsl #16
438c2ecf20Sopenharmony_ci#define put_byte_3	lsl #24
448c2ecf20Sopenharmony_ci#else
458c2ecf20Sopenharmony_ci#define lspull          lsl
468c2ecf20Sopenharmony_ci#define lspush          lsr
478c2ecf20Sopenharmony_ci#define get_byte_0	lsr #24
488c2ecf20Sopenharmony_ci#define get_byte_1	lsr #16
498c2ecf20Sopenharmony_ci#define get_byte_2	lsr #8
508c2ecf20Sopenharmony_ci#define get_byte_3      lsl #0
518c2ecf20Sopenharmony_ci#define put_byte_0	lsl #24
528c2ecf20Sopenharmony_ci#define put_byte_1	lsl #16
538c2ecf20Sopenharmony_ci#define put_byte_2	lsl #8
548c2ecf20Sopenharmony_ci#define put_byte_3      lsl #0
558c2ecf20Sopenharmony_ci#endif
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* Select code for any configuration running in BE8 mode */
588c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_ENDIAN_BE8
598c2ecf20Sopenharmony_ci#define ARM_BE8(code...) code
608c2ecf20Sopenharmony_ci#else
618c2ecf20Sopenharmony_ci#define ARM_BE8(code...)
628c2ecf20Sopenharmony_ci#endif
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci/*
658c2ecf20Sopenharmony_ci * Data preload for architectures that support it
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 5
688c2ecf20Sopenharmony_ci#define PLD(code...)	code
698c2ecf20Sopenharmony_ci#else
708c2ecf20Sopenharmony_ci#define PLD(code...)
718c2ecf20Sopenharmony_ci#endif
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * This can be used to enable code to cacheline align the destination
758c2ecf20Sopenharmony_ci * pointer when bulk writing to memory.  Experiments on StrongARM and
768c2ecf20Sopenharmony_ci * XScale didn't show this a worthwhile thing to do when the cache is not
778c2ecf20Sopenharmony_ci * set to write-allocate (this would need further testing on XScale when WA
788c2ecf20Sopenharmony_ci * is used).
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * On Feroceon there is much to gain however, regardless of cache mode.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_FEROCEON
838c2ecf20Sopenharmony_ci#define CALGN(code...) code
848c2ecf20Sopenharmony_ci#else
858c2ecf20Sopenharmony_ci#define CALGN(code...)
868c2ecf20Sopenharmony_ci#endif
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define IMM12_MASK 0xfff
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/*
918c2ecf20Sopenharmony_ci * Enable and disable interrupts
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6
948c2ecf20Sopenharmony_ci	.macro	disable_irq_notrace
958c2ecf20Sopenharmony_ci	cpsid	i
968c2ecf20Sopenharmony_ci	.endm
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	.macro	enable_irq_notrace
998c2ecf20Sopenharmony_ci	cpsie	i
1008c2ecf20Sopenharmony_ci	.endm
1018c2ecf20Sopenharmony_ci#else
1028c2ecf20Sopenharmony_ci	.macro	disable_irq_notrace
1038c2ecf20Sopenharmony_ci	msr	cpsr_c, #PSR_I_BIT | SVC_MODE
1048c2ecf20Sopenharmony_ci	.endm
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	.macro	enable_irq_notrace
1078c2ecf20Sopenharmony_ci	msr	cpsr_c, #SVC_MODE
1088c2ecf20Sopenharmony_ci	.endm
1098c2ecf20Sopenharmony_ci#endif
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 7
1128c2ecf20Sopenharmony_ci	.macro	dsb, args
1138c2ecf20Sopenharmony_ci	mcr	p15, 0, r0, c7, c10, 4
1148c2ecf20Sopenharmony_ci	.endm
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	.macro	isb, args
1178c2ecf20Sopenharmony_ci	mcr	p15, 0, r0, c7, c5, 4
1188c2ecf20Sopenharmony_ci	.endm
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	.macro asm_trace_hardirqs_off, save=1
1228c2ecf20Sopenharmony_ci#if defined(CONFIG_TRACE_IRQFLAGS)
1238c2ecf20Sopenharmony_ci	.if \save
1248c2ecf20Sopenharmony_ci	stmdb   sp!, {r0-r3, ip, lr}
1258c2ecf20Sopenharmony_ci	.endif
1268c2ecf20Sopenharmony_ci	bl	trace_hardirqs_off
1278c2ecf20Sopenharmony_ci	.if \save
1288c2ecf20Sopenharmony_ci	ldmia	sp!, {r0-r3, ip, lr}
1298c2ecf20Sopenharmony_ci	.endif
1308c2ecf20Sopenharmony_ci#endif
1318c2ecf20Sopenharmony_ci	.endm
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	.macro asm_trace_hardirqs_on, cond=al, save=1
1348c2ecf20Sopenharmony_ci#if defined(CONFIG_TRACE_IRQFLAGS)
1358c2ecf20Sopenharmony_ci	/*
1368c2ecf20Sopenharmony_ci	 * actually the registers should be pushed and pop'd conditionally, but
1378c2ecf20Sopenharmony_ci	 * after bl the flags are certainly clobbered
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	.if \save
1408c2ecf20Sopenharmony_ci	stmdb   sp!, {r0-r3, ip, lr}
1418c2ecf20Sopenharmony_ci	.endif
1428c2ecf20Sopenharmony_ci	bl\cond	trace_hardirqs_on
1438c2ecf20Sopenharmony_ci	.if \save
1448c2ecf20Sopenharmony_ci	ldmia	sp!, {r0-r3, ip, lr}
1458c2ecf20Sopenharmony_ci	.endif
1468c2ecf20Sopenharmony_ci#endif
1478c2ecf20Sopenharmony_ci	.endm
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	.macro disable_irq, save=1
1508c2ecf20Sopenharmony_ci	disable_irq_notrace
1518c2ecf20Sopenharmony_ci	asm_trace_hardirqs_off \save
1528c2ecf20Sopenharmony_ci	.endm
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	.macro enable_irq
1558c2ecf20Sopenharmony_ci	asm_trace_hardirqs_on
1568c2ecf20Sopenharmony_ci	enable_irq_notrace
1578c2ecf20Sopenharmony_ci	.endm
1588c2ecf20Sopenharmony_ci/*
1598c2ecf20Sopenharmony_ci * Save the current IRQ state and disable IRQs.  Note that this macro
1608c2ecf20Sopenharmony_ci * assumes FIQs are enabled, and that the processor is in SVC mode.
1618c2ecf20Sopenharmony_ci */
1628c2ecf20Sopenharmony_ci	.macro	save_and_disable_irqs, oldcpsr
1638c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_V7M
1648c2ecf20Sopenharmony_ci	mrs	\oldcpsr, primask
1658c2ecf20Sopenharmony_ci#else
1668c2ecf20Sopenharmony_ci	mrs	\oldcpsr, cpsr
1678c2ecf20Sopenharmony_ci#endif
1688c2ecf20Sopenharmony_ci	disable_irq
1698c2ecf20Sopenharmony_ci	.endm
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	.macro	save_and_disable_irqs_notrace, oldcpsr
1728c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_V7M
1738c2ecf20Sopenharmony_ci	mrs	\oldcpsr, primask
1748c2ecf20Sopenharmony_ci#else
1758c2ecf20Sopenharmony_ci	mrs	\oldcpsr, cpsr
1768c2ecf20Sopenharmony_ci#endif
1778c2ecf20Sopenharmony_ci	disable_irq_notrace
1788c2ecf20Sopenharmony_ci	.endm
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/*
1818c2ecf20Sopenharmony_ci * Restore interrupt state previously stored in a register.  We don't
1828c2ecf20Sopenharmony_ci * guarantee that this will preserve the flags.
1838c2ecf20Sopenharmony_ci */
1848c2ecf20Sopenharmony_ci	.macro	restore_irqs_notrace, oldcpsr
1858c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_V7M
1868c2ecf20Sopenharmony_ci	msr	primask, \oldcpsr
1878c2ecf20Sopenharmony_ci#else
1888c2ecf20Sopenharmony_ci	msr	cpsr_c, \oldcpsr
1898c2ecf20Sopenharmony_ci#endif
1908c2ecf20Sopenharmony_ci	.endm
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	.macro restore_irqs, oldcpsr
1938c2ecf20Sopenharmony_ci	tst	\oldcpsr, #PSR_I_BIT
1948c2ecf20Sopenharmony_ci	asm_trace_hardirqs_on cond=eq
1958c2ecf20Sopenharmony_ci	restore_irqs_notrace \oldcpsr
1968c2ecf20Sopenharmony_ci	.endm
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci/*
1998c2ecf20Sopenharmony_ci * Assembly version of "adr rd, BSYM(sym)".  This should only be used to
2008c2ecf20Sopenharmony_ci * reference local symbols in the same assembly file which are to be
2018c2ecf20Sopenharmony_ci * resolved by the assembler.  Other usage is undefined.
2028c2ecf20Sopenharmony_ci */
2038c2ecf20Sopenharmony_ci	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
2048c2ecf20Sopenharmony_ci	.macro	badr\c, rd, sym
2058c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL
2068c2ecf20Sopenharmony_ci	adr\c	\rd, \sym + 1
2078c2ecf20Sopenharmony_ci#else
2088c2ecf20Sopenharmony_ci	adr\c	\rd, \sym
2098c2ecf20Sopenharmony_ci#endif
2108c2ecf20Sopenharmony_ci	.endm
2118c2ecf20Sopenharmony_ci	.endr
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/*
2148c2ecf20Sopenharmony_ci * Get current thread_info.
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_ci	.macro	get_thread_info, rd
2178c2ecf20Sopenharmony_ci ARM(	mov	\rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT	)
2188c2ecf20Sopenharmony_ci THUMB(	mov	\rd, sp			)
2198c2ecf20Sopenharmony_ci THUMB(	lsr	\rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT	)
2208c2ecf20Sopenharmony_ci	mov	\rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
2218c2ecf20Sopenharmony_ci	.endm
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/*
2248c2ecf20Sopenharmony_ci * Increment/decrement the preempt count.
2258c2ecf20Sopenharmony_ci */
2268c2ecf20Sopenharmony_ci#ifdef CONFIG_PREEMPT_COUNT
2278c2ecf20Sopenharmony_ci	.macro	inc_preempt_count, ti, tmp
2288c2ecf20Sopenharmony_ci	ldr	\tmp, [\ti, #TI_PREEMPT]	@ get preempt count
2298c2ecf20Sopenharmony_ci	add	\tmp, \tmp, #1			@ increment it
2308c2ecf20Sopenharmony_ci	str	\tmp, [\ti, #TI_PREEMPT]
2318c2ecf20Sopenharmony_ci	.endm
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	.macro	dec_preempt_count, ti, tmp
2348c2ecf20Sopenharmony_ci	ldr	\tmp, [\ti, #TI_PREEMPT]	@ get preempt count
2358c2ecf20Sopenharmony_ci	sub	\tmp, \tmp, #1			@ decrement it
2368c2ecf20Sopenharmony_ci	str	\tmp, [\ti, #TI_PREEMPT]
2378c2ecf20Sopenharmony_ci	.endm
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	.macro	dec_preempt_count_ti, ti, tmp
2408c2ecf20Sopenharmony_ci	get_thread_info \ti
2418c2ecf20Sopenharmony_ci	dec_preempt_count \ti, \tmp
2428c2ecf20Sopenharmony_ci	.endm
2438c2ecf20Sopenharmony_ci#else
2448c2ecf20Sopenharmony_ci	.macro	inc_preempt_count, ti, tmp
2458c2ecf20Sopenharmony_ci	.endm
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	.macro	dec_preempt_count, ti, tmp
2488c2ecf20Sopenharmony_ci	.endm
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	.macro	dec_preempt_count_ti, ti, tmp
2518c2ecf20Sopenharmony_ci	.endm
2528c2ecf20Sopenharmony_ci#endif
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci#define USERL(l, x...)				\
2558c2ecf20Sopenharmony_ci9999:	x;					\
2568c2ecf20Sopenharmony_ci	ex_entry	9999b,l;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci#define USER(x...)	USERL(9001f, x)
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
2618c2ecf20Sopenharmony_ci#define ALT_SMP(instr...)					\
2628c2ecf20Sopenharmony_ci9998:	instr
2638c2ecf20Sopenharmony_ci/*
2648c2ecf20Sopenharmony_ci * Note: if you get assembler errors from ALT_UP() when building with
2658c2ecf20Sopenharmony_ci * CONFIG_THUMB2_KERNEL, you almost certainly need to use
2668c2ecf20Sopenharmony_ci * ALT_SMP( W(instr) ... )
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_ci#define ALT_UP(instr...)					\
2698c2ecf20Sopenharmony_ci	.pushsection ".alt.smp.init", "a"			;\
2708c2ecf20Sopenharmony_ci	.long	9998b - .					;\
2718c2ecf20Sopenharmony_ci9997:	instr							;\
2728c2ecf20Sopenharmony_ci	.if . - 9997b == 2					;\
2738c2ecf20Sopenharmony_ci		nop						;\
2748c2ecf20Sopenharmony_ci	.endif							;\
2758c2ecf20Sopenharmony_ci	.if . - 9997b != 4					;\
2768c2ecf20Sopenharmony_ci		.error "ALT_UP() content must assemble to exactly 4 bytes";\
2778c2ecf20Sopenharmony_ci	.endif							;\
2788c2ecf20Sopenharmony_ci	.popsection
2798c2ecf20Sopenharmony_ci#define ALT_UP_B(label)					\
2808c2ecf20Sopenharmony_ci	.pushsection ".alt.smp.init", "a"			;\
2818c2ecf20Sopenharmony_ci	.long	9998b - .					;\
2828c2ecf20Sopenharmony_ci	W(b)	. + (label - 9998b)					;\
2838c2ecf20Sopenharmony_ci	.popsection
2848c2ecf20Sopenharmony_ci#else
2858c2ecf20Sopenharmony_ci#define ALT_SMP(instr...)
2868c2ecf20Sopenharmony_ci#define ALT_UP(instr...) instr
2878c2ecf20Sopenharmony_ci#define ALT_UP_B(label) b label
2888c2ecf20Sopenharmony_ci#endif
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/*
2918c2ecf20Sopenharmony_ci * Instruction barrier
2928c2ecf20Sopenharmony_ci */
2938c2ecf20Sopenharmony_ci	.macro	instr_sync
2948c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7
2958c2ecf20Sopenharmony_ci	isb
2968c2ecf20Sopenharmony_ci#elif __LINUX_ARM_ARCH__ == 6
2978c2ecf20Sopenharmony_ci	mcr	p15, 0, r0, c7, c5, 4
2988c2ecf20Sopenharmony_ci#endif
2998c2ecf20Sopenharmony_ci	.endm
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/*
3028c2ecf20Sopenharmony_ci * SMP data memory barrier
3038c2ecf20Sopenharmony_ci */
3048c2ecf20Sopenharmony_ci	.macro	smp_dmb mode
3058c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
3068c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 7
3078c2ecf20Sopenharmony_ci	.ifeqs "\mode","arm"
3088c2ecf20Sopenharmony_ci	ALT_SMP(dmb	ish)
3098c2ecf20Sopenharmony_ci	.else
3108c2ecf20Sopenharmony_ci	ALT_SMP(W(dmb)	ish)
3118c2ecf20Sopenharmony_ci	.endif
3128c2ecf20Sopenharmony_ci#elif __LINUX_ARM_ARCH__ == 6
3138c2ecf20Sopenharmony_ci	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
3148c2ecf20Sopenharmony_ci#else
3158c2ecf20Sopenharmony_ci#error Incompatible SMP platform
3168c2ecf20Sopenharmony_ci#endif
3178c2ecf20Sopenharmony_ci	.ifeqs "\mode","arm"
3188c2ecf20Sopenharmony_ci	ALT_UP(nop)
3198c2ecf20Sopenharmony_ci	.else
3208c2ecf20Sopenharmony_ci	ALT_UP(W(nop))
3218c2ecf20Sopenharmony_ci	.endif
3228c2ecf20Sopenharmony_ci#endif
3238c2ecf20Sopenharmony_ci	.endm
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci#if defined(CONFIG_CPU_V7M)
3268c2ecf20Sopenharmony_ci	/*
3278c2ecf20Sopenharmony_ci	 * setmode is used to assert to be in svc mode during boot. For v7-M
3288c2ecf20Sopenharmony_ci	 * this is done in __v7m_setup, so setmode can be empty here.
3298c2ecf20Sopenharmony_ci	 */
3308c2ecf20Sopenharmony_ci	.macro	setmode, mode, reg
3318c2ecf20Sopenharmony_ci	.endm
3328c2ecf20Sopenharmony_ci#elif defined(CONFIG_THUMB2_KERNEL)
3338c2ecf20Sopenharmony_ci	.macro	setmode, mode, reg
3348c2ecf20Sopenharmony_ci	mov	\reg, #\mode
3358c2ecf20Sopenharmony_ci	msr	cpsr_c, \reg
3368c2ecf20Sopenharmony_ci	.endm
3378c2ecf20Sopenharmony_ci#else
3388c2ecf20Sopenharmony_ci	.macro	setmode, mode, reg
3398c2ecf20Sopenharmony_ci	msr	cpsr_c, #\mode
3408c2ecf20Sopenharmony_ci	.endm
3418c2ecf20Sopenharmony_ci#endif
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/*
3448c2ecf20Sopenharmony_ci * Helper macro to enter SVC mode cleanly and mask interrupts. reg is
3458c2ecf20Sopenharmony_ci * a scratch register for the macro to overwrite.
3468c2ecf20Sopenharmony_ci *
3478c2ecf20Sopenharmony_ci * This macro is intended for forcing the CPU into SVC mode at boot time.
3488c2ecf20Sopenharmony_ci * you cannot return to the original mode.
3498c2ecf20Sopenharmony_ci */
3508c2ecf20Sopenharmony_ci.macro safe_svcmode_maskall reg:req
3518c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M)
3528c2ecf20Sopenharmony_ci	mrs	\reg , cpsr
3538c2ecf20Sopenharmony_ci	eor	\reg, \reg, #HYP_MODE
3548c2ecf20Sopenharmony_ci	tst	\reg, #MODE_MASK
3558c2ecf20Sopenharmony_ci	bic	\reg , \reg , #MODE_MASK
3568c2ecf20Sopenharmony_ci	orr	\reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE
3578c2ecf20Sopenharmony_ciTHUMB(	orr	\reg , \reg , #PSR_T_BIT	)
3588c2ecf20Sopenharmony_ci	bne	1f
3598c2ecf20Sopenharmony_ci	orr	\reg, \reg, #PSR_A_BIT
3608c2ecf20Sopenharmony_ci	badr	lr, 2f
3618c2ecf20Sopenharmony_ci	msr	spsr_cxsf, \reg
3628c2ecf20Sopenharmony_ci	__MSR_ELR_HYP(14)
3638c2ecf20Sopenharmony_ci	__ERET
3648c2ecf20Sopenharmony_ci1:	msr	cpsr_c, \reg
3658c2ecf20Sopenharmony_ci2:
3668c2ecf20Sopenharmony_ci#else
3678c2ecf20Sopenharmony_ci/*
3688c2ecf20Sopenharmony_ci * workaround for possibly broken pre-v6 hardware
3698c2ecf20Sopenharmony_ci * (akita, Sharp Zaurus C-1000, PXA270-based)
3708c2ecf20Sopenharmony_ci */
3718c2ecf20Sopenharmony_ci	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, \reg
3728c2ecf20Sopenharmony_ci#endif
3738c2ecf20Sopenharmony_ci.endm
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/*
3768c2ecf20Sopenharmony_ci * STRT/LDRT access macros with ARM and Thumb-2 variants
3778c2ecf20Sopenharmony_ci */
3788c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	.macro	usraccoff, instr, reg, ptr, inc, off, cond, abort, t=TUSER()
3818c2ecf20Sopenharmony_ci9999:
3828c2ecf20Sopenharmony_ci	.if	\inc == 1
3838c2ecf20Sopenharmony_ci	\instr\()b\t\cond\().w \reg, [\ptr, #\off]
3848c2ecf20Sopenharmony_ci	.elseif	\inc == 4
3858c2ecf20Sopenharmony_ci	\instr\t\cond\().w \reg, [\ptr, #\off]
3868c2ecf20Sopenharmony_ci	.else
3878c2ecf20Sopenharmony_ci	.error	"Unsupported inc macro argument"
3888c2ecf20Sopenharmony_ci	.endif
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	ex_entry	9999b, \abort
3918c2ecf20Sopenharmony_ci	.endm
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	.macro	usracc, instr, reg, ptr, inc, cond, rept, abort
3948c2ecf20Sopenharmony_ci	@ explicit IT instruction needed because of the label
3958c2ecf20Sopenharmony_ci	@ introduced by the USER macro
3968c2ecf20Sopenharmony_ci	.ifnc	\cond,al
3978c2ecf20Sopenharmony_ci	.if	\rept == 1
3988c2ecf20Sopenharmony_ci	itt	\cond
3998c2ecf20Sopenharmony_ci	.elseif	\rept == 2
4008c2ecf20Sopenharmony_ci	ittt	\cond
4018c2ecf20Sopenharmony_ci	.else
4028c2ecf20Sopenharmony_ci	.error	"Unsupported rept macro argument"
4038c2ecf20Sopenharmony_ci	.endif
4048c2ecf20Sopenharmony_ci	.endif
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	@ Slightly optimised to avoid incrementing the pointer twice
4078c2ecf20Sopenharmony_ci	usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
4088c2ecf20Sopenharmony_ci	.if	\rept == 2
4098c2ecf20Sopenharmony_ci	usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
4108c2ecf20Sopenharmony_ci	.endif
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	add\cond \ptr, #\rept * \inc
4138c2ecf20Sopenharmony_ci	.endm
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci#else	/* !CONFIG_THUMB2_KERNEL */
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	.macro	usracc, instr, reg, ptr, inc, cond, rept, abort, t=TUSER()
4188c2ecf20Sopenharmony_ci	.rept	\rept
4198c2ecf20Sopenharmony_ci9999:
4208c2ecf20Sopenharmony_ci	.if	\inc == 1
4218c2ecf20Sopenharmony_ci	\instr\()b\t\cond \reg, [\ptr], #\inc
4228c2ecf20Sopenharmony_ci	.elseif	\inc == 4
4238c2ecf20Sopenharmony_ci	\instr\t\cond \reg, [\ptr], #\inc
4248c2ecf20Sopenharmony_ci	.else
4258c2ecf20Sopenharmony_ci	.error	"Unsupported inc macro argument"
4268c2ecf20Sopenharmony_ci	.endif
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	ex_entry	9999b, \abort
4298c2ecf20Sopenharmony_ci	.endr
4308c2ecf20Sopenharmony_ci	.endm
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci#endif	/* CONFIG_THUMB2_KERNEL */
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	.macro	strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
4358c2ecf20Sopenharmony_ci	usracc	str, \reg, \ptr, \inc, \cond, \rept, \abort
4368c2ecf20Sopenharmony_ci	.endm
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	.macro	ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
4398c2ecf20Sopenharmony_ci	usracc	ldr, \reg, \ptr, \inc, \cond, \rept, \abort
4408c2ecf20Sopenharmony_ci	.endm
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/* Utility macro for declaring string literals */
4438c2ecf20Sopenharmony_ci	.macro	string name:req, string
4448c2ecf20Sopenharmony_ci	.type \name , #object
4458c2ecf20Sopenharmony_ci\name:
4468c2ecf20Sopenharmony_ci	.asciz "\string"
4478c2ecf20Sopenharmony_ci	.size \name , . - \name
4488c2ecf20Sopenharmony_ci	.endm
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
4518c2ecf20Sopenharmony_ci	.macro	ret\c, reg
4528c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6
4538c2ecf20Sopenharmony_ci	mov\c	pc, \reg
4548c2ecf20Sopenharmony_ci#else
4558c2ecf20Sopenharmony_ci	.ifeqs	"\reg", "lr"
4568c2ecf20Sopenharmony_ci	bx\c	\reg
4578c2ecf20Sopenharmony_ci	.else
4588c2ecf20Sopenharmony_ci	mov\c	pc, \reg
4598c2ecf20Sopenharmony_ci	.endif
4608c2ecf20Sopenharmony_ci#endif
4618c2ecf20Sopenharmony_ci	.endm
4628c2ecf20Sopenharmony_ci	.endr
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	.macro	ret.w, reg
4658c2ecf20Sopenharmony_ci	ret	\reg
4668c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL
4678c2ecf20Sopenharmony_ci	nop
4688c2ecf20Sopenharmony_ci#endif
4698c2ecf20Sopenharmony_ci	.endm
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	.macro	bug, msg, line
4728c2ecf20Sopenharmony_ci#ifdef CONFIG_THUMB2_KERNEL
4738c2ecf20Sopenharmony_ci1:	.inst	0xde02
4748c2ecf20Sopenharmony_ci#else
4758c2ecf20Sopenharmony_ci1:	.inst	0xe7f001f2
4768c2ecf20Sopenharmony_ci#endif
4778c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_BUGVERBOSE
4788c2ecf20Sopenharmony_ci	.pushsection .rodata.str, "aMS", %progbits, 1
4798c2ecf20Sopenharmony_ci2:	.asciz	"\msg"
4808c2ecf20Sopenharmony_ci	.popsection
4818c2ecf20Sopenharmony_ci	.pushsection __bug_table, "aw"
4828c2ecf20Sopenharmony_ci	.align	2
4838c2ecf20Sopenharmony_ci	.word	1b, 2b
4848c2ecf20Sopenharmony_ci	.hword	\line
4858c2ecf20Sopenharmony_ci	.popsection
4868c2ecf20Sopenharmony_ci#endif
4878c2ecf20Sopenharmony_ci	.endm
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci#ifdef CONFIG_KPROBES
4908c2ecf20Sopenharmony_ci#define _ASM_NOKPROBE(entry)				\
4918c2ecf20Sopenharmony_ci	.pushsection "_kprobe_blacklist", "aw" ;	\
4928c2ecf20Sopenharmony_ci	.balign 4 ;					\
4938c2ecf20Sopenharmony_ci	.long entry;					\
4948c2ecf20Sopenharmony_ci	.popsection
4958c2ecf20Sopenharmony_ci#else
4968c2ecf20Sopenharmony_ci#define _ASM_NOKPROBE(entry)
4978c2ecf20Sopenharmony_ci#endif
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	.macro		__adldst_l, op, reg, sym, tmp, c
5008c2ecf20Sopenharmony_ci	.if		__LINUX_ARM_ARCH__ < 7
5018c2ecf20Sopenharmony_ci	ldr\c		\tmp, .La\@
5028c2ecf20Sopenharmony_ci	.subsection	1
5038c2ecf20Sopenharmony_ci	.align		2
5048c2ecf20Sopenharmony_ci.La\@:	.long		\sym - .Lpc\@
5058c2ecf20Sopenharmony_ci	.previous
5068c2ecf20Sopenharmony_ci	.else
5078c2ecf20Sopenharmony_ci	.ifnb		\c
5088c2ecf20Sopenharmony_ci THUMB(	ittt		\c			)
5098c2ecf20Sopenharmony_ci	.endif
5108c2ecf20Sopenharmony_ci	movw\c		\tmp, #:lower16:\sym - .Lpc\@
5118c2ecf20Sopenharmony_ci	movt\c		\tmp, #:upper16:\sym - .Lpc\@
5128c2ecf20Sopenharmony_ci	.endif
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci#ifndef CONFIG_THUMB2_KERNEL
5158c2ecf20Sopenharmony_ci	.set		.Lpc\@, . + 8			// PC bias
5168c2ecf20Sopenharmony_ci	.ifc		\op, add
5178c2ecf20Sopenharmony_ci	add\c		\reg, \tmp, pc
5188c2ecf20Sopenharmony_ci	.else
5198c2ecf20Sopenharmony_ci	\op\c		\reg, [pc, \tmp]
5208c2ecf20Sopenharmony_ci	.endif
5218c2ecf20Sopenharmony_ci#else
5228c2ecf20Sopenharmony_ci.Lb\@:	add\c		\tmp, \tmp, pc
5238c2ecf20Sopenharmony_ci	/*
5248c2ecf20Sopenharmony_ci	 * In Thumb-2 builds, the PC bias depends on whether we are currently
5258c2ecf20Sopenharmony_ci	 * emitting into a .arm or a .thumb section. The size of the add opcode
5268c2ecf20Sopenharmony_ci	 * above will be 2 bytes when emitting in Thumb mode and 4 bytes when
5278c2ecf20Sopenharmony_ci	 * emitting in ARM mode, so let's use this to account for the bias.
5288c2ecf20Sopenharmony_ci	 */
5298c2ecf20Sopenharmony_ci	.set		.Lpc\@, . + (. - .Lb\@)
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	.ifnc		\op, add
5328c2ecf20Sopenharmony_ci	\op\c		\reg, [\tmp]
5338c2ecf20Sopenharmony_ci	.endif
5348c2ecf20Sopenharmony_ci#endif
5358c2ecf20Sopenharmony_ci	.endm
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/*
5388c2ecf20Sopenharmony_ci	 * mov_l - move a constant value or [relocated] address into a register
5398c2ecf20Sopenharmony_ci	 */
5408c2ecf20Sopenharmony_ci	.macro		mov_l, dst:req, imm:req
5418c2ecf20Sopenharmony_ci	.if		CONFIG_RELOCATABLE == 1 || __LINUX_ARM_ARCH__ < 7
5428c2ecf20Sopenharmony_ci	ldr		\dst, =\imm
5438c2ecf20Sopenharmony_ci	.else
5448c2ecf20Sopenharmony_ci	movw		\dst, #:lower16:\imm
5458c2ecf20Sopenharmony_ci	movt		\dst, #:upper16:\imm
5468c2ecf20Sopenharmony_ci	.endif
5478c2ecf20Sopenharmony_ci	.endm
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	/*
5508c2ecf20Sopenharmony_ci	 * adr_l - adr pseudo-op with unlimited range
5518c2ecf20Sopenharmony_ci	 *
5528c2ecf20Sopenharmony_ci	 * @dst: destination register
5538c2ecf20Sopenharmony_ci	 * @sym: name of the symbol
5548c2ecf20Sopenharmony_ci	 * @cond: conditional opcode suffix
5558c2ecf20Sopenharmony_ci	 */
5568c2ecf20Sopenharmony_ci	.macro		adr_l, dst:req, sym:req, cond
5578c2ecf20Sopenharmony_ci	__adldst_l	add, \dst, \sym, \dst, \cond
5588c2ecf20Sopenharmony_ci	.endm
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/*
5618c2ecf20Sopenharmony_ci	 * ldr_l - ldr <literal> pseudo-op with unlimited range
5628c2ecf20Sopenharmony_ci	 *
5638c2ecf20Sopenharmony_ci	 * @dst: destination register
5648c2ecf20Sopenharmony_ci	 * @sym: name of the symbol
5658c2ecf20Sopenharmony_ci	 * @cond: conditional opcode suffix
5668c2ecf20Sopenharmony_ci	 */
5678c2ecf20Sopenharmony_ci	.macro		ldr_l, dst:req, sym:req, cond
5688c2ecf20Sopenharmony_ci	__adldst_l	ldr, \dst, \sym, \dst, \cond
5698c2ecf20Sopenharmony_ci	.endm
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	/*
5728c2ecf20Sopenharmony_ci	 * str_l - str <literal> pseudo-op with unlimited range
5738c2ecf20Sopenharmony_ci	 *
5748c2ecf20Sopenharmony_ci	 * @src: source register
5758c2ecf20Sopenharmony_ci	 * @sym: name of the symbol
5768c2ecf20Sopenharmony_ci	 * @tmp: mandatory scratch register
5778c2ecf20Sopenharmony_ci	 * @cond: conditional opcode suffix
5788c2ecf20Sopenharmony_ci	 */
5798c2ecf20Sopenharmony_ci	.macro		str_l, src:req, sym:req, tmp:req, cond
5808c2ecf20Sopenharmony_ci	__adldst_l	str, \src, \sym, \tmp, \cond
5818c2ecf20Sopenharmony_ci	.endm
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci#endif /* __ASM_ASSEMBLER_H__ */
584