We should probably always run with the mmu on, so let's enable it from setup with an identity map. Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx> --- arm/cstart.S | 33 ++++++++++++++++++++++++++++++++ config/config-arm.mak | 3 ++- lib/arm/asm/mmu.h | 34 ++++++++++++++++++++++++++++++++- lib/arm/mmu.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/arm/processor.c | 11 +++++++++++ lib/arm/setup.c | 3 +++ 6 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 lib/arm/mmu.c diff --git a/arm/cstart.S b/arm/cstart.S index cc87ece4b6b40..a1ccfb24bb4e0 100644 --- a/arm/cstart.S +++ b/arm/cstart.S @@ -72,6 +72,39 @@ halt: b 1b /* + * asm_mmu_enable + * Inputs: + * (r0 - lo, r1 - hi) is the base address of the translation table + * Outputs: none + */ +.equ PRRR, 0xeeaa4400 @ MAIR0 (from Linux kernel) +.equ NMRR, 0xff000004 @ MAIR1 (from Linux kernel) +.globl asm_mmu_enable +asm_mmu_enable: + /* TTBCR */ + mrc p15, 0, r2, c2, c0, 2 + orr r2, #(1 << 31) @ TTB_EAE + mcr p15, 0, r2, c2, c0, 2 + + /* MAIR */ + ldr r2, =PRRR + mrc p15, 0, r2, c10, c2, 0 + ldr r2, =NMRR + mrc p15, 0, r2, c10, c2, 1 + + /* TTBR0 */ + mcrr p15, 0, r0, r1, c2 + + /* SCTLR */ + mrc p15, 0, r2, c1, c0, 0 + orr r2, #CR_C + orr r2, #CR_I + orr r2, #CR_M + mcr p15, 0, r2, c1, c0, 0 + + mov pc, lr + +/* * Vector stubs * Simplified version of the Linux kernel implementation * arch/arm/kernel/entry-armv.S diff --git a/config/config-arm.mak b/config/config-arm.mak index 8a274c50332b0..86e1d75169b59 100644 --- a/config/config-arm.mak +++ b/config/config-arm.mak @@ -42,7 +42,8 @@ cflatobjs += \ lib/arm/io.o \ lib/arm/setup.o \ lib/arm/spinlock.o \ - lib/arm/processor.o + lib/arm/processor.o \ + lib/arm/mmu.o libeabi = lib/arm/libeabi.a eabiobjs = lib/arm/eabi_compat.o diff --git a/lib/arm/asm/mmu.h b/lib/arm/asm/mmu.h index 987928b2c432c..451c7493c2aba 100644 --- a/lib/arm/asm/mmu.h +++ b/lib/arm/asm/mmu.h @@ -5,7 +5,39 @@ * * This work is licensed under the terms of the GNU LGPL, version 2. */ +#include "asm/page.h" +#include "asm/barrier.h" +#include "alloc.h" -#define mmu_enabled() (0) +#define PTRS_PER_PGD 4 +#define PGDIR_SHIFT 30 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1)) + +#define pgd_free(pgd) free(pgd) +static inline pgd_t *pgd_alloc(void) +{ + pgd_t *pgd = memalign(L1_CACHE_BYTES, PTRS_PER_PGD * sizeof(pgd_t)); + memset(pgd, 0, PTRS_PER_PGD * sizeof(pgd_t)); + return pgd; +} + +static inline void local_flush_tlb_all(void) +{ + asm volatile("mcr p15, 0, %0, c8, c7, 0" :: "r" (0)); + dsb(); + isb(); +} + +static inline void flush_tlb_all(void) +{ + //TODO + local_flush_tlb_all(); +} + +extern bool mmu_enabled(void); +extern void mmu_enable(pgd_t *pgtable); +extern void mmu_enable_idmap(void); +extern void mmu_init_io_sect(pgd_t *pgtable); #endif /* __ASMARM_MMU_H_ */ diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c new file mode 100644 index 0000000000000..c9d39bf6464b8 --- /dev/null +++ b/lib/arm/mmu.c @@ -0,0 +1,53 @@ +/* + * MMU enable and page table manipulation functions + * + * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjones@xxxxxxxxxx> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "asm/setup.h" +#include "asm/mmu.h" +#include "asm/pgtable-hwdef.h" + +static bool mmu_on; +static pgd_t idmap[PTRS_PER_PGD] __attribute__((aligned(L1_CACHE_BYTES))); + +bool mmu_enabled(void) +{ + return mmu_on; +} + +extern void asm_mmu_enable(phys_addr_t pgtable); +void mmu_enable(pgd_t *pgtable) +{ + asm_mmu_enable(__pa(pgtable)); + flush_tlb_all(); + mmu_on = true; +} + +void mmu_init_io_sect(pgd_t *pgtable) +{ + /* + * mach-virt reserves the first 1G section for I/O + */ + pgd_val(pgtable[0]) = PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_USER; + pgd_val(pgtable[0]) |= PMD_SECT_UNCACHED; +} + +void mmu_enable_idmap(void) +{ + unsigned long sect, end; + + mmu_init_io_sect(idmap); + + end = sizeof(long) == 8 || !(PHYS_END >> 32) ? PHYS_END : 0xfffff000; + + for (sect = PHYS_OFFSET & PGDIR_MASK; sect < end; sect += PGDIR_SIZE) { + int i = sect >> PGDIR_SHIFT; + pgd_val(idmap[i]) = sect; + pgd_val(idmap[i]) |= PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_USER; + pgd_val(idmap[i]) |= PMD_SECT_S | PMD_SECT_WBWA; + } + + mmu_enable(idmap); +} diff --git a/lib/arm/processor.c b/lib/arm/processor.c index 382a128edd415..866d11975b23b 100644 --- a/lib/arm/processor.c +++ b/lib/arm/processor.c @@ -92,6 +92,17 @@ void do_handle_exception(enum vector v, struct pt_regs *regs) printf("Exception frame registers:\n"); show_regs(regs); + if (v == EXCPTN_DABT) { + unsigned long far, fsr; + asm volatile("mrc p15, 0, %0, c6, c0, 0": "=r" (far)); + asm volatile("mrc p15, 0, %0, c5, c0, 0": "=r" (fsr)); + printf("DFAR: %08lx DFSR: %08lx\n", far, fsr); + } else if (v == EXCPTN_PABT) { + unsigned long far, fsr; + asm volatile("mrc p15, 0, %0, c6, c0, 2": "=r" (far)); + asm volatile("mrc p15, 0, %0, c5, c0, 1": "=r" (fsr)); + printf("IFAR: %08lx IFSR: %08lx\n", far, fsr); + } abort(); } diff --git a/lib/arm/setup.c b/lib/arm/setup.c index 3941c9757dcb2..5fa37ca35f383 100644 --- a/lib/arm/setup.c +++ b/lib/arm/setup.c @@ -16,6 +16,7 @@ #include "alloc.h" #include "asm/setup.h" #include "asm/page.h" +#include "asm/mmu.h" extern unsigned long stacktop; extern void io_init(void); @@ -57,6 +58,8 @@ static void mem_init(phys_addr_t freemem_start) phys_alloc_init(freemem_start, mem_end - freemem_start); phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES); + + mmu_enable_idmap(); } void setup(unsigned long arg __unused, unsigned long id __unused, -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html