]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - arch/arm/kernel/head.S
ARM: move CP15 definitions to separate header file
[linux-3.10.git] / arch / arm / kernel / head.S
index 136abb610948461f00596edb4d658253b37e4faf..a2e9694a68eec8693ac1597da2827ad4edfec9b6 100644 (file)
 #include <linux/init.h>
 
 #include <asm/assembler.h>
+#include <asm/cp15.h>
 #include <asm/domain.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
 #include <asm/memory.h>
 #include <asm/thread_info.h>
-#include <asm/system.h>
+#include <asm/pgtable.h>
 
 #ifdef CONFIG_DEBUG_LL
 #include <mach/debug-macro.S>
 #define KERNEL_RAM_VADDR       (PAGE_OFFSET + TEXT_OFFSET)
 #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
 #error KERNEL_RAM_VADDR must start at 0xXXXX8000
+#endif
+
+#ifdef CONFIG_ARM_LPAE
+       /* LPAE requires an additional page for the PGD */
+#define PG_DIR_SIZE    0x5000
+#define PMD_ORDER      3
+#else
+#define PG_DIR_SIZE    0x4000
+#define PMD_ORDER      2
 #endif
 
        .globl  swapper_pg_dir
-       .equ    swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
+       .equ    swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
 
        .macro  pgtbl, rd, phys
-       add     \rd, \phys, #TEXT_OFFSET - 0x4000
+       add     \rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE
        .endm
 
 #ifdef CONFIG_XIP_KERNEL
@@ -89,13 +99,21 @@ ENTRY(stext)
  THUMB( it     eq )            @ force fixup-able long branch encoding
        beq     __error_p                       @ yes, error 'p'
 
+#ifdef CONFIG_ARM_LPAE
+       mrc     p15, 0, r3, c0, c1, 4           @ read ID_MMFR0
+       and     r3, r3, #0xf                    @ extract VMSA support
+       cmp     r3, #5                          @ long-descriptor translation table format?
+ THUMB( it     lo )                            @ force fixup-able long branch encoding
+       blo     __error_p                       @ only classic page table format
+#endif
+
 #ifndef CONFIG_XIP_KERNEL
        adr     r3, 2f
        ldmia   r3, {r4, r8}
        sub     r4, r3, r4                      @ (PHYS_OFFSET - PAGE_OFFSET)
        add     r8, r8, r4                      @ PHYS_OFFSET
 #else
-       ldr     r8, =PLAT_PHYS_OFFSET
+       ldr     r8, =PHYS_OFFSET                @ always constant in this case
 #endif
 
        /*
@@ -148,11 +166,11 @@ __create_page_tables:
        pgtbl   r4, r8                          @ page table address
 
        /*
-        * Clear the 16K level 1 swapper page table
+        * Clear the swapper page table
         */
        mov     r0, r4
        mov     r3, #0
-       add     r6, r0, #0x4000
+       add     r6, r0, #PG_DIR_SIZE
 1:     str     r3, [r0], #4
        str     r3, [r0], #4
        str     r3, [r0], #4
@@ -160,41 +178,60 @@ __create_page_tables:
        teq     r0, r6
        bne     1b
 
+#ifdef CONFIG_ARM_LPAE
+       /*
+        * Build the PGD table (first level) to point to the PMD table. A PGD
+        * entry is 64-bit wide.
+        */
+       mov     r0, r4
+       add     r3, r4, #0x1000                 @ first PMD table address
+       orr     r3, r3, #3                      @ PGD block type
+       mov     r6, #4                          @ PTRS_PER_PGD
+       mov     r7, #1 << (55 - 32)             @ L_PGD_SWAPPER
+1:     str     r3, [r0], #4                    @ set bottom PGD entry bits
+       str     r7, [r0], #4                    @ set top PGD entry bits
+       add     r3, r3, #0x1000                 @ next PMD table
+       subs    r6, r6, #1
+       bne     1b
+
+       add     r4, r4, #0x1000                 @ point to the PMD tables
+#endif
+
        ldr     r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
 
        /*
         * Create identity mapping to cater for __enable_mmu.
         * This identity mapping will be removed by paging_init().
         */
-       adr     r0, __enable_mmu_loc
+       adr     r0, __turn_mmu_on_loc
        ldmia   r0, {r3, r5, r6}
        sub     r0, r0, r3                      @ virt->phys offset
-       add     r5, r5, r0                      @ phys __enable_mmu
-       add     r6, r6, r0                      @ phys __enable_mmu_end
-       mov     r5, r5, lsr #20
-       mov     r6, r6, lsr #20
-
-1:     orr     r3, r7, r5, lsl #20             @ flags + kernel base
-       str     r3, [r4, r5, lsl #2]            @ identity mapping
-       teq     r5, r6
-       addne   r5, r5, #1                      @ next section
-       bne     1b
+       add     r5, r5, r0                      @ phys __turn_mmu_on
+       add     r6, r6, r0                      @ phys __turn_mmu_on_end
+       mov     r5, r5, lsr #SECTION_SHIFT
+       mov     r6, r6, lsr #SECTION_SHIFT
+
+1:     orr     r3, r7, r5, lsl #SECTION_SHIFT  @ flags + kernel base
+       str     r3, [r4, r5, lsl #PMD_ORDER]    @ identity mapping
+       cmp     r5, r6
+       addlo   r5, r5, #1                      @ next section
+       blo     1b
 
        /*
         * Now setup the pagetables for our kernel direct
         * mapped region.
         */
        mov     r3, pc
-       mov     r3, r3, lsr #20
-       orr     r3, r7, r3, lsl #20
-       add     r0, r4,  #(KERNEL_START & 0xff000000) >> 18
-       str     r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
+       mov     r3, r3, lsr #SECTION_SHIFT
+       orr     r3, r7, r3, lsl #SECTION_SHIFT
+       add     r0, r4,  #(KERNEL_START & 0xff000000) >> (SECTION_SHIFT - PMD_ORDER)
+       str     r3, [r0, #((KERNEL_START & 0x00f00000) >> SECTION_SHIFT) << PMD_ORDER]!
        ldr     r6, =(KERNEL_END - 1)
-       add     r0, r0, #4
-       add     r6, r4, r6, lsr #18
+       add     r0, r0, #1 << PMD_ORDER
+       add     r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
 1:     cmp     r0, r6
-       add     r3, r3, #1 << 20
-       strls   r3, [r0], #4
+       add     r3, r3, #1 << SECTION_SHIFT
+       strls   r3, [r0], #1 << PMD_ORDER
        bls     1b
 
 #ifdef CONFIG_XIP_KERNEL
@@ -203,11 +240,11 @@ __create_page_tables:
         */
        add     r3, r8, #TEXT_OFFSET
        orr     r3, r3, r7
-       add     r0, r4,  #(KERNEL_RAM_VADDR & 0xff000000) >> 18
-       str     r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
+       add     r0, r4,  #(KERNEL_RAM_VADDR & 0xff000000) >> (SECTION_SHIFT - PMD_ORDER)
+       str     r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> (SECTION_SHIFT - PMD_ORDER)]!
        ldr     r6, =(_end - 1)
        add     r0, r0, #4
-       add     r6, r4, r6, lsr #18
+       add     r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
 1:     cmp     r0, r6
        add     r3, r3, #1 << 20
        strls   r3, [r0], #4
@@ -215,15 +252,15 @@ __create_page_tables:
 #endif
 
        /*
-        * Then map boot params address in r2 or
-        * the first 1MB of ram if boot params address is not specified.
+        * Then map boot params address in r2 or the first 1MB (2MB with LPAE)
+        * of ram if boot params address is not specified.
         */
-       mov     r0, r2, lsr #20
-       movs    r0, r0, lsl #20
+       mov     r0, r2, lsr #SECTION_SHIFT
+       movs    r0, r0, lsl #SECTION_SHIFT
        moveq   r0, r8
        sub     r3, r0, r8
        add     r3, r3, #PAGE_OFFSET
-       add     r3, r4, r3, lsr #18
+       add     r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
        orr     r6, r7, r0
        str     r6, [r3]
 
@@ -234,23 +271,31 @@ __create_page_tables:
         * This allows debug messages to be output
         * via a serial console before paging_init.
         */
-       addruart r7, r3
+       addruart r7, r3, r0
 
-       mov     r3, r3, lsr #20
-       mov     r3, r3, lsl #2
+       mov     r3, r3, lsr #SECTION_SHIFT
+       mov     r3, r3, lsl #PMD_ORDER
 
        add     r0, r4, r3
        rsb     r3, r3, #0x4000                 @ PTRS_PER_PGD*sizeof(long)
        cmp     r3, #0x0800                     @ limit to 512MB
        movhi   r3, #0x0800
        add     r6, r0, r3
-       mov     r3, r7, lsr #20
+       mov     r3, r7, lsr #SECTION_SHIFT
        ldr     r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
-       orr     r3, r7, r3, lsl #20
+       orr     r3, r7, r3, lsl #SECTION_SHIFT
+#ifdef CONFIG_ARM_LPAE
+       mov     r7, #1 << (54 - 32)             @ XN
+#else
+       orr     r3, r3, #PMD_SECT_XN
+#endif
 1:     str     r3, [r0], #4
-       add     r3, r3, #1 << 20
-       teq     r0, r6
-       bne     1b
+#ifdef CONFIG_ARM_LPAE
+       str     r7, [r0], #4
+#endif
+       add     r3, r3, #1 << SECTION_SHIFT
+       cmp     r0, r6
+       blo     1b
 
 #else /* CONFIG_DEBUG_ICEDCC */
        /* we don't need any serial debugging mappings for ICEDCC */
@@ -262,7 +307,7 @@ __create_page_tables:
         * If we're using the NetWinder or CATS, we also need to map
         * in the 16550-type serial port for the debug messages
         */
-       add     r0, r4, #0xff000000 >> 18
+       add     r0, r4, #0xff000000 >> (SECTION_SHIFT - PMD_ORDER)
        orr     r3, r7, #0x7c000000
        str     r3, [r0]
 #endif
@@ -272,21 +317,24 @@ __create_page_tables:
         * Similar reasons here - for debug.  This is
         * only for Acorn RiscPC architectures.
         */
-       add     r0, r4, #0x02000000 >> 18
+       add     r0, r4, #0x02000000 >> (SECTION_SHIFT - PMD_ORDER)
        orr     r3, r7, #0x02000000
        str     r3, [r0]
-       add     r0, r4, #0xd8000000 >> 18
+       add     r0, r4, #0xd8000000 >> (SECTION_SHIFT - PMD_ORDER)
        str     r3, [r0]
 #endif
+#endif
+#ifdef CONFIG_ARM_LPAE
+       sub     r4, r4, #0x1000         @ point to the PGD table
 #endif
        mov     pc, lr
 ENDPROC(__create_page_tables)
        .ltorg
        .align
-__enable_mmu_loc:
+__turn_mmu_on_loc:
        .long   .
-       .long   __enable_mmu
-       .long   __enable_mmu_end
+       .long   __turn_mmu_on
+       .long   __turn_mmu_on_end
 
 #if defined(CONFIG_SMP)
        __CPUINIT
@@ -356,7 +404,7 @@ __secondary_data:
  *  r13 = *virtual* address to jump to upon completion
  */
 __enable_mmu:
-#ifdef CONFIG_ALIGNMENT_TRAP
+#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
        orr     r0, r0, #CR_A
 #else
        bic     r0, r0, #CR_A
@@ -370,12 +418,17 @@ __enable_mmu:
 #ifdef CONFIG_CPU_ICACHE_DISABLE
        bic     r0, r0, #CR_I
 #endif
+#ifdef CONFIG_ARM_LPAE
+       mov     r5, #0
+       mcrr    p15, 0, r4, r5, c2              @ load TTBR0
+#else
        mov     r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
                      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
                      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
                      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
        mcr     p15, 0, r5, c3, c0, 0           @ load domain access register
        mcr     p15, 0, r4, c2, c0, 0           @ load page table pointer
+#endif
        b       __turn_mmu_on
 ENDPROC(__enable_mmu)
 
@@ -394,15 +447,19 @@ ENDPROC(__enable_mmu)
  * other registers depend on the function called upon completion
  */
        .align  5
-__turn_mmu_on:
+       .pushsection    .idmap.text, "ax"
+ENTRY(__turn_mmu_on)
        mov     r0, r0
+       instr_sync
        mcr     p15, 0, r0, c1, c0, 0           @ write control reg
        mrc     p15, 0, r3, c0, c0, 0           @ read id reg
+       instr_sync
        mov     r3, r3
        mov     r3, r13
        mov     pc, r3
-__enable_mmu_end:
+__turn_mmu_on_end:
 ENDPROC(__turn_mmu_on)
+       .popsection
 
 
 #ifdef CONFIG_SMP_ON_UP