summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-04-08 13:37:28 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-04-08 13:37:28 +0200
commit78c371d3e76266747ed7335adaf1d04945e53776 (patch)
treef7341b2d4851068058fcab8636b58c555712e5e8 /arch
parent5dd56a8d698289237ddd2cfd10cc4668d563b417 (diff)
parentf6b77fe9f9439564d312e75fe713f61b0467c8f8 (diff)
downloadbarebox-78c371d3e76266747ed7335adaf1d04945e53776.tar.gz
barebox-78c371d3e76266747ed7335adaf1d04945e53776.tar.xz
Merge branch 'for-next/arm'
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/cpu/entry.c3
-rw-r--r--arch/arm/cpu/mmu.c164
-rw-r--r--arch/arm/cpu/start.c2
-rw-r--r--arch/arm/cpu/uncompress.c2
-rw-r--r--arch/arm/include/asm/barebox-arm.h2
-rw-r--r--arch/arm/lib/barebox.lds.S1
6 files changed, 133 insertions, 41 deletions
diff --git a/arch/arm/cpu/entry.c b/arch/arm/cpu/entry.c
index 3b74c6a6c1..0cdcfece73 100644
--- a/arch/arm/cpu/entry.c
+++ b/arch/arm/cpu/entry.c
@@ -1,6 +1,7 @@
#include <types.h>
#include <asm/cache.h>
+#include <asm/barebox-arm.h>
#include "entry.h"
@@ -26,7 +27,7 @@
void __naked __noreturn barebox_arm_entry(unsigned long membase,
unsigned long memsize, void *boarddata)
{
- arm_setup_stack(membase + memsize - 16);
+ arm_setup_stack(arm_mem_stack(membase, membase + memsize) + STACK_SIZE - 16);
arm_early_mmu_cache_invalidate();
if (IS_ENABLED(CONFIG_PBL_MULTI_IMAGES))
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/cpu/start.c b/arch/arm/cpu/start.c
index d03d1edfaf..e037d91f9c 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -193,7 +193,7 @@ __noreturn void barebox_non_pbl_start(unsigned long membase,
if (totalsize) {
unsigned long mem = arm_mem_boarddata(membase, endmem,
totalsize);
- pr_debug("found %s in boarddata, copying to 0x%lu\n",
+ pr_debug("found %s in boarddata, copying to 0x%08lx\n",
name, mem);
barebox_boarddata = memcpy((void *)mem, boarddata,
totalsize);
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index 5bcce6b9e3..b8e2e9ffd7 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -60,7 +60,7 @@ void __noreturn barebox_multi_pbl_start(unsigned long membase,
* to the current address. Otherwise it may be a readonly location.
* Copy and relocate to the start of the memory in this case.
*/
- if (pc > membase && pc < membase + memsize)
+ if (pc > membase && pc - membase < memsize)
relocate_to_current_adr();
else
relocate_to_adr(membase);
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 67133265d1..8e7b45c33d 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -97,7 +97,7 @@ void *barebox_arm_boot_dtb(void);
static inline unsigned long arm_mem_stack(unsigned long membase,
unsigned long endmem)
{
- return endmem - STACK_SIZE;
+ return endmem - SZ_64K - STACK_SIZE;
}
static inline unsigned long arm_mem_ttb(unsigned long membase,
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 = .;