[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