macro.h 9.5 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0+ */
2 3 4 5 6 7 8 9
/*
 * include/asm-arm/macro.h
 *
 * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
 */

#ifndef __ASM_ARM_MACRO_H__
#define __ASM_ARM_MACRO_H__
10 11 12 13 14

#ifdef CONFIG_ARM64
#include <asm/system.h>
#endif

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#ifdef __ASSEMBLY__

/*
 * These macros provide a convenient way to write 8, 16 and 32 bit data
 * to any address.
 * Registers r4 and r5 are used, any data in these registers are
 * overwritten by the macros.
 * The macros are valid for any ARM architecture, they do not implement
 * any memory barriers so caution is recommended when using these when the
 * caches are enabled or on a multi-core system.
 */

.macro	write32, addr, data
	ldr	r4, =\addr
	ldr	r5, =\data
	str	r5, [r4]
.endm

.macro	write16, addr, data
	ldr	r4, =\addr
	ldrh	r5, =\data
	strh	r5, [r4]
.endm

.macro	write8, addr, data
	ldr	r4, =\addr
	ldrb	r5, =\data
	strb	r5, [r4]
.endm

/*
 * This macro generates a loop that can be used for delays in the code.
 * Register r4 is used, any data in this register is overwritten by the
 * macro.
 * The macro is valid for any ARM architeture. The actual time spent in the
 * loop will vary from CPU to CPU though.
 */

.macro	wait_timer, time
	ldr	r4, =\time
1:
	nop
	subs	r4, r4, #1
	bcs	1b
.endm

D
David Feng 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#ifdef CONFIG_ARM64
/*
 * Register aliases.
 */
lr	.req	x30

/*
 * Branch according to exception level
 */
.macro	switch_el, xreg, el3_label, el2_label, el1_label
	mrs	\xreg, CurrentEL
	cmp	\xreg, 0xc
	b.eq	\el3_label
	cmp	\xreg, 0x8
	b.eq	\el2_label
	cmp	\xreg, 0x4
	b.eq	\el1_label
.endm

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
/*
 * Branch if we are not in the highest exception level
 */
.macro	branch_if_not_highest_el, xreg, label
	switch_el \xreg, 3f, 2f, 1f

2:	mrs	\xreg, ID_AA64PFR0_EL1
	and	\xreg, \xreg, #(ID_AA64PFR0_EL1_EL3)
	cbnz	\xreg, \label
	b	3f

1:	mrs	\xreg, ID_AA64PFR0_EL1
	and	\xreg, \xreg, #(ID_AA64PFR0_EL1_EL3 | ID_AA64PFR0_EL1_EL2)
	cbnz	\xreg, \label

3:
.endm

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/*
 * Branch if current processor is a Cortex-A57 core.
 */
.macro	branch_if_a57_core, xreg, a57_label
	mrs	\xreg, midr_el1
	lsr	\xreg, \xreg, #4
	and	\xreg, \xreg, #0x00000FFF
	cmp	\xreg, #0xD07		/* Cortex-A57 MPCore processor. */
	b.eq	\a57_label
.endm

/*
 * Branch if current processor is a Cortex-A53 core.
 */
.macro	branch_if_a53_core, xreg, a53_label
	mrs	\xreg, midr_el1
	lsr	\xreg, \xreg, #4
	and	\xreg, \xreg, #0x00000FFF
	cmp	\xreg, #0xD03		/* Cortex-A53 MPCore processor. */
	b.eq	\a53_label
.endm

D
David Feng 已提交
120 121 122 123 124
/*
 * Branch if current processor is a slave,
 * choose processor with all zero affinity value as the master.
 */
.macro	branch_if_slave, xreg, slave_label
125 126
#ifdef CONFIG_ARMV8_MULTIENTRY
	/* NOTE: MPIDR handling will be erroneous on multi-cluster machines */
D
David Feng 已提交
127 128 129 130 131 132 133 134 135 136 137 138
	mrs	\xreg, mpidr_el1
	tst	\xreg, #0xff		/* Test Affinity 0 */
	b.ne	\slave_label
	lsr	\xreg, \xreg, #8
	tst	\xreg, #0xff		/* Test Affinity 1 */
	b.ne	\slave_label
	lsr	\xreg, \xreg, #8
	tst	\xreg, #0xff		/* Test Affinity 2 */
	b.ne	\slave_label
	lsr	\xreg, \xreg, #16
	tst	\xreg, #0xff		/* Test Affinity 3 */
	b.ne	\slave_label
139
#endif
D
David Feng 已提交
140 141 142 143 144 145 146
.endm

/*
 * Branch if current processor is a master,
 * choose processor with all zero affinity value as the master.
 */
.macro	branch_if_master, xreg1, xreg2, master_label
147 148
#ifdef CONFIG_ARMV8_MULTIENTRY
	/* NOTE: MPIDR handling will be erroneous on multi-cluster machines */
D
David Feng 已提交
149 150
	mrs	\xreg1, mpidr_el1
	lsr	\xreg2, \xreg1, #32
151
	lsl	\xreg2, \xreg2, #32
D
David Feng 已提交
152 153 154 155
	lsl	\xreg1, \xreg1, #40
	lsr	\xreg1, \xreg1, #40
	orr	\xreg1, \xreg1, \xreg2
	cbz	\xreg1, \master_label
156 157 158
#else
	b 	\master_label
#endif
D
David Feng 已提交
159 160
.endm

161 162 163 164 165 166 167 168 169 170 171 172
/*
 * Switch from EL3 to EL2 for ARMv8
 * @ep:     kernel entry point
 * @flag:   The execution state flag for lower exception
 *          level, ES_TO_AARCH64 or ES_TO_AARCH32
 * @tmp:    temporary register
 *
 * For loading 32-bit OS, x1 is machine nr and x2 is ftaddr.
 * For loading 64-bit OS, x0 is physical address to the FDT blob.
 * They will be passed to the guest.
 */
.macro armv8_switch_to_el2_m, ep, flag, tmp
173
	msr	cptr_el3, xzr		/* Disable coprocessor traps to EL3 */
174 175
	mov	\tmp, #CPTR_EL2_RES1
	msr	cptr_el2, \tmp		/* Disable coprocessor traps to EL2 */
176

D
David Feng 已提交
177 178 179
	/* Initialize Generic Timers */
	msr	cntvoff_el2, xzr

180 181 182 183 184 185
	/* Initialize SCTLR_EL2
	 *
	 * setting RES1 bits (29,28,23,22,18,16,11,5,4) to 1
	 * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
	 * EE,WXN,I,SA,C,A,M to 0
	 */
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	ldr	\tmp, =(SCTLR_EL2_RES1 | SCTLR_EL2_EE_LE |\
			SCTLR_EL2_WXN_DIS | SCTLR_EL2_ICACHE_DIS |\
			SCTLR_EL2_SA_DIS | SCTLR_EL2_DCACHE_DIS |\
			SCTLR_EL2_ALIGN_DIS | SCTLR_EL2_MMU_DIS)
	msr	sctlr_el2, \tmp

	mov	\tmp, sp
	msr	sp_el2, \tmp		/* Migrate SP */
	mrs	\tmp, vbar_el3
	msr	vbar_el2, \tmp		/* Migrate VBAR */

	/* Check switch to AArch64 EL2 or AArch32 Hypervisor mode */
	cmp	\flag, #ES_TO_AARCH32
	b.eq	1f

	/*
	 * The next lower exception level is AArch64, 64bit EL2 | HCE |
203 204
	 * RES1 (Bits[5:4]) | Non-secure EL0/EL1.
	 * and the SMD depends on requirements.
205
	 */
206 207 208 209
#ifdef CONFIG_ARMV8_PSCI
	ldr	\tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
			SCR_EL3_RES1 | SCR_EL3_NS_EN)
#else
210 211 212
	ldr	\tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
			SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
			SCR_EL3_NS_EN)
213
#endif
214 215 216 217

#ifdef CONFIG_ARMV8_EA_EL3_FIRST
	orr	\tmp, \tmp, #SCR_EL3_EA_EN
#endif
218
	msr	scr_el3, \tmp
219 220

	/* Return to the EL2_SP2 mode from EL3 */
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
	ldr	\tmp, =(SPSR_EL_DEBUG_MASK | SPSR_EL_SERR_MASK |\
			SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
			SPSR_EL_M_AARCH64 | SPSR_EL_M_EL2H)
	msr	spsr_el3, \tmp
	msr	elr_el3, \ep
	eret

1:
	/*
	 * The next lower exception level is AArch32, 32bit EL2 | HCE |
	 * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
	 */
	ldr	\tmp, =(SCR_EL3_RW_AARCH32 | SCR_EL3_HCE_EN |\
			SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
			SCR_EL3_NS_EN)
	msr	scr_el3, \tmp

	/* Return to AArch32 Hypervisor mode */
	ldr     \tmp, =(SPSR_EL_END_LE | SPSR_EL_ASYN_MASK |\
			SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
			SPSR_EL_T_A32 | SPSR_EL_M_AARCH32 |\
			SPSR_EL_M_HYP)
	msr	spsr_el3, \tmp
	msr     elr_el3, \ep
245 246 247
	eret
.endm

248 249 250 251 252 253 254 255 256 257 258
/*
 * Switch from EL2 to EL1 for ARMv8
 * @ep:     kernel entry point
 * @flag:   The execution state flag for lower exception
 *          level, ES_TO_AARCH64 or ES_TO_AARCH32
 * @tmp:    temporary register
 *
 * For loading 32-bit OS, x1 is machine nr and x2 is ftaddr.
 * For loading 64-bit OS, x0 is physical address to the FDT blob.
 * They will be passed to the guest.
 */
259
.macro armv8_switch_to_el1_m, ep, flag, tmp, tmp2
260
	/* Initialize Generic Timers */
261 262 263 264 265
	mrs	\tmp, cnthctl_el2
	/* Enable EL1 access to timers */
	orr	\tmp, \tmp, #(CNTHCTL_EL2_EL1PCEN_EN |\
		CNTHCTL_EL2_EL1PCTEN_EN)
	msr	cnthctl_el2, \tmp
266 267 268
	msr	cntvoff_el2, xzr

	/* Initilize MPID/MPIDR registers */
269 270 271 272
	mrs	\tmp, midr_el1
	msr	vpidr_el2, \tmp
	mrs	\tmp, mpidr_el1
	msr	vmpidr_el2, \tmp
273 274

	/* Disable coprocessor traps */
275 276
	mov	\tmp, #CPTR_EL2_RES1
	msr	cptr_el2, \tmp		/* Disable coprocessor traps to EL2 */
277
	msr	hstr_el2, xzr		/* Disable coprocessor traps to EL2 */
278 279
	mov	\tmp, #CPACR_EL1_FPEN_EN
	msr	cpacr_el1, \tmp		/* Enable FP/SIMD at EL1 */
280 281 282 283 284 285 286 287

	/* SCTLR_EL1 initialization
	 *
	 * setting RES1 bits (29,28,23,22,20,11) to 1
	 * and RES0 bits (31,30,27,21,17,13,10,6) +
	 * UCI,EE,EOE,WXN,nTWE,nTWI,UCT,DZE,I,UMA,SED,ITD,
	 * CP15BEN,SA0,SA,C,A,M to 0
	 */
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	ldr	\tmp, =(SCTLR_EL1_RES1 | SCTLR_EL1_UCI_DIS |\
			SCTLR_EL1_EE_LE | SCTLR_EL1_WXN_DIS |\
			SCTLR_EL1_NTWE_DIS | SCTLR_EL1_NTWI_DIS |\
			SCTLR_EL1_UCT_DIS | SCTLR_EL1_DZE_DIS |\
			SCTLR_EL1_ICACHE_DIS | SCTLR_EL1_UMA_DIS |\
			SCTLR_EL1_SED_EN | SCTLR_EL1_ITD_EN |\
			SCTLR_EL1_CP15BEN_DIS | SCTLR_EL1_SA0_DIS |\
			SCTLR_EL1_SA_DIS | SCTLR_EL1_DCACHE_DIS |\
			SCTLR_EL1_ALIGN_DIS | SCTLR_EL1_MMU_DIS)
	msr	sctlr_el1, \tmp

	mov	\tmp, sp
	msr	sp_el1, \tmp		/* Migrate SP */
	mrs	\tmp, vbar_el2
	msr	vbar_el1, \tmp		/* Migrate VBAR */

	/* Check switch to AArch64 EL1 or AArch32 Supervisor mode */
	cmp	\flag, #ES_TO_AARCH32
	b.eq	1f

	/* Initialize HCR_EL2 */
309 310 311 312 313 314 315 316
	/* Only disable PAuth traps if PAuth is supported */
	mrs	\tmp, id_aa64isar1_el1
	ldr	\tmp2, =(ID_AA64ISAR1_EL1_GPI | ID_AA64ISAR1_EL1_GPA | \
		      ID_AA64ISAR1_EL1_API | ID_AA64ISAR1_EL1_APA)
	tst	\tmp, \tmp2
	mov	\tmp2, #(HCR_EL2_RW_AARCH64 | HCR_EL2_HCD_DIS)
	orr	\tmp, \tmp2, #(HCR_EL2_APK | HCR_EL2_API)
	csel	\tmp, \tmp2, \tmp, eq
317
	msr	hcr_el2, \tmp
318

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	/*
	 * Detect whether the system has a configurable memory system
	 * architecture at EL1&0
	 */
	mrs	\tmp, id_aa64mmfr0_el1
	lsr	\tmp, \tmp, #48
	and	\tmp, \tmp, #((ID_AA64MMFR0_EL1_MSA_MASK | \
			ID_AA64MMFR0_EL1_MSA_FRAC_MASK) >> 48)
	cmp	\tmp, #((ID_AA64MMFR0_EL1_MSA_USE_FRAC | \
			ID_AA64MMFR0_EL1_MSA_FRAC_VMSA) >> 48)
	bne	2f

	/* Ensure the EL1&0 VMSA is enabled */
	mov	\tmp, #(VTCR_EL2_MSA)
	msr	vtcr_el2, \tmp
2:

336
	/* Return to the EL1_SP1 mode from EL2 */
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	ldr	\tmp, =(SPSR_EL_DEBUG_MASK | SPSR_EL_SERR_MASK |\
			SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
			SPSR_EL_M_AARCH64 | SPSR_EL_M_EL1H)
	msr	spsr_el2, \tmp
	msr     elr_el2, \ep
	eret

1:
	/* Initialize HCR_EL2 */
	ldr	\tmp, =(HCR_EL2_RW_AARCH32 | HCR_EL2_HCD_DIS)
	msr	hcr_el2, \tmp

	/* Return to AArch32 Supervisor mode from EL2 */
	ldr	\tmp, =(SPSR_EL_END_LE | SPSR_EL_ASYN_MASK |\
			SPSR_EL_IRQ_MASK | SPSR_EL_FIQ_MASK |\
			SPSR_EL_T_A32 | SPSR_EL_M_AARCH32 |\
			SPSR_EL_M_SVC)
	msr     spsr_el2, \tmp
	msr     elr_el2, \ep
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
	eret
.endm

#if defined(CONFIG_GICV3)
.macro gic_wait_for_interrupt_m xreg1
0 :	wfi
	mrs     \xreg1, ICC_IAR1_EL1
	msr     ICC_EOIR1_EL1, \xreg1
	cbnz    \xreg1, 0b
.endm
#elif defined(CONFIG_GICV2)
.macro gic_wait_for_interrupt_m xreg1, wreg2
0 :	wfi
	ldr     \wreg2, [\xreg1, GICC_AIAR]
	str     \wreg2, [\xreg1, GICC_AEOIR]
371
	and	\wreg2, \wreg2, #0x3ff
372 373 374 375
	cbnz    \wreg2, 0b
.endm
#endif

D
David Feng 已提交
376 377
#endif /* CONFIG_ARM64 */

378 379
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ARM_MACRO_H__ */