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 <drjo...@redhat.com>
---
 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 <drjo...@redhat.com>
+ *
+ * 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to