[RFC PATCH 3/4] ARM64: Big Endian fixes for kernel booting

Ankit Jindal ankit.jindal at linaro.org
Fri Oct 11 08:22:14 EDT 2013


- Enable appropriate bits for big endian kernel in SYSCTLR.EL2 and
  SYSCTLR.EL1 registers
- Swap entry point for secondary core for big endian kernel
- Set machine type to "aarch64b" for big endian and "aarch64l"
  for little endian.

Signed-off-by: Ankit Jindal <ankit.jindal at linaro.org>
Signed-off-by: Tushar Jagad <tushar.jagad at linaro.org>
---
 arch/arm64/include/asm/assembler.h |    7 +++++++
 arch/arm64/kernel/head.S           |   34 ++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/setup.c          |   19 +++++++++++++++----
 arch/arm64/kernel/smp_spin_table.c |    5 +++--
 arch/arm64/mm/proc.S               |    2 +-
 5 files changed, 60 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 5aceb83..473faf3 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -22,6 +22,13 @@
 
 #include <asm/ptrace.h>
 
+/* Select code for any configuration running in BE mode */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define ARM_BE(code...) code
+#else
+#define ARM_BE(code...)
+#endif
+
 /*
  * Stack pushing/popping (register pairs only). Equivalent to store decrement
  * before, load increment after.
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 7090c12..45dc50d 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -122,6 +122,7 @@
 	.word	0				// reserved
 
 ENTRY(stext)
+	ARM_BE(bl      setend_be)
 	mov	x21, x0				// x21=FDT
 	bl	__calc_phys_offset		// x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
 	bl	el2_setup			// Drop to EL1
@@ -148,6 +149,34 @@ ENTRY(stext)
 ENDPROC(stext)
 
 /*
+ * Set el0-el1-el2 to Big endian
+ */
+
+#if defined(CONFIG_CPU_BIG_ENDIAN)
+ENTRY(setend_be)
+	mrs     x21, CurrentEL
+        cmp     x21, #PSR_MODE_EL2t
+	b.ne  	setend_be_el1_el0
+
+setend_be_el2:
+	mrs     x21, sctlr_el2
+        mov     x22, #(1<<25)
+        orr     x21, x21, x22
+        msr     sctlr_el2, x21
+	isb
+
+setend_be_el1_el0:
+	mrs     x21, sctlr_el1
+        mov     x22, #(3<<24)
+        orr     x21, x21, x22
+        msr     sctlr_el1, x21
+	isb
+
+	ret
+ENDPROC(setend_be)
+#endif /* defined(CONFIG_CPU_BIG_ENDIAN) */
+
+/*
  * If we're fortunate enough to boot at EL2, ensure that the world is
  * sane before dropping to EL1.
  */
@@ -181,7 +210,11 @@ ENTRY(el2_setup)
 
 	/* sctlr_el1 */
 	mov	x0, #0x0800			// Set/clear RES{1,0} bits
+#if defined(CONFIG_CPU_BIG_ENDIAN)
+	movk	x0, #0x33d0, lsl #16
+#else
 	movk	x0, #0x30d0, lsl #16
+#endif
 	msr	sctlr_el1, x0
 
 	/* Coprocessor traps. */
@@ -235,6 +268,7 @@ ENTRY(__boot_cpu_mode)
 	 * cores are held until we're ready for them to initialise.
 	 */
 ENTRY(secondary_holding_pen)
+	ARM_BE(bl 	setend_be)
 	bl	__calc_phys_offset		// x24=phys offset
 	bl	el2_setup			// Drop to EL1
 	mrs	x0, mpidr_el1
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 055cfb8..d47ae6d 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -64,6 +64,9 @@ static const char *cpu_name;
 static const char *machine_name;
 phys_addr_t __fdt_pointer __initdata;
 
+static union { char c[8]; unsigned long l; } endian_test = { { 'l', '?', '?',  '?', '?', '?', '?','b' } };
+#define ENDIANNESS ((char)endian_test.l)
+
 /*
  * Standard memory resources
  */
@@ -117,8 +120,10 @@ static void __init setup_processor(void)
 
 	printk("CPU: %s [%08x] revision %d\n",
 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
-
-	sprintf(init_utsname()->machine, "aarch64");
+	
+	snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
+                 "aarch64", ENDIANNESS);
+	
 	elf_hwcap = 0;
 }
 
@@ -310,9 +315,15 @@ static const char *hwcap_str[] = {
 static int c_show(struct seq_file *m, void *v)
 {
 	int i;
+#if 0
+	int num = 1;
+	char c;
+	char *cptr = (char *)#
+	c = (*cptr) ? 'l' : 'b';
+#endif
 
-	seq_printf(m, "Processor\t: %s rev %d (%s)\n",
-		   cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
+	seq_printf(m, "Processor\t: %s rev %d (%s%c)\n",
+		   cpu_name, read_cpuid_id() & 15, ELF_PLATFORM, ENDIANNESS);
 
 	for_each_online_cpu(i) {
 		/*
diff --git a/arch/arm64/kernel/smp_spin_table.c b/arch/arm64/kernel/smp_spin_table.c
index 7c35fa6..7ad68bc 100644
--- a/arch/arm64/kernel/smp_spin_table.c
+++ b/arch/arm64/kernel/smp_spin_table.c
@@ -46,9 +46,10 @@ static int __init smp_spin_table_prepare_cpu(int cpu)
 
 	if (!cpu_release_addr[cpu])
 		return -ENODEV;
-
+	
 	release_addr = __va(cpu_release_addr[cpu]);
-	release_addr[0] = (void *)__pa(secondary_holding_pen);
+	release_addr[0] = (void *)cpu_to_le64(__pa(secondary_holding_pen));	
+
 	__flush_dcache_area(release_addr, sizeof(release_addr[0]));
 
 	/*
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index b1b31bb..380a707 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -166,5 +166,5 @@ ENDPROC(__cpu_setup)
 	 */
 	.type	crval, #object
 crval:
-	.word	0x030802e2			// clear
+	.word	0x000802e2			// clear
 	.word	0x0405d11d			// set
-- 
1.7.9.5




More information about the linux-arm-kernel mailing list