Message ID | 1312988619-16804-10-git-send-email-catalin.marinas@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wednesday 10 August 2011 18:03:32 Catalin Marinas wrote: > This patch adds the MMU initialisation for the LPAE page table format. > The swapper_pg_dir size with LPAE is 5 rather than 4 pages. A new > proc-v7lpae.S file contains the initialisation, context switch and > save/restore code for ARMv7 with the LPAE. The TTBRx split is based on > the PAGE_OFFSET with TTBR1 used for the kernel mappings. The 36-bit > mappings (supersections) and a few other memory types in mmu.c are > conditionally compiled. Looks like this patch breaks ARMv4. I can't boot kernel anymore on my s3c2442- based PDA after this patch. Reverting it helps. Any ideas? > Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> > --- > arch/arm/kernel/head.S | 117 +++++++++---- > arch/arm/mm/Makefile | 4 + > arch/arm/mm/mmu.c | 34 ++++- > arch/arm/mm/proc-macros.S | 5 +- > arch/arm/mm/proc-v7lpae.S | 422 > +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 542 > insertions(+), 40 deletions(-) > create mode 100644 arch/arm/mm/proc-v7lpae.S > > diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S > index d8231b2..0bdafc4 100644 > --- a/arch/arm/kernel/head.S > +++ b/arch/arm/kernel/head.S > @@ -21,6 +21,7 @@ > #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> > @@ -38,11 +39,20 @@ > #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 > @@ -148,11 +158,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,6 +170,25 @@ __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 > > /* > @@ -171,30 +200,30 @@ __create_page_tables: > 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 > + mov r5, r5, lsr #SECTION_SHIFT > + mov r6, r6, lsr #SECTION_SHIFT > > -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 > +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, #SECTION_SHIFT >> 20 @ 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 & 0x00e00000) >> (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 +232,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 +244,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] > > @@ -236,21 +265,27 @@ __create_page_tables: > */ > addruart r7, r3 > > - 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 > +#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 +297,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,13 +307,16 @@ __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 > @@ -370,12 +408,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) > > diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile > index bca7e61..48639e7 100644 > --- a/arch/arm/mm/Makefile > +++ b/arch/arm/mm/Makefile > @@ -91,7 +91,11 @@ obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o > obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o > obj-$(CONFIG_CPU_V6) += proc-v6.o > obj-$(CONFIG_CPU_V6K) += proc-v6.o > +ifeq ($(CONFIG_ARM_LPAE),y) > +obj-$(CONFIG_CPU_V7) += proc-v7lpae.o > +else > obj-$(CONFIG_CPU_V7) += proc-v7.o > +endif > > AFLAGS_proc-v6.o :=-Wa,-march=armv6 > AFLAGS_proc-v7.o :=-Wa,-march=armv7-a > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c > index c990280..1ba2a5a 100644 > --- a/arch/arm/mm/mmu.c > +++ b/arch/arm/mm/mmu.c > @@ -150,6 +150,7 @@ static int __init early_nowrite(char *__unused) > } > early_param("nowb", early_nowrite); > > +#ifndef CONFIG_ARM_LPAE > static int __init early_ecc(char *p) > { > if (memcmp(p, "on", 2) == 0) > @@ -159,6 +160,7 @@ static int __init early_ecc(char *p) > return 0; > } > early_param("ecc", early_ecc); > +#endif > > static int __init noalign_setup(char *__unused) > { > @@ -228,10 +230,12 @@ static struct mem_type mem_types[] = { > .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, > .domain = DOMAIN_KERNEL, > }, > +#ifndef CONFIG_ARM_LPAE > [MT_MINICLEAN] = { > .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE, > .domain = DOMAIN_KERNEL, > }, > +#endif > [MT_LOW_VECTORS] = { > .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | > L_PTE_RDONLY, > @@ -421,6 +425,7 @@ static void __init build_mem_type_table(void) > * ARMv6 and above have extended page tables. > */ > if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { > +#ifndef CONFIG_ARM_LPAE > /* > * Mark cache clean areas and XIP ROM read only > * from SVC mode and no access from userspace. > @@ -428,6 +433,7 @@ static void __init build_mem_type_table(void) > mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; > mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; > mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; > +#endif > > if (is_smp()) { > /* > @@ -466,6 +472,18 @@ static void __init build_mem_type_table(void) > mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; > } > > +#ifdef CONFIG_ARM_LPAE > + /* > + * Do not generate access flag faults for the kernel mappings. > + */ > + for (i = 0; i < ARRAY_SIZE(mem_types); i++) { > + mem_types[i].prot_pte |= PTE_EXT_AF; > + mem_types[i].prot_sect |= PMD_SECT_AF; > + } > + kern_pgprot |= PTE_EXT_AF; > + vecs_pgprot |= PTE_EXT_AF; > +#endif > + > for (i = 0; i < 16; i++) { > unsigned long v = pgprot_val(protection_map[i]); > protection_map[i] = __pgprot(v | user_pgprot); > @@ -564,8 +582,10 @@ static void __init alloc_init_section(pud_t *pud, > unsigned long addr, if (((addr | end | phys) & ~SECTION_MASK) == 0) { > pmd_t *p = pmd; > > +#ifndef CONFIG_ARM_LPAE > if (addr & SECTION_SIZE) > pmd++; > +#endif > > do { > *pmd = __pmd(phys | type->prot_sect); > @@ -595,6 +615,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long > addr, unsigned long end, } while (pud++, addr = next, addr != end); > } > > +#ifndef CONFIG_ARM_LPAE > static void __init create_36bit_mapping(struct map_desc *md, > const struct mem_type *type) > { > @@ -654,6 +675,7 @@ static void __init create_36bit_mapping(struct map_desc > *md, pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT; > } while (addr != end); > } > +#endif /* !CONFIG_ARM_LPAE */ > > /* > * Create the page directory entries and any necessary > @@ -685,6 +707,7 @@ static void __init create_mapping(struct map_desc *md) > > type = &mem_types[md->type]; > > +#ifndef CONFIG_ARM_LPAE > /* > * Catch 36-bit addresses > */ > @@ -692,6 +715,7 @@ static void __init create_mapping(struct map_desc *md) > create_36bit_mapping(md, type); > return; > } > +#endif > > addr = md->virtual & PAGE_MASK; > phys = __pfn_to_phys(md->pfn); > @@ -889,6 +913,14 @@ static inline void prepare_page_table(void) > pmd_clear(pmd_off_k(addr)); > } > > +#ifdef CONFIG_ARM_LPAE > +/* the first page is reserved for pgd */ > +#define SWAPPER_PG_DIR_SIZE (PAGE_SIZE + \ > + PTRS_PER_PGD * PTRS_PER_PMD * sizeof(pmd_t)) > +#else > +#define SWAPPER_PG_DIR_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) > +#endif > + > /* > * Reserve the special regions of memory > */ > @@ -898,7 +930,7 @@ void __init arm_mm_memblock_reserve(void) > * Reserve the page tables. These are already in use, > * and can only be in node 0. > */ > - memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t)); > + memblock_reserve(__pa(swapper_pg_dir), SWAPPER_PG_DIR_SIZE); > > #ifdef CONFIG_SA1111 > /* > diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S > index 307a4de..2d8ff3a 100644 > --- a/arch/arm/mm/proc-macros.S > +++ b/arch/arm/mm/proc-macros.S > @@ -91,8 +91,9 @@ > #if L_PTE_SHARED != PTE_EXT_SHARED > #error PTE shared bit mismatch > #endif > -#if (L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\ > - L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED > +#if !defined (CONFIG_ARM_LPAE) && \ > + (L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\ > + L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED > #error Invalid Linux PTE bit settings > #endif > #endif /* CONFIG_MMU */ > diff --git a/arch/arm/mm/proc-v7lpae.S b/arch/arm/mm/proc-v7lpae.S > new file mode 100644 > index 0000000..0bee213 > --- /dev/null > +++ b/arch/arm/mm/proc-v7lpae.S > @@ -0,0 +1,422 @@ > +/* > + * arch/arm/mm/proc-v7lpae.S > + * > + * Copyright (C) 2001 Deep Blue Solutions Ltd. > + * Copyright (C) 2011 ARM Ltd. > + * Author: Catalin Marinas <catalin.marinas@arm.com> > + * based on arch/arm/mm/proc-v7.S > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + */ > +#include <linux/init.h> > +#include <linux/linkage.h> > +#include <asm/assembler.h> > +#include <asm/asm-offsets.h> > +#include <asm/hwcap.h> > +#include <asm/pgtable-hwdef.h> > +#include <asm/pgtable.h> > + > +#include "proc-macros.S" > + > +#define TTB_IRGN_NC (0 << 8) > +#define TTB_IRGN_WBWA (1 << 8) > +#define TTB_IRGN_WT (2 << 8) > +#define TTB_IRGN_WB (3 << 8) > +#define TTB_RGN_NC (0 << 10) > +#define TTB_RGN_OC_WBWA (1 << 10) > +#define TTB_RGN_OC_WT (2 << 10) > +#define TTB_RGN_OC_WB (3 << 10) > +#define TTB_S (3 << 12) > +#define TTB_EAE (1 << 31) > + > +/* PTWs cacheable, inner WB not shareable, outer WB not shareable */ > +#define TTB_FLAGS_UP (TTB_IRGN_WB|TTB_RGN_OC_WB) > +#define PMD_FLAGS_UP (PMD_SECT_WB) > + > +/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */ > +#define TTB_FLAGS_SMP (TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA) > +#define PMD_FLAGS_SMP (PMD_SECT_WBWA|PMD_SECT_S) > + > +ENTRY(cpu_v7_proc_init) > + mov pc, lr > +ENDPROC(cpu_v7_proc_init) > + > +ENTRY(cpu_v7_proc_fin) > + mrc p15, 0, r0, c1, c0, 0 @ ctrl register > + bic r0, r0, #0x1000 @ ...i............ > + bic r0, r0, #0x0006 @ .............ca. > + mcr p15, 0, r0, c1, c0, 0 @ disable caches > + mov pc, lr > +ENDPROC(cpu_v7_proc_fin) > + > +/* > + * cpu_v7_reset(loc) > + * > + * Perform a soft reset of the system. Put the CPU into the > + * same state as it would be if it had been reset, and branch > + * to what would be the reset vector. > + * > + * - loc - location to jump to for soft reset > + */ > + .align 5 > +ENTRY(cpu_v7_reset) > + mov pc, r0 > +ENDPROC(cpu_v7_reset) > + > +/* > + * cpu_v7_do_idle() > + * > + * Idle the processor (eg, wait for interrupt). > + * > + * IRQs are already disabled. > + */ > +ENTRY(cpu_v7_do_idle) > + dsb @ WFI may enter a low-power mode > + wfi > + mov pc, lr > +ENDPROC(cpu_v7_do_idle) > + > +ENTRY(cpu_v7_dcache_clean_area) > +#ifndef TLB_CAN_READ_FROM_L1_CACHE > + dcache_line_size r2, r3 > +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry > + add r0, r0, r2 > + subs r1, r1, r2 > + bhi 1b > + dsb > +#endif > + mov pc, lr > +ENDPROC(cpu_v7_dcache_clean_area) > + > +/* > + * cpu_v7_switch_mm(pgd_phys, tsk) > + * > + * Set the translation table base pointer to be pgd_phys > + * > + * - pgd_phys - physical address of new TTB > + * > + * It is assumed that: > + * - we are not using split page tables > + */ > +ENTRY(cpu_v7_switch_mm) > +#ifdef CONFIG_MMU > + ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id > + mov r2, #0 > + and r3, r1, #0xff > + mov r3, r3, lsl #(48 - 32) @ ASID > + mcrr p15, 0, r0, r3, c2 @ set TTB 0 > + isb > +#endif > + mov pc, lr > +ENDPROC(cpu_v7_switch_mm) > + > +/* > + * cpu_v7_set_pte_ext(ptep, pte) > + * > + * Set a level 2 translation table entry. > + * > + * - ptep - pointer to level 2 translation table entry > + * (hardware version is stored at +2048 bytes) > + * - pte - PTE value to store > + * - ext - value for extended PTE bits > + */ > +ENTRY(cpu_v7_set_pte_ext) > +#ifdef CONFIG_MMU > + tst r2, #L_PTE_PRESENT > + beq 1f > + tst r3, #1 << (55 - 32) @ L_PTE_DIRTY > + orreq r2, #L_PTE_RDONLY > +1: strd r2, r3, [r0] > + mcr p15, 0, r0, c7, c10, 1 @ flush_pte > +#endif > + mov pc, lr > +ENDPROC(cpu_v7_set_pte_ext) > + > +cpu_v7_name: > + .ascii "ARMv7 Processor" > + .align > + > + /* > + * Memory region attributes for LPAE (defined in pgtable-3level.h): > + * > + * n = AttrIndx[2:0] > + * > + * n MAIR > + * UNCACHED 000 00000000 > + * BUFFERABLE 001 01000100 > + * DEV_WC 001 01000100 > + * WRITETHROUGH 010 10101010 > + * WRITEBACK 011 11101110 > + * DEV_CACHED 011 11101110 > + * DEV_SHARED 100 00000100 > + * DEV_NONSHARED 100 00000100 > + * unused 101 > + * unused 110 > + * WRITEALLOC 111 11111111 > + */ > +.equ MAIR0, 0xeeaa4400 @ MAIR0 > +.equ MAIR1, 0xff000004 @ MAIR1 > + > +/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */ > +.globl cpu_v7_suspend_size > +.equ cpu_v7_suspend_size, 4 * 10 > +#ifdef CONFIG_PM_SLEEP > +ENTRY(cpu_v7_do_suspend) > + stmfd sp!, {r4 - r11, lr} > + mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID > + mrc p15, 0, r5, c13, c0, 1 @ Context ID > + mrc p15, 0, r6, c3, c0, 0 @ Domain ID > + mrrc p15, 0, r7, r8, c2 @ TTB 0 > + mrrc p15, 1, r2, r3, c2 @ TTB 1 > + mrc p15, 0, r9, c1, c0, 0 @ Control register > + mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register > + mrc p15, 0, r11, c1, c0, 2 @ Co-processor access control > + stmia r0, {r2 - r11} > + ldmfd sp!, {r4 - r11, pc} > +ENDPROC(cpu_v7_do_suspend) > + > +ENTRY(cpu_v7_do_resume) > + mov ip, #0 > + mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs > + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache > + ldmia r0, {r2 - r11} > + mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID > + mcr p15, 0, r5, c13, c0, 1 @ Context ID > + mcr p15, 0, r6, c3, c0, 0 @ Domain ID > + mcrr p15, 0, r7, r8, c2 @ TTB 0 > + mcrr p15, 1, r2, r3, c2 @ TTB 1 > + mcr p15, 0, ip, c2, c0, 2 @ TTB control register > + mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register > + mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control > + ldr r4, =MAIR0 > + ldr r5, =MAIR1 > + mcr p15, 0, r4, c10, c2, 0 @ write MAIR0 > + mcr p15, 0, r5, c10, c2, 1 @ write MAIR1 > + isb > + mov r0, r9 @ control register > + mov r2, r7, lsr #14 @ get TTB0 base > + mov r2, r2, lsl #14 > + ldr r3, cpu_resume_l1_flags > + b cpu_resume_mmu > +ENDPROC(cpu_v7_do_resume) > +cpu_resume_l1_flags: > + ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP) > + ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP) > +#else > +#define cpu_v7_do_suspend 0 > +#define cpu_v7_do_resume 0 > +#endif > + > + __CPUINIT > + > +/* > + * __v7_setup > + * > + * Initialise TLB, Caches, and MMU state ready to switch the MMU > + * on. Return in r0 the new CP15 C1 control register setting. > + * > + * This should be able to cover all ARMv7 cores with LPAE. > + * > + * It is assumed that: > + * - cache type register is implemented > + */ > +__v7_ca15mp_setup: > + mov r10, #0 > +1: > +#ifdef CONFIG_SMP > + ALT_SMP(mrc p15, 0, r0, c1, c0, 1) > + ALT_UP(mov r0, #(1 << 6)) @ fake it for UP > + tst r0, #(1 << 6) @ SMP/nAMP mode enabled? > + orreq r0, r0, #(1 << 6) @ Enable SMP/nAMP mode > + orreq r0, r0, r10 @ Enable CPU-specific SMP bits > + mcreq p15, 0, r0, c1, c0, 1 > +#endif > +__v7_setup: > + adr r12, __v7_setup_stack @ the local stack > + stmia r12, {r0-r5, r7, r9, r11, lr} > + bl v7_flush_dcache_all > + ldmia r12, {r0-r5, r7, r9, r11, lr} > + > + mov r10, #0 > + mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate > + dsb > +#ifdef CONFIG_MMU > + mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs > + mov r5, #TTB_EAE > + ALT_SMP(orr r5, r5, #TTB_FLAGS_SMP) > + ALT_SMP(orr r5, r5, #TTB_FLAGS_SMP << 16) > + ALT_UP(orr r5, r5, #TTB_FLAGS_UP) > + ALT_UP(orr r5, r5, #TTB_FLAGS_UP << 16) > + mrc p15, 0, r10, c2, c0, 2 > + orr r10, r10, r5 > +#if PHYS_OFFSET <= PAGE_OFFSET > + /* > + * TTBR0/TTBR1 split (PAGE_OFFSET): > + * 0x40000000: T0SZ = 2, T1SZ = 0 (not used) > + * 0x80000000: T0SZ = 0, T1SZ = 1 > + * 0xc0000000: T0SZ = 0, T1SZ = 2 > + * > + * Only use this feature if PAGE_OFFSET <= PAGE_OFFSET, otherwise > + * booting secondary CPUs would end up using TTBR1 for the identity > + * mapping set up in TTBR0. > + */ > + orr r10, r10, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ > +#endif > + mcr p15, 0, r10, c2, c0, 2 @ TTB control register > + mov r5, #0 > +#if defined CONFIG_VMSPLIT_2G > + /* PAGE_OFFSET == 0x80000000, T1SZ == 1 */ > + add r6, r8, #1 << 4 @ skip two L1 entries > +#elif defined CONFIG_VMSPLIT_3G > + /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */ > + add r6, r8, #4096 * (1 + 3) @ only L2 used, skip pgd+3*pmd > +#else > + mov r6, r8 > +#endif > + mcrr p15, 1, r6, r5, c2 @ load TTBR1 > + ldr r5, =MAIR0 > + ldr r6, =MAIR1 > + mcr p15, 0, r5, c10, c2, 0 @ write MAIR0 > + mcr p15, 0, r6, c10, c2, 1 @ write MAIR1 > +#endif > + adr r5, v7_crval > + ldmia r5, {r5, r6} > +#ifdef CONFIG_CPU_ENDIAN_BE8 > + orr r6, r6, #1 << 25 @ big-endian page tables > +#endif > +#ifdef CONFIG_SWP_EMULATE > + orr r5, r5, #(1 << 10) @ set SW bit in "clear" > + bic r6, r6, #(1 << 10) @ clear it in "mmuset" > +#endif > + mrc p15, 0, r0, c1, c0, 0 @ read control register > + bic r0, r0, r5 @ clear bits them > + orr r0, r0, r6 @ set them > + THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions > + mov pc, lr @ return to head.S:__ret > +ENDPROC(__v7_setup) > + > + /* AT > + * TFR EV X F IHD LR S > + * .EEE ..EE PUI. .TAT 4RVI ZWRS BLDP WCAM > + * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced > + * 11 0 110 1 0011 1100 .111 1101 < we want > + */ > + .type v7_crval, #object > +v7_crval: > + crval clear=0x0120c302, mmuset=0x30c23c7d, ucset=0x00c01c7c > + > +__v7_setup_stack: > + .space 4 * 11 @ 11 registers > + > + __INITDATA > + > + .type v7_processor_functions, #object > +ENTRY(v7_processor_functions) > + .word v7_early_abort > + .word v7_pabort > + .word cpu_v7_proc_init > + .word cpu_v7_proc_fin > + .word cpu_v7_reset > + .word cpu_v7_do_idle > + .word cpu_v7_dcache_clean_area > + .word cpu_v7_switch_mm > + .word cpu_v7_set_pte_ext > + .word 0 > + .word 0 > + .word 0 > + .size v7_processor_functions, . - v7_processor_functions > + > + .section ".rodata" > + > + .type cpu_arch_name, #object > +cpu_arch_name: > + .asciz "armv7" > + .size cpu_arch_name, . - cpu_arch_name > + > + .type cpu_elf_name, #object > +cpu_elf_name: > + .asciz "v7" > + .size cpu_elf_name, . - cpu_elf_name > + .align > + > + .section ".proc.info.init", #alloc, #execinstr > + > + .type __v7_ca15mp_proc_info, #object > +__v7_ca15mp_proc_info: > + .long 0x410fc0f0 @ Required ID value > + .long 0xff0ffff0 @ Mask for ID > + ALT_SMP(.long \ > + PMD_TYPE_SECT | \ > + PMD_SECT_AP_WRITE | \ > + PMD_SECT_AP_READ | \ > + PMD_SECT_AF | \ > + PMD_FLAGS_SMP) > + ALT_UP(.long \ > + PMD_TYPE_SECT | \ > + PMD_SECT_AP_WRITE | \ > + PMD_SECT_AP_READ | \ > + PMD_SECT_AF | \ > + PMD_FLAGS_UP) > + /* PMD_SECT_XN is set explicitly in head.S for LPAE */ > + .long PMD_TYPE_SECT | \ > + PMD_SECT_XN | \ > + PMD_SECT_AP_WRITE | \ > + PMD_SECT_AP_READ | \ > + PMD_SECT_AF > + b __v7_ca15mp_setup > + .long cpu_arch_name > + .long cpu_elf_name > + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP| HWCAP_T > LS + .long cpu_v7_name > + .long v7_processor_functions > + .long v7wbi_tlb_fns > + .long v6_user_fns > + .long v7_cache_fns > + .size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info > + > + /* > + * Match any ARMv7 processor core. > + */ > + .type __v7_proc_info, #object > +__v7_proc_info: > + .long 0x000f0000 @ Required ID value > + .long 0x000f0000 @ Mask for ID > + ALT_SMP(.long \ > + PMD_TYPE_SECT | \ > + PMD_SECT_AP_WRITE | \ > + PMD_SECT_AP_READ | \ > + PMD_SECT_AF | \ > + PMD_FLAGS_SMP) > + ALT_UP(.long \ > + PMD_TYPE_SECT | \ > + PMD_SECT_AP_WRITE | \ > + PMD_SECT_AP_READ | \ > + PMD_SECT_AF | \ > + PMD_FLAGS_UP) > + /* PMD_SECT_XN is set explicitly in head.S for LPAE */ > + .long PMD_TYPE_SECT | \ > + PMD_SECT_XN | \ > + PMD_SECT_AP_WRITE | \ > + PMD_SECT_AP_READ | \ > + PMD_SECT_AF > + W(b) __v7_setup > + .long cpu_arch_name > + .long cpu_elf_name > + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP| HWCAP_T > LS + .long cpu_v7_name > + .long v7_processor_functions > + .long v7wbi_tlb_fns > + .long v6_user_fns > + .long v7_cache_fns > + .size __v7_proc_info, . - __v7_proc_info > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Wed, 2011-08-10 at 16:03 +0100, Catalin Marinas wrote: > +/* > + * cpu_v7_set_pte_ext(ptep, pte) > + * > + * Set a level 2 translation table entry. > + * > + * - ptep - pointer to level 2 translation table entry > + * (hardware version is stored at +2048 bytes) +2048 thing not true for LPAE? > + * - pte - PTE value to store > + * - ext - value for extended PTE bits "ext" is not actually present/used in this variant, rather pte is split between r1 and r2? > + */ > +ENTRY(cpu_v7_set_pte_ext) > +#ifdef CONFIG_MMU > + tst r2, #L_PTE_PRESENT > + beq 1f > + tst r3, #1 << (55 - 32) @ L_PTE_DIRTY > + orreq r2, #L_PTE_RDONLY > +1: strd r2, r3, [r0] AIUI this 64-bit store is not atomic. Is there something about the ARM architecture which would prevent the MMU prefetching the half written entry and caching it in the TLB? i.e. If you are transitioning from a "0..0 | 0..0 (!L_PTE_PRESENT)" entry to a "ST | UFF ( L_PTE_PRESENT)" entry you will temporarily be in the "0..0 | UFF ( L_PTE_PRESENT)" state. (or vice versa going the other way if you do the writes in the other order). This might mean that a subsequent access through the VA corresponding to this PTE goes to the wrong place. I'm asking because we had a very subtle bug on x86 Xen relating to this sort of issue ages ago, it was hell to debug ;-). Ian. > + mcr p15, 0, r0, c7, c10, 1 @ flush_pte > +#endif > + mov pc, lr > +ENDPROC(cpu_v7_set_pte_ext)
On Fri, Aug 19, 2011 at 11:25:57AM +0100, Ian Campbell wrote: > On Wed, 2011-08-10 at 16:03 +0100, Catalin Marinas wrote: > > +/* > > + * cpu_v7_set_pte_ext(ptep, pte) > > + * > > + * Set a level 2 translation table entry. > > + * > > + * - ptep - pointer to level 2 translation table entry > > + * (hardware version is stored at +2048 bytes) > > +2048 thing not true for LPAE? > > > + * - pte - PTE value to store > > + * - ext - value for extended PTE bits > > "ext" is not actually present/used in this variant, rather pte is split > between r1 and r2? Yes, you are right, the comments have just been copied from proc-v7.S. I'll go through them again make sure they are still valid. > > + */ > > +ENTRY(cpu_v7_set_pte_ext) > > +#ifdef CONFIG_MMU > > + tst r2, #L_PTE_PRESENT > > + beq 1f > > + tst r3, #1 << (55 - 32) @ L_PTE_DIRTY > > + orreq r2, #L_PTE_RDONLY > > +1: strd r2, r3, [r0] > > AIUI this 64-bit store is not atomic. Is there something about the ARM > architecture which would prevent the MMU prefetching the half written > entry and caching it in the TLB? CPU implementations that include LPAE guarantee the atomicity of a double-word store (STRD) if the alignment is correct. Thanks.
On Fri, 2011-08-19 at 12:10 +0100, Catalin Marinas wrote: > > > > + */ > > > +ENTRY(cpu_v7_set_pte_ext) > > > +#ifdef CONFIG_MMU > > > + tst r2, #L_PTE_PRESENT > > > + beq 1f > > > + tst r3, #1 << (55 - 32) @ L_PTE_DIRTY > > > + orreq r2, #L_PTE_RDONLY > > > +1: strd r2, r3, [r0] > > > > AIUI this 64-bit store is not atomic. Is there something about the > ARM > > architecture which would prevent the MMU prefetching the half > written > > entry and caching it in the TLB? > > CPU implementations that include LPAE guarantee the atomicity of a > double-word store (STRD) if the alignment is correct. Ah, I was looking at the standard v7 docs and not the LPAE extensions, I see it now. Thanks, Ian.
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index d8231b2..0bdafc4 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -21,6 +21,7 @@ #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> @@ -38,11 +39,20 @@ #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 @@ -148,11 +158,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,6 +170,25 @@ __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 /* @@ -171,30 +200,30 @@ __create_page_tables: 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 + mov r5, r5, lsr #SECTION_SHIFT + mov r6, r6, lsr #SECTION_SHIFT -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 +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, #SECTION_SHIFT >> 20 @ 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 & 0x00e00000) >> (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 +232,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 +244,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] @@ -236,21 +265,27 @@ __create_page_tables: */ addruart r7, r3 - 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 +#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 +297,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,13 +307,16 @@ __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 @@ -370,12 +408,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) diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index bca7e61..48639e7 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -91,7 +91,11 @@ obj-$(CONFIG_CPU_MOHAWK) += proc-mohawk.o obj-$(CONFIG_CPU_FEROCEON) += proc-feroceon.o obj-$(CONFIG_CPU_V6) += proc-v6.o obj-$(CONFIG_CPU_V6K) += proc-v6.o +ifeq ($(CONFIG_ARM_LPAE),y) +obj-$(CONFIG_CPU_V7) += proc-v7lpae.o +else obj-$(CONFIG_CPU_V7) += proc-v7.o +endif AFLAGS_proc-v6.o :=-Wa,-march=armv6 AFLAGS_proc-v7.o :=-Wa,-march=armv7-a diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index c990280..1ba2a5a 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -150,6 +150,7 @@ static int __init early_nowrite(char *__unused) } early_param("nowb", early_nowrite); +#ifndef CONFIG_ARM_LPAE static int __init early_ecc(char *p) { if (memcmp(p, "on", 2) == 0) @@ -159,6 +160,7 @@ static int __init early_ecc(char *p) return 0; } early_param("ecc", early_ecc); +#endif static int __init noalign_setup(char *__unused) { @@ -228,10 +230,12 @@ static struct mem_type mem_types[] = { .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, +#ifndef CONFIG_ARM_LPAE [MT_MINICLEAN] = { .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE, .domain = DOMAIN_KERNEL, }, +#endif [MT_LOW_VECTORS] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_RDONLY, @@ -421,6 +425,7 @@ static void __init build_mem_type_table(void) * ARMv6 and above have extended page tables. */ if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { +#ifndef CONFIG_ARM_LPAE /* * Mark cache clean areas and XIP ROM read only * from SVC mode and no access from userspace. @@ -428,6 +433,7 @@ static void __init build_mem_type_table(void) mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE; +#endif if (is_smp()) { /* @@ -466,6 +472,18 @@ static void __init build_mem_type_table(void) mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_BUFFERABLE; } +#ifdef CONFIG_ARM_LPAE + /* + * Do not generate access flag faults for the kernel mappings. + */ + for (i = 0; i < ARRAY_SIZE(mem_types); i++) { + mem_types[i].prot_pte |= PTE_EXT_AF; + mem_types[i].prot_sect |= PMD_SECT_AF; + } + kern_pgprot |= PTE_EXT_AF; + vecs_pgprot |= PTE_EXT_AF; +#endif + for (i = 0; i < 16; i++) { unsigned long v = pgprot_val(protection_map[i]); protection_map[i] = __pgprot(v | user_pgprot); @@ -564,8 +582,10 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr, if (((addr | end | phys) & ~SECTION_MASK) == 0) { pmd_t *p = pmd; +#ifndef CONFIG_ARM_LPAE if (addr & SECTION_SIZE) pmd++; +#endif do { *pmd = __pmd(phys | type->prot_sect); @@ -595,6 +615,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, } while (pud++, addr = next, addr != end); } +#ifndef CONFIG_ARM_LPAE static void __init create_36bit_mapping(struct map_desc *md, const struct mem_type *type) { @@ -654,6 +675,7 @@ static void __init create_36bit_mapping(struct map_desc *md, pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT; } while (addr != end); } +#endif /* !CONFIG_ARM_LPAE */ /* * Create the page directory entries and any necessary @@ -685,6 +707,7 @@ static void __init create_mapping(struct map_desc *md) type = &mem_types[md->type]; +#ifndef CONFIG_ARM_LPAE /* * Catch 36-bit addresses */ @@ -692,6 +715,7 @@ static void __init create_mapping(struct map_desc *md) create_36bit_mapping(md, type); return; } +#endif addr = md->virtual & PAGE_MASK; phys = __pfn_to_phys(md->pfn); @@ -889,6 +913,14 @@ static inline void prepare_page_table(void) pmd_clear(pmd_off_k(addr)); } +#ifdef CONFIG_ARM_LPAE +/* the first page is reserved for pgd */ +#define SWAPPER_PG_DIR_SIZE (PAGE_SIZE + \ + PTRS_PER_PGD * PTRS_PER_PMD * sizeof(pmd_t)) +#else +#define SWAPPER_PG_DIR_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) +#endif + /* * Reserve the special regions of memory */ @@ -898,7 +930,7 @@ void __init arm_mm_memblock_reserve(void) * Reserve the page tables. These are already in use, * and can only be in node 0. */ - memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t)); + memblock_reserve(__pa(swapper_pg_dir), SWAPPER_PG_DIR_SIZE); #ifdef CONFIG_SA1111 /* diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 307a4de..2d8ff3a 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -91,8 +91,9 @@ #if L_PTE_SHARED != PTE_EXT_SHARED #error PTE shared bit mismatch #endif -#if (L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\ - L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED +#if !defined (CONFIG_ARM_LPAE) && \ + (L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\ + L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED #error Invalid Linux PTE bit settings #endif #endif /* CONFIG_MMU */ diff --git a/arch/arm/mm/proc-v7lpae.S b/arch/arm/mm/proc-v7lpae.S new file mode 100644 index 0000000..0bee213 --- /dev/null +++ b/arch/arm/mm/proc-v7lpae.S @@ -0,0 +1,422 @@ +/* + * arch/arm/mm/proc-v7lpae.S + * + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * Copyright (C) 2011 ARM Ltd. + * Author: Catalin Marinas <catalin.marinas@arm.com> + * based on arch/arm/mm/proc-v7.S + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/init.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/asm-offsets.h> +#include <asm/hwcap.h> +#include <asm/pgtable-hwdef.h> +#include <asm/pgtable.h> + +#include "proc-macros.S" + +#define TTB_IRGN_NC (0 << 8) +#define TTB_IRGN_WBWA (1 << 8) +#define TTB_IRGN_WT (2 << 8) +#define TTB_IRGN_WB (3 << 8) +#define TTB_RGN_NC (0 << 10) +#define TTB_RGN_OC_WBWA (1 << 10) +#define TTB_RGN_OC_WT (2 << 10) +#define TTB_RGN_OC_WB (3 << 10) +#define TTB_S (3 << 12) +#define TTB_EAE (1 << 31) + +/* PTWs cacheable, inner WB not shareable, outer WB not shareable */ +#define TTB_FLAGS_UP (TTB_IRGN_WB|TTB_RGN_OC_WB) +#define PMD_FLAGS_UP (PMD_SECT_WB) + +/* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */ +#define TTB_FLAGS_SMP (TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA) +#define PMD_FLAGS_SMP (PMD_SECT_WBWA|PMD_SECT_S) + +ENTRY(cpu_v7_proc_init) + mov pc, lr +ENDPROC(cpu_v7_proc_init) + +ENTRY(cpu_v7_proc_fin) + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x0006 @ .............ca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + mov pc, lr +ENDPROC(cpu_v7_proc_fin) + +/* + * cpu_v7_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * - loc - location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_v7_reset) + mov pc, r0 +ENDPROC(cpu_v7_reset) + +/* + * cpu_v7_do_idle() + * + * Idle the processor (eg, wait for interrupt). + * + * IRQs are already disabled. + */ +ENTRY(cpu_v7_do_idle) + dsb @ WFI may enter a low-power mode + wfi + mov pc, lr +ENDPROC(cpu_v7_do_idle) + +ENTRY(cpu_v7_dcache_clean_area) +#ifndef TLB_CAN_READ_FROM_L1_CACHE + dcache_line_size r2, r3 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, r2 + subs r1, r1, r2 + bhi 1b + dsb +#endif + mov pc, lr +ENDPROC(cpu_v7_dcache_clean_area) + +/* + * cpu_v7_switch_mm(pgd_phys, tsk) + * + * Set the translation table base pointer to be pgd_phys + * + * - pgd_phys - physical address of new TTB + * + * It is assumed that: + * - we are not using split page tables + */ +ENTRY(cpu_v7_switch_mm) +#ifdef CONFIG_MMU + ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id + mov r2, #0 + and r3, r1, #0xff + mov r3, r3, lsl #(48 - 32) @ ASID + mcrr p15, 0, r0, r3, c2 @ set TTB 0 + isb +#endif + mov pc, lr +ENDPROC(cpu_v7_switch_mm) + +/* + * cpu_v7_set_pte_ext(ptep, pte) + * + * Set a level 2 translation table entry. + * + * - ptep - pointer to level 2 translation table entry + * (hardware version is stored at +2048 bytes) + * - pte - PTE value to store + * - ext - value for extended PTE bits + */ +ENTRY(cpu_v7_set_pte_ext) +#ifdef CONFIG_MMU + tst r2, #L_PTE_PRESENT + beq 1f + tst r3, #1 << (55 - 32) @ L_PTE_DIRTY + orreq r2, #L_PTE_RDONLY +1: strd r2, r3, [r0] + mcr p15, 0, r0, c7, c10, 1 @ flush_pte +#endif + mov pc, lr +ENDPROC(cpu_v7_set_pte_ext) + +cpu_v7_name: + .ascii "ARMv7 Processor" + .align + + /* + * Memory region attributes for LPAE (defined in pgtable-3level.h): + * + * n = AttrIndx[2:0] + * + * n MAIR + * UNCACHED 000 00000000 + * BUFFERABLE 001 01000100 + * DEV_WC 001 01000100 + * WRITETHROUGH 010 10101010 + * WRITEBACK 011 11101110 + * DEV_CACHED 011 11101110 + * DEV_SHARED 100 00000100 + * DEV_NONSHARED 100 00000100 + * unused 101 + * unused 110 + * WRITEALLOC 111 11111111 + */ +.equ MAIR0, 0xeeaa4400 @ MAIR0 +.equ MAIR1, 0xff000004 @ MAIR1 + +/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */ +.globl cpu_v7_suspend_size +.equ cpu_v7_suspend_size, 4 * 10 +#ifdef CONFIG_PM_SLEEP +ENTRY(cpu_v7_do_suspend) + stmfd sp!, {r4 - r11, lr} + mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID + mrc p15, 0, r5, c13, c0, 1 @ Context ID + mrc p15, 0, r6, c3, c0, 0 @ Domain ID + mrrc p15, 0, r7, r8, c2 @ TTB 0 + mrrc p15, 1, r2, r3, c2 @ TTB 1 + mrc p15, 0, r9, c1, c0, 0 @ Control register + mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r11, c1, c0, 2 @ Co-processor access control + stmia r0, {r2 - r11} + ldmfd sp!, {r4 - r11, pc} +ENDPROC(cpu_v7_do_suspend) + +ENTRY(cpu_v7_do_resume) + mov ip, #0 + mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + ldmia r0, {r2 - r11} + mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID + mcr p15, 0, r5, c13, c0, 1 @ Context ID + mcr p15, 0, r6, c3, c0, 0 @ Domain ID + mcrr p15, 0, r7, r8, c2 @ TTB 0 + mcrr p15, 1, r2, r3, c2 @ TTB 1 + mcr p15, 0, ip, c2, c0, 2 @ TTB control register + mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control + ldr r4, =MAIR0 + ldr r5, =MAIR1 + mcr p15, 0, r4, c10, c2, 0 @ write MAIR0 + mcr p15, 0, r5, c10, c2, 1 @ write MAIR1 + isb + mov r0, r9 @ control register + mov r2, r7, lsr #14 @ get TTB0 base + mov r2, r2, lsl #14 + ldr r3, cpu_resume_l1_flags + b cpu_resume_mmu +ENDPROC(cpu_v7_do_resume) +cpu_resume_l1_flags: + ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP) + ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP) +#else +#define cpu_v7_do_suspend 0 +#define cpu_v7_do_resume 0 +#endif + + __CPUINIT + +/* + * __v7_setup + * + * Initialise TLB, Caches, and MMU state ready to switch the MMU + * on. Return in r0 the new CP15 C1 control register setting. + * + * This should be able to cover all ARMv7 cores with LPAE. + * + * It is assumed that: + * - cache type register is implemented + */ +__v7_ca15mp_setup: + mov r10, #0 +1: +#ifdef CONFIG_SMP + ALT_SMP(mrc p15, 0, r0, c1, c0, 1) + ALT_UP(mov r0, #(1 << 6)) @ fake it for UP + tst r0, #(1 << 6) @ SMP/nAMP mode enabled? + orreq r0, r0, #(1 << 6) @ Enable SMP/nAMP mode + orreq r0, r0, r10 @ Enable CPU-specific SMP bits + mcreq p15, 0, r0, c1, c0, 1 +#endif +__v7_setup: + adr r12, __v7_setup_stack @ the local stack + stmia r12, {r0-r5, r7, r9, r11, lr} + bl v7_flush_dcache_all + ldmia r12, {r0-r5, r7, r9, r11, lr} + + mov r10, #0 + mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate + dsb +#ifdef CONFIG_MMU + mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs + mov r5, #TTB_EAE + ALT_SMP(orr r5, r5, #TTB_FLAGS_SMP) + ALT_SMP(orr r5, r5, #TTB_FLAGS_SMP << 16) + ALT_UP(orr r5, r5, #TTB_FLAGS_UP) + ALT_UP(orr r5, r5, #TTB_FLAGS_UP << 16) + mrc p15, 0, r10, c2, c0, 2 + orr r10, r10, r5 +#if PHYS_OFFSET <= PAGE_OFFSET + /* + * TTBR0/TTBR1 split (PAGE_OFFSET): + * 0x40000000: T0SZ = 2, T1SZ = 0 (not used) + * 0x80000000: T0SZ = 0, T1SZ = 1 + * 0xc0000000: T0SZ = 0, T1SZ = 2 + * + * Only use this feature if PAGE_OFFSET <= PAGE_OFFSET, otherwise + * booting secondary CPUs would end up using TTBR1 for the identity + * mapping set up in TTBR0. + */ + orr r10, r10, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ +#endif + mcr p15, 0, r10, c2, c0, 2 @ TTB control register + mov r5, #0 +#if defined CONFIG_VMSPLIT_2G + /* PAGE_OFFSET == 0x80000000, T1SZ == 1 */ + add r6, r8, #1 << 4 @ skip two L1 entries +#elif defined CONFIG_VMSPLIT_3G + /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */ + add r6, r8, #4096 * (1 + 3) @ only L2 used, skip pgd+3*pmd +#else + mov r6, r8 +#endif + mcrr p15, 1, r6, r5, c2 @ load TTBR1 + ldr r5, =MAIR0 + ldr r6, =MAIR1 + mcr p15, 0, r5, c10, c2, 0 @ write MAIR0 + mcr p15, 0, r6, c10, c2, 1 @ write MAIR1 +#endif + adr r5, v7_crval + ldmia r5, {r5, r6} +#ifdef CONFIG_CPU_ENDIAN_BE8 + orr r6, r6, #1 << 25 @ big-endian page tables +#endif +#ifdef CONFIG_SWP_EMULATE + orr r5, r5, #(1 << 10) @ set SW bit in "clear" + bic r6, r6, #(1 << 10) @ clear it in "mmuset" +#endif + mrc p15, 0, r0, c1, c0, 0 @ read control register + bic r0, r0, r5 @ clear bits them + orr r0, r0, r6 @ set them + THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions + mov pc, lr @ return to head.S:__ret +ENDPROC(__v7_setup) + + /* AT + * TFR EV X F IHD LR S + * .EEE ..EE PUI. .TAT 4RVI ZWRS BLDP WCAM + * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced + * 11 0 110 1 0011 1100 .111 1101 < we want + */ + .type v7_crval, #object +v7_crval: + crval clear=0x0120c302, mmuset=0x30c23c7d, ucset=0x00c01c7c + +__v7_setup_stack: + .space 4 * 11 @ 11 registers + + __INITDATA + + .type v7_processor_functions, #object +ENTRY(v7_processor_functions) + .word v7_early_abort + .word v7_pabort + .word cpu_v7_proc_init + .word cpu_v7_proc_fin + .word cpu_v7_reset + .word cpu_v7_do_idle + .word cpu_v7_dcache_clean_area + .word cpu_v7_switch_mm + .word cpu_v7_set_pte_ext + .word 0 + .word 0 + .word 0 + .size v7_processor_functions, . - v7_processor_functions + + .section ".rodata" + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv7" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v7" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info.init", #alloc, #execinstr + + .type __v7_ca15mp_proc_info, #object +__v7_ca15mp_proc_info: + .long 0x410fc0f0 @ Required ID value + .long 0xff0ffff0 @ Mask for ID + ALT_SMP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_SECT_AF | \ + PMD_FLAGS_SMP) + ALT_UP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_SECT_AF | \ + PMD_FLAGS_UP) + /* PMD_SECT_XN is set explicitly in head.S for LPAE */ + .long PMD_TYPE_SECT | \ + PMD_SECT_XN | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_SECT_AF + b __v7_ca15mp_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS + .long cpu_v7_name + .long v7_processor_functions + .long v7wbi_tlb_fns + .long v6_user_fns + .long v7_cache_fns + .size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info + + /* + * Match any ARMv7 processor core. + */ + .type __v7_proc_info, #object +__v7_proc_info: + .long 0x000f0000 @ Required ID value + .long 0x000f0000 @ Mask for ID + ALT_SMP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_SECT_AF | \ + PMD_FLAGS_SMP) + ALT_UP(.long \ + PMD_TYPE_SECT | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_SECT_AF | \ + PMD_FLAGS_UP) + /* PMD_SECT_XN is set explicitly in head.S for LPAE */ + .long PMD_TYPE_SECT | \ + PMD_SECT_XN | \ + PMD_SECT_AP_WRITE | \ + PMD_SECT_AP_READ | \ + PMD_SECT_AF + W(b) __v7_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS + .long cpu_v7_name + .long v7_processor_functions + .long v7wbi_tlb_fns + .long v6_user_fns + .long v7_cache_fns + .size __v7_proc_info, . - __v7_proc_info
This patch adds the MMU initialisation for the LPAE page table format. The swapper_pg_dir size with LPAE is 5 rather than 4 pages. A new proc-v7lpae.S file contains the initialisation, context switch and save/restore code for ARMv7 with the LPAE. The TTBRx split is based on the PAGE_OFFSET with TTBR1 used for the kernel mappings. The 36-bit mappings (supersections) and a few other memory types in mmu.c are conditionally compiled. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> --- arch/arm/kernel/head.S | 117 +++++++++---- arch/arm/mm/Makefile | 4 + arch/arm/mm/mmu.c | 34 ++++- arch/arm/mm/proc-macros.S | 5 +- arch/arm/mm/proc-v7lpae.S | 422 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 542 insertions(+), 40 deletions(-) create mode 100644 arch/arm/mm/proc-v7lpae.S