All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v4 0/2] armv8: Support loading 32-bit OS in AArch32 execution state
@ 2016-06-08  5:14 Alison Wang
  2016-06-08  5:14 ` [U-Boot] [PATCH v4 1/2] " Alison Wang
  2016-06-08  5:14 ` [U-Boot] [PATCH v4 2/2] armv8: fsl-layerscape: SMP support for loading 32-bit OS Alison Wang
  0 siblings, 2 replies; 14+ messages in thread
From: Alison Wang @ 2016-06-08  5:14 UTC (permalink / raw)
  To: u-boot

This series is to support loading a 32-bit OS, the execution state will
change from AArch64 to AArch32 when jumping to kernel. The architecture
information will be got through checking FIT image, then U-Boot will
load 32-bit OS or 64-bit OS automatically.

Spin-table method is used for secondary cores to load 32-bit OS. The
architecture information will be got through checking FIT image and
saved in the os_arch element of spin-table, then the secondary cores
will check os_arch and jump to 32-bit OS or 64-bit OS automatically.

---------------------------------------
Changes in v4:
- Correct config ARM64_SUPPORT_AARCH32.
- Omit arch and ftaddr arguments.
- Rename "xreg5" to "tmp".
- Use xxx_RES1 to combine all RES1 fields in xxx register.
- Use an immediate cmp directly.
- Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.

Changes in v3:
- Comments the functions and the arguments.
- Rename the real parameters.
- Use the macros instead of the magic values.
- Remove the redundant codes.
- Clean up all of the mess in boot_jump_linux().
- Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system doesn't support AArch32 state.
- Adjust the arguments for armv8_switch_to_el2_m and armv8_switch_to_el1_m.

Changes in v2:
- armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is used
  to switch to AArch64 EL2 or AArch32 Hyp.
- armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is used
  to switch to AArch64 EL1 or AArch32 SVC.
- Support to call armv8_switch_to_el2_m and armv8_switch_to_el1_m.

Alison Wang (2):
      armv8: Support loading 32-bit OS in AArch32 execution state
      armv8: fsl-layerscape: SMP support for loading 32-bit OS

 arch/arm/Kconfig                              |   6 ++++
 arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S  |  35 +++++++++++++++++---
 arch/arm/cpu/armv8/fsl-layerscape/mp.c        |  10 ++++++
 arch/arm/cpu/armv8/start.S                    |   1 +
 arch/arm/cpu/armv8/transition.S               |   8 ++---
 arch/arm/include/asm/arch-fsl-layerscape/mp.h |   6 ++++
 arch/arm/include/asm/macro.h                  | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
 arch/arm/include/asm/system.h                 | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 arch/arm/lib/bootm.c                          |  24 +++++++++++---
 common/image-fit.c                            |  19 ++++++++++-
 10 files changed, 336 insertions(+), 56 deletions(-)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-08  5:14 [U-Boot] [PATCH v4 0/2] armv8: Support loading 32-bit OS in AArch32 execution state Alison Wang
@ 2016-06-08  5:14 ` Alison Wang
  2016-06-08 12:14   ` Alexander Graf
  2016-06-08  5:14 ` [U-Boot] [PATCH v4 2/2] armv8: fsl-layerscape: SMP support for loading 32-bit OS Alison Wang
  1 sibling, 1 reply; 14+ messages in thread
From: Alison Wang @ 2016-06-08  5:14 UTC (permalink / raw)
  To: u-boot

To support loading a 32-bit OS, the execution state will change from
AArch64 to AArch32 when jumping to kernel.

The architecture information will be got through checking FIT
image, then U-Boot will load 32-bit OS or 64-bit OS automatically.

Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
Signed-off-by: Alison Wang <alison.wang@nxp.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
Changes in v4:
- Correct config ARM64_SUPPORT_AARCH32.
- Omit arch and ftaddr arguments.
- Rename "xreg5" to "tmp".
- Use xxx_RES1 to combine all RES1 fields in xxx register.
- Use an immediate cmp directly.
- Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.

Changes in v3:
- Comments the functions and the arguments.
- Rename the real parameters.
- Use the macros instead of the magic values.
- Remove the redundant codes.
- Clean up all of the mess in boot_jump_linux().
- Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system doesn't support AArch32 state.

Changes in v2:
- armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is used
  to switch to AArch64 EL2 or AArch32 Hyp.
- armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is used
  to switch to AArch64 EL1 or AArch32 SVC.

 arch/arm/Kconfig                |   6 ++
 arch/arm/cpu/armv8/start.S      |   1 +
 arch/arm/cpu/armv8/transition.S |   8 +-
 arch/arm/include/asm/macro.h    | 172 ++++++++++++++++++++++++++++++----------
 arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
 arch/arm/lib/bootm.c            |  19 ++++-
 common/image-fit.c              |  19 ++++-
 7 files changed, 284 insertions(+), 52 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 77eab66..9cf4acd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
 	  If SoC does not support L2CACHE or one do not want to enable
 	  L2CACHE, choose this option.
 
+config ARM64_SUPPORT_AARCH32
+	bool "ARM64 system support AArch32 execution state"
+	default y if ARM64 && !TARGET_THUNDERX_88XX
+	help
+	  This ARM64 system supports AArch32 execution state.
+
 choice
 	prompt "Target select"
 	default TARGET_HIKEY
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index e933021..dd69501 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -234,6 +234,7 @@ WEAK(lowlevel_init)
 	/*
 	 * All slaves will enter EL2 and optionally EL1.
 	 */
+	ldr	x3, =ES_TO_AARCH64
 	bl	armv8_switch_to_el2
 #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
 	bl	armv8_switch_to_el1
diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S
index 253a39b..e61b6ae 100644
--- a/arch/arm/cpu/armv8/transition.S
+++ b/arch/arm/cpu/armv8/transition.S
@@ -11,13 +11,13 @@
 #include <asm/macro.h>
 
 ENTRY(armv8_switch_to_el2)
-	switch_el x0, 1f, 0f, 0f
+	switch_el x4, 1f, 0f, 0f
 0:	ret
-1:	armv8_switch_to_el2_m x0
+1:	armv8_switch_to_el2_m x0, x3, x4
 ENDPROC(armv8_switch_to_el2)
 
 ENTRY(armv8_switch_to_el1)
-	switch_el x0, 0f, 1f, 0f
+	switch_el x4, 0f, 1f, 0f
 0:	ret
-1:	armv8_switch_to_el1_m x0, x1
+1:	armv8_switch_to_el1_m x0, x3, x4
 ENDPROC(armv8_switch_to_el1)
diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
index 9bb0efa..109724f 100644
--- a/arch/arm/include/asm/macro.h
+++ b/arch/arm/include/asm/macro.h
@@ -8,6 +8,9 @@
 
 #ifndef __ASM_ARM_MACRO_H__
 #define __ASM_ARM_MACRO_H__
+
+#include <asm/system.h>
+
 #ifdef __ASSEMBLY__
 
 /*
@@ -135,13 +138,20 @@ lr	.req	x30
 #endif
 .endm
 
-.macro armv8_switch_to_el2_m, xreg1
-	/* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1 */
-	mov	\xreg1, #0x5b1
-	msr	scr_el3, \xreg1
+/*
+ * 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
+ *
+ * x1 is machine nr and x2 is ftaddr, they will be passed
+ * to the guest.
+ */
+.macro armv8_switch_to_el2_m, ep, flag, tmp
 	msr	cptr_el3, xzr		/* Disable coprocessor traps to EL3 */
-	mov	\xreg1, #0x33ff
-	msr	cptr_el2, \xreg1	/* Disable coprocessor traps to EL2 */
+	mov	\tmp, #CPTR_EL2_RES1
+	msr	cptr_el2, \tmp		/* Disable coprocessor traps to EL2 */
 
 	/* Initialize Generic Timers */
 	msr	cntvoff_el2, xzr
@@ -152,45 +162,91 @@ lr	.req	x30
 	 * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
 	 * EE,WXN,I,SA,C,A,M to 0
 	 */
-	mov	\xreg1, #0x0830
-	movk	\xreg1, #0x30C5, lsl #16
-	msr	sctlr_el2, \xreg1
+	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 |
+	 * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
+	 */
+	ldr	\tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
+			SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
+			SCR_EL3_NS_EN)
+	msr	scr_el3, \tmp
 
 	/* Return to the EL2_SP2 mode from EL3 */
-	mov	\xreg1, sp
-	msr	sp_el2, \xreg1		/* Migrate SP */
-	mrs	\xreg1, vbar_el3
-	msr	vbar_el2, \xreg1	/* Migrate VBAR */
-	mov	\xreg1, #0x3c9
-	msr	spsr_el3, \xreg1	/* EL2_SP2 | D | A | I | F */
+	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, lr
 	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
+
+	mov	\ep, #0
+	eret
 .endm
 
-.macro armv8_switch_to_el1_m, xreg1, xreg2
+/*
+ * 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
+ *
+ * x1 is machine nr and x2 is ftaddr, they will be passed
+ * to the guest.
+ */
+.macro armv8_switch_to_el1_m, ep, flag, tmp
 	/* Initialize Generic Timers */
-	mrs	\xreg1, cnthctl_el2
-	orr	\xreg1, \xreg1, #0x3	/* Enable EL1 access to timers */
-	msr	cnthctl_el2, \xreg1
+	mrs	\tmp, cnthctl_el2
+	/* Enable EL1 access to timers */
+	orr	\tmp, \tmp, #(CNTHCTL_EL2_EL1PCEN_EN |\
+		CNTHCTL_EL2_EL1PCTEN_EN)
+	msr	cnthctl_el2, \tmp
 	msr	cntvoff_el2, xzr
 
 	/* Initilize MPID/MPIDR registers */
-	mrs	\xreg1, midr_el1
-	mrs	\xreg2, mpidr_el1
-	msr	vpidr_el2, \xreg1
-	msr	vmpidr_el2, \xreg2
+	mrs	\tmp, midr_el1
+	msr	vpidr_el2, \tmp
+	mrs	\tmp, mpidr_el1
+	msr	vmpidr_el2, \tmp
 
 	/* Disable coprocessor traps */
-	mov	\xreg1, #0x33ff
-	msr	cptr_el2, \xreg1	/* Disable coprocessor traps to EL2 */
+	mov	\tmp, #CPTR_EL2_RES1
+	msr	cptr_el2, \tmp		/* Disable coprocessor traps to EL2 */
 	msr	hstr_el2, xzr		/* Disable coprocessor traps to EL2 */
-	mov	\xreg1, #3 << 20
-	msr	cpacr_el1, \xreg1	/* Enable FP/SIMD at EL1 */
-
-	/* Initialize HCR_EL2 */
-	mov	\xreg1, #(1 << 31)		/* 64bit EL1 */
-	orr	\xreg1, \xreg1, #(1 << 29)	/* Disable HVC */
-	msr	hcr_el2, \xreg1
+	mov	\tmp, #CPACR_EL1_FPEN_EN
+	msr	cpacr_el1, \tmp		/* Enable FP/SIMD@EL1 */
 
 	/* SCTLR_EL1 initialization
 	 *
@@ -199,19 +255,53 @@ lr	.req	x30
 	 * UCI,EE,EOE,WXN,nTWE,nTWI,UCT,DZE,I,UMA,SED,ITD,
 	 * CP15BEN,SA0,SA,C,A,M to 0
 	 */
-	mov	\xreg1, #0x0800
-	movk	\xreg1, #0x30d0, lsl #16
-	msr	sctlr_el1, \xreg1
+	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 */
+	ldr	\tmp, =(HCR_EL2_RW_AARCH64 | HCR_EL2_HCD_DIS)
+	msr	hcr_el2, \tmp
 
 	/* Return to the EL1_SP1 mode from EL2 */
-	mov	\xreg1, sp
-	msr	sp_el1, \xreg1		/* Migrate SP */
-	mrs	\xreg1, vbar_el2
-	msr	vbar_el1, \xreg1	/* Migrate VBAR */
-	mov	\xreg1, #0x3c5
-	msr	spsr_el2, \xreg1	/* EL1_SP1 | D | A | I | F */
+	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, lr
 	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
+
+	mov	\ep, #0
+	eret
 .endm
 
 #if defined(CONFIG_GICV3)
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 2bdc0be..14f30dd 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -17,6 +17,95 @@
 #define CR_WXN		(1 << 19)	/* Write Permision Imply XN	*/
 #define CR_EE		(1 << 25)	/* Exception (Big) Endian	*/
 
+#define ES_TO_AARCH64		1
+#define ES_TO_AARCH32		0
+
+/*
+ * SCR_EL3 bits definitions
+ */
+#define SCR_EL3_RW_AARCH64	(1 << 10) /* Next lower level is AArch64     */
+#define SCR_EL3_RW_AARCH32	(0 << 10) /* Lower lowers level are AArch32  */
+#define SCR_EL3_HCE_EN		(1 << 8)  /* Hypervisor Call enable          */
+#define SCR_EL3_SMD_DIS		(1 << 7)  /* Secure Monitor Call disable     */
+#define SCR_EL3_RES1		(3 << 4)  /* Reserved, RES1                  */
+#define SCR_EL3_NS_EN		(1 << 0)  /* EL0 and EL1 in Non-scure state  */
+
+/*
+ * SPSR_EL3/SPSR_EL2 bits definitions
+ */
+#define SPSR_EL_END_LE		(0 << 9)  /* Exception Little-endian          */
+#define SPSR_EL_DEBUG_MASK	(1 << 9)  /* Debug exception masked           */
+#define SPSR_EL_ASYN_MASK	(1 << 8)  /* Asynchronous data abort masked   */
+#define SPSR_EL_SERR_MASK	(1 << 8)  /* System Error exception masked    */
+#define SPSR_EL_IRQ_MASK	(1 << 7)  /* IRQ exception masked             */
+#define SPSR_EL_FIQ_MASK	(1 << 6)  /* FIQ exception masked             */
+#define SPSR_EL_T_A32		(0 << 5)  /* AArch32 instruction set A32      */
+#define SPSR_EL_M_AARCH64	(0 << 4)  /* Exception taken from AArch64     */
+#define SPSR_EL_M_AARCH32	(1 << 4)  /* Exception taken from AArch32     */
+#define SPSR_EL_M_SVC		(0x3)     /* Exception taken from SVC mode    */
+#define SPSR_EL_M_HYP		(0xa)     /* Exception taken from HYP mode    */
+#define SPSR_EL_M_EL1H		(5)       /* Exception taken from EL1h mode   */
+#define SPSR_EL_M_EL2H		(9)       /* Exception taken from EL2h mode   */
+
+/*
+ * CPTR_EL2 bits definitions
+ */
+#define CPTR_EL2_RES1		(3 << 12 | 0x3ff)           /* Reserved, RES1 */
+
+/*
+ * SCTLR_EL2 bits definitions
+ */
+#define SCTLR_EL2_RES1		(3 << 28 | 3 << 22 | 1 << 18 | 1 << 16 |\
+				 1 << 11 | 3 << 4)	    /* Reserved, RES1 */
+#define SCTLR_EL2_EE_LE		(0 << 25) /* Exception Little-endian          */
+#define SCTLR_EL2_WXN_DIS	(0 << 19) /* Write permission is not XN       */
+#define SCTLR_EL2_ICACHE_DIS	(0 << 12) /* Instruction cache disabled       */
+#define SCTLR_EL2_SA_DIS	(0 << 3)  /* Stack Alignment Check disabled   */
+#define SCTLR_EL2_DCACHE_DIS	(0 << 2)  /* Data cache disabled              */
+#define SCTLR_EL2_ALIGN_DIS	(0 << 1)  /* Alignment check disabled         */
+#define SCTLR_EL2_MMU_DIS	(0)       /* MMU disabled                     */
+
+/*
+ * CNTHCTL_EL2 bits definitions
+ */
+#define CNTHCTL_EL2_EL1PCEN_EN	(1 << 1)  /* Physical timer regs accessible   */
+#define CNTHCTL_EL2_EL1PCTEN_EN	(1 << 0)  /* Physical counter accessible      */
+
+/*
+ * HCR_EL2 bits definitions
+ */
+#define HCR_EL2_RW_AARCH64	(1 << 31) /* EL1 is AArch64                   */
+#define HCR_EL2_RW_AARCH32	(0 << 31) /* Lower levels are AArch32         */
+#define HCR_EL2_HCD_DIS		(1 << 29) /* Hypervisor Call disabled         */
+
+/*
+ * CPACR_EL1 bits definitions
+ */
+#define CPACR_EL1_FPEN_EN	(3 << 20) /* SIMD and FP instruction enabled  */
+
+/*
+ * SCTLR_EL1 bits definitions
+ */
+#define SCTLR_EL1_RES1		(3 << 28 | 3 << 22 | 1 << 20 |\
+				 1 << 11) /* Reserved, RES1                   */
+#define SCTLR_EL1_UCI_DIS	(0 << 26) /* Cache instruction disabled       */
+#define SCTLR_EL1_EE_LE		(0 << 25) /* Exception Little-endian          */
+#define SCTLR_EL1_WXN_DIS	(0 << 19) /* Write permission is not XN       */
+#define SCTLR_EL1_NTWE_DIS	(0 << 18) /* WFE instruction disabled         */
+#define SCTLR_EL1_NTWI_DIS	(0 << 16) /* WFI instruction disabled         */
+#define SCTLR_EL1_UCT_DIS	(0 << 15) /* CTR_EL0 access disabled          */
+#define SCTLR_EL1_DZE_DIS	(0 << 14) /* DC ZVA instruction disabled      */
+#define SCTLR_EL1_ICACHE_DIS	(0 << 12) /* Instruction cache disabled       */
+#define SCTLR_EL1_UMA_DIS	(0 << 9)  /* User Mask Access disabled        */
+#define SCTLR_EL1_SED_EN	(0 << 8)  /* SETEND instruction enabled       */
+#define SCTLR_EL1_ITD_EN	(0 << 7)  /* IT instruction enabled           */
+#define SCTLR_EL1_CP15BEN_DIS	(0 << 5)  /* CP15 barrier operation disabled  */
+#define SCTLR_EL1_SA0_DIS	(0 << 4)  /* Stack Alignment EL0 disabled     */
+#define SCTLR_EL1_SA_DIS	(0 << 3)  /* Stack Alignment EL1 disabled     */
+#define SCTLR_EL1_DCACHE_DIS	(0 << 2)  /* Data cache disabled              */
+#define SCTLR_EL1_ALIGN_DIS	(0 << 1)  /* Alignment check disabled         */
+#define SCTLR_EL1_MMU_DIS	(0)       /* MMU disabled                     */
+
 #ifndef __ASSEMBLY__
 
 u64 get_page_table_size(void);
@@ -100,8 +189,26 @@ void __asm_invalidate_icache_all(void);
 int __asm_flush_l3_cache(void);
 void __asm_switch_ttbr(u64 new_ttbr);
 
-void armv8_switch_to_el2(void);
-void armv8_switch_to_el1(void);
+/*
+ * Switch from EL3 to EL2 for ARMv8
+ *
+ * @entry_point: kernel entry point
+ * @mach_nr:     machine nr
+ * @fdt_addr:    fdt address
+ * @es_flag:     execution state flag, ES_TO_AARCH64 or ES_TO_AARCH32
+ */
+void armv8_switch_to_el2(u64 entry_point, u64 mach_nr, u64 fdt_addr,
+			 u64 es_flag);
+/*
+ * Switch from EL2 to EL1 for ARMv8
+ *
+ * @entry_point: kernel entry point
+ * @mach_nr:     machine nr
+ * @fdt_addr:    fdt address
+ * @es_flag:     execution state flag, ES_TO_AARCH64 or ES_TO_AARCH32
+ */
+void armv8_switch_to_el1(u64 entry_point, u64 mach_nr, u64 fdt_addr,
+			 u64 es_flag);
 void gic_init(void);
 void gic_send_sgi(unsigned long sgino);
 void wait_for_wakeup(void);
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 0838d89..1bbf85c 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -189,13 +189,19 @@ static void setup_end_tag(bd_t *bd)
 __weak void setup_board_tags(struct tag **in_params) {}
 
 #ifdef CONFIG_ARM64
-static void do_nonsec_virt_switch(void)
+static void do_nonsec_virt_switch(bootm_headers_t *images, int flag)
 {
 	smp_kick_all_cpus();
 	dcache_disable();	/* flush cache before swtiching to EL2 */
-	armv8_switch_to_el2();
+
 #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
-	armv8_switch_to_el1();
+	armv8_switch_to_el2((u64)images->ep, (u64)gd->bd->bi_arch_number,
+			    (u64)images->ft_addr, ES_TO_AARCH64);
+	armv8_switch_to_el1((u64)images->ep, (u64)gd->bd->bi_arch_number,
+			    (u64)images->ft_addr, flag);
+#else
+	armv8_switch_to_el2((u64)images->ep, (u64)gd->bd->bi_arch_number,
+			    (u64)images->ft_addr, flag);
 #endif
 }
 #endif
@@ -275,6 +281,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
 	void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
 			void *res2);
 	int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
+	int es_flag = ES_TO_AARCH64;
 
 	kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
 				void *res2))images->ep;
@@ -286,7 +293,11 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
 	announce_and_cleanup(fake);
 
 	if (!fake) {
-		do_nonsec_virt_switch();
+		if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
+		    (images->os.arch == IH_ARCH_ARM))
+			es_flag = ES_TO_AARCH32;
+
+		do_nonsec_virt_switch(images, es_flag);
 		kernel_entry(images->ft_addr, NULL, NULL, NULL);
 	}
 #else
diff --git a/common/image-fit.c b/common/image-fit.c
index 9873957..4458037 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -26,6 +26,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <u-boot/md5.h>
 #include <u-boot/sha1.h>
 #include <u-boot/sha256.h>
+#include <generated/autoconf.h>
 
 /*****************************************************************************/
 /* New uImage format routines */
@@ -1160,11 +1161,18 @@ int fit_image_check_os(const void *fit, int noffset, uint8_t os)
 int fit_image_check_arch(const void *fit, int noffset, uint8_t arch)
 {
 	uint8_t image_arch;
+	int aarch32_support = 0;
+
+#ifdef CONFIG_ARM64_SUPPORT_AARCH32
+	aarch32_support = 1;
+#endif
 
 	if (fit_image_get_arch(fit, noffset, &image_arch))
 		return 0;
 	return (arch == image_arch) ||
-		(arch == IH_ARCH_I386 && image_arch == IH_ARCH_X86_64);
+		(arch == IH_ARCH_I386 && image_arch == IH_ARCH_X86_64) ||
+		(arch == IH_ARCH_ARM64 && image_arch == IH_ARCH_ARM &&
+		 aarch32_support);
 }
 
 /**
@@ -1593,6 +1601,9 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 	int type_ok, os_ok;
 	ulong load, data, len;
 	uint8_t os;
+#ifndef USE_HOSTCC
+	uint8_t os_arch;
+#endif
 	const char *prop_name;
 	int ret;
 
@@ -1676,6 +1687,12 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
 		return -ENOEXEC;
 	}
 #endif
+
+#ifndef USE_HOSTCC
+	fit_image_get_arch(fit, noffset, &os_arch);
+	images->os.arch = os_arch;
+#endif
+
 	if (image_type == IH_TYPE_FLATDT &&
 	    !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) {
 		puts("FDT image is compressed");
-- 
2.1.0.27.g96db324

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 2/2] armv8: fsl-layerscape: SMP support for loading 32-bit OS
  2016-06-08  5:14 [U-Boot] [PATCH v4 0/2] armv8: Support loading 32-bit OS in AArch32 execution state Alison Wang
  2016-06-08  5:14 ` [U-Boot] [PATCH v4 1/2] " Alison Wang
@ 2016-06-08  5:14 ` Alison Wang
  1 sibling, 0 replies; 14+ messages in thread
From: Alison Wang @ 2016-06-08  5:14 UTC (permalink / raw)
  To: u-boot

Spin-table method is used for secondary cores to load 32-bit OS. The
architecture information will be got through checking FIT image and
saved in the os_arch element of spin-table, then the secondary cores
will check os_arch and jump to 32-bit OS or 64-bit OS automatically.

Signed-off-by: Alison Wang <alison.wang@nxp.com>
Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
---
Changes in v4:
- Omit arch and ftaddr arguments.

Changes in v3:
- Adjust the arguments for armv8_switch_to_el2_m and armv8_switch_to_el1_m. 

Changes in v2:
- Support to call armv8_switch_to_el2_m and armv8_switch_to_el1_m. 

 arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S  | 35 ++++++++++++++++++++++++---
 arch/arm/cpu/armv8/fsl-layerscape/mp.c        | 10 ++++++++
 arch/arm/include/asm/arch-fsl-layerscape/mp.h |  6 +++++
 arch/arm/lib/bootm.c                          |  5 ++++
 4 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
index 04831ca..32e9511 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
+++ b/arch/arm/cpu/armv8/fsl-layerscape/lowlevel.S
@@ -13,6 +13,8 @@
 #ifdef CONFIG_MP
 #include <asm/arch/mp.h>
 #endif
+#include <asm/u-boot.h>
+#include <asm/system.h>
 
 ENTRY(lowlevel_init)
 	mov	x29, lr			/* Save LR */
@@ -320,6 +322,12 @@ ENTRY(secondary_boot_func)
         gic_wait_for_interrupt_m x0, w1
 #endif
 
+	ldr	x5, [x11, #24]
+	ldr	x6, =IH_ARCH_DEFAULT
+	cmp	x6, x5
+	b.ne	slave_cpu
+
+	ldr	x3, =ES_TO_AARCH64
 	bl secondary_switch_to_el2
 #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
 	bl secondary_switch_to_el1
@@ -337,19 +345,38 @@ slave_cpu:
 	tbz     x1, #25, cpu_is_le
 	rev     x0, x0                  /* BE to LE conversion */
 cpu_is_le:
+
+	ldr	x5, [x11, #24]
+	ldr	x6, =IH_ARCH_DEFAULT
+	cmp	x6, x5
+	b.eq	1f
+
+#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
+	ldr	x3, =ES_TO_AARCH64
+	bl	secondary_switch_to_el2
+	ldr	x0, [x11]
+	ldr	x3, =ES_TO_AARCH32
+	bl	secondary_switch_to_el1
+#else
+	ldr	x0, [x11]
+	ldr	x3, =ES_TO_AARCH32
+	bl	secondary_switch_to_el2
+#endif
+
+1:
 	br	x0			/* branch to the given address */
 ENDPROC(secondary_boot_func)
 
 ENTRY(secondary_switch_to_el2)
-	switch_el x0, 1f, 0f, 0f
+	switch_el x4, 1f, 0f, 0f
 0:	ret
-1:	armv8_switch_to_el2_m x0
+1:	armv8_switch_to_el2_m x0, x3, x4
 ENDPROC(secondary_switch_to_el2)
 
 ENTRY(secondary_switch_to_el1)
-	switch_el x0, 0f, 1f, 0f
+	switch_el x4, 0f, 1f, 0f
 0:	ret
-1:	armv8_switch_to_el1_m x0, x1
+1:	armv8_switch_to_el1_m x0, x3, x4
 ENDPROC(secondary_switch_to_el1)
 
 	/* Ensure that the literals used by the secondary boot code are
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/mp.c b/arch/arm/cpu/armv8/fsl-layerscape/mp.c
index df7ffb8..dd91550 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/mp.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/mp.c
@@ -22,6 +22,16 @@ phys_addr_t determine_mp_bootpg(void)
 	return (phys_addr_t)&secondary_boot_code;
 }
 
+void update_os_arch_secondary_cores(uint8_t os_arch)
+{
+	u64 *table = get_spin_tbl_addr();
+	int i;
+
+	for (i = 1; i < CONFIG_MAX_CPUS; i++)
+		table[i * WORDS_PER_SPIN_TABLE_ENTRY +
+			SPIN_TABLE_ELEM_OS_ARCH_IDX] = os_arch;
+}
+
 int fsl_layerscape_wake_seconday_cores(void)
 {
 	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/mp.h b/arch/arm/include/asm/arch-fsl-layerscape/mp.h
index e46e076..55f0e0c 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/mp.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/mp.h
@@ -13,6 +13,7 @@
 *      uint64_t entry_addr;
 *      uint64_t status;
 *      uint64_t lpid;
+*      uint64_t os_arch;
 * };
 * we pad this struct to 64 bytes so each entry is in its own cacheline
 * the actual spin table is an array of these structures
@@ -20,6 +21,7 @@
 #define SPIN_TABLE_ELEM_ENTRY_ADDR_IDX	0
 #define SPIN_TABLE_ELEM_STATUS_IDX	1
 #define SPIN_TABLE_ELEM_LPID_IDX	2
+#define SPIN_TABLE_ELEM_OS_ARCH_IDX	3
 #define WORDS_PER_SPIN_TABLE_ENTRY	8	/* pad to 64 bytes */
 #define SPIN_TABLE_ELEM_SIZE		64
 
@@ -35,4 +37,8 @@ phys_addr_t determine_mp_bootpg(void);
 void secondary_boot_func(void);
 int is_core_online(u64 cpu_id);
 #endif
+
+#define IH_ARCH_ARM		2	/* ARM */
+#define IH_ARCH_ARM64		22	/* ARM64 */
+
 #endif /* _FSL_LAYERSCAPE_MP_H */
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 1bbf85c..4dca065 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -274,6 +274,10 @@ bool armv7_boot_nonsec(void)
 }
 #endif
 
+__weak void update_os_arch_secondary_cores(uint8_t os_arch)
+{
+}
+
 /* Subcommand: GO */
 static void boot_jump_linux(bootm_headers_t *images, int flag)
 {
@@ -293,6 +297,7 @@ static void boot_jump_linux(bootm_headers_t *images, int flag)
 	announce_and_cleanup(fake);
 
 	if (!fake) {
+		update_os_arch_secondary_cores(images->os.arch);
 		if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
 		    (images->os.arch == IH_ARCH_ARM))
 			es_flag = ES_TO_AARCH32;
-- 
2.1.0.27.g96db324

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-08  5:14 ` [U-Boot] [PATCH v4 1/2] " Alison Wang
@ 2016-06-08 12:14   ` Alexander Graf
  2016-06-15  3:04     ` Huan Wang
  0 siblings, 1 reply; 14+ messages in thread
From: Alexander Graf @ 2016-06-08 12:14 UTC (permalink / raw)
  To: u-boot

On 06/08/2016 07:14 AM, Alison Wang wrote:
> To support loading a 32-bit OS, the execution state will change from
> AArch64 to AArch32 when jumping to kernel.
>
> The architecture information will be got through checking FIT
> image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
>
> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
> Signed-off-by: Alison Wang <alison.wang@nxp.com>
> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> ---
> Changes in v4:
> - Correct config ARM64_SUPPORT_AARCH32.
> - Omit arch and ftaddr arguments.
> - Rename "xreg5" to "tmp".
> - Use xxx_RES1 to combine all RES1 fields in xxx register.
> - Use an immediate cmp directly.
> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>
> Changes in v3:
> - Comments the functions and the arguments.
> - Rename the real parameters.
> - Use the macros instead of the magic values.
> - Remove the redundant codes.
> - Clean up all of the mess in boot_jump_linux().
> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system doesn't support AArch32 state.
>
> Changes in v2:
> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is used
>    to switch to AArch64 EL2 or AArch32 Hyp.
> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is used
>    to switch to AArch64 EL1 or AArch32 SVC.
>
>   arch/arm/Kconfig                |   6 ++
>   arch/arm/cpu/armv8/start.S      |   1 +
>   arch/arm/cpu/armv8/transition.S |   8 +-
>   arch/arm/include/asm/macro.h    | 172 ++++++++++++++++++++++++++++++----------
>   arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>   arch/arm/lib/bootm.c            |  19 ++++-
>   common/image-fit.c              |  19 ++++-
>   7 files changed, 284 insertions(+), 52 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 77eab66..9cf4acd 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>   	  If SoC does not support L2CACHE or one do not want to enable
>   	  L2CACHE, choose this option.
>   
> +config ARM64_SUPPORT_AARCH32
> +	bool "ARM64 system support AArch32 execution state"
> +	default y if ARM64 && !TARGET_THUNDERX_88XX
> +	help
> +	  This ARM64 system supports AArch32 execution state.
> +
>   choice
>   	prompt "Target select"
>   	default TARGET_HIKEY
> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
> index e933021..dd69501 100644
> --- a/arch/arm/cpu/armv8/start.S
> +++ b/arch/arm/cpu/armv8/start.S
> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>   	/*
>   	 * All slaves will enter EL2 and optionally EL1.
>   	 */
> +	ldr	x3, =ES_TO_AARCH64
>   	bl	armv8_switch_to_el2
>   #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>   	bl	armv8_switch_to_el1
> diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S
> index 253a39b..e61b6ae 100644
> --- a/arch/arm/cpu/armv8/transition.S
> +++ b/arch/arm/cpu/armv8/transition.S
> @@ -11,13 +11,13 @@
>   #include <asm/macro.h>
>   
>   ENTRY(armv8_switch_to_el2)
> -	switch_el x0, 1f, 0f, 0f
> +	switch_el x4, 1f, 0f, 0f
>   0:	ret
> -1:	armv8_switch_to_el2_m x0
> +1:	armv8_switch_to_el2_m x0, x3, x4
>   ENDPROC(armv8_switch_to_el2)
>   
>   ENTRY(armv8_switch_to_el1)
> -	switch_el x0, 0f, 1f, 0f
> +	switch_el x4, 0f, 1f, 0f
>   0:	ret
> -1:	armv8_switch_to_el1_m x0, x1
> +1:	armv8_switch_to_el1_m x0, x3, x4
>   ENDPROC(armv8_switch_to_el1)
> diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
> index 9bb0efa..109724f 100644
> --- a/arch/arm/include/asm/macro.h
> +++ b/arch/arm/include/asm/macro.h
> @@ -8,6 +8,9 @@
>   
>   #ifndef __ASM_ARM_MACRO_H__
>   #define __ASM_ARM_MACRO_H__
> +
> +#include <asm/system.h>
> +
>   #ifdef __ASSEMBLY__
>   
>   /*
> @@ -135,13 +138,20 @@ lr	.req	x30
>   #endif
>   .endm
>   
> -.macro armv8_switch_to_el2_m, xreg1
> -	/* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1 */
> -	mov	\xreg1, #0x5b1
> -	msr	scr_el3, \xreg1
> +/*
> + * 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
> + *
> + * x1 is machine nr and x2 is ftaddr, they will be passed
> + * to the guest.
> + */
> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>   	msr	cptr_el3, xzr		/* Disable coprocessor traps to EL3 */
> -	mov	\xreg1, #0x33ff
> -	msr	cptr_el2, \xreg1	/* Disable coprocessor traps to EL2 */
> +	mov	\tmp, #CPTR_EL2_RES1
> +	msr	cptr_el2, \tmp		/* Disable coprocessor traps to EL2 */
>   
>   	/* Initialize Generic Timers */
>   	msr	cntvoff_el2, xzr
> @@ -152,45 +162,91 @@ lr	.req	x30
>   	 * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>   	 * EE,WXN,I,SA,C,A,M to 0
>   	 */
> -	mov	\xreg1, #0x0830
> -	movk	\xreg1, #0x30C5, lsl #16
> -	msr	sctlr_el2, \xreg1
> +	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 |
> +	 * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
> +	 */
> +	ldr	\tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
> +			SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
> +			SCR_EL3_NS_EN)
> +	msr	scr_el3, \tmp
>   
>   	/* Return to the EL2_SP2 mode from EL3 */
> -	mov	\xreg1, sp
> -	msr	sp_el2, \xreg1		/* Migrate SP */
> -	mrs	\xreg1, vbar_el3
> -	msr	vbar_el2, \xreg1	/* Migrate VBAR */
> -	mov	\xreg1, #0x3c9
> -	msr	spsr_el3, \xreg1	/* EL2_SP2 | D | A | I | F */
> +	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, lr

So if we switch into AArch64 mode, we return ...

>   	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
> +
> +	mov	\ep, #0

... while if we switch to AArch32 mode we jump to ep.

I think it would make a lot of sense if we could *always* jump to ep. 
Just swizzle the argument order so that you get

                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
                    (images->os.arch == IH_ARCH_ARM))
                        armv8_switch_to_el2(0, gd->bd->bi_arch_number, 
(uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
                else
armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep, 
ES_TO_AARCH64);

If you *really really really* are attached to booting into EL1, just add 
a small function that calls armv8_switch_to_el1() for you and pass the 
pointer to that as ep to the el2 switch. If I were you I'd just remove 
the EL1 mess.


Alex

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-08 12:14   ` Alexander Graf
@ 2016-06-15  3:04     ` Huan Wang
  2016-06-15  7:41       ` Alexander Graf
  2016-06-15  7:42       ` Alexander Graf
  0 siblings, 2 replies; 14+ messages in thread
From: Huan Wang @ 2016-06-15  3:04 UTC (permalink / raw)
  To: u-boot

Hi, Alex,

> On 06/08/2016 07:14 AM, Alison Wang wrote:
> > To support loading a 32-bit OS, the execution state will change from
> > AArch64 to AArch32 when jumping to kernel.
> >
> > The architecture information will be got through checking FIT
> > image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
> >
> > Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
> > Signed-off-by: Alison Wang <alison.wang@nxp.com>
> > Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> > ---
> > Changes in v4:
> > - Correct config ARM64_SUPPORT_AARCH32.
> > - Omit arch and ftaddr arguments.
> > - Rename "xreg5" to "tmp".
> > - Use xxx_RES1 to combine all RES1 fields in xxx register.
> > - Use an immediate cmp directly.
> > - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
> >
> > Changes in v3:
> > - Comments the functions and the arguments.
> > - Rename the real parameters.
> > - Use the macros instead of the magic values.
> > - Remove the redundant codes.
> > - Clean up all of the mess in boot_jump_linux().
> > - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
> doesn't support AArch32 state.
> >
> > Changes in v2:
> > - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
> used
> >    to switch to AArch64 EL2 or AArch32 Hyp.
> > - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
> used
> >    to switch to AArch64 EL1 or AArch32 SVC.
> >
> >   arch/arm/Kconfig                |   6 ++
> >   arch/arm/cpu/armv8/start.S      |   1 +
> >   arch/arm/cpu/armv8/transition.S |   8 +-
> >   arch/arm/include/asm/macro.h    | 172
> ++++++++++++++++++++++++++++++----------
> >   arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
> >   arch/arm/lib/bootm.c            |  19 ++++-
> >   common/image-fit.c              |  19 ++++-
> >   7 files changed, 284 insertions(+), 52 deletions(-)
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 77eab66..9cf4acd 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
> >   	  If SoC does not support L2CACHE or one do not want to enable
> >   	  L2CACHE, choose this option.
> >
> > +config ARM64_SUPPORT_AARCH32
> > +	bool "ARM64 system support AArch32 execution state"
> > +	default y if ARM64 && !TARGET_THUNDERX_88XX
> > +	help
> > +	  This ARM64 system supports AArch32 execution state.
> > +
> >   choice
> >   	prompt "Target select"
> >   	default TARGET_HIKEY
> > diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
> > index e933021..dd69501 100644
> > --- a/arch/arm/cpu/armv8/start.S
> > +++ b/arch/arm/cpu/armv8/start.S
> > @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
> >   	/*
> >   	 * All slaves will enter EL2 and optionally EL1.
> >   	 */
> > +	ldr	x3, =ES_TO_AARCH64
> >   	bl	armv8_switch_to_el2
> >   #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
> >   	bl	armv8_switch_to_el1
> > diff --git a/arch/arm/cpu/armv8/transition.S
> b/arch/arm/cpu/armv8/transition.S
> > index 253a39b..e61b6ae 100644
> > --- a/arch/arm/cpu/armv8/transition.S
> > +++ b/arch/arm/cpu/armv8/transition.S
> > @@ -11,13 +11,13 @@
> >   #include <asm/macro.h>
> >
> >   ENTRY(armv8_switch_to_el2)
> > -	switch_el x0, 1f, 0f, 0f
> > +	switch_el x4, 1f, 0f, 0f
> >   0:	ret
> > -1:	armv8_switch_to_el2_m x0
> > +1:	armv8_switch_to_el2_m x0, x3, x4
> >   ENDPROC(armv8_switch_to_el2)
> >
> >   ENTRY(armv8_switch_to_el1)
> > -	switch_el x0, 0f, 1f, 0f
> > +	switch_el x4, 0f, 1f, 0f
> >   0:	ret
> > -1:	armv8_switch_to_el1_m x0, x1
> > +1:	armv8_switch_to_el1_m x0, x3, x4
> >   ENDPROC(armv8_switch_to_el1)
> > diff --git a/arch/arm/include/asm/macro.h
> b/arch/arm/include/asm/macro.h
> > index 9bb0efa..109724f 100644
> > --- a/arch/arm/include/asm/macro.h
> > +++ b/arch/arm/include/asm/macro.h
> > @@ -8,6 +8,9 @@
> >
> >   #ifndef __ASM_ARM_MACRO_H__
> >   #define __ASM_ARM_MACRO_H__
> > +
> > +#include <asm/system.h>
> > +
> >   #ifdef __ASSEMBLY__
> >
> >   /*
> > @@ -135,13 +138,20 @@ lr	.req	x30
> >   #endif
> >   .endm
> >
> > -.macro armv8_switch_to_el2_m, xreg1
> > -	/* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1
> */
> > -	mov	\xreg1, #0x5b1
> > -	msr	scr_el3, \xreg1
> > +/*
> > + * 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
> > + *
> > + * x1 is machine nr and x2 is ftaddr, they will be passed
> > + * to the guest.
> > + */
> > +.macro armv8_switch_to_el2_m, ep, flag, tmp
> >   	msr	cptr_el3, xzr		/* Disable coprocessor traps to EL3
> */
> > -	mov	\xreg1, #0x33ff
> > -	msr	cptr_el2, \xreg1	/* Disable coprocessor traps to EL2 */
> > +	mov	\tmp, #CPTR_EL2_RES1
> > +	msr	cptr_el2, \tmp		/* Disable coprocessor traps to EL2
> */
> >
> >   	/* Initialize Generic Timers */
> >   	msr	cntvoff_el2, xzr
> > @@ -152,45 +162,91 @@ lr	.req	x30
> >   	 * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
> >   	 * EE,WXN,I,SA,C,A,M to 0
> >   	 */
> > -	mov	\xreg1, #0x0830
> > -	movk	\xreg1, #0x30C5, lsl #16
> > -	msr	sctlr_el2, \xreg1
> > +	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 |
> > +	 * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
> > +	 */
> > +	ldr	\tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
> > +			SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
> > +			SCR_EL3_NS_EN)
> > +	msr	scr_el3, \tmp
> >
> >   	/* Return to the EL2_SP2 mode from EL3 */
> > -	mov	\xreg1, sp
> > -	msr	sp_el2, \xreg1		/* Migrate SP */
> > -	mrs	\xreg1, vbar_el3
> > -	msr	vbar_el2, \xreg1	/* Migrate VBAR */
> > -	mov	\xreg1, #0x3c9
> > -	msr	spsr_el3, \xreg1	/* EL2_SP2 | D | A | I | F */
> > +	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, lr
> 
> So if we switch into AArch64 mode, we return ...
> 
> >   	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
> > +
> > +	mov	\ep, #0
> 
> ... while if we switch to AArch32 mode we jump to ep.
> 
> I think it would make a lot of sense if we could *always* jump to ep.
> Just swizzle the argument order so that you get
> 
>                 if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>                     (images->os.arch == IH_ARCH_ARM))
>                         armv8_switch_to_el2(0, gd->bd->bi_arch_number,
> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
>                 else
> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
> ES_TO_AARCH64);
[Alison Wang] I don't agree it would make a lot of sense if we could *always*
jump to ep.
If we switch to EL2 AArch32 mode, it will happen at the last minute from U-Boot
to kernel. The ep is the entry pointer for kernel. 
If we switch to EL2 AArch64 mode, it will happen earlier. For primary core, it will
call kernel entry after the switch. For secondary cores, it will switch from EL3 AArch64
to EL2 AArch64 first, then it will wait until the spin-table is written by the kernel,
later it will jump to kernel.
> 
> If you *really really really* are attached to booting into EL1, just add
> a small function that calls armv8_switch_to_el1() for you and pass the
> pointer to that as ep to the el2 switch. If I were you I'd just remove
> the EL1 mess.
[Alison Wang] I agreed with you to remove the EL1 mess.


Best Regards,
Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-15  3:04     ` Huan Wang
@ 2016-06-15  7:41       ` Alexander Graf
  2016-06-15  7:42       ` Alexander Graf
  1 sibling, 0 replies; 14+ messages in thread
From: Alexander Graf @ 2016-06-15  7:41 UTC (permalink / raw)
  To: u-boot



> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
> 
> Hi, Alex,
> 
>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
>>> To support loading a 32-bit OS, the execution state will change from
>>> AArch64 to AArch32 when jumping to kernel.
>>> 
>>> The architecture information will be got through checking FIT
>>> image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
>>> 
>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
>>> ---
>>> Changes in v4:
>>> - Correct config ARM64_SUPPORT_AARCH32.
>>> - Omit arch and ftaddr arguments.
>>> - Rename "xreg5" to "tmp".
>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
>>> - Use an immediate cmp directly.
>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>>> 
>>> Changes in v3:
>>> - Comments the functions and the arguments.
>>> - Rename the real parameters.
>>> - Use the macros instead of the magic values.
>>> - Remove the redundant codes.
>>> - Clean up all of the mess in boot_jump_linux().
>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
>> doesn't support AArch32 state.
>>> 
>>> Changes in v2:
>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
>> used
>>>   to switch to AArch64 EL2 or AArch32 Hyp.
>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
>> used
>>>   to switch to AArch64 EL1 or AArch32 SVC.
>>> 
>>>  arch/arm/Kconfig                |   6 ++
>>>  arch/arm/cpu/armv8/start.S      |   1 +
>>>  arch/arm/cpu/armv8/transition.S |   8 +-
>>>  arch/arm/include/asm/macro.h    | 172
>> ++++++++++++++++++++++++++++++----------
>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>>>  arch/arm/lib/bootm.c            |  19 ++++-
>>>  common/image-fit.c              |  19 ++++-
>>>  7 files changed, 284 insertions(+), 52 deletions(-)
>>> 
>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>> index 77eab66..9cf4acd 100644
>>> --- a/arch/arm/Kconfig
>>> +++ b/arch/arm/Kconfig
>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>>>        If SoC does not support L2CACHE or one do not want to enable
>>>        L2CACHE, choose this option.
>>> 
>>> +config ARM64_SUPPORT_AARCH32
>>> +    bool "ARM64 system support AArch32 execution state"
>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
>>> +    help
>>> +      This ARM64 system supports AArch32 execution state.
>>> +
>>>  choice
>>>      prompt "Target select"
>>>      default TARGET_HIKEY
>>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
>>> index e933021..dd69501 100644
>>> --- a/arch/arm/cpu/armv8/start.S
>>> +++ b/arch/arm/cpu/armv8/start.S
>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>>>      /*
>>>       * All slaves will enter EL2 and optionally EL1.
>>>       */
>>> +    ldr    x3, =ES_TO_AARCH64
>>>      bl    armv8_switch_to_el2
>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>>>      bl    armv8_switch_to_el1
>>> diff --git a/arch/arm/cpu/armv8/transition.S
>> b/arch/arm/cpu/armv8/transition.S
>>> index 253a39b..e61b6ae 100644
>>> --- a/arch/arm/cpu/armv8/transition.S
>>> +++ b/arch/arm/cpu/armv8/transition.S
>>> @@ -11,13 +11,13 @@
>>>  #include <asm/macro.h>
>>> 
>>>  ENTRY(armv8_switch_to_el2)
>>> -    switch_el x0, 1f, 0f, 0f
>>> +    switch_el x4, 1f, 0f, 0f
>>>  0:    ret
>>> -1:    armv8_switch_to_el2_m x0
>>> +1:    armv8_switch_to_el2_m x0, x3, x4
>>>  ENDPROC(armv8_switch_to_el2)
>>> 
>>>  ENTRY(armv8_switch_to_el1)
>>> -    switch_el x0, 0f, 1f, 0f
>>> +    switch_el x4, 0f, 1f, 0f
>>>  0:    ret
>>> -1:    armv8_switch_to_el1_m x0, x1
>>> +1:    armv8_switch_to_el1_m x0, x3, x4
>>>  ENDPROC(armv8_switch_to_el1)
>>> diff --git a/arch/arm/include/asm/macro.h
>> b/arch/arm/include/asm/macro.h
>>> index 9bb0efa..109724f 100644
>>> --- a/arch/arm/include/asm/macro.h
>>> +++ b/arch/arm/include/asm/macro.h
>>> @@ -8,6 +8,9 @@
>>> 
>>>  #ifndef __ASM_ARM_MACRO_H__
>>>  #define __ASM_ARM_MACRO_H__
>>> +
>>> +#include <asm/system.h>
>>> +
>>>  #ifdef __ASSEMBLY__
>>> 
>>>  /*
>>> @@ -135,13 +138,20 @@ lr    .req    x30
>>>  #endif
>>>  .endm
>>> 
>>> -.macro armv8_switch_to_el2_m, xreg1
>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1
>> */
>>> -    mov    \xreg1, #0x5b1
>>> -    msr    scr_el3, \xreg1
>>> +/*
>>> + * 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
>>> + *
>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
>>> + * to the guest.
>>> + */
>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
>> */
>>> -    mov    \xreg1, #0x33ff
>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2 */
>>> +    mov    \tmp, #CPTR_EL2_RES1
>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to EL2
>> */
>>> 
>>>      /* Initialize Generic Timers */
>>>      msr    cntvoff_el2, xzr
>>> @@ -152,45 +162,91 @@ lr    .req    x30
>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>>>       * EE,WXN,I,SA,C,A,M to 0
>>>       */
>>> -    mov    \xreg1, #0x0830
>>> -    movk    \xreg1, #0x30C5, lsl #16
>>> -    msr    sctlr_el2, \xreg1
>>> +    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 |
>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>> +     */
>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>> +            SCR_EL3_NS_EN)
>>> +    msr    scr_el3, \tmp
>>> 
>>>      /* Return to the EL2_SP2 mode from EL3 */
>>> -    mov    \xreg1, sp
>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
>>> -    mrs    \xreg1, vbar_el3
>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
>>> -    mov    \xreg1, #0x3c9
>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
>>> +    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, lr
>> 
>> So if we switch into AArch64 mode, we return ...
>> 
>>>      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
>>> +
>>> +    mov    \ep, #0
>> 
>> ... while if we switch to AArch32 mode we jump to ep.
>> 
>> I think it would make a lot of sense if we could *always* jump to ep.
>> Just swizzle the argument order so that you get
>> 
>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>>                    (images->os.arch == IH_ARCH_ARM))
>>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
>> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
>>                else
>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
>> ES_TO_AARCH64);
> [Alison Wang] I don't agree it would make a lot of sense if we could *always*
> jump to ep.
> If we switch to EL2 AArch32 mode, it will happen at the last minute from U-Boot
> to kernel. The ep is the entry pointer for kernel. 
> If we switch to EL2 AArch64 mode, it will happen earlier. For primary core, it will
> call kernel entry after the switch. For secondary cores, it will switch from EL3 AArch64
> to EL2 AArch64 first, then it will wait until the spin-table is written by the kernel,
> later it will jump to kernel.
>> 
>> If you *really really really* are attached to booting into EL1, just add
>> a small function that calls armv8_switch_to_el1() for you and pass the
>> pointer to that as ep to the el2 switch. If I were you I'd just remove
>> the EL1 mess.
> [Alison Wang] I agreed with you to remove the EL1 mess.
> 
> 
> Best Regards,
> Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-15  3:04     ` Huan Wang
  2016-06-15  7:41       ` Alexander Graf
@ 2016-06-15  7:42       ` Alexander Graf
  2016-06-15  8:08         ` Huan Wang
  2016-06-30  7:16         ` Huan Wang
  1 sibling, 2 replies; 14+ messages in thread
From: Alexander Graf @ 2016-06-15  7:42 UTC (permalink / raw)
  To: u-boot



> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
> 
> Hi, Alex,
> 
>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
>>> To support loading a 32-bit OS, the execution state will change from
>>> AArch64 to AArch32 when jumping to kernel.
>>> 
>>> The architecture information will be got through checking FIT
>>> image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
>>> 
>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
>>> ---
>>> Changes in v4:
>>> - Correct config ARM64_SUPPORT_AARCH32.
>>> - Omit arch and ftaddr arguments.
>>> - Rename "xreg5" to "tmp".
>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
>>> - Use an immediate cmp directly.
>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>>> 
>>> Changes in v3:
>>> - Comments the functions and the arguments.
>>> - Rename the real parameters.
>>> - Use the macros instead of the magic values.
>>> - Remove the redundant codes.
>>> - Clean up all of the mess in boot_jump_linux().
>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
>> doesn't support AArch32 state.
>>> 
>>> Changes in v2:
>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
>> used
>>>   to switch to AArch64 EL2 or AArch32 Hyp.
>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
>> used
>>>   to switch to AArch64 EL1 or AArch32 SVC.
>>> 
>>>  arch/arm/Kconfig                |   6 ++
>>>  arch/arm/cpu/armv8/start.S      |   1 +
>>>  arch/arm/cpu/armv8/transition.S |   8 +-
>>>  arch/arm/include/asm/macro.h    | 172
>> ++++++++++++++++++++++++++++++----------
>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>>>  arch/arm/lib/bootm.c            |  19 ++++-
>>>  common/image-fit.c              |  19 ++++-
>>>  7 files changed, 284 insertions(+), 52 deletions(-)
>>> 
>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>>> index 77eab66..9cf4acd 100644
>>> --- a/arch/arm/Kconfig
>>> +++ b/arch/arm/Kconfig
>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>>>        If SoC does not support L2CACHE or one do not want to enable
>>>        L2CACHE, choose this option.
>>> 
>>> +config ARM64_SUPPORT_AARCH32
>>> +    bool "ARM64 system support AArch32 execution state"
>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
>>> +    help
>>> +      This ARM64 system supports AArch32 execution state.
>>> +
>>>  choice
>>>      prompt "Target select"
>>>      default TARGET_HIKEY
>>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
>>> index e933021..dd69501 100644
>>> --- a/arch/arm/cpu/armv8/start.S
>>> +++ b/arch/arm/cpu/armv8/start.S
>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>>>      /*
>>>       * All slaves will enter EL2 and optionally EL1.
>>>       */
>>> +    ldr    x3, =ES_TO_AARCH64
>>>      bl    armv8_switch_to_el2
>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>>>      bl    armv8_switch_to_el1
>>> diff --git a/arch/arm/cpu/armv8/transition.S
>> b/arch/arm/cpu/armv8/transition.S
>>> index 253a39b..e61b6ae 100644
>>> --- a/arch/arm/cpu/armv8/transition.S
>>> +++ b/arch/arm/cpu/armv8/transition.S
>>> @@ -11,13 +11,13 @@
>>>  #include <asm/macro.h>
>>> 
>>>  ENTRY(armv8_switch_to_el2)
>>> -    switch_el x0, 1f, 0f, 0f
>>> +    switch_el x4, 1f, 0f, 0f
>>>  0:    ret
>>> -1:    armv8_switch_to_el2_m x0
>>> +1:    armv8_switch_to_el2_m x0, x3, x4
>>>  ENDPROC(armv8_switch_to_el2)
>>> 
>>>  ENTRY(armv8_switch_to_el1)
>>> -    switch_el x0, 0f, 1f, 0f
>>> +    switch_el x4, 0f, 1f, 0f
>>>  0:    ret
>>> -1:    armv8_switch_to_el1_m x0, x1
>>> +1:    armv8_switch_to_el1_m x0, x3, x4
>>>  ENDPROC(armv8_switch_to_el1)
>>> diff --git a/arch/arm/include/asm/macro.h
>> b/arch/arm/include/asm/macro.h
>>> index 9bb0efa..109724f 100644
>>> --- a/arch/arm/include/asm/macro.h
>>> +++ b/arch/arm/include/asm/macro.h
>>> @@ -8,6 +8,9 @@
>>> 
>>>  #ifndef __ASM_ARM_MACRO_H__
>>>  #define __ASM_ARM_MACRO_H__
>>> +
>>> +#include <asm/system.h>
>>> +
>>>  #ifdef __ASSEMBLY__
>>> 
>>>  /*
>>> @@ -135,13 +138,20 @@ lr    .req    x30
>>>  #endif
>>>  .endm
>>> 
>>> -.macro armv8_switch_to_el2_m, xreg1
>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1
>> */
>>> -    mov    \xreg1, #0x5b1
>>> -    msr    scr_el3, \xreg1
>>> +/*
>>> + * 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
>>> + *
>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
>>> + * to the guest.
>>> + */
>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
>> */
>>> -    mov    \xreg1, #0x33ff
>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2 */
>>> +    mov    \tmp, #CPTR_EL2_RES1
>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to EL2
>> */
>>> 
>>>      /* Initialize Generic Timers */
>>>      msr    cntvoff_el2, xzr
>>> @@ -152,45 +162,91 @@ lr    .req    x30
>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>>>       * EE,WXN,I,SA,C,A,M to 0
>>>       */
>>> -    mov    \xreg1, #0x0830
>>> -    movk    \xreg1, #0x30C5, lsl #16
>>> -    msr    sctlr_el2, \xreg1
>>> +    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 |
>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>> +     */
>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>> +            SCR_EL3_NS_EN)
>>> +    msr    scr_el3, \tmp
>>> 
>>>      /* Return to the EL2_SP2 mode from EL3 */
>>> -    mov    \xreg1, sp
>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
>>> -    mrs    \xreg1, vbar_el3
>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
>>> -    mov    \xreg1, #0x3c9
>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
>>> +    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, lr
>> 
>> So if we switch into AArch64 mode, we return ...
>> 
>>>      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
>>> +
>>> +    mov    \ep, #0
>> 
>> ... while if we switch to AArch32 mode we jump to ep.
>> 
>> I think it would make a lot of sense if we could *always* jump to ep.
>> Just swizzle the argument order so that you get
>> 
>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>>                    (images->os.arch == IH_ARCH_ARM))
>>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
>> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
>>                else
>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
>> ES_TO_AARCH64);
> [Alison Wang] I don't agree it would make a lot of sense if we could *always*
> jump to ep.
> If we switch to EL2 AArch32 mode, it will happen at the last minute from U-Boot
> to kernel. The ep is the entry pointer for kernel. 
> If we switch to EL2 AArch64 mode, it will happen earlier. For primary core, it will
> call kernel entry after the switch. For secondary cores, it will switch from EL3 AArch64
> to EL2 AArch64 first, then it will wait until the spin-table is written by the kernel,
> later it will jump to kernel.

Then jump to a separate function that continues the execution stream. I really think we should keep the interface between both flags as identical as possible.

>> 
>> If you *really really really* are attached to booting into EL1, just add
>> a small function that calls armv8_switch_to_el1() for you and pass the
>> pointer to that as ep to the el2 switch. If I were you I'd just remove
>> the EL1 mess.
> [Alison Wang] I agreed with you to remove the EL1 mess.

Awesome, thanks.

Alex

> 
> 
> Best Regards,
> Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-15  7:42       ` Alexander Graf
@ 2016-06-15  8:08         ` Huan Wang
  2016-06-15  8:21           ` Alexander Graf
  2016-06-30  7:16         ` Huan Wang
  1 sibling, 1 reply; 14+ messages in thread
From: Huan Wang @ 2016-06-15  8:08 UTC (permalink / raw)
  To: u-boot

> > Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
> >
> > Hi, Alex,
> >
> >>> On 06/08/2016 07:14 AM, Alison Wang wrote:
> >>> To support loading a 32-bit OS, the execution state will change from
> >>> AArch64 to AArch32 when jumping to kernel.
> >>>
> >>> The architecture information will be got through checking FIT image,
> >>> then U-Boot will load 32-bit OS or 64-bit OS automatically.
> >>>
> >>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
> >>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
> >>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> >>> ---
> >>> Changes in v4:
> >>> - Correct config ARM64_SUPPORT_AARCH32.
> >>> - Omit arch and ftaddr arguments.
> >>> - Rename "xreg5" to "tmp".
> >>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
> >>> - Use an immediate cmp directly.
> >>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
> >>>
> >>> Changes in v3:
> >>> - Comments the functions and the arguments.
> >>> - Rename the real parameters.
> >>> - Use the macros instead of the magic values.
> >>> - Remove the redundant codes.
> >>> - Clean up all of the mess in boot_jump_linux().
> >>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
> >> doesn't support AArch32 state.
> >>>
> >>> Changes in v2:
> >>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
> >> used
> >>>   to switch to AArch64 EL2 or AArch32 Hyp.
> >>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
> >> used
> >>>   to switch to AArch64 EL1 or AArch32 SVC.
> >>>
> >>>  arch/arm/Kconfig                |   6 ++
> >>>  arch/arm/cpu/armv8/start.S      |   1 +
> >>>  arch/arm/cpu/armv8/transition.S |   8 +-
> >>>  arch/arm/include/asm/macro.h    | 172
> >> ++++++++++++++++++++++++++++++----------
> >>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
> >>>  arch/arm/lib/bootm.c            |  19 ++++-
> >>>  common/image-fit.c              |  19 ++++-
> >>>  7 files changed, 284 insertions(+), 52 deletions(-)
> >>>
> >>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
> >>> 77eab66..9cf4acd 100644
> >>> --- a/arch/arm/Kconfig
> >>> +++ b/arch/arm/Kconfig
> >>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
> >>>        If SoC does not support L2CACHE or one do not want to enable
> >>>        L2CACHE, choose this option.
> >>>
> >>> +config ARM64_SUPPORT_AARCH32
> >>> +    bool "ARM64 system support AArch32 execution state"
> >>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
> >>> +    help
> >>> +      This ARM64 system supports AArch32 execution state.
> >>> +
> >>>  choice
> >>>      prompt "Target select"
> >>>      default TARGET_HIKEY
> >>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
> >>> index e933021..dd69501 100644
> >>> --- a/arch/arm/cpu/armv8/start.S
> >>> +++ b/arch/arm/cpu/armv8/start.S
> >>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
> >>>      /*
> >>>       * All slaves will enter EL2 and optionally EL1.
> >>>       */
> >>> +    ldr    x3, =ES_TO_AARCH64
> >>>      bl    armv8_switch_to_el2
> >>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
> >>>      bl    armv8_switch_to_el1
> >>> diff --git a/arch/arm/cpu/armv8/transition.S
> >> b/arch/arm/cpu/armv8/transition.S
> >>> index 253a39b..e61b6ae 100644
> >>> --- a/arch/arm/cpu/armv8/transition.S
> >>> +++ b/arch/arm/cpu/armv8/transition.S
> >>> @@ -11,13 +11,13 @@
> >>>  #include <asm/macro.h>
> >>>
> >>>  ENTRY(armv8_switch_to_el2)
> >>> -    switch_el x0, 1f, 0f, 0f
> >>> +    switch_el x4, 1f, 0f, 0f
> >>>  0:    ret
> >>> -1:    armv8_switch_to_el2_m x0
> >>> +1:    armv8_switch_to_el2_m x0, x3, x4
> >>>  ENDPROC(armv8_switch_to_el2)
> >>>
> >>>  ENTRY(armv8_switch_to_el1)
> >>> -    switch_el x0, 0f, 1f, 0f
> >>> +    switch_el x4, 0f, 1f, 0f
> >>>  0:    ret
> >>> -1:    armv8_switch_to_el1_m x0, x1
> >>> +1:    armv8_switch_to_el1_m x0, x3, x4
> >>>  ENDPROC(armv8_switch_to_el1)
> >>> diff --git a/arch/arm/include/asm/macro.h
> >> b/arch/arm/include/asm/macro.h
> >>> index 9bb0efa..109724f 100644
> >>> --- a/arch/arm/include/asm/macro.h
> >>> +++ b/arch/arm/include/asm/macro.h
> >>> @@ -8,6 +8,9 @@
> >>>
> >>>  #ifndef __ASM_ARM_MACRO_H__
> >>>  #define __ASM_ARM_MACRO_H__
> >>> +
> >>> +#include <asm/system.h>
> >>> +
> >>>  #ifdef __ASSEMBLY__
> >>>
> >>>  /*
> >>> @@ -135,13 +138,20 @@ lr    .req    x30
> >>>  #endif
> >>>  .endm
> >>>
> >>> -.macro armv8_switch_to_el2_m, xreg1
> >>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
> EL0/EL1
> >> */
> >>> -    mov    \xreg1, #0x5b1
> >>> -    msr    scr_el3, \xreg1
> >>> +/*
> >>> + * 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
> >>> + *
> >>> + * x1 is machine nr and x2 is ftaddr, they will be passed
> >>> + * to the guest.
> >>> + */
> >>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
> >>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
> >> */
> >>> -    mov    \xreg1, #0x33ff
> >>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2
> */
> >>> +    mov    \tmp, #CPTR_EL2_RES1
> >>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
> EL2
> >> */
> >>>
> >>>      /* Initialize Generic Timers */
> >>>      msr    cntvoff_el2, xzr
> >>> @@ -152,45 +162,91 @@ lr    .req    x30
> >>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
> >>>       * EE,WXN,I,SA,C,A,M to 0
> >>>       */
> >>> -    mov    \xreg1, #0x0830
> >>> -    movk    \xreg1, #0x30C5, lsl #16
> >>> -    msr    sctlr_el2, \xreg1
> >>> +    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 |
> >>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
> >>> +     */
> >>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
> >>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
> >>> +            SCR_EL3_NS_EN)
> >>> +    msr    scr_el3, \tmp
> >>>
> >>>      /* Return to the EL2_SP2 mode from EL3 */
> >>> -    mov    \xreg1, sp
> >>> -    msr    sp_el2, \xreg1        /* Migrate SP */
> >>> -    mrs    \xreg1, vbar_el3
> >>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
> >>> -    mov    \xreg1, #0x3c9
> >>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
> >>> +    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, lr
> >>
> >> So if we switch into AArch64 mode, we return ...
> >>
> >>>      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
> >>> +
> >>> +    mov    \ep, #0
> >>
> >> ... while if we switch to AArch32 mode we jump to ep.
> >>
> >> I think it would make a lot of sense if we could *always* jump to ep.
> >> Just swizzle the argument order so that you get
> >>
> >>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
> >>                    (images->os.arch == IH_ARCH_ARM))
> >>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
> >> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
> >>                else
> >> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
> >> ES_TO_AARCH64);
> > [Alison Wang] I don't agree it would make a lot of sense if we could
> > *always* jump to ep.
> > If we switch to EL2 AArch32 mode, it will happen at the last minute
> > from U-Boot to kernel. The ep is the entry pointer for kernel.
> > If we switch to EL2 AArch64 mode, it will happen earlier. For primary
> > core, it will call kernel entry after the switch. For secondary cores,
> > it will switch from EL3 AArch64 to EL2 AArch64 first, then it will
> > wait until the spin-table is written by the kernel, later it will jump
> to kernel.
> 
> Then jump to a separate function that continues the execution stream. I
> really think we should keep the interface between both flags as
> identical as possible.
[Alison Wang] In this v4 patch, the interface armv8_switch_to_el2() is same
for both flags. Well, how about listening to other's opinion? :)

York, could you give us your advice? Thanks. 
> 
> >>
> >> If you *really really really* are attached to booting into EL1, just
> >> add a small function that calls armv8_switch_to_el1() for you and
> >> pass the pointer to that as ep to the el2 switch. If I were you I'd
> >> just remove the EL1 mess.
> > [Alison Wang] I agreed with you to remove the EL1 mess.
> 
> Awesome, thanks.
> 

Best Regards,
Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-15  8:08         ` Huan Wang
@ 2016-06-15  8:21           ` Alexander Graf
  2016-06-15  8:33             ` Huan Wang
  0 siblings, 1 reply; 14+ messages in thread
From: Alexander Graf @ 2016-06-15  8:21 UTC (permalink / raw)
  To: u-boot



On 15.06.16 10:08, Huan Wang wrote:
>>> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
>>>
>>> Hi, Alex,
>>>
>>>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
>>>>> To support loading a 32-bit OS, the execution state will change from
>>>>> AArch64 to AArch32 when jumping to kernel.
>>>>>
>>>>> The architecture information will be got through checking FIT image,
>>>>> then U-Boot will load 32-bit OS or 64-bit OS automatically.
>>>>>
>>>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
>>>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
>>>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
>>>>> ---
>>>>> Changes in v4:
>>>>> - Correct config ARM64_SUPPORT_AARCH32.
>>>>> - Omit arch and ftaddr arguments.
>>>>> - Rename "xreg5" to "tmp".
>>>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
>>>>> - Use an immediate cmp directly.
>>>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>>>>>
>>>>> Changes in v3:
>>>>> - Comments the functions and the arguments.
>>>>> - Rename the real parameters.
>>>>> - Use the macros instead of the magic values.
>>>>> - Remove the redundant codes.
>>>>> - Clean up all of the mess in boot_jump_linux().
>>>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
>>>> doesn't support AArch32 state.
>>>>>
>>>>> Changes in v2:
>>>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
>>>> used
>>>>>   to switch to AArch64 EL2 or AArch32 Hyp.
>>>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
>>>> used
>>>>>   to switch to AArch64 EL1 or AArch32 SVC.
>>>>>
>>>>>  arch/arm/Kconfig                |   6 ++
>>>>>  arch/arm/cpu/armv8/start.S      |   1 +
>>>>>  arch/arm/cpu/armv8/transition.S |   8 +-
>>>>>  arch/arm/include/asm/macro.h    | 172
>>>> ++++++++++++++++++++++++++++++----------
>>>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>>>>>  arch/arm/lib/bootm.c            |  19 ++++-
>>>>>  common/image-fit.c              |  19 ++++-
>>>>>  7 files changed, 284 insertions(+), 52 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
>>>>> 77eab66..9cf4acd 100644
>>>>> --- a/arch/arm/Kconfig
>>>>> +++ b/arch/arm/Kconfig
>>>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>>>>>        If SoC does not support L2CACHE or one do not want to enable
>>>>>        L2CACHE, choose this option.
>>>>>
>>>>> +config ARM64_SUPPORT_AARCH32
>>>>> +    bool "ARM64 system support AArch32 execution state"
>>>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
>>>>> +    help
>>>>> +      This ARM64 system supports AArch32 execution state.
>>>>> +
>>>>>  choice
>>>>>      prompt "Target select"
>>>>>      default TARGET_HIKEY
>>>>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
>>>>> index e933021..dd69501 100644
>>>>> --- a/arch/arm/cpu/armv8/start.S
>>>>> +++ b/arch/arm/cpu/armv8/start.S
>>>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>>>>>      /*
>>>>>       * All slaves will enter EL2 and optionally EL1.
>>>>>       */
>>>>> +    ldr    x3, =ES_TO_AARCH64
>>>>>      bl    armv8_switch_to_el2
>>>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>>>>>      bl    armv8_switch_to_el1
>>>>> diff --git a/arch/arm/cpu/armv8/transition.S
>>>> b/arch/arm/cpu/armv8/transition.S
>>>>> index 253a39b..e61b6ae 100644
>>>>> --- a/arch/arm/cpu/armv8/transition.S
>>>>> +++ b/arch/arm/cpu/armv8/transition.S
>>>>> @@ -11,13 +11,13 @@
>>>>>  #include <asm/macro.h>
>>>>>
>>>>>  ENTRY(armv8_switch_to_el2)
>>>>> -    switch_el x0, 1f, 0f, 0f
>>>>> +    switch_el x4, 1f, 0f, 0f
>>>>>  0:    ret
>>>>> -1:    armv8_switch_to_el2_m x0
>>>>> +1:    armv8_switch_to_el2_m x0, x3, x4
>>>>>  ENDPROC(armv8_switch_to_el2)
>>>>>
>>>>>  ENTRY(armv8_switch_to_el1)
>>>>> -    switch_el x0, 0f, 1f, 0f
>>>>> +    switch_el x4, 0f, 1f, 0f
>>>>>  0:    ret
>>>>> -1:    armv8_switch_to_el1_m x0, x1
>>>>> +1:    armv8_switch_to_el1_m x0, x3, x4
>>>>>  ENDPROC(armv8_switch_to_el1)
>>>>> diff --git a/arch/arm/include/asm/macro.h
>>>> b/arch/arm/include/asm/macro.h
>>>>> index 9bb0efa..109724f 100644
>>>>> --- a/arch/arm/include/asm/macro.h
>>>>> +++ b/arch/arm/include/asm/macro.h
>>>>> @@ -8,6 +8,9 @@
>>>>>
>>>>>  #ifndef __ASM_ARM_MACRO_H__
>>>>>  #define __ASM_ARM_MACRO_H__
>>>>> +
>>>>> +#include <asm/system.h>
>>>>> +
>>>>>  #ifdef __ASSEMBLY__
>>>>>
>>>>>  /*
>>>>> @@ -135,13 +138,20 @@ lr    .req    x30
>>>>>  #endif
>>>>>  .endm
>>>>>
>>>>> -.macro armv8_switch_to_el2_m, xreg1
>>>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
>> EL0/EL1
>>>> */
>>>>> -    mov    \xreg1, #0x5b1
>>>>> -    msr    scr_el3, \xreg1
>>>>> +/*
>>>>> + * 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
>>>>> + *
>>>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
>>>>> + * to the guest.
>>>>> + */
>>>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>>>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
>>>> */
>>>>> -    mov    \xreg1, #0x33ff
>>>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2
>> */
>>>>> +    mov    \tmp, #CPTR_EL2_RES1
>>>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
>> EL2
>>>> */
>>>>>
>>>>>      /* Initialize Generic Timers */
>>>>>      msr    cntvoff_el2, xzr
>>>>> @@ -152,45 +162,91 @@ lr    .req    x30
>>>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>>>>>       * EE,WXN,I,SA,C,A,M to 0
>>>>>       */
>>>>> -    mov    \xreg1, #0x0830
>>>>> -    movk    \xreg1, #0x30C5, lsl #16
>>>>> -    msr    sctlr_el2, \xreg1
>>>>> +    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 |
>>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>>>> +     */
>>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
>>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>>>> +            SCR_EL3_NS_EN)
>>>>> +    msr    scr_el3, \tmp
>>>>>
>>>>>      /* Return to the EL2_SP2 mode from EL3 */
>>>>> -    mov    \xreg1, sp
>>>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
>>>>> -    mrs    \xreg1, vbar_el3
>>>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
>>>>> -    mov    \xreg1, #0x3c9
>>>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
>>>>> +    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, lr
>>>>
>>>> So if we switch into AArch64 mode, we return ...
>>>>
>>>>>      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
>>>>> +
>>>>> +    mov    \ep, #0
>>>>
>>>> ... while if we switch to AArch32 mode we jump to ep.
>>>>
>>>> I think it would make a lot of sense if we could *always* jump to ep.
>>>> Just swizzle the argument order so that you get
>>>>
>>>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>>>>                    (images->os.arch == IH_ARCH_ARM))
>>>>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
>>>> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
>>>>                else
>>>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
>>>> ES_TO_AARCH64);
>>> [Alison Wang] I don't agree it would make a lot of sense if we could
>>> *always* jump to ep.
>>> If we switch to EL2 AArch32 mode, it will happen at the last minute
>>> from U-Boot to kernel. The ep is the entry pointer for kernel.
>>> If we switch to EL2 AArch64 mode, it will happen earlier. For primary
>>> core, it will call kernel entry after the switch. For secondary cores,
>>> it will switch from EL3 AArch64 to EL2 AArch64 first, then it will
>>> wait until the spin-table is written by the kernel, later it will jump
>> to kernel.
>>
>> Then jump to a separate function that continues the execution stream. I
>> really think we should keep the interface between both flags as
>> identical as possible.
> [Alison Wang] In this v4 patch, the interface armv8_switch_to_el2() is same
> for both flags. Well, how about listening to other's opinion? :)

Is it? I thought when you switch to AA32 mode, you jump to ep while if
you switch to AA64 mode, you just return.

That means while the prototype is identical, the behavior is different, no?


Alex

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-15  8:21           ` Alexander Graf
@ 2016-06-15  8:33             ` Huan Wang
  0 siblings, 0 replies; 14+ messages in thread
From: Huan Wang @ 2016-06-15  8:33 UTC (permalink / raw)
  To: u-boot

> On 15.06.16 10:08, Huan Wang wrote:
> >>> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
> >>>
> >>> Hi, Alex,
> >>>
> >>>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
> >>>>> To support loading a 32-bit OS, the execution state will change
> >>>>> from
> >>>>> AArch64 to AArch32 when jumping to kernel.
> >>>>>
> >>>>> The architecture information will be got through checking FIT
> >>>>> image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
> >>>>>
> >>>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
> >>>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
> >>>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> >>>>> ---
> >>>>> Changes in v4:
> >>>>> - Correct config ARM64_SUPPORT_AARCH32.
> >>>>> - Omit arch and ftaddr arguments.
> >>>>> - Rename "xreg5" to "tmp".
> >>>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
> >>>>> - Use an immediate cmp directly.
> >>>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
> >>>>>
> >>>>> Changes in v3:
> >>>>> - Comments the functions and the arguments.
> >>>>> - Rename the real parameters.
> >>>>> - Use the macros instead of the magic values.
> >>>>> - Remove the redundant codes.
> >>>>> - Clean up all of the mess in boot_jump_linux().
> >>>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
> >>>> doesn't support AArch32 state.
> >>>>>
> >>>>> Changes in v2:
> >>>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m
> >>>>> is
> >>>> used
> >>>>>   to switch to AArch64 EL2 or AArch32 Hyp.
> >>>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m
> >>>>> is
> >>>> used
> >>>>>   to switch to AArch64 EL1 or AArch32 SVC.
> >>>>>
> >>>>>  arch/arm/Kconfig                |   6 ++
> >>>>>  arch/arm/cpu/armv8/start.S      |   1 +
> >>>>>  arch/arm/cpu/armv8/transition.S |   8 +-
> >>>>>  arch/arm/include/asm/macro.h    | 172
> >>>> ++++++++++++++++++++++++++++++----------
> >>>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
> >>>>>  arch/arm/lib/bootm.c            |  19 ++++-
> >>>>>  common/image-fit.c              |  19 ++++-
> >>>>>  7 files changed, 284 insertions(+), 52 deletions(-)
> >>>>>
> >>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
> >>>>> 77eab66..9cf4acd 100644
> >>>>> --- a/arch/arm/Kconfig
> >>>>> +++ b/arch/arm/Kconfig
> >>>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
> >>>>>        If SoC does not support L2CACHE or one do not want to
> enable
> >>>>>        L2CACHE, choose this option.
> >>>>>
> >>>>> +config ARM64_SUPPORT_AARCH32
> >>>>> +    bool "ARM64 system support AArch32 execution state"
> >>>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
> >>>>> +    help
> >>>>> +      This ARM64 system supports AArch32 execution state.
> >>>>> +
> >>>>>  choice
> >>>>>      prompt "Target select"
> >>>>>      default TARGET_HIKEY
> >>>>> diff --git a/arch/arm/cpu/armv8/start.S
> >>>>> b/arch/arm/cpu/armv8/start.S index e933021..dd69501 100644
> >>>>> --- a/arch/arm/cpu/armv8/start.S
> >>>>> +++ b/arch/arm/cpu/armv8/start.S
> >>>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
> >>>>>      /*
> >>>>>       * All slaves will enter EL2 and optionally EL1.
> >>>>>       */
> >>>>> +    ldr    x3, =ES_TO_AARCH64
> >>>>>      bl    armv8_switch_to_el2
> >>>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
> >>>>>      bl    armv8_switch_to_el1
> >>>>> diff --git a/arch/arm/cpu/armv8/transition.S
> >>>> b/arch/arm/cpu/armv8/transition.S
> >>>>> index 253a39b..e61b6ae 100644
> >>>>> --- a/arch/arm/cpu/armv8/transition.S
> >>>>> +++ b/arch/arm/cpu/armv8/transition.S
> >>>>> @@ -11,13 +11,13 @@
> >>>>>  #include <asm/macro.h>
> >>>>>
> >>>>>  ENTRY(armv8_switch_to_el2)
> >>>>> -    switch_el x0, 1f, 0f, 0f
> >>>>> +    switch_el x4, 1f, 0f, 0f
> >>>>>  0:    ret
> >>>>> -1:    armv8_switch_to_el2_m x0
> >>>>> +1:    armv8_switch_to_el2_m x0, x3, x4
> >>>>>  ENDPROC(armv8_switch_to_el2)
> >>>>>
> >>>>>  ENTRY(armv8_switch_to_el1)
> >>>>> -    switch_el x0, 0f, 1f, 0f
> >>>>> +    switch_el x4, 0f, 1f, 0f
> >>>>>  0:    ret
> >>>>> -1:    armv8_switch_to_el1_m x0, x1
> >>>>> +1:    armv8_switch_to_el1_m x0, x3, x4
> >>>>>  ENDPROC(armv8_switch_to_el1)
> >>>>> diff --git a/arch/arm/include/asm/macro.h
> >>>> b/arch/arm/include/asm/macro.h
> >>>>> index 9bb0efa..109724f 100644
> >>>>> --- a/arch/arm/include/asm/macro.h
> >>>>> +++ b/arch/arm/include/asm/macro.h
> >>>>> @@ -8,6 +8,9 @@
> >>>>>
> >>>>>  #ifndef __ASM_ARM_MACRO_H__
> >>>>>  #define __ASM_ARM_MACRO_H__
> >>>>> +
> >>>>> +#include <asm/system.h>
> >>>>> +
> >>>>>  #ifdef __ASSEMBLY__
> >>>>>
> >>>>>  /*
> >>>>> @@ -135,13 +138,20 @@ lr    .req    x30
> >>>>>  #endif
> >>>>>  .endm
> >>>>>
> >>>>> -.macro armv8_switch_to_el2_m, xreg1
> >>>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
> >> EL0/EL1
> >>>> */
> >>>>> -    mov    \xreg1, #0x5b1
> >>>>> -    msr    scr_el3, \xreg1
> >>>>> +/*
> >>>>> + * 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
> >>>>> + *
> >>>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
> >>>>> + * to the guest.
> >>>>> + */
> >>>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
> >>>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to
> EL3
> >>>> */
> >>>>> -    mov    \xreg1, #0x33ff
> >>>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to
> EL2
> >> */
> >>>>> +    mov    \tmp, #CPTR_EL2_RES1
> >>>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
> >> EL2
> >>>> */
> >>>>>
> >>>>>      /* Initialize Generic Timers */
> >>>>>      msr    cntvoff_el2, xzr
> >>>>> @@ -152,45 +162,91 @@ lr    .req    x30
> >>>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
> >>>>>       * EE,WXN,I,SA,C,A,M to 0
> >>>>>       */
> >>>>> -    mov    \xreg1, #0x0830
> >>>>> -    movk    \xreg1, #0x30C5, lsl #16
> >>>>> -    msr    sctlr_el2, \xreg1
> >>>>> +    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
> |
> >>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
> >>>>> +     */
> >>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
> >>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
> >>>>> +            SCR_EL3_NS_EN)
> >>>>> +    msr    scr_el3, \tmp
> >>>>>
> >>>>>      /* Return to the EL2_SP2 mode from EL3 */
> >>>>> -    mov    \xreg1, sp
> >>>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
> >>>>> -    mrs    \xreg1, vbar_el3
> >>>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
> >>>>> -    mov    \xreg1, #0x3c9
> >>>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
> >>>>> +    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, lr
> >>>>
> >>>> So if we switch into AArch64 mode, we return ...
> >>>>
> >>>>>      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
> >>>>> +
> >>>>> +    mov    \ep, #0
> >>>>
> >>>> ... while if we switch to AArch32 mode we jump to ep.
> >>>>
> >>>> I think it would make a lot of sense if we could *always* jump to
> ep.
> >>>> Just swizzle the argument order so that you get
> >>>>
> >>>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
> >>>>                    (images->os.arch == IH_ARCH_ARM))
> >>>>                        armv8_switch_to_el2(0,
> >>>> gd->bd->bi_arch_number, (uintptr_t)images->ft_addr, (u64)images->ep,
> ES_TO_AARCH32);
> >>>>                else
> >>>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
> >>>> ES_TO_AARCH64);
> >>> [Alison Wang] I don't agree it would make a lot of sense if we could
> >>> *always* jump to ep.
> >>> If we switch to EL2 AArch32 mode, it will happen at the last minute
> >>> from U-Boot to kernel. The ep is the entry pointer for kernel.
> >>> If we switch to EL2 AArch64 mode, it will happen earlier. For
> >>> primary core, it will call kernel entry after the switch. For
> >>> secondary cores, it will switch from EL3 AArch64 to EL2 AArch64
> >>> first, then it will wait until the spin-table is written by the
> >>> kernel, later it will jump
> >> to kernel.
> >>
> >> Then jump to a separate function that continues the execution stream.
> >> I really think we should keep the interface between both flags as
> >> identical as possible.
> > [Alison Wang] In this v4 patch, the interface armv8_switch_to_el2() is
> > same for both flags. Well, how about listening to other's opinion? :)
> 
> Is it? I thought when you switch to AA32 mode, you jump to ep while if
> you switch to AA64 mode, you just return.
> 
> That means while the prototype is identical, the behavior is different,
> no?
> 
[Alison Wang] Your thought is right. One jumps to ep, the other returns.


Best Regards,
Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-15  7:42       ` Alexander Graf
  2016-06-15  8:08         ` Huan Wang
@ 2016-06-30  7:16         ` Huan Wang
  2016-06-30  8:41           ` Alexander Graf
  1 sibling, 1 reply; 14+ messages in thread
From: Huan Wang @ 2016-06-30  7:16 UTC (permalink / raw)
  To: u-boot

Hi, Alex,

> > Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
> >
> > Hi, Alex,
> >
> >>> On 06/08/2016 07:14 AM, Alison Wang wrote:
> >>> To support loading a 32-bit OS, the execution state will change from
> >>> AArch64 to AArch32 when jumping to kernel.
> >>>
> >>> The architecture information will be got through checking FIT image,
> >>> then U-Boot will load 32-bit OS or 64-bit OS automatically.
> >>>
> >>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
> >>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
> >>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> >>> ---
> >>> Changes in v4:
> >>> - Correct config ARM64_SUPPORT_AARCH32.
> >>> - Omit arch and ftaddr arguments.
> >>> - Rename "xreg5" to "tmp".
> >>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
> >>> - Use an immediate cmp directly.
> >>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
> >>>
> >>> Changes in v3:
> >>> - Comments the functions and the arguments.
> >>> - Rename the real parameters.
> >>> - Use the macros instead of the magic values.
> >>> - Remove the redundant codes.
> >>> - Clean up all of the mess in boot_jump_linux().
> >>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
> >> doesn't support AArch32 state.
> >>>
> >>> Changes in v2:
> >>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
> >> used
> >>>   to switch to AArch64 EL2 or AArch32 Hyp.
> >>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
> >> used
> >>>   to switch to AArch64 EL1 or AArch32 SVC.
> >>>
> >>>  arch/arm/Kconfig                |   6 ++
> >>>  arch/arm/cpu/armv8/start.S      |   1 +
> >>>  arch/arm/cpu/armv8/transition.S |   8 +-
> >>>  arch/arm/include/asm/macro.h    | 172
> >> ++++++++++++++++++++++++++++++----------
> >>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
> >>>  arch/arm/lib/bootm.c            |  19 ++++-
> >>>  common/image-fit.c              |  19 ++++-
> >>>  7 files changed, 284 insertions(+), 52 deletions(-)
> >>>
> >>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
> >>> 77eab66..9cf4acd 100644
> >>> --- a/arch/arm/Kconfig
> >>> +++ b/arch/arm/Kconfig
> >>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
> >>>        If SoC does not support L2CACHE or one do not want to enable
> >>>        L2CACHE, choose this option.
> >>>
> >>> +config ARM64_SUPPORT_AARCH32
> >>> +    bool "ARM64 system support AArch32 execution state"
> >>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
> >>> +    help
> >>> +      This ARM64 system supports AArch32 execution state.
> >>> +
> >>>  choice
> >>>      prompt "Target select"
> >>>      default TARGET_HIKEY
> >>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
> >>> index e933021..dd69501 100644
> >>> --- a/arch/arm/cpu/armv8/start.S
> >>> +++ b/arch/arm/cpu/armv8/start.S
> >>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
> >>>      /*
> >>>       * All slaves will enter EL2 and optionally EL1.
> >>>       */
> >>> +    ldr    x3, =ES_TO_AARCH64
> >>>      bl    armv8_switch_to_el2
> >>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
> >>>      bl    armv8_switch_to_el1
> >>> diff --git a/arch/arm/cpu/armv8/transition.S
> >> b/arch/arm/cpu/armv8/transition.S
> >>> index 253a39b..e61b6ae 100644
> >>> --- a/arch/arm/cpu/armv8/transition.S
> >>> +++ b/arch/arm/cpu/armv8/transition.S
> >>> @@ -11,13 +11,13 @@
> >>>  #include <asm/macro.h>
> >>>
> >>>  ENTRY(armv8_switch_to_el2)
> >>> -    switch_el x0, 1f, 0f, 0f
> >>> +    switch_el x4, 1f, 0f, 0f
> >>>  0:    ret
> >>> -1:    armv8_switch_to_el2_m x0
> >>> +1:    armv8_switch_to_el2_m x0, x3, x4
> >>>  ENDPROC(armv8_switch_to_el2)
> >>>
> >>>  ENTRY(armv8_switch_to_el1)
> >>> -    switch_el x0, 0f, 1f, 0f
> >>> +    switch_el x4, 0f, 1f, 0f
> >>>  0:    ret
> >>> -1:    armv8_switch_to_el1_m x0, x1
> >>> +1:    armv8_switch_to_el1_m x0, x3, x4
> >>>  ENDPROC(armv8_switch_to_el1)
> >>> diff --git a/arch/arm/include/asm/macro.h
> >> b/arch/arm/include/asm/macro.h
> >>> index 9bb0efa..109724f 100644
> >>> --- a/arch/arm/include/asm/macro.h
> >>> +++ b/arch/arm/include/asm/macro.h
> >>> @@ -8,6 +8,9 @@
> >>>
> >>>  #ifndef __ASM_ARM_MACRO_H__
> >>>  #define __ASM_ARM_MACRO_H__
> >>> +
> >>> +#include <asm/system.h>
> >>> +
> >>>  #ifdef __ASSEMBLY__
> >>>
> >>>  /*
> >>> @@ -135,13 +138,20 @@ lr    .req    x30
> >>>  #endif
> >>>  .endm
> >>>
> >>> -.macro armv8_switch_to_el2_m, xreg1
> >>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
> EL0/EL1
> >> */
> >>> -    mov    \xreg1, #0x5b1
> >>> -    msr    scr_el3, \xreg1
> >>> +/*
> >>> + * 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
> >>> + *
> >>> + * x1 is machine nr and x2 is ftaddr, they will be passed
> >>> + * to the guest.
> >>> + */
> >>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
> >>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
> >> */
> >>> -    mov    \xreg1, #0x33ff
> >>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2
> */
> >>> +    mov    \tmp, #CPTR_EL2_RES1
> >>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
> EL2
> >> */
> >>>
> >>>      /* Initialize Generic Timers */
> >>>      msr    cntvoff_el2, xzr
> >>> @@ -152,45 +162,91 @@ lr    .req    x30
> >>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
> >>>       * EE,WXN,I,SA,C,A,M to 0
> >>>       */
> >>> -    mov    \xreg1, #0x0830
> >>> -    movk    \xreg1, #0x30C5, lsl #16
> >>> -    msr    sctlr_el2, \xreg1
> >>> +    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 |
> >>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
> >>> +     */
> >>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
> >>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
> >>> +            SCR_EL3_NS_EN)
> >>> +    msr    scr_el3, \tmp
> >>>
> >>>      /* Return to the EL2_SP2 mode from EL3 */
> >>> -    mov    \xreg1, sp
> >>> -    msr    sp_el2, \xreg1        /* Migrate SP */
> >>> -    mrs    \xreg1, vbar_el3
> >>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
> >>> -    mov    \xreg1, #0x3c9
> >>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
> >>> +    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, lr
> >>
> >> So if we switch into AArch64 mode, we return ...
> >>
> >>>      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
> >>> +
> >>> +    mov    \ep, #0
> >>
> >> ... while if we switch to AArch32 mode we jump to ep.
> >>
> >> I think it would make a lot of sense if we could *always* jump to ep.
> >> Just swizzle the argument order so that you get
> >>
> >>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
> >>                    (images->os.arch == IH_ARCH_ARM))
> >>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
> >> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
> >>                else
> >> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
> >> ES_TO_AARCH64);
> > [Alison Wang] I don't agree it would make a lot of sense if we could
> > *always* jump to ep.
> > If we switch to EL2 AArch32 mode, it will happen at the last minute
> > from U-Boot to kernel. The ep is the entry pointer for kernel.
> > If we switch to EL2 AArch64 mode, it will happen earlier. For primary
> > core, it will call kernel entry after the switch. For secondary cores,
> > it will switch from EL3 AArch64 to EL2 AArch64 first, then it will
> > wait until the spin-table is written by the kernel, later it will jump
> to kernel.
> 
> Then jump to a separate function that continues the execution stream. I
> really think we should keep the interface between both flags as
> identical as possible.
[Alison Wang] I think you are right. I will change the code to *always*
jump to ep in v5.
> 
> >>
> >> If you *really really really* are attached to booting into EL1, just
> >> add a small function that calls armv8_switch_to_el1() for you and
> >> pass the pointer to that as ep to the el2 switch. If I were you I'd
> >> just remove the EL1 mess.
> > [Alison Wang] I agreed with you to remove the EL1 mess.
> 
> Awesome, thanks.
[Alison Wang] When I tried to remove the EL1 mess, I found CONFIG_ARMV8_SWITCH_TO_EL1
is enabled for Versatile Express Aemv8a. If that platform uses it, I have a concern
about removing it.


Best Regards,
Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-30  7:16         ` Huan Wang
@ 2016-06-30  8:41           ` Alexander Graf
  2016-07-04  3:39             ` Huan Wang
  0 siblings, 1 reply; 14+ messages in thread
From: Alexander Graf @ 2016-06-30  8:41 UTC (permalink / raw)
  To: u-boot



On 30.06.16 09:16, Huan Wang wrote:
> Hi, Alex,
> 
>>> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
>>>
>>> Hi, Alex,
>>>
>>>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
>>>>> To support loading a 32-bit OS, the execution state will change from
>>>>> AArch64 to AArch32 when jumping to kernel.
>>>>>
>>>>> The architecture information will be got through checking FIT image,
>>>>> then U-Boot will load 32-bit OS or 64-bit OS automatically.
>>>>>
>>>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
>>>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
>>>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
>>>>> ---
>>>>> Changes in v4:
>>>>> - Correct config ARM64_SUPPORT_AARCH32.
>>>>> - Omit arch and ftaddr arguments.
>>>>> - Rename "xreg5" to "tmp".
>>>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
>>>>> - Use an immediate cmp directly.
>>>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>>>>>
>>>>> Changes in v3:
>>>>> - Comments the functions and the arguments.
>>>>> - Rename the real parameters.
>>>>> - Use the macros instead of the magic values.
>>>>> - Remove the redundant codes.
>>>>> - Clean up all of the mess in boot_jump_linux().
>>>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
>>>> doesn't support AArch32 state.
>>>>>
>>>>> Changes in v2:
>>>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m is
>>>> used
>>>>>   to switch to AArch64 EL2 or AArch32 Hyp.
>>>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m is
>>>> used
>>>>>   to switch to AArch64 EL1 or AArch32 SVC.
>>>>>
>>>>>  arch/arm/Kconfig                |   6 ++
>>>>>  arch/arm/cpu/armv8/start.S      |   1 +
>>>>>  arch/arm/cpu/armv8/transition.S |   8 +-
>>>>>  arch/arm/include/asm/macro.h    | 172
>>>> ++++++++++++++++++++++++++++++----------
>>>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>>>>>  arch/arm/lib/bootm.c            |  19 ++++-
>>>>>  common/image-fit.c              |  19 ++++-
>>>>>  7 files changed, 284 insertions(+), 52 deletions(-)
>>>>>
>>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
>>>>> 77eab66..9cf4acd 100644
>>>>> --- a/arch/arm/Kconfig
>>>>> +++ b/arch/arm/Kconfig
>>>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>>>>>        If SoC does not support L2CACHE or one do not want to enable
>>>>>        L2CACHE, choose this option.
>>>>>
>>>>> +config ARM64_SUPPORT_AARCH32
>>>>> +    bool "ARM64 system support AArch32 execution state"
>>>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
>>>>> +    help
>>>>> +      This ARM64 system supports AArch32 execution state.
>>>>> +
>>>>>  choice
>>>>>      prompt "Target select"
>>>>>      default TARGET_HIKEY
>>>>> diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
>>>>> index e933021..dd69501 100644
>>>>> --- a/arch/arm/cpu/armv8/start.S
>>>>> +++ b/arch/arm/cpu/armv8/start.S
>>>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>>>>>      /*
>>>>>       * All slaves will enter EL2 and optionally EL1.
>>>>>       */
>>>>> +    ldr    x3, =ES_TO_AARCH64
>>>>>      bl    armv8_switch_to_el2
>>>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>>>>>      bl    armv8_switch_to_el1
>>>>> diff --git a/arch/arm/cpu/armv8/transition.S
>>>> b/arch/arm/cpu/armv8/transition.S
>>>>> index 253a39b..e61b6ae 100644
>>>>> --- a/arch/arm/cpu/armv8/transition.S
>>>>> +++ b/arch/arm/cpu/armv8/transition.S
>>>>> @@ -11,13 +11,13 @@
>>>>>  #include <asm/macro.h>
>>>>>
>>>>>  ENTRY(armv8_switch_to_el2)
>>>>> -    switch_el x0, 1f, 0f, 0f
>>>>> +    switch_el x4, 1f, 0f, 0f
>>>>>  0:    ret
>>>>> -1:    armv8_switch_to_el2_m x0
>>>>> +1:    armv8_switch_to_el2_m x0, x3, x4
>>>>>  ENDPROC(armv8_switch_to_el2)
>>>>>
>>>>>  ENTRY(armv8_switch_to_el1)
>>>>> -    switch_el x0, 0f, 1f, 0f
>>>>> +    switch_el x4, 0f, 1f, 0f
>>>>>  0:    ret
>>>>> -1:    armv8_switch_to_el1_m x0, x1
>>>>> +1:    armv8_switch_to_el1_m x0, x3, x4
>>>>>  ENDPROC(armv8_switch_to_el1)
>>>>> diff --git a/arch/arm/include/asm/macro.h
>>>> b/arch/arm/include/asm/macro.h
>>>>> index 9bb0efa..109724f 100644
>>>>> --- a/arch/arm/include/asm/macro.h
>>>>> +++ b/arch/arm/include/asm/macro.h
>>>>> @@ -8,6 +8,9 @@
>>>>>
>>>>>  #ifndef __ASM_ARM_MACRO_H__
>>>>>  #define __ASM_ARM_MACRO_H__
>>>>> +
>>>>> +#include <asm/system.h>
>>>>> +
>>>>>  #ifdef __ASSEMBLY__
>>>>>
>>>>>  /*
>>>>> @@ -135,13 +138,20 @@ lr    .req    x30
>>>>>  #endif
>>>>>  .endm
>>>>>
>>>>> -.macro armv8_switch_to_el2_m, xreg1
>>>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
>> EL0/EL1
>>>> */
>>>>> -    mov    \xreg1, #0x5b1
>>>>> -    msr    scr_el3, \xreg1
>>>>> +/*
>>>>> + * 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
>>>>> + *
>>>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
>>>>> + * to the guest.
>>>>> + */
>>>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>>>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to EL3
>>>> */
>>>>> -    mov    \xreg1, #0x33ff
>>>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to EL2
>> */
>>>>> +    mov    \tmp, #CPTR_EL2_RES1
>>>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
>> EL2
>>>> */
>>>>>
>>>>>      /* Initialize Generic Timers */
>>>>>      msr    cntvoff_el2, xzr
>>>>> @@ -152,45 +162,91 @@ lr    .req    x30
>>>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>>>>>       * EE,WXN,I,SA,C,A,M to 0
>>>>>       */
>>>>> -    mov    \xreg1, #0x0830
>>>>> -    movk    \xreg1, #0x30C5, lsl #16
>>>>> -    msr    sctlr_el2, \xreg1
>>>>> +    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 |
>>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>>>> +     */
>>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
>>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>>>> +            SCR_EL3_NS_EN)
>>>>> +    msr    scr_el3, \tmp
>>>>>
>>>>>      /* Return to the EL2_SP2 mode from EL3 */
>>>>> -    mov    \xreg1, sp
>>>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
>>>>> -    mrs    \xreg1, vbar_el3
>>>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
>>>>> -    mov    \xreg1, #0x3c9
>>>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
>>>>> +    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, lr
>>>>
>>>> So if we switch into AArch64 mode, we return ...
>>>>
>>>>>      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
>>>>> +
>>>>> +    mov    \ep, #0
>>>>
>>>> ... while if we switch to AArch32 mode we jump to ep.
>>>>
>>>> I think it would make a lot of sense if we could *always* jump to ep.
>>>> Just swizzle the argument order so that you get
>>>>
>>>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>>>>                    (images->os.arch == IH_ARCH_ARM))
>>>>                        armv8_switch_to_el2(0, gd->bd->bi_arch_number,
>>>> (uintptr_t)images->ft_addr, (u64)images->ep, ES_TO_AARCH32);
>>>>                else
>>>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
>>>> ES_TO_AARCH64);
>>> [Alison Wang] I don't agree it would make a lot of sense if we could
>>> *always* jump to ep.
>>> If we switch to EL2 AArch32 mode, it will happen at the last minute
>>> from U-Boot to kernel. The ep is the entry pointer for kernel.
>>> If we switch to EL2 AArch64 mode, it will happen earlier. For primary
>>> core, it will call kernel entry after the switch. For secondary cores,
>>> it will switch from EL3 AArch64 to EL2 AArch64 first, then it will
>>> wait until the spin-table is written by the kernel, later it will jump
>> to kernel.
>>
>> Then jump to a separate function that continues the execution stream. I
>> really think we should keep the interface between both flags as
>> identical as possible.
> [Alison Wang] I think you are right. I will change the code to *always*
> jump to ep in v5.
>>
>>>>
>>>> If you *really really really* are attached to booting into EL1, just
>>>> add a small function that calls armv8_switch_to_el1() for you and
>>>> pass the pointer to that as ep to the el2 switch. If I were you I'd
>>>> just remove the EL1 mess.
>>> [Alison Wang] I agreed with you to remove the EL1 mess.
>>
>> Awesome, thanks.
> [Alison Wang] When I tried to remove the EL1 mess, I found CONFIG_ARMV8_SWITCH_TO_EL1
> is enabled for Versatile Express Aemv8a. If that platform uses it, I have a concern
> about removing it.

Do you have access to the respective simulator? It's probably only
enabled because in the very very very early days of Linux bringup Linux
didn't know how to run in EL2 yet. So we can probably just drop it.

But let's CC people who might know :).


Alex

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-06-30  8:41           ` Alexander Graf
@ 2016-07-04  3:39             ` Huan Wang
  2016-07-06 16:55               ` york sun
  0 siblings, 1 reply; 14+ messages in thread
From: Huan Wang @ 2016-07-04  3:39 UTC (permalink / raw)
  To: u-boot

> On 30.06.16 09:16, Huan Wang wrote:
> > Hi, Alex,
> >
> >>> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
> >>>
> >>> Hi, Alex,
> >>>
> >>>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
> >>>>> To support loading a 32-bit OS, the execution state will change
> >>>>> from
> >>>>> AArch64 to AArch32 when jumping to kernel.
> >>>>>
> >>>>> The architecture information will be got through checking FIT
> >>>>> image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
> >>>>>
> >>>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
> >>>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
> >>>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
> >>>>> ---
> >>>>> Changes in v4:
> >>>>> - Correct config ARM64_SUPPORT_AARCH32.
> >>>>> - Omit arch and ftaddr arguments.
> >>>>> - Rename "xreg5" to "tmp".
> >>>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
> >>>>> - Use an immediate cmp directly.
> >>>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
> >>>>>
> >>>>> Changes in v3:
> >>>>> - Comments the functions and the arguments.
> >>>>> - Rename the real parameters.
> >>>>> - Use the macros instead of the magic values.
> >>>>> - Remove the redundant codes.
> >>>>> - Clean up all of the mess in boot_jump_linux().
> >>>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
> >>>> doesn't support AArch32 state.
> >>>>>
> >>>>> Changes in v2:
> >>>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m
> >>>>> is
> >>>> used
> >>>>>   to switch to AArch64 EL2 or AArch32 Hyp.
> >>>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m
> >>>>> is
> >>>> used
> >>>>>   to switch to AArch64 EL1 or AArch32 SVC.
> >>>>>
> >>>>>  arch/arm/Kconfig                |   6 ++
> >>>>>  arch/arm/cpu/armv8/start.S      |   1 +
> >>>>>  arch/arm/cpu/armv8/transition.S |   8 +-
> >>>>>  arch/arm/include/asm/macro.h    | 172
> >>>> ++++++++++++++++++++++++++++++----------
> >>>>>  arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
> >>>>>  arch/arm/lib/bootm.c            |  19 ++++-
> >>>>>  common/image-fit.c              |  19 ++++-
> >>>>>  7 files changed, 284 insertions(+), 52 deletions(-)
> >>>>>
> >>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
> >>>>> 77eab66..9cf4acd 100644
> >>>>> --- a/arch/arm/Kconfig
> >>>>> +++ b/arch/arm/Kconfig
> >>>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
> >>>>>        If SoC does not support L2CACHE or one do not want to
> enable
> >>>>>        L2CACHE, choose this option.
> >>>>>
> >>>>> +config ARM64_SUPPORT_AARCH32
> >>>>> +    bool "ARM64 system support AArch32 execution state"
> >>>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
> >>>>> +    help
> >>>>> +      This ARM64 system supports AArch32 execution state.
> >>>>> +
> >>>>>  choice
> >>>>>      prompt "Target select"
> >>>>>      default TARGET_HIKEY
> >>>>> diff --git a/arch/arm/cpu/armv8/start.S
> >>>>> b/arch/arm/cpu/armv8/start.S index e933021..dd69501 100644
> >>>>> --- a/arch/arm/cpu/armv8/start.S
> >>>>> +++ b/arch/arm/cpu/armv8/start.S
> >>>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
> >>>>>      /*
> >>>>>       * All slaves will enter EL2 and optionally EL1.
> >>>>>       */
> >>>>> +    ldr    x3, =ES_TO_AARCH64
> >>>>>      bl    armv8_switch_to_el2
> >>>>>  #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
> >>>>>      bl    armv8_switch_to_el1
> >>>>> diff --git a/arch/arm/cpu/armv8/transition.S
> >>>> b/arch/arm/cpu/armv8/transition.S
> >>>>> index 253a39b..e61b6ae 100644
> >>>>> --- a/arch/arm/cpu/armv8/transition.S
> >>>>> +++ b/arch/arm/cpu/armv8/transition.S
> >>>>> @@ -11,13 +11,13 @@
> >>>>>  #include <asm/macro.h>
> >>>>>
> >>>>>  ENTRY(armv8_switch_to_el2)
> >>>>> -    switch_el x0, 1f, 0f, 0f
> >>>>> +    switch_el x4, 1f, 0f, 0f
> >>>>>  0:    ret
> >>>>> -1:    armv8_switch_to_el2_m x0
> >>>>> +1:    armv8_switch_to_el2_m x0, x3, x4
> >>>>>  ENDPROC(armv8_switch_to_el2)
> >>>>>
> >>>>>  ENTRY(armv8_switch_to_el1)
> >>>>> -    switch_el x0, 0f, 1f, 0f
> >>>>> +    switch_el x4, 0f, 1f, 0f
> >>>>>  0:    ret
> >>>>> -1:    armv8_switch_to_el1_m x0, x1
> >>>>> +1:    armv8_switch_to_el1_m x0, x3, x4
> >>>>>  ENDPROC(armv8_switch_to_el1)
> >>>>> diff --git a/arch/arm/include/asm/macro.h
> >>>> b/arch/arm/include/asm/macro.h
> >>>>> index 9bb0efa..109724f 100644
> >>>>> --- a/arch/arm/include/asm/macro.h
> >>>>> +++ b/arch/arm/include/asm/macro.h
> >>>>> @@ -8,6 +8,9 @@
> >>>>>
> >>>>>  #ifndef __ASM_ARM_MACRO_H__
> >>>>>  #define __ASM_ARM_MACRO_H__
> >>>>> +
> >>>>> +#include <asm/system.h>
> >>>>> +
> >>>>>  #ifdef __ASSEMBLY__
> >>>>>
> >>>>>  /*
> >>>>> @@ -135,13 +138,20 @@ lr    .req    x30
> >>>>>  #endif
> >>>>>  .endm
> >>>>>
> >>>>> -.macro armv8_switch_to_el2_m, xreg1
> >>>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
> >> EL0/EL1
> >>>> */
> >>>>> -    mov    \xreg1, #0x5b1
> >>>>> -    msr    scr_el3, \xreg1
> >>>>> +/*
> >>>>> + * 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
> >>>>> + *
> >>>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
> >>>>> + * to the guest.
> >>>>> + */
> >>>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
> >>>>>      msr    cptr_el3, xzr        /* Disable coprocessor traps to
> EL3
> >>>> */
> >>>>> -    mov    \xreg1, #0x33ff
> >>>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to
> EL2
> >> */
> >>>>> +    mov    \tmp, #CPTR_EL2_RES1
> >>>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
> >> EL2
> >>>> */
> >>>>>
> >>>>>      /* Initialize Generic Timers */
> >>>>>      msr    cntvoff_el2, xzr
> >>>>> @@ -152,45 +162,91 @@ lr    .req    x30
> >>>>>       * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
> >>>>>       * EE,WXN,I,SA,C,A,M to 0
> >>>>>       */
> >>>>> -    mov    \xreg1, #0x0830
> >>>>> -    movk    \xreg1, #0x30C5, lsl #16
> >>>>> -    msr    sctlr_el2, \xreg1
> >>>>> +    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
> |
> >>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
> >>>>> +     */
> >>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
> >>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
> >>>>> +            SCR_EL3_NS_EN)
> >>>>> +    msr    scr_el3, \tmp
> >>>>>
> >>>>>      /* Return to the EL2_SP2 mode from EL3 */
> >>>>> -    mov    \xreg1, sp
> >>>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
> >>>>> -    mrs    \xreg1, vbar_el3
> >>>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
> >>>>> -    mov    \xreg1, #0x3c9
> >>>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
> >>>>> +    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, lr
> >>>>
> >>>> So if we switch into AArch64 mode, we return ...
> >>>>
> >>>>>      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
> >>>>> +
> >>>>> +    mov    \ep, #0
> >>>>
> >>>> ... while if we switch to AArch32 mode we jump to ep.
> >>>>
> >>>> I think it would make a lot of sense if we could *always* jump to
> ep.
> >>>> Just swizzle the argument order so that you get
> >>>>
> >>>>                if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
> >>>>                    (images->os.arch == IH_ARCH_ARM))
> >>>>                        armv8_switch_to_el2(0,
> >>>> gd->bd->bi_arch_number, (uintptr_t)images->ft_addr, (u64)images->ep,
> ES_TO_AARCH32);
> >>>>                else
> >>>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
> >>>> ES_TO_AARCH64);
> >>> [Alison Wang] I don't agree it would make a lot of sense if we could
> >>> *always* jump to ep.
> >>> If we switch to EL2 AArch32 mode, it will happen at the last minute
> >>> from U-Boot to kernel. The ep is the entry pointer for kernel.
> >>> If we switch to EL2 AArch64 mode, it will happen earlier. For
> >>> primary core, it will call kernel entry after the switch. For
> >>> secondary cores, it will switch from EL3 AArch64 to EL2 AArch64
> >>> first, then it will wait until the spin-table is written by the
> >>> kernel, later it will jump
> >> to kernel.
> >>
> >> Then jump to a separate function that continues the execution stream.
> >> I really think we should keep the interface between both flags as
> >> identical as possible.
> > [Alison Wang] I think you are right. I will change the code to
> > *always* jump to ep in v5.
> >>
> >>>>
> >>>> If you *really really really* are attached to booting into EL1,
> >>>> just add a small function that calls armv8_switch_to_el1() for you
> >>>> and pass the pointer to that as ep to the el2 switch. If I were you
> >>>> I'd just remove the EL1 mess.
> >>> [Alison Wang] I agreed with you to remove the EL1 mess.
> >>
> >> Awesome, thanks.
> > [Alison Wang] When I tried to remove the EL1 mess, I found
> > CONFIG_ARMV8_SWITCH_TO_EL1 is enabled for Versatile Express Aemv8a. If
> > that platform uses it, I have a concern about removing it.
> 
> Do you have access to the respective simulator? It's probably only
> enabled because in the very very very early days of Linux bringup Linux
> didn't know how to run in EL2 yet. So we can probably just drop it.
> 
> But let's CC people who might know :).
> 
[Alison Wang] Alex, thanks for the explanation.

Does anyone disagree to remove CONFIG_ARMV8_SWITCH_TO_EL1 and other corresponding functions?
If there is no disagreement, I will remove them in the v5 patches.


Best Regards,
Alison Wang

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [U-Boot] [PATCH v4 1/2] armv8: Support loading 32-bit OS in AArch32 execution state
  2016-07-04  3:39             ` Huan Wang
@ 2016-07-06 16:55               ` york sun
  0 siblings, 0 replies; 14+ messages in thread
From: york sun @ 2016-07-06 16:55 UTC (permalink / raw)
  To: u-boot

On 07/03/2016 08:39 PM, Huan Wang wrote:
>> On 30.06.16 09:16, Huan Wang wrote:
>>> Hi, Alex,
>>>
>>>>> Am 15.06.2016 um 05:04 schrieb Huan Wang <alison.wang@nxp.com>:
>>>>>
>>>>> Hi, Alex,
>>>>>
>>>>>>> On 06/08/2016 07:14 AM, Alison Wang wrote:
>>>>>>> To support loading a 32-bit OS, the execution state will change
>>>>>>> from
>>>>>>> AArch64 to AArch32 when jumping to kernel.
>>>>>>>
>>>>>>> The architecture information will be got through checking FIT
>>>>>>> image, then U-Boot will load 32-bit OS or 64-bit OS automatically.
>>>>>>>
>>>>>>> Signed-off-by: Ebony Zhu <ebony.zhu@nxp.com>
>>>>>>> Signed-off-by: Alison Wang <alison.wang@nxp.com>
>>>>>>> Signed-off-by: Chenhui Zhao <chenhui.zhao@nxp.com>
>>>>>>> ---
>>>>>>> Changes in v4:
>>>>>>> - Correct config ARM64_SUPPORT_AARCH32.
>>>>>>> - Omit arch and ftaddr arguments.
>>>>>>> - Rename "xreg5" to "tmp".
>>>>>>> - Use xxx_RES1 to combine all RES1 fields in xxx register.
>>>>>>> - Use an immediate cmp directly.
>>>>>>> - Use #ifdef for CONFIG_ARM64_SUPPORT_AARCH32.
>>>>>>>
>>>>>>> Changes in v3:
>>>>>>> - Comments the functions and the arguments.
>>>>>>> - Rename the real parameters.
>>>>>>> - Use the macros instead of the magic values.
>>>>>>> - Remove the redundant codes.
>>>>>>> - Clean up all of the mess in boot_jump_linux().
>>>>>>> - Add CONFIG_ARM64_SUPPORT_AARCH32 to detect for some ARM64 system
>>>>>> doesn't support AArch32 state.
>>>>>>>
>>>>>>> Changes in v2:
>>>>>>> - armv8_switch_to_el2_aarch32() is removed. armv8_switch_to_el2_m
>>>>>>> is
>>>>>> used
>>>>>>>    to switch to AArch64 EL2 or AArch32 Hyp.
>>>>>>> - armv8_switch_to_el1_aarch32() is removed. armv8_switch_to_el1_m
>>>>>>> is
>>>>>> used
>>>>>>>    to switch to AArch64 EL1 or AArch32 SVC.
>>>>>>>
>>>>>>>   arch/arm/Kconfig                |   6 ++
>>>>>>>   arch/arm/cpu/armv8/start.S      |   1 +
>>>>>>>   arch/arm/cpu/armv8/transition.S |   8 +-
>>>>>>>   arch/arm/include/asm/macro.h    | 172
>>>>>> ++++++++++++++++++++++++++++++----------
>>>>>>>   arch/arm/include/asm/system.h   | 111 +++++++++++++++++++++++++-
>>>>>>>   arch/arm/lib/bootm.c            |  19 ++++-
>>>>>>>   common/image-fit.c              |  19 ++++-
>>>>>>>   7 files changed, 284 insertions(+), 52 deletions(-)
>>>>>>>
>>>>>>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index
>>>>>>> 77eab66..9cf4acd 100644
>>>>>>> --- a/arch/arm/Kconfig
>>>>>>> +++ b/arch/arm/Kconfig
>>>>>>> @@ -91,6 +91,12 @@ config SYS_L2CACHE_OFF
>>>>>>>         If SoC does not support L2CACHE or one do not want to
>> enable
>>>>>>>         L2CACHE, choose this option.
>>>>>>>
>>>>>>> +config ARM64_SUPPORT_AARCH32
>>>>>>> +    bool "ARM64 system support AArch32 execution state"
>>>>>>> +    default y if ARM64 && !TARGET_THUNDERX_88XX
>>>>>>> +    help
>>>>>>> +      This ARM64 system supports AArch32 execution state.
>>>>>>> +
>>>>>>>   choice
>>>>>>>       prompt "Target select"
>>>>>>>       default TARGET_HIKEY
>>>>>>> diff --git a/arch/arm/cpu/armv8/start.S
>>>>>>> b/arch/arm/cpu/armv8/start.S index e933021..dd69501 100644
>>>>>>> --- a/arch/arm/cpu/armv8/start.S
>>>>>>> +++ b/arch/arm/cpu/armv8/start.S
>>>>>>> @@ -234,6 +234,7 @@ WEAK(lowlevel_init)
>>>>>>>       /*
>>>>>>>        * All slaves will enter EL2 and optionally EL1.
>>>>>>>        */
>>>>>>> +    ldr    x3, =ES_TO_AARCH64
>>>>>>>       bl    armv8_switch_to_el2
>>>>>>>   #ifdef CONFIG_ARMV8_SWITCH_TO_EL1
>>>>>>>       bl    armv8_switch_to_el1
>>>>>>> diff --git a/arch/arm/cpu/armv8/transition.S
>>>>>> b/arch/arm/cpu/armv8/transition.S
>>>>>>> index 253a39b..e61b6ae 100644
>>>>>>> --- a/arch/arm/cpu/armv8/transition.S
>>>>>>> +++ b/arch/arm/cpu/armv8/transition.S
>>>>>>> @@ -11,13 +11,13 @@
>>>>>>>   #include <asm/macro.h>
>>>>>>>
>>>>>>>   ENTRY(armv8_switch_to_el2)
>>>>>>> -    switch_el x0, 1f, 0f, 0f
>>>>>>> +    switch_el x4, 1f, 0f, 0f
>>>>>>>   0:    ret
>>>>>>> -1:    armv8_switch_to_el2_m x0
>>>>>>> +1:    armv8_switch_to_el2_m x0, x3, x4
>>>>>>>   ENDPROC(armv8_switch_to_el2)
>>>>>>>
>>>>>>>   ENTRY(armv8_switch_to_el1)
>>>>>>> -    switch_el x0, 0f, 1f, 0f
>>>>>>> +    switch_el x4, 0f, 1f, 0f
>>>>>>>   0:    ret
>>>>>>> -1:    armv8_switch_to_el1_m x0, x1
>>>>>>> +1:    armv8_switch_to_el1_m x0, x3, x4
>>>>>>>   ENDPROC(armv8_switch_to_el1)
>>>>>>> diff --git a/arch/arm/include/asm/macro.h
>>>>>> b/arch/arm/include/asm/macro.h
>>>>>>> index 9bb0efa..109724f 100644
>>>>>>> --- a/arch/arm/include/asm/macro.h
>>>>>>> +++ b/arch/arm/include/asm/macro.h
>>>>>>> @@ -8,6 +8,9 @@
>>>>>>>
>>>>>>>   #ifndef __ASM_ARM_MACRO_H__
>>>>>>>   #define __ASM_ARM_MACRO_H__
>>>>>>> +
>>>>>>> +#include <asm/system.h>
>>>>>>> +
>>>>>>>   #ifdef __ASSEMBLY__
>>>>>>>
>>>>>>>   /*
>>>>>>> @@ -135,13 +138,20 @@ lr    .req    x30
>>>>>>>   #endif
>>>>>>>   .endm
>>>>>>>
>>>>>>> -.macro armv8_switch_to_el2_m, xreg1
>>>>>>> -    /* 64bit EL2 | HCE | SMD | RES1 (Bits[5:4]) | Non-secure
>>>> EL0/EL1
>>>>>> */
>>>>>>> -    mov    \xreg1, #0x5b1
>>>>>>> -    msr    scr_el3, \xreg1
>>>>>>> +/*
>>>>>>> + * 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
>>>>>>> + *
>>>>>>> + * x1 is machine nr and x2 is ftaddr, they will be passed
>>>>>>> + * to the guest.
>>>>>>> + */
>>>>>>> +.macro armv8_switch_to_el2_m, ep, flag, tmp
>>>>>>>       msr    cptr_el3, xzr        /* Disable coprocessor traps to
>> EL3
>>>>>> */
>>>>>>> -    mov    \xreg1, #0x33ff
>>>>>>> -    msr    cptr_el2, \xreg1    /* Disable coprocessor traps to
>> EL2
>>>> */
>>>>>>> +    mov    \tmp, #CPTR_EL2_RES1
>>>>>>> +    msr    cptr_el2, \tmp        /* Disable coprocessor traps to
>>>> EL2
>>>>>> */
>>>>>>>
>>>>>>>       /* Initialize Generic Timers */
>>>>>>>       msr    cntvoff_el2, xzr
>>>>>>> @@ -152,45 +162,91 @@ lr    .req    x30
>>>>>>>        * and RES0 bits (31,30,27,26,24,21,20,17,15-13,10-6) +
>>>>>>>        * EE,WXN,I,SA,C,A,M to 0
>>>>>>>        */
>>>>>>> -    mov    \xreg1, #0x0830
>>>>>>> -    movk    \xreg1, #0x30C5, lsl #16
>>>>>>> -    msr    sctlr_el2, \xreg1
>>>>>>> +    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
>> |
>>>>>>> +     * SMD | RES1 (Bits[5:4]) | Non-secure EL0/EL1.
>>>>>>> +     */
>>>>>>> +    ldr    \tmp, =(SCR_EL3_RW_AARCH64 | SCR_EL3_HCE_EN |\
>>>>>>> +            SCR_EL3_SMD_DIS | SCR_EL3_RES1 |\
>>>>>>> +            SCR_EL3_NS_EN)
>>>>>>> +    msr    scr_el3, \tmp
>>>>>>>
>>>>>>>       /* Return to the EL2_SP2 mode from EL3 */
>>>>>>> -    mov    \xreg1, sp
>>>>>>> -    msr    sp_el2, \xreg1        /* Migrate SP */
>>>>>>> -    mrs    \xreg1, vbar_el3
>>>>>>> -    msr    vbar_el2, \xreg1    /* Migrate VBAR */
>>>>>>> -    mov    \xreg1, #0x3c9
>>>>>>> -    msr    spsr_el3, \xreg1    /* EL2_SP2 | D | A | I | F */
>>>>>>> +    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, lr
>>>>>>
>>>>>> So if we switch into AArch64 mode, we return ...
>>>>>>
>>>>>>>       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
>>>>>>> +
>>>>>>> +    mov    \ep, #0
>>>>>>
>>>>>> ... while if we switch to AArch32 mode we jump to ep.
>>>>>>
>>>>>> I think it would make a lot of sense if we could *always* jump to
>> ep.
>>>>>> Just swizzle the argument order so that you get
>>>>>>
>>>>>>                 if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
>>>>>>                     (images->os.arch == IH_ARCH_ARM))
>>>>>>                         armv8_switch_to_el2(0,
>>>>>> gd->bd->bi_arch_number, (uintptr_t)images->ft_addr, (u64)images->ep,
>> ES_TO_AARCH32);
>>>>>>                 else
>>>>>> armv8_switch_to_el2((uintptr_t)images->ft_addr, 0 0, images->ep,
>>>>>> ES_TO_AARCH64);
>>>>> [Alison Wang] I don't agree it would make a lot of sense if we could
>>>>> *always* jump to ep.
>>>>> If we switch to EL2 AArch32 mode, it will happen at the last minute
>>>>> from U-Boot to kernel. The ep is the entry pointer for kernel.
>>>>> If we switch to EL2 AArch64 mode, it will happen earlier. For
>>>>> primary core, it will call kernel entry after the switch. For
>>>>> secondary cores, it will switch from EL3 AArch64 to EL2 AArch64
>>>>> first, then it will wait until the spin-table is written by the
>>>>> kernel, later it will jump
>>>> to kernel.
>>>>
>>>> Then jump to a separate function that continues the execution stream.
>>>> I really think we should keep the interface between both flags as
>>>> identical as possible.
>>> [Alison Wang] I think you are right. I will change the code to
>>> *always* jump to ep in v5.
>>>>
>>>>>>
>>>>>> If you *really really really* are attached to booting into EL1,
>>>>>> just add a small function that calls armv8_switch_to_el1() for you
>>>>>> and pass the pointer to that as ep to the el2 switch. If I were you
>>>>>> I'd just remove the EL1 mess.
>>>>> [Alison Wang] I agreed with you to remove the EL1 mess.
>>>>
>>>> Awesome, thanks.
>>> [Alison Wang] When I tried to remove the EL1 mess, I found
>>> CONFIG_ARMV8_SWITCH_TO_EL1 is enabled for Versatile Express Aemv8a. If
>>> that platform uses it, I have a concern about removing it.
>>
>> Do you have access to the respective simulator? It's probably only
>> enabled because in the very very very early days of Linux bringup Linux
>> didn't know how to run in EL2 yet. So we can probably just drop it.
>>
>> But let's CC people who might know :).
>>
> [Alison Wang] Alex, thanks for the explanation.
>
> Does anyone disagree to remove CONFIG_ARMV8_SWITCH_TO_EL1 and other corresponding functions?
> If there is no disagreement, I will remove them in the v5 patches.
>

If nobody uses EL1, go ahead to drop it. It may be a good idea to check 
this macro and throw an error if found.

York

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2016-07-06 16:55 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-08  5:14 [U-Boot] [PATCH v4 0/2] armv8: Support loading 32-bit OS in AArch32 execution state Alison Wang
2016-06-08  5:14 ` [U-Boot] [PATCH v4 1/2] " Alison Wang
2016-06-08 12:14   ` Alexander Graf
2016-06-15  3:04     ` Huan Wang
2016-06-15  7:41       ` Alexander Graf
2016-06-15  7:42       ` Alexander Graf
2016-06-15  8:08         ` Huan Wang
2016-06-15  8:21           ` Alexander Graf
2016-06-15  8:33             ` Huan Wang
2016-06-30  7:16         ` Huan Wang
2016-06-30  8:41           ` Alexander Graf
2016-07-04  3:39             ` Huan Wang
2016-07-06 16:55               ` york sun
2016-06-08  5:14 ` [U-Boot] [PATCH v4 2/2] armv8: fsl-layerscape: SMP support for loading 32-bit OS Alison Wang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.