Add core support for ARMv6/v7 big-endian
authorCatalin Marinas <catalin.marinas@arm.com>
Sat, 30 May 2009 13:00:18 +0000 (14:00 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Sat, 30 May 2009 13:00:18 +0000 (14:00 +0100)
Starting with ARMv6, the CPUs support the BE-8 variant of big-endian
(byte-invariant). This patch adds the core support:

- setting of the BE-8 mode via the CPSR.E register for both kernel and
  user threads
- big-endian page table walking
- REV used to rotate instructions read from memory during fault
  processing as they are still little-endian format
- Kconfig and Makefile support for BE-8. The --be8 option must be passed
  to the final linking stage to convert the instructions to
  little-endian

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
12 files changed:
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head.S
arch/arm/include/asm/processor.h
arch/arm/include/asm/ptrace.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/process.c
arch/arm/mm/Kconfig
arch/arm/mm/abort-ev6.S
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S

index e84729b..1167a4e 100644 (file)
@@ -11,6 +11,9 @@
 # Copyright (C) 1995-2001 by Russell King
 
 LDFLAGS_vmlinux        :=-p --no-undefined -X
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux        += --be8
+endif
 CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
 OBJCOPYFLAGS   :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
 GZFLAGS                :=-9
index fbe5eef..ce39dc5 100644 (file)
@@ -40,7 +40,7 @@ ifeq ($(CONFIG_PXA_SHARPSL),y)
 OBJS           += head-sharpsl.o
 endif
 
-ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
+ifeq ($(CONFIG_CPU_ENDIAN_BE32),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS           += big-endian.o
 else
@@ -78,6 +78,9 @@ EXTRA_AFLAGS  := -Wa,-march=all
 # linker symbols.  We only define initrd_phys and params_phys if the
 # machine class defined the corresponding makefile variable.
 LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR)
+ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+LDFLAGS_vmlinux += --be8
+endif
 ifneq ($(INITRD_PHYS),)
 LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS)
 endif
index b371fba..01d49be 100644 (file)
@@ -438,6 +438,9 @@ __armv4_mmu_cache_on:
                mrc     p15, 0, r0, c1, c0, 0   @ read control reg
                orr     r0, r0, #0x5000         @ I-cache enable, RR cache replacement
                orr     r0, r0, #0x0030
+#ifdef CONFIG_CPU_ENDIAN_BE8
+               orr     r0, r0, #1 << 25        @ big-endian page tables
+#endif
                bl      __common_mmu_cache_on
                mov     r0, #0
                mcr     p15, 0, r0, c8, c7, 0   @ flush I,D TLBs
@@ -455,6 +458,9 @@ __armv7_mmu_cache_on:
                mrc     p15, 0, r0, c1, c0, 0   @ read control reg
                orr     r0, r0, #0x5000         @ I-cache enable, RR cache replacement
                orr     r0, r0, #0x003c         @ write buffer
+#ifdef CONFIG_CPU_ENDIAN_BE8
+               orr     r0, r0, #1 << 25        @ big-endian page tables
+#endif
                orrne   r0, r0, #1              @ MMU enabled
                movne   r1, #-1
                mcrne   p15, 0, r3, c2, c0, 0   @ load page table pointer
index 1845892..6a89567 100644 (file)
@@ -71,6 +71,7 @@ struct thread_struct {
                regs->ARM_cpsr = USR26_MODE;                            \
        if (elf_hwcap & HWCAP_THUMB && pc & 1)                          \
                regs->ARM_cpsr |= PSR_T_BIT;                            \
+       regs->ARM_cpsr |= PSR_ENDSTATE;                                 \
        regs->ARM_pc = pc & ~1;         /* pc */                        \
        regs->ARM_sp = sp;              /* sp */                        \
        regs->ARM_r2 = stack[2];        /* r2 (envp) */                 \
index 4a4290f..67b833c 100644 (file)
@@ -50,6 +50,7 @@
 #define PSR_F_BIT      0x00000040
 #define PSR_I_BIT      0x00000080
 #define PSR_A_BIT      0x00000100
+#define PSR_E_BIT      0x00000200
 #define PSR_J_BIT      0x01000000
 #define PSR_Q_BIT      0x08000000
 #define PSR_V_BIT      0x10000000
 #define PSR_IT_MASK    0x0600fc00      /* If-Then execution state mask */
 #define PSR_ENDIAN_MASK        0x00000200      /* Endianness state mask */
 
+/*
+ * Default endianness state
+ */
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define PSR_ENDSTATE   PSR_E_BIT
+#else
+#define PSR_ENDSTATE   0
+#endif
+
 #ifndef __ASSEMBLY__
 
 /*
index d662a2f..9d7ce43 100644 (file)
@@ -482,6 +482,9 @@ __und_usr:
        subeq   r4, r2, #4                      @ ARM instr at LR - 4
        subne   r4, r2, #2                      @ Thumb instr at LR - 2
 1:     ldreqt  r0, [r4]
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       reveq   r0, r0                          @ little endian instruction
+#endif
        beq     call_fpe
        @ Thumb instruction
 #if __LINUX_ARM_ARCH__ >= 7
index b55cb03..366e509 100644 (file)
@@ -210,6 +210,9 @@ ENTRY(vector_swi)
   A710(        teq     ip, #0x0f000000                                         )
   A710(        bne     .Larm710bug                                             )
 #endif
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       rev     r10, r10                        @ little endian instruction
+#endif
 
 #elif defined(CONFIG_AEABI)
 
index c3265a2..1585423 100644 (file)
@@ -365,7 +365,7 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
        regs.ARM_r2 = (unsigned long)fn;
        regs.ARM_r3 = (unsigned long)do_exit;
        regs.ARM_pc = (unsigned long)kernel_thread_helper;
-       regs.ARM_cpsr = SVC_MODE;
+       regs.ARM_cpsr = SVC_MODE | PSR_ENDSTATE;
 
        return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
 }
index 76bbcde..a25f34b 100644 (file)
@@ -639,6 +639,20 @@ config CPU_BIG_ENDIAN
          port must properly enable any big-endian related features
          of your chipset/board/processor.
 
+config CPU_ENDIAN_BE8
+       bool
+       depends on CPU_BIG_ENDIAN
+       default CPU_V6 || CPU_V7
+       help
+         Support for the BE-8 (big-endian) mode on ARMv6 and ARMv7 processors.
+
+config CPU_ENDIAN_BE32
+       bool
+       depends on CPU_BIG_ENDIAN
+       default !CPU_ENDIAN_BE8
+       help
+         Support for the BE-32 (big-endian) mode on pre-ARMv6 processors.
+
 config CPU_HIGH_VECTOR
        depends on !MMU && CPU_CP15 && !CPU_ARM740T
        bool "Select the High exception vector"
index 6f7e709..f332df7 100644 (file)
@@ -37,6 +37,9 @@ ENTRY(v6_early_abort)
        movne   pc, lr
        do_thumb_abort
        ldreq   r3, [r2]                        @ read aborted ARM instruction
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       reveq   r3, r3
+#endif
        do_ldrd_abort
        tst     r3, #1 << 20                    @ L = 0 -> write
        orreq   r1, r1, #1 << 11                @ yes.
index 087e239..524ddae 100644 (file)
@@ -170,6 +170,9 @@ __v6_setup:
 #endif /* CONFIG_MMU */
        adr     r5, v6_crval
        ldmia   r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       orr     r6, r6, #1 << 25                @ big-endian page tables
+#endif
        mrc     p15, 0, r0, c1, c0, 0           @ read control register
        bic     r0, r0, r5                      @ clear bits them
        orr     r0, r0, r6                      @ set them
index 0a8ffd3..4f84864 100644 (file)
@@ -253,6 +253,9 @@ __v7_setup:
        mcr     p15, 0, r6, c10, c2, 1          @ write NMRR
        adr     r5, v7_crval
        ldmia   r5, {r5, r6}
+#ifdef CONFIG_CPU_ENDIAN_BE8
+       orr     r6, r6, #1 << 25                @ big-endian page tables
+#endif
        mrc     p15, 0, r0, c1, c0, 0           @ read control register
        bic     r0, r0, r5                      @ clear bits them
        orr     r0, r0, r6                      @ set them