summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-04-01 11:02:18 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-04-01 14:00:29 +0200
commitf6b77fe9f9439564d312e75fe713f61b0467c8f8 (patch)
tree627d52efe2006394fdbb59fe5d6d95a98d415a78 /arch
parent75c96bd2459ea013bf6bf4eea7f53094a4d66e93 (diff)
downloadbarebox-f6b77fe9f9439564d312e75fe713f61b0467c8f8.tar.gz
barebox-f6b77fe9f9439564d312e75fe713f61b0467c8f8.tar.xz
ARM: Rework vector table setup
The current vector table setup has some shortcomings. First of all currently the case when the high vectors are inside SDRAM (that is, SDRAM reaches the end of the address space) is not supported. In this case we create a secondary page table for the section containing the vectors which gets overwritten by the general SDRAM secondary page table entries creation afterwards. On ARMv7 and later the exception table setup can be improved: Here the vector table address is configurable in the VBAR register. We can use this register to skip remapping the vector table. With this patch we first try to use the VBAR register before doing something else. Also, when we have to use the high vectors we first try a request_sdram_region to test if the vector table memory is already mapped. While at it sprinkle some comments into the code. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/cpu/mmu.c164
-rw-r--r--arch/arm/lib/barebox.lds.S1
2 files changed, 128 insertions, 37 deletions
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c
index bc5325faba..a31bce4c50 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu.c
@@ -272,59 +272,149 @@ static int arm_mmu_remap_sdram(struct memory_bank *bank)
*/
#define ARM_VECTORS_SIZE (sizeof(u32) * 8 * 2)
-/*
- * Map vectors and zero page
+#define ARM_HIGH_VECTORS 0xffff0000
+#define ARM_LOW_VECTORS 0x0
+
+/**
+ * create_vector_table - create a vector table at given address
+ * @adr - The address where the vector table should be created
+ *
+ * After executing this function the vector table is found at the
+ * virtual address @adr.
*/
-static void vectors_init(void)
+static void create_vector_table(unsigned long adr)
{
- u32 *exc, *zero = NULL;
+ struct resource *vectors_sdram;
void *vectors;
- u32 cr;
+ u32 *exc;
+ int idx;
- cr = get_cr();
- cr |= CR_V;
- set_cr(cr);
- cr = get_cr();
-
- if (cr & CR_V) {
+ vectors_sdram = request_sdram_region("vector table", adr, SZ_4K);
+ if (vectors_sdram) {
/*
- * If we can use high vectors, create the second level
- * page table for the high vectors and zero page
+ * The vector table address is inside the SDRAM physical
+ * address space. Use the existing identity mapping for
+ * the vector table.
*/
- exc = arm_create_pte(0xfff00000);
- zero = arm_create_pte(0x0);
-
- /* Set the zero page to faulting */
- zero[0] = 0;
+ pr_debug("Creating vector table, virt = phys = 0x%08lx\n", adr);
+ vectors = (void *)vectors_sdram->start;
} else {
/*
- * Otherwise map the vectors to the zero page. We have to
- * live without being able to catch NULL pointer dereferences
+ * The vector table address is outside of SDRAM. Create
+ * a secondary page table for the section and map
+ * allocated memory to the vector address.
*/
- exc = arm_create_pte(0x0);
-
- if (cpu_architecture() >= CPU_ARCH_ARMv7) {
- /*
- * ARMv7 CPUs allow to remap low vectors from
- * 0x0 to an arbitrary address using VBAR
- * register, so let's make sure we have it
- * pointing to the correct address
- */
- set_vbar(0x0);
- }
+ vectors = xmemalign(PAGE_SIZE, PAGE_SIZE);
+ pr_debug("Creating vector table, virt = 0x%p, phys = 0x%08lx\n",
+ vectors, adr);
+ exc = arm_create_pte(adr);
+ idx = (adr & (SZ_1M - 1)) >> PAGE_SHIFT;
+ exc[idx] = (u32)vectors | PTE_TYPE_SMALL | pte_flags_cached;
}
arm_fixup_vectors();
- vectors = xmemalign(PAGE_SIZE, PAGE_SIZE);
memset(vectors, 0, PAGE_SIZE);
memcpy(vectors, __exceptions_start, __exceptions_stop - __exceptions_start);
+}
- if (cr & CR_V)
- exc[256 - 16] = (u32)vectors | PTE_TYPE_SMALL |
- pte_flags_cached;
- else
- exc[0] = (u32)vectors | PTE_TYPE_SMALL | pte_flags_cached;
+/**
+ * set_vector_table - let CPU use the vector table at given address
+ * @adr - The address of the vector table
+ *
+ * Depending on the CPU the possibilities differ. ARMv7 and later allow
+ * to map the vector table to arbitrary addresses. Other CPUs only allow
+ * vectors at 0xffff0000 or at 0x0.
+ */
+static int set_vector_table(unsigned long adr)
+{
+ u32 cr;
+
+ if (cpu_architecture() >= CPU_ARCH_ARMv7) {
+ pr_debug("Vectors are at 0x%08lx\n", adr);
+ set_vbar(adr);
+ return 0;
+ }
+
+ if (adr == ARM_HIGH_VECTORS) {
+ cr = get_cr();
+ cr |= CR_V;
+ set_cr(cr);
+ cr = get_cr();
+ if (cr & CR_V) {
+ pr_debug("Vectors are at 0x%08lx\n", adr);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+ }
+
+ if (adr == ARM_LOW_VECTORS) {
+ cr = get_cr();
+ cr &= ~CR_V;
+ set_cr(cr);
+ cr = get_cr();
+ if (cr & CR_V) {
+ return -EINVAL;
+ } else {
+ pr_debug("Vectors are at 0x%08lx\n", adr);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void create_zero_page(void)
+{
+ struct resource *zero_sdram;
+ u32 *zero;
+
+ zero_sdram = request_sdram_region("zero page", 0x0, SZ_4K);
+ if (zero_sdram) {
+ /*
+ * Here we would need to set the second level page table
+ * entry to faulting. This is not yet implemented.
+ */
+ pr_debug("zero page is in SDRAM area, currently not supported\n");
+ } else {
+ zero = arm_create_pte(0x0);
+ zero[0] = 0;
+ pr_debug("Created zero page\n");
+ }
+}
+
+/*
+ * Map vectors and zero page
+ */
+static void vectors_init(void)
+{
+ /*
+ * First try to use the vectors where they actually are, works
+ * on ARMv7 and later.
+ */
+ if (!set_vector_table((unsigned long)__exceptions_start)) {
+ arm_fixup_vectors();
+ create_zero_page();
+ return;
+ }
+
+ /*
+ * Next try high vectors at 0xffff0000.
+ */
+ if (!set_vector_table(ARM_HIGH_VECTORS)) {
+ create_zero_page();
+ create_vector_table(ARM_HIGH_VECTORS);
+ return;
+ }
+
+ /*
+ * As a last resort use low vectors at 0x0. With this we can't
+ * set the zero page to faulting and can't catch NULL pointer
+ * exceptions.
+ */
+ set_vector_table(ARM_LOW_VECTORS);
+ create_vector_table(ARM_LOW_VECTORS);
}
/*
diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S
index 5344557860..6dc8bd2f3c 100644
--- a/arch/arm/lib/barebox.lds.S
+++ b/arch/arm/lib/barebox.lds.S
@@ -43,6 +43,7 @@ SECTIONS
__bare_init_start = .;
*(.text_bare_init*)
__bare_init_end = .;
+ . = ALIGN(4);
__exceptions_start = .;
KEEP(*(.text_exceptions*))
__exceptions_stop = .;