Linux Audio

Check our new training course

Loading...
v5.9
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2/*
  3 *  arch/arm/include/asm/assembler.h
  4 *
  5 *  Copyright (C) 1996-2000 Russell King
  6 *
 
 
 
 
  7 *  This file contains arm architecture specific defines
  8 *  for the different processors.
  9 *
 10 *  Do not include any C declarations in this file - it is included by
 11 *  assembler source.
 12 */
 13#ifndef __ASM_ASSEMBLER_H__
 14#define __ASM_ASSEMBLER_H__
 15
 16#ifndef __ASSEMBLY__
 17#error "Only include this from assembly code"
 18#endif
 19
 20#include <asm/ptrace.h>
 
 21#include <asm/opcodes-virt.h>
 22#include <asm/asm-offsets.h>
 23#include <asm/page.h>
 24#include <asm/thread_info.h>
 25#include <asm/uaccess-asm.h>
 26
 27#define IOMEM(x)	(x)
 28
 29/*
 30 * Endian independent macros for shifting bytes within registers.
 31 */
 32#ifndef __ARMEB__
 33#define lspull          lsr
 34#define lspush          lsl
 35#define get_byte_0      lsl #0
 36#define get_byte_1	lsr #8
 37#define get_byte_2	lsr #16
 38#define get_byte_3	lsr #24
 39#define put_byte_0      lsl #0
 40#define put_byte_1	lsl #8
 41#define put_byte_2	lsl #16
 42#define put_byte_3	lsl #24
 43#else
 44#define lspull          lsl
 45#define lspush          lsr
 46#define get_byte_0	lsr #24
 47#define get_byte_1	lsr #16
 48#define get_byte_2	lsr #8
 49#define get_byte_3      lsl #0
 50#define put_byte_0	lsl #24
 51#define put_byte_1	lsl #16
 52#define put_byte_2	lsl #8
 53#define put_byte_3      lsl #0
 54#endif
 55
 56/* Select code for any configuration running in BE8 mode */
 57#ifdef CONFIG_CPU_ENDIAN_BE8
 58#define ARM_BE8(code...) code
 59#else
 60#define ARM_BE8(code...)
 61#endif
 62
 63/*
 64 * Data preload for architectures that support it
 65 */
 66#if __LINUX_ARM_ARCH__ >= 5
 67#define PLD(code...)	code
 68#else
 69#define PLD(code...)
 70#endif
 71
 72/*
 73 * This can be used to enable code to cacheline align the destination
 74 * pointer when bulk writing to memory.  Experiments on StrongARM and
 75 * XScale didn't show this a worthwhile thing to do when the cache is not
 76 * set to write-allocate (this would need further testing on XScale when WA
 77 * is used).
 78 *
 79 * On Feroceon there is much to gain however, regardless of cache mode.
 80 */
 81#ifdef CONFIG_CPU_FEROCEON
 82#define CALGN(code...) code
 83#else
 84#define CALGN(code...)
 85#endif
 86
 87#define IMM12_MASK 0xfff
 88
 89/*
 90 * Enable and disable interrupts
 91 */
 92#if __LINUX_ARM_ARCH__ >= 6
 93	.macro	disable_irq_notrace
 94	cpsid	i
 95	.endm
 96
 97	.macro	enable_irq_notrace
 98	cpsie	i
 99	.endm
100#else
101	.macro	disable_irq_notrace
102	msr	cpsr_c, #PSR_I_BIT | SVC_MODE
103	.endm
104
105	.macro	enable_irq_notrace
106	msr	cpsr_c, #SVC_MODE
107	.endm
108#endif
109
110	.macro asm_trace_hardirqs_off, save=1
111#if defined(CONFIG_TRACE_IRQFLAGS)
112	.if \save
113	stmdb   sp!, {r0-r3, ip, lr}
114	.endif
115	bl	trace_hardirqs_off
116	.if \save
117	ldmia	sp!, {r0-r3, ip, lr}
118	.endif
119#endif
120	.endm
121
122	.macro asm_trace_hardirqs_on, cond=al, save=1
123#if defined(CONFIG_TRACE_IRQFLAGS)
124	/*
125	 * actually the registers should be pushed and pop'd conditionally, but
126	 * after bl the flags are certainly clobbered
127	 */
128	.if \save
129	stmdb   sp!, {r0-r3, ip, lr}
130	.endif
131	bl\cond	trace_hardirqs_on
132	.if \save
133	ldmia	sp!, {r0-r3, ip, lr}
134	.endif
135#endif
136	.endm
137
138	.macro disable_irq, save=1
139	disable_irq_notrace
140	asm_trace_hardirqs_off \save
141	.endm
142
143	.macro enable_irq
144	asm_trace_hardirqs_on
145	enable_irq_notrace
146	.endm
147/*
148 * Save the current IRQ state and disable IRQs.  Note that this macro
149 * assumes FIQs are enabled, and that the processor is in SVC mode.
150 */
151	.macro	save_and_disable_irqs, oldcpsr
152#ifdef CONFIG_CPU_V7M
153	mrs	\oldcpsr, primask
154#else
155	mrs	\oldcpsr, cpsr
156#endif
157	disable_irq
158	.endm
159
160	.macro	save_and_disable_irqs_notrace, oldcpsr
161#ifdef CONFIG_CPU_V7M
162	mrs	\oldcpsr, primask
163#else
164	mrs	\oldcpsr, cpsr
165#endif
166	disable_irq_notrace
167	.endm
168
169/*
170 * Restore interrupt state previously stored in a register.  We don't
171 * guarantee that this will preserve the flags.
172 */
173	.macro	restore_irqs_notrace, oldcpsr
174#ifdef CONFIG_CPU_V7M
175	msr	primask, \oldcpsr
176#else
177	msr	cpsr_c, \oldcpsr
178#endif
179	.endm
180
181	.macro restore_irqs, oldcpsr
182	tst	\oldcpsr, #PSR_I_BIT
183	asm_trace_hardirqs_on cond=eq
184	restore_irqs_notrace \oldcpsr
185	.endm
186
187/*
188 * Assembly version of "adr rd, BSYM(sym)".  This should only be used to
189 * reference local symbols in the same assembly file which are to be
190 * resolved by the assembler.  Other usage is undefined.
191 */
192	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
193	.macro	badr\c, rd, sym
194#ifdef CONFIG_THUMB2_KERNEL
195	adr\c	\rd, \sym + 1
196#else
197	adr\c	\rd, \sym
198#endif
199	.endm
200	.endr
201
202/*
203 * Get current thread_info.
204 */
205	.macro	get_thread_info, rd
206 ARM(	mov	\rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT	)
207 THUMB(	mov	\rd, sp			)
208 THUMB(	lsr	\rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT	)
209	mov	\rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
210	.endm
211
212/*
213 * Increment/decrement the preempt count.
214 */
215#ifdef CONFIG_PREEMPT_COUNT
216	.macro	inc_preempt_count, ti, tmp
217	ldr	\tmp, [\ti, #TI_PREEMPT]	@ get preempt count
218	add	\tmp, \tmp, #1			@ increment it
219	str	\tmp, [\ti, #TI_PREEMPT]
220	.endm
221
222	.macro	dec_preempt_count, ti, tmp
223	ldr	\tmp, [\ti, #TI_PREEMPT]	@ get preempt count
224	sub	\tmp, \tmp, #1			@ decrement it
225	str	\tmp, [\ti, #TI_PREEMPT]
226	.endm
227
228	.macro	dec_preempt_count_ti, ti, tmp
229	get_thread_info \ti
230	dec_preempt_count \ti, \tmp
231	.endm
232#else
233	.macro	inc_preempt_count, ti, tmp
234	.endm
235
236	.macro	dec_preempt_count, ti, tmp
237	.endm
238
239	.macro	dec_preempt_count_ti, ti, tmp
240	.endm
241#endif
242
243#define USERL(l, x...)				\
2449999:	x;					\
245	.pushsection __ex_table,"a";		\
246	.align	3;				\
247	.long	9999b,l;			\
248	.popsection
249
250#define USER(x...)	USERL(9001f, x)
251
252#ifdef CONFIG_SMP
253#define ALT_SMP(instr...)					\
2549998:	instr
255/*
256 * Note: if you get assembler errors from ALT_UP() when building with
257 * CONFIG_THUMB2_KERNEL, you almost certainly need to use
258 * ALT_SMP( W(instr) ... )
259 */
260#define ALT_UP(instr...)					\
261	.pushsection ".alt.smp.init", "a"			;\
262	.long	9998b						;\
2639997:	instr							;\
264	.if . - 9997b == 2					;\
265		nop						;\
266	.endif							;\
267	.if . - 9997b != 4					;\
268		.error "ALT_UP() content must assemble to exactly 4 bytes";\
269	.endif							;\
270	.popsection
271#define ALT_UP_B(label)					\
 
272	.pushsection ".alt.smp.init", "a"			;\
273	.long	9998b						;\
274	W(b)	. + (label - 9998b)					;\
275	.popsection
276#else
277#define ALT_SMP(instr...)
278#define ALT_UP(instr...) instr
279#define ALT_UP_B(label) b label
280#endif
281
282/*
283 * Instruction barrier
284 */
285	.macro	instr_sync
286#if __LINUX_ARM_ARCH__ >= 7
287	isb
288#elif __LINUX_ARM_ARCH__ == 6
289	mcr	p15, 0, r0, c7, c5, 4
290#endif
291	.endm
292
293/*
294 * SMP data memory barrier
295 */
296	.macro	smp_dmb mode
297#ifdef CONFIG_SMP
298#if __LINUX_ARM_ARCH__ >= 7
299	.ifeqs "\mode","arm"
300	ALT_SMP(dmb	ish)
301	.else
302	ALT_SMP(W(dmb)	ish)
303	.endif
304#elif __LINUX_ARM_ARCH__ == 6
305	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
306#else
307#error Incompatible SMP platform
308#endif
309	.ifeqs "\mode","arm"
310	ALT_UP(nop)
311	.else
312	ALT_UP(W(nop))
313	.endif
314#endif
315	.endm
316
317#if defined(CONFIG_CPU_V7M)
318	/*
319	 * setmode is used to assert to be in svc mode during boot. For v7-M
320	 * this is done in __v7m_setup, so setmode can be empty here.
321	 */
322	.macro	setmode, mode, reg
323	.endm
324#elif defined(CONFIG_THUMB2_KERNEL)
325	.macro	setmode, mode, reg
326	mov	\reg, #\mode
327	msr	cpsr_c, \reg
328	.endm
329#else
330	.macro	setmode, mode, reg
331	msr	cpsr_c, #\mode
332	.endm
333#endif
334
335/*
336 * Helper macro to enter SVC mode cleanly and mask interrupts. reg is
337 * a scratch register for the macro to overwrite.
338 *
339 * This macro is intended for forcing the CPU into SVC mode at boot time.
340 * you cannot return to the original mode.
341 */
342.macro safe_svcmode_maskall reg:req
343#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M)
344	mrs	\reg , cpsr
345	eor	\reg, \reg, #HYP_MODE
346	tst	\reg, #MODE_MASK
347	bic	\reg , \reg , #MODE_MASK
348	orr	\reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE
349THUMB(	orr	\reg , \reg , #PSR_T_BIT	)
350	bne	1f
351	orr	\reg, \reg, #PSR_A_BIT
352	badr	lr, 2f
353	msr	spsr_cxsf, \reg
354	__MSR_ELR_HYP(14)
355	__ERET
3561:	msr	cpsr_c, \reg
3572:
358#else
359/*
360 * workaround for possibly broken pre-v6 hardware
361 * (akita, Sharp Zaurus C-1000, PXA270-based)
362 */
363	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, \reg
364#endif
365.endm
366
367/*
368 * STRT/LDRT access macros with ARM and Thumb-2 variants
369 */
370#ifdef CONFIG_THUMB2_KERNEL
371
372	.macro	usraccoff, instr, reg, ptr, inc, off, cond, abort, t=TUSER()
3739999:
374	.if	\inc == 1
375	\instr\()b\t\cond\().w \reg, [\ptr, #\off]
376	.elseif	\inc == 4
377	\instr\t\cond\().w \reg, [\ptr, #\off]
378	.else
379	.error	"Unsupported inc macro argument"
380	.endif
381
382	.pushsection __ex_table,"a"
383	.align	3
384	.long	9999b, \abort
385	.popsection
386	.endm
387
388	.macro	usracc, instr, reg, ptr, inc, cond, rept, abort
389	@ explicit IT instruction needed because of the label
390	@ introduced by the USER macro
391	.ifnc	\cond,al
392	.if	\rept == 1
393	itt	\cond
394	.elseif	\rept == 2
395	ittt	\cond
396	.else
397	.error	"Unsupported rept macro argument"
398	.endif
399	.endif
400
401	@ Slightly optimised to avoid incrementing the pointer twice
402	usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
403	.if	\rept == 2
404	usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
405	.endif
406
407	add\cond \ptr, #\rept * \inc
408	.endm
409
410#else	/* !CONFIG_THUMB2_KERNEL */
411
412	.macro	usracc, instr, reg, ptr, inc, cond, rept, abort, t=TUSER()
413	.rept	\rept
4149999:
415	.if	\inc == 1
416	\instr\()b\t\cond \reg, [\ptr], #\inc
417	.elseif	\inc == 4
418	\instr\t\cond \reg, [\ptr], #\inc
419	.else
420	.error	"Unsupported inc macro argument"
421	.endif
422
423	.pushsection __ex_table,"a"
424	.align	3
425	.long	9999b, \abort
426	.popsection
427	.endr
428	.endm
429
430#endif	/* CONFIG_THUMB2_KERNEL */
431
432	.macro	strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
433	usracc	str, \reg, \ptr, \inc, \cond, \rept, \abort
434	.endm
435
436	.macro	ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
437	usracc	ldr, \reg, \ptr, \inc, \cond, \rept, \abort
438	.endm
439
440/* Utility macro for declaring string literals */
441	.macro	string name:req, string
442	.type \name , #object
443\name:
444	.asciz "\string"
445	.size \name , . - \name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446	.endm
447
448	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
449	.macro	ret\c, reg
450#if __LINUX_ARM_ARCH__ < 6
451	mov\c	pc, \reg
452#else
453	.ifeqs	"\reg", "lr"
454	bx\c	\reg
455	.else
456	mov\c	pc, \reg
457	.endif
458#endif
459	.endm
460	.endr
461
462	.macro	ret.w, reg
463	ret	\reg
464#ifdef CONFIG_THUMB2_KERNEL
465	nop
466#endif
467	.endm
468
469	.macro	bug, msg, line
470#ifdef CONFIG_THUMB2_KERNEL
4711:	.inst	0xde02
472#else
4731:	.inst	0xe7f001f2
474#endif
475#ifdef CONFIG_DEBUG_BUGVERBOSE
476	.pushsection .rodata.str, "aMS", %progbits, 1
4772:	.asciz	"\msg"
478	.popsection
479	.pushsection __bug_table, "aw"
480	.align	2
481	.word	1b, 2b
482	.hword	\line
483	.popsection
484#endif
485	.endm
486
487#ifdef CONFIG_KPROBES
488#define _ASM_NOKPROBE(entry)				\
489	.pushsection "_kprobe_blacklist", "aw" ;	\
490	.balign 4 ;					\
491	.long entry;					\
492	.popsection
493#else
494#define _ASM_NOKPROBE(entry)
495#endif
496
497#endif /* __ASM_ASSEMBLER_H__ */
v4.17
 
  1/*
  2 *  arch/arm/include/asm/assembler.h
  3 *
  4 *  Copyright (C) 1996-2000 Russell King
  5 *
  6 * This program is free software; you can redistribute it and/or modify
  7 * it under the terms of the GNU General Public License version 2 as
  8 * published by the Free Software Foundation.
  9 *
 10 *  This file contains arm architecture specific defines
 11 *  for the different processors.
 12 *
 13 *  Do not include any C declarations in this file - it is included by
 14 *  assembler source.
 15 */
 16#ifndef __ASM_ASSEMBLER_H__
 17#define __ASM_ASSEMBLER_H__
 18
 19#ifndef __ASSEMBLY__
 20#error "Only include this from assembly code"
 21#endif
 22
 23#include <asm/ptrace.h>
 24#include <asm/domain.h>
 25#include <asm/opcodes-virt.h>
 26#include <asm/asm-offsets.h>
 27#include <asm/page.h>
 28#include <asm/thread_info.h>
 
 29
 30#define IOMEM(x)	(x)
 31
 32/*
 33 * Endian independent macros for shifting bytes within registers.
 34 */
 35#ifndef __ARMEB__
 36#define lspull          lsr
 37#define lspush          lsl
 38#define get_byte_0      lsl #0
 39#define get_byte_1	lsr #8
 40#define get_byte_2	lsr #16
 41#define get_byte_3	lsr #24
 42#define put_byte_0      lsl #0
 43#define put_byte_1	lsl #8
 44#define put_byte_2	lsl #16
 45#define put_byte_3	lsl #24
 46#else
 47#define lspull          lsl
 48#define lspush          lsr
 49#define get_byte_0	lsr #24
 50#define get_byte_1	lsr #16
 51#define get_byte_2	lsr #8
 52#define get_byte_3      lsl #0
 53#define put_byte_0	lsl #24
 54#define put_byte_1	lsl #16
 55#define put_byte_2	lsl #8
 56#define put_byte_3      lsl #0
 57#endif
 58
 59/* Select code for any configuration running in BE8 mode */
 60#ifdef CONFIG_CPU_ENDIAN_BE8
 61#define ARM_BE8(code...) code
 62#else
 63#define ARM_BE8(code...)
 64#endif
 65
 66/*
 67 * Data preload for architectures that support it
 68 */
 69#if __LINUX_ARM_ARCH__ >= 5
 70#define PLD(code...)	code
 71#else
 72#define PLD(code...)
 73#endif
 74
 75/*
 76 * This can be used to enable code to cacheline align the destination
 77 * pointer when bulk writing to memory.  Experiments on StrongARM and
 78 * XScale didn't show this a worthwhile thing to do when the cache is not
 79 * set to write-allocate (this would need further testing on XScale when WA
 80 * is used).
 81 *
 82 * On Feroceon there is much to gain however, regardless of cache mode.
 83 */
 84#ifdef CONFIG_CPU_FEROCEON
 85#define CALGN(code...) code
 86#else
 87#define CALGN(code...)
 88#endif
 89
 90#define IMM12_MASK 0xfff
 91
 92/*
 93 * Enable and disable interrupts
 94 */
 95#if __LINUX_ARM_ARCH__ >= 6
 96	.macro	disable_irq_notrace
 97	cpsid	i
 98	.endm
 99
100	.macro	enable_irq_notrace
101	cpsie	i
102	.endm
103#else
104	.macro	disable_irq_notrace
105	msr	cpsr_c, #PSR_I_BIT | SVC_MODE
106	.endm
107
108	.macro	enable_irq_notrace
109	msr	cpsr_c, #SVC_MODE
110	.endm
111#endif
112
113	.macro asm_trace_hardirqs_off, save=1
114#if defined(CONFIG_TRACE_IRQFLAGS)
115	.if \save
116	stmdb   sp!, {r0-r3, ip, lr}
117	.endif
118	bl	trace_hardirqs_off
119	.if \save
120	ldmia	sp!, {r0-r3, ip, lr}
121	.endif
122#endif
123	.endm
124
125	.macro asm_trace_hardirqs_on, cond=al, save=1
126#if defined(CONFIG_TRACE_IRQFLAGS)
127	/*
128	 * actually the registers should be pushed and pop'd conditionally, but
129	 * after bl the flags are certainly clobbered
130	 */
131	.if \save
132	stmdb   sp!, {r0-r3, ip, lr}
133	.endif
134	bl\cond	trace_hardirqs_on
135	.if \save
136	ldmia	sp!, {r0-r3, ip, lr}
137	.endif
138#endif
139	.endm
140
141	.macro disable_irq, save=1
142	disable_irq_notrace
143	asm_trace_hardirqs_off \save
144	.endm
145
146	.macro enable_irq
147	asm_trace_hardirqs_on
148	enable_irq_notrace
149	.endm
150/*
151 * Save the current IRQ state and disable IRQs.  Note that this macro
152 * assumes FIQs are enabled, and that the processor is in SVC mode.
153 */
154	.macro	save_and_disable_irqs, oldcpsr
155#ifdef CONFIG_CPU_V7M
156	mrs	\oldcpsr, primask
157#else
158	mrs	\oldcpsr, cpsr
159#endif
160	disable_irq
161	.endm
162
163	.macro	save_and_disable_irqs_notrace, oldcpsr
164#ifdef CONFIG_CPU_V7M
165	mrs	\oldcpsr, primask
166#else
167	mrs	\oldcpsr, cpsr
168#endif
169	disable_irq_notrace
170	.endm
171
172/*
173 * Restore interrupt state previously stored in a register.  We don't
174 * guarantee that this will preserve the flags.
175 */
176	.macro	restore_irqs_notrace, oldcpsr
177#ifdef CONFIG_CPU_V7M
178	msr	primask, \oldcpsr
179#else
180	msr	cpsr_c, \oldcpsr
181#endif
182	.endm
183
184	.macro restore_irqs, oldcpsr
185	tst	\oldcpsr, #PSR_I_BIT
186	asm_trace_hardirqs_on cond=eq
187	restore_irqs_notrace \oldcpsr
188	.endm
189
190/*
191 * Assembly version of "adr rd, BSYM(sym)".  This should only be used to
192 * reference local symbols in the same assembly file which are to be
193 * resolved by the assembler.  Other usage is undefined.
194 */
195	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
196	.macro	badr\c, rd, sym
197#ifdef CONFIG_THUMB2_KERNEL
198	adr\c	\rd, \sym + 1
199#else
200	adr\c	\rd, \sym
201#endif
202	.endm
203	.endr
204
205/*
206 * Get current thread_info.
207 */
208	.macro	get_thread_info, rd
209 ARM(	mov	\rd, sp, lsr #THREAD_SIZE_ORDER + PAGE_SHIFT	)
210 THUMB(	mov	\rd, sp			)
211 THUMB(	lsr	\rd, \rd, #THREAD_SIZE_ORDER + PAGE_SHIFT	)
212	mov	\rd, \rd, lsl #THREAD_SIZE_ORDER + PAGE_SHIFT
213	.endm
214
215/*
216 * Increment/decrement the preempt count.
217 */
218#ifdef CONFIG_PREEMPT_COUNT
219	.macro	inc_preempt_count, ti, tmp
220	ldr	\tmp, [\ti, #TI_PREEMPT]	@ get preempt count
221	add	\tmp, \tmp, #1			@ increment it
222	str	\tmp, [\ti, #TI_PREEMPT]
223	.endm
224
225	.macro	dec_preempt_count, ti, tmp
226	ldr	\tmp, [\ti, #TI_PREEMPT]	@ get preempt count
227	sub	\tmp, \tmp, #1			@ decrement it
228	str	\tmp, [\ti, #TI_PREEMPT]
229	.endm
230
231	.macro	dec_preempt_count_ti, ti, tmp
232	get_thread_info \ti
233	dec_preempt_count \ti, \tmp
234	.endm
235#else
236	.macro	inc_preempt_count, ti, tmp
237	.endm
238
239	.macro	dec_preempt_count, ti, tmp
240	.endm
241
242	.macro	dec_preempt_count_ti, ti, tmp
243	.endm
244#endif
245
246#define USER(x...)				\
2479999:	x;					\
248	.pushsection __ex_table,"a";		\
249	.align	3;				\
250	.long	9999b,9001f;			\
251	.popsection
252
 
 
253#ifdef CONFIG_SMP
254#define ALT_SMP(instr...)					\
2559998:	instr
256/*
257 * Note: if you get assembler errors from ALT_UP() when building with
258 * CONFIG_THUMB2_KERNEL, you almost certainly need to use
259 * ALT_SMP( W(instr) ... )
260 */
261#define ALT_UP(instr...)					\
262	.pushsection ".alt.smp.init", "a"			;\
263	.long	9998b						;\
2649997:	instr							;\
265	.if . - 9997b == 2					;\
266		nop						;\
267	.endif							;\
268	.if . - 9997b != 4					;\
269		.error "ALT_UP() content must assemble to exactly 4 bytes";\
270	.endif							;\
271	.popsection
272#define ALT_UP_B(label)					\
273	.equ	up_b_offset, label - 9998b			;\
274	.pushsection ".alt.smp.init", "a"			;\
275	.long	9998b						;\
276	W(b)	. + up_b_offset					;\
277	.popsection
278#else
279#define ALT_SMP(instr...)
280#define ALT_UP(instr...) instr
281#define ALT_UP_B(label) b label
282#endif
283
284/*
285 * Instruction barrier
286 */
287	.macro	instr_sync
288#if __LINUX_ARM_ARCH__ >= 7
289	isb
290#elif __LINUX_ARM_ARCH__ == 6
291	mcr	p15, 0, r0, c7, c5, 4
292#endif
293	.endm
294
295/*
296 * SMP data memory barrier
297 */
298	.macro	smp_dmb mode
299#ifdef CONFIG_SMP
300#if __LINUX_ARM_ARCH__ >= 7
301	.ifeqs "\mode","arm"
302	ALT_SMP(dmb	ish)
303	.else
304	ALT_SMP(W(dmb)	ish)
305	.endif
306#elif __LINUX_ARM_ARCH__ == 6
307	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
308#else
309#error Incompatible SMP platform
310#endif
311	.ifeqs "\mode","arm"
312	ALT_UP(nop)
313	.else
314	ALT_UP(W(nop))
315	.endif
316#endif
317	.endm
318
319#if defined(CONFIG_CPU_V7M)
320	/*
321	 * setmode is used to assert to be in svc mode during boot. For v7-M
322	 * this is done in __v7m_setup, so setmode can be empty here.
323	 */
324	.macro	setmode, mode, reg
325	.endm
326#elif defined(CONFIG_THUMB2_KERNEL)
327	.macro	setmode, mode, reg
328	mov	\reg, #\mode
329	msr	cpsr_c, \reg
330	.endm
331#else
332	.macro	setmode, mode, reg
333	msr	cpsr_c, #\mode
334	.endm
335#endif
336
337/*
338 * Helper macro to enter SVC mode cleanly and mask interrupts. reg is
339 * a scratch register for the macro to overwrite.
340 *
341 * This macro is intended for forcing the CPU into SVC mode at boot time.
342 * you cannot return to the original mode.
343 */
344.macro safe_svcmode_maskall reg:req
345#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M)
346	mrs	\reg , cpsr
347	eor	\reg, \reg, #HYP_MODE
348	tst	\reg, #MODE_MASK
349	bic	\reg , \reg , #MODE_MASK
350	orr	\reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE
351THUMB(	orr	\reg , \reg , #PSR_T_BIT	)
352	bne	1f
353	orr	\reg, \reg, #PSR_A_BIT
354	badr	lr, 2f
355	msr	spsr_cxsf, \reg
356	__MSR_ELR_HYP(14)
357	__ERET
3581:	msr	cpsr_c, \reg
3592:
360#else
361/*
362 * workaround for possibly broken pre-v6 hardware
363 * (akita, Sharp Zaurus C-1000, PXA270-based)
364 */
365	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, \reg
366#endif
367.endm
368
369/*
370 * STRT/LDRT access macros with ARM and Thumb-2 variants
371 */
372#ifdef CONFIG_THUMB2_KERNEL
373
374	.macro	usraccoff, instr, reg, ptr, inc, off, cond, abort, t=TUSER()
3759999:
376	.if	\inc == 1
377	\instr\cond\()b\()\t\().w \reg, [\ptr, #\off]
378	.elseif	\inc == 4
379	\instr\cond\()\t\().w \reg, [\ptr, #\off]
380	.else
381	.error	"Unsupported inc macro argument"
382	.endif
383
384	.pushsection __ex_table,"a"
385	.align	3
386	.long	9999b, \abort
387	.popsection
388	.endm
389
390	.macro	usracc, instr, reg, ptr, inc, cond, rept, abort
391	@ explicit IT instruction needed because of the label
392	@ introduced by the USER macro
393	.ifnc	\cond,al
394	.if	\rept == 1
395	itt	\cond
396	.elseif	\rept == 2
397	ittt	\cond
398	.else
399	.error	"Unsupported rept macro argument"
400	.endif
401	.endif
402
403	@ Slightly optimised to avoid incrementing the pointer twice
404	usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
405	.if	\rept == 2
406	usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
407	.endif
408
409	add\cond \ptr, #\rept * \inc
410	.endm
411
412#else	/* !CONFIG_THUMB2_KERNEL */
413
414	.macro	usracc, instr, reg, ptr, inc, cond, rept, abort, t=TUSER()
415	.rept	\rept
4169999:
417	.if	\inc == 1
418	\instr\cond\()b\()\t \reg, [\ptr], #\inc
419	.elseif	\inc == 4
420	\instr\cond\()\t \reg, [\ptr], #\inc
421	.else
422	.error	"Unsupported inc macro argument"
423	.endif
424
425	.pushsection __ex_table,"a"
426	.align	3
427	.long	9999b, \abort
428	.popsection
429	.endr
430	.endm
431
432#endif	/* CONFIG_THUMB2_KERNEL */
433
434	.macro	strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
435	usracc	str, \reg, \ptr, \inc, \cond, \rept, \abort
436	.endm
437
438	.macro	ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
439	usracc	ldr, \reg, \ptr, \inc, \cond, \rept, \abort
440	.endm
441
442/* Utility macro for declaring string literals */
443	.macro	string name:req, string
444	.type \name , #object
445\name:
446	.asciz "\string"
447	.size \name , . - \name
448	.endm
449
450	.macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
451#ifndef CONFIG_CPU_USE_DOMAINS
452	adds	\tmp, \addr, #\size - 1
453	sbcccs	\tmp, \tmp, \limit
454	bcs	\bad
455#endif
456	.endm
457
458	.macro	uaccess_disable, tmp, isb=1
459#ifdef CONFIG_CPU_SW_DOMAIN_PAN
460	/*
461	 * Whenever we re-enter userspace, the domains should always be
462	 * set appropriately.
463	 */
464	mov	\tmp, #DACR_UACCESS_DISABLE
465	mcr	p15, 0, \tmp, c3, c0, 0		@ Set domain register
466	.if	\isb
467	instr_sync
468	.endif
469#endif
470	.endm
471
472	.macro	uaccess_enable, tmp, isb=1
473#ifdef CONFIG_CPU_SW_DOMAIN_PAN
474	/*
475	 * Whenever we re-enter userspace, the domains should always be
476	 * set appropriately.
477	 */
478	mov	\tmp, #DACR_UACCESS_ENABLE
479	mcr	p15, 0, \tmp, c3, c0, 0
480	.if	\isb
481	instr_sync
482	.endif
483#endif
484	.endm
485
486	.macro	uaccess_save, tmp
487#ifdef CONFIG_CPU_SW_DOMAIN_PAN
488	mrc	p15, 0, \tmp, c3, c0, 0
489	str	\tmp, [sp, #SVC_DACR]
490#endif
491	.endm
492
493	.macro	uaccess_restore
494#ifdef CONFIG_CPU_SW_DOMAIN_PAN
495	ldr	r0, [sp, #SVC_DACR]
496	mcr	p15, 0, r0, c3, c0, 0
497#endif
498	.endm
499
500	.irp	c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo
501	.macro	ret\c, reg
502#if __LINUX_ARM_ARCH__ < 6
503	mov\c	pc, \reg
504#else
505	.ifeqs	"\reg", "lr"
506	bx\c	\reg
507	.else
508	mov\c	pc, \reg
509	.endif
510#endif
511	.endm
512	.endr
513
514	.macro	ret.w, reg
515	ret	\reg
516#ifdef CONFIG_THUMB2_KERNEL
517	nop
518#endif
519	.endm
520
521	.macro	bug, msg, line
522#ifdef CONFIG_THUMB2_KERNEL
5231:	.inst	0xde02
524#else
5251:	.inst	0xe7f001f2
526#endif
527#ifdef CONFIG_DEBUG_BUGVERBOSE
528	.pushsection .rodata.str, "aMS", %progbits, 1
5292:	.asciz	"\msg"
530	.popsection
531	.pushsection __bug_table, "aw"
532	.align	2
533	.word	1b, 2b
534	.hword	\line
535	.popsection
536#endif
537	.endm
538
539#ifdef CONFIG_KPROBES
540#define _ASM_NOKPROBE(entry)				\
541	.pushsection "_kprobe_blacklist", "aw" ;	\
542	.balign 4 ;					\
543	.long entry;					\
544	.popsection
545#else
546#define _ASM_NOKPROBE(entry)
547#endif
548
549#endif /* __ASM_ASSEMBLER_H__ */