summaryrefslogtreecommitdiffstats
path: root/arch/arm/lib32
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/lib32')
-rw-r--r--arch/arm/lib32/.gitignore2
-rw-r--r--arch/arm/lib32/Makefile4
-rw-r--r--arch/arm/lib32/arm_architected_timer.c17
-rw-r--r--arch/arm/lib32/armlinux.c7
-rw-r--r--arch/arm/lib32/barebox.lds.S14
-rw-r--r--arch/arm/lib32/bootm.c10
-rw-r--r--arch/arm/lib32/bootu.c7
-rw-r--r--arch/arm/lib32/bootz.c5
-rw-r--r--arch/arm/lib32/io.c69
-rw-r--r--arch/arm/lib32/module.c2
-rw-r--r--arch/arm/lib32/optee-early.c1
-rw-r--r--arch/arm/lib32/runtime-offset.S2
-rw-r--r--arch/arm/lib32/setjmp.S1
-rw-r--r--arch/arm/lib32/start-kernel-optee.S2
-rw-r--r--arch/arm/lib32/unwind.c138
15 files changed, 207 insertions, 74 deletions
diff --git a/arch/arm/lib32/.gitignore b/arch/arm/lib32/.gitignore
index d1165788c9..03987a7009 100644
--- a/arch/arm/lib32/.gitignore
+++ b/arch/arm/lib32/.gitignore
@@ -1 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
barebox.lds
diff --git a/arch/arm/lib32/Makefile b/arch/arm/lib32/Makefile
index ec6a3aea67..d54fb7644c 100644
--- a/arch/arm/lib32/Makefile
+++ b/arch/arm/lib32/Makefile
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
obj-$(CONFIG_ARM_LINUX) += armlinux.o
obj-$(CONFIG_CMD_BOOTZ) += bootz.o
obj-$(CONFIG_BOOTM) += bootm.o
@@ -29,6 +31,8 @@ extra-y += barebox.lds
pbl-y += lib1funcs.o
pbl-y += ashldi3.o
pbl-y += div0.o
+pbl-$(CONFIG_CPU_32v7) += arm_architected_timer.o
+CFLAGS_arm_architected_timer.o := -march=armv7-a
obj-pbl-y += setjmp.o
diff --git a/arch/arm/lib32/arm_architected_timer.c b/arch/arm/lib32/arm_architected_timer.c
new file mode 100644
index 0000000000..54eca13f8b
--- /dev/null
+++ b/arch/arm/lib32/arm_architected_timer.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <asm/system.h>
+#include <clock.h>
+#include <common.h>
+
+/* Unlike the ARMv8, the timer is not generic to ARM32 */
+void arm_architected_timer_udelay(unsigned long us)
+{
+ unsigned long long ticks, cntfrq = get_cntfrq();
+ unsigned long long start = get_cntpct();
+
+ ticks = DIV_ROUND_DOWN_ULL((us * cntfrq), 1000000);
+
+ while ((long)(start + ticks - get_cntpct()) > 0)
+ ;
+}
diff --git a/arch/arm/lib32/armlinux.c b/arch/arm/lib32/armlinux.c
index 6cb7d4b5f3..eb30f4a952 100644
--- a/arch/arm/lib32/armlinux.c
+++ b/arch/arm/lib32/armlinux.c
@@ -18,6 +18,7 @@
#include <memory.h>
#include <of.h>
#include <magicvar.h>
+#include <zero_page.h>
#include <asm/byteorder.h>
#include <asm/setup.h>
@@ -265,8 +266,12 @@ void start_linux(void *adr, int swap, unsigned long initrd_address,
pr_debug("booting kernel with devicetree\n");
params = oftree;
} else {
- setup_tags(initrd_address, initrd_size, swap);
params = armlinux_get_bootparams();
+
+ if ((unsigned long)params < PAGE_SIZE)
+ zero_page_access();
+
+ setup_tags(initrd_address, initrd_size, swap);
}
architecture = armlinux_get_architecture();
diff --git a/arch/arm/lib32/barebox.lds.S b/arch/arm/lib32/barebox.lds.S
index 77a5c525c5..ec145569be 100644
--- a/arch/arm/lib32/barebox.lds.S
+++ b/arch/arm/lib32/barebox.lds.S
@@ -1,11 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* SPDX-FileCopyrightText: 2000-2004 Wolfgang Denk <wd@denx.de>, DENX Software Engineering */
-#include <asm-generic/barebox.lds.h>
+#include <asm/barebox.lds.h>
#include <asm/secure.h>
-OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
-OUTPUT_ARCH(arm)
+OUTPUT_FORMAT(BAREBOX_OUTPUT_FORMAT)
+OUTPUT_ARCH(BAREBOX_OUTPUT_ARCH)
ENTRY(start)
SECTIONS
{
@@ -71,13 +71,7 @@ SECTIONS
. = .;
- .rel_dyn_start : { *(.__rel_dyn_start) }
- .rel.dyn : { *(.rel*) }
- .rel_dyn_end : { *(.__rel_dyn_end) }
-
- .__dynsym_start : { *(.__dynsym_start) }
- .dynsym : { *(.dynsym) }
- .__dynsym_end : { *(.__dynsym_end) }
+ BAREBOX_RELOCATION_TABLE
_edata = .;
.image_end : { *(.__image_end) }
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index 28a645a9d0..aeb873a3a7 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <bootm.h>
#include <boot.h>
#include <common.h>
@@ -292,7 +294,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
}
if (IS_ENABLED(CONFIG_BOOTM_OPTEE)) {
- if (data->tee_file && !IS_ENABLED(CONFIG_BOOTM_FORCE_SIGNED_IMAGES)) {
+ if (data->tee_file && !bootm_signed_images_are_forced()) {
ret = bootm_load_tee_from_file(data);
if (ret)
return ret;
@@ -325,6 +327,10 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
if (data->dryrun)
return 0;
+ ret = of_overlay_load_firmware();
+ if (ret)
+ return ret;
+
if (data->tee_res)
tee = (void *)data->tee_res->start;
else
@@ -421,7 +427,7 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data, void **outfdt)
if (IS_BUILTIN(CONFIG_OFTREE)) {
struct device_node *root;
- root = of_unflatten_dtb(oftree);
+ root = of_unflatten_dtb(oftree, header->totalsize);
if (IS_ERR(root)) {
pr_err("unable to unflatten devicetree\n");
goto err_free;
diff --git a/arch/arm/lib32/bootu.c b/arch/arm/lib32/bootu.c
index 24c744da58..31c3c56cc5 100644
--- a/arch/arm/lib32/bootu.c
+++ b/arch/arm/lib32/bootu.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <command.h>
#include <fs.h>
@@ -8,7 +10,7 @@
static int do_bootu(int argc, char *argv[])
{
- int fd;
+ int fd, ret;
void *kernel = NULL;
void *oftree = NULL;
@@ -25,6 +27,9 @@ static int do_bootu(int argc, char *argv[])
#ifdef CONFIG_OFTREE
oftree = of_get_fixed_tree(NULL);
#endif
+ ret = of_overlay_load_firmware();
+ if (ret)
+ return ret;
start_linux(kernel, 0, 0, 0, oftree, ARM_STATE_SECURE, NULL);
diff --git a/arch/arm/lib32/bootz.c b/arch/arm/lib32/bootz.c
index a2a26ac2f9..7b3b32d418 100644
--- a/arch/arm/lib32/bootz.c
+++ b/arch/arm/lib32/bootz.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <command.h>
#include <fs.h>
@@ -111,6 +113,9 @@ static int do_bootz(int argc, char *argv[])
#ifdef CONFIG_OFTREE
oftree = of_get_fixed_tree(NULL);
#endif
+ ret = of_overlay_load_firmware();
+ if (ret)
+ return ret;
start_linux(zimage, swap, 0, 0, oftree, ARM_STATE_SECURE, NULL);
diff --git a/arch/arm/lib32/io.c b/arch/arm/lib32/io.c
index abfd887aac..780b1083a6 100644
--- a/arch/arm/lib32/io.c
+++ b/arch/arm/lib32/io.c
@@ -1,47 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <module.h>
#include <linux/types.h>
+#include <asm/unaligned.h>
#include <io.h>
/*
* Copy data from IO memory space to "real" memory space.
- * This needs to be optimized.
*/
void memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
{
- unsigned char *t = to;
- while (count) {
+ while (count && !PTR_IS_ALIGNED(from, 4)) {
+ *(u8 *)to = __raw_readb(from);
+ from++;
+ to++;
count--;
- *t = readb(from);
- t++;
+ }
+
+ while (count >= 4) {
+ put_unaligned(__raw_readl(from), (u32 *)to);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ *(u8 *)to = __raw_readb(from);
from++;
+ to++;
+ count--;
}
}
/*
* Copy data from "real" memory space to IO memory space.
- * This needs to be optimized.
*/
void memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
{
- const unsigned char *f = from;
- while (count) {
+ while (count && !IS_ALIGNED((unsigned long)to, 4)) {
+ __raw_writeb(*(u8 *)from, to);
+ from++;
+ to++;
count--;
- writeb(*f, to);
- f++;
+ }
+
+ while (count >= 4) {
+ __raw_writel(get_unaligned((u32 *)from), to);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ __raw_writeb(*(u8 *)from, to);
+ from++;
to++;
+ count--;
}
}
/*
* "memset" on IO memory space.
- * This needs to be optimized.
*/
void memset_io(volatile void __iomem *dst, int c, size_t count)
{
- while (count) {
+ u32 qc = (u8)c;
+
+ qc |= qc << 8;
+ qc |= qc << 16;
+
+ while (count && !PTR_IS_ALIGNED(dst, 4)) {
+ __raw_writeb(c, dst);
+ dst++;
count--;
- writeb(c, dst);
+ }
+
+ while (count >= 4) {
+ __raw_writel(qc, dst);
+ dst += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ __raw_writeb(c, dst);
dst++;
+ count--;
}
}
diff --git a/arch/arm/lib32/module.c b/arch/arm/lib32/module.c
index 5073675180..7214e3c73c 100644
--- a/arch/arm/lib32/module.c
+++ b/arch/arm/lib32/module.c
@@ -38,7 +38,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
- if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) {
+ if (rel->r_offset > dstsec->sh_size - sizeof(u32)) {
printf("%s: out of bounds relocation, "
"section %u reloc %u offset %d size %d\n",
module->name, relindex, i, rel->r_offset,
diff --git a/arch/arm/lib32/optee-early.c b/arch/arm/lib32/optee-early.c
index 197325b8a0..735d829c99 100644
--- a/arch/arm/lib32/optee-early.c
+++ b/arch/arm/lib32/optee-early.c
@@ -9,6 +9,7 @@
#include <asm/setjmp.h>
#include <tee/optee.h>
#include <debug_ll.h>
+#include <string.h>
static jmp_buf tee_buf;
diff --git a/arch/arm/lib32/runtime-offset.S b/arch/arm/lib32/runtime-offset.S
index f86ca7865e..ac104de119 100644
--- a/arch/arm/lib32/runtime-offset.S
+++ b/arch/arm/lib32/runtime-offset.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
#include <asm/assembler.h>
diff --git a/arch/arm/lib32/setjmp.S b/arch/arm/lib32/setjmp.S
index 626d915da1..cc6cafa4af 100644
--- a/arch/arm/lib32/setjmp.S
+++ b/arch/arm/lib32/setjmp.S
@@ -33,6 +33,7 @@ ENTRY(longjmp)
1:
bx lr
ENDPROC(longjmp)
+.popsection
.pushsection .text.initjmp, "ax"
ENTRY(initjmp)
diff --git a/arch/arm/lib32/start-kernel-optee.S b/arch/arm/lib32/start-kernel-optee.S
index 92da4b63c9..261ab39ba7 100644
--- a/arch/arm/lib32/start-kernel-optee.S
+++ b/arch/arm/lib32/start-kernel-optee.S
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
#include <linux/linkage.h>
ENTRY(start_kernel_optee)
diff --git a/arch/arm/lib32/unwind.c b/arch/arm/lib32/unwind.c
index 02fae3c253..c355bba1b7 100644
--- a/arch/arm/lib32/unwind.c
+++ b/arch/arm/lib32/unwind.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
#include <common.h>
#include <init.h>
#include <asm/stacktrace.h>
@@ -26,7 +28,7 @@ EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
struct unwind_ctrl_block {
unsigned long vrs[16]; /* virtual register set */
- unsigned long *insn; /* pointer to the current instructions word */
+ const unsigned long *insn; /* pointer to the current instructions word */
int entries; /* number of entries left to interpret */
int byte; /* current byte number in the instructions word */
};
@@ -40,8 +42,9 @@ enum regs {
#define THREAD_SIZE 8192
-extern struct unwind_idx __start_unwind_idx[];
-extern struct unwind_idx __stop_unwind_idx[];
+extern const struct unwind_idx __start_unwind_idx[];
+static const struct unwind_idx *__origin_unwind_idx;
+extern const struct unwind_idx __stop_unwind_idx[];
/* Convert a prel31 symbol to an absolute address */
#define prel31_to_addr(ptr) \
@@ -62,51 +65,106 @@ static void dump_backtrace_entry(unsigned long where, unsigned long from,
unsigned long frame)
{
#ifdef CONFIG_KALLSYMS
- pr_warning("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
+ eprintf("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
#else
- pr_warning("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
+ eprintf("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
#endif
}
/*
- * Binary search in the unwind index. The entries entries are
+ * Binary search in the unwind index. The entries are
* guaranteed to be sorted in ascending order by the linker.
+ *
+ * start = first entry
+ * origin = first entry with positive offset (or stop if there is no such entry)
+ * stop - 1 = last entry
*/
-static struct unwind_idx *search_index(unsigned long addr,
- struct unwind_idx *first,
- struct unwind_idx *last)
+static const struct unwind_idx *search_index(unsigned long addr,
+ const struct unwind_idx *start,
+ const struct unwind_idx *origin,
+ const struct unwind_idx *stop)
{
- pr_debug("%s(%08lx, %p, %p)\n", __func__, addr, first, last);
+ unsigned long addr_prel31;
+
+ pr_debug("%s(%08lx, %p, %p, %p)\n",
+ __func__, addr, start, origin, stop);
+
+ /*
+ * only search in the section with the matching sign. This way the
+ * prel31 numbers can be compared as unsigned longs.
+ */
+ if (addr < (unsigned long)start)
+ /* negative offsets: [start; origin) */
+ stop = origin;
+ else
+ /* positive offsets: [origin; stop) */
+ start = origin;
+
+ /* prel31 for address relavive to start */
+ addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
+
+ while (start < stop - 1) {
+ const struct unwind_idx *mid = start + ((stop - start) >> 1);
+
+ /*
+ * As addr_prel31 is relative to start an offset is needed to
+ * make it relative to mid.
+ */
+ if (addr_prel31 - ((unsigned long)mid - (unsigned long)start) <
+ mid->addr_offset)
+ stop = mid;
+ else {
+ /* keep addr_prel31 relative to start */
+ addr_prel31 -= ((unsigned long)mid -
+ (unsigned long)start);
+ start = mid;
+ }
+ }
- if (addr < first->addr) {
- pr_warning("unwind: Unknown symbol address %08lx\n", addr);
+ if (likely(start->addr_offset <= addr_prel31))
+ return start;
+ else {
+ eprintf("unwind: Unknown symbol address %08lx\n", addr);
return NULL;
- } else if (addr >= last->addr)
- return last;
+ }
+}
- while (first < last - 1) {
- struct unwind_idx *mid = first + ((last - first + 1) >> 1);
+static const struct unwind_idx *unwind_find_origin(
+ const struct unwind_idx *start, const struct unwind_idx *stop)
+{
+ pr_debug("%s(%p, %p)\n", __func__, start, stop);
+ while (start < stop - 1) {
+ const struct unwind_idx *mid = start + ((stop - start) >> 1);
- if (addr < mid->addr)
- last = mid;
+ if (mid->addr_offset >= 0x40000000)
+ /* negative offset */
+ start = mid;
else
- first = mid;
+ /* positive offset */
+ stop = mid;
}
- return first;
-}
+ pr_debug("%s -> %p\n", __func__, stop);
+ return stop;
+ }
-static struct unwind_idx *unwind_find_idx(unsigned long addr)
+static const struct unwind_idx *unwind_find_idx(unsigned long addr)
{
- struct unwind_idx *idx = NULL;
+ const struct unwind_idx *idx = NULL;
pr_debug("%s(%08lx)\n", __func__, addr);
- if (is_kernel_text(addr))
+ if (is_kernel_text(addr)) {
+ if (unlikely(!__origin_unwind_idx))
+ __origin_unwind_idx =
+ unwind_find_origin(__start_unwind_idx,
+ __stop_unwind_idx);
+
/* main unwind table */
idx = search_index(addr, __start_unwind_idx,
- __stop_unwind_idx - 1);
- else {
+ __origin_unwind_idx,
+ __stop_unwind_idx);
+ } else {
/* module unwinding not supported */
}
@@ -119,7 +177,7 @@ static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
unsigned long ret;
if (ctrl->entries <= 0) {
- pr_warning("unwind: Corrupt unwind table\n");
+ eprintf("unwind: Corrupt unwind table\n");
return 0;
}
@@ -156,7 +214,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
insn = (insn << 8) | unwind_get_byte(ctrl);
mask = insn & 0x0fff;
if (mask == 0) {
- pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n",
+ eprintf("unwind: 'Refuse to unwind' instruction %04lx\n",
insn);
return -URC_FAILURE;
}
@@ -195,7 +253,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
int reg = 0;
if (mask == 0 || mask & 0xf0) {
- pr_warning("unwind: Spare encoding %04lx\n",
+ eprintf("unwind: Spare encoding %04lx\n",
(insn << 8) | mask);
return -URC_FAILURE;
}
@@ -213,7 +271,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
} else {
- pr_warning("unwind: Unhandled instruction %02lx\n", insn);
+ eprintf("unwind: Unhandled instruction %02lx\n", insn);
return -URC_FAILURE;
}
@@ -230,7 +288,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
int unwind_frame(struct stackframe *frame)
{
unsigned long high, low;
- struct unwind_idx *idx;
+ const struct unwind_idx *idx;
struct unwind_ctrl_block ctrl;
/* only go to a higher address on the stack */
@@ -245,7 +303,7 @@ int unwind_frame(struct stackframe *frame)
idx = unwind_find_idx(frame->pc);
if (!idx) {
- pr_warning("unwind: Index not found %08lx\n", frame->pc);
+ eprintf("unwind: Index not found %08lx\n", frame->pc);
return -URC_FAILURE;
}
@@ -264,7 +322,7 @@ int unwind_frame(struct stackframe *frame)
/* only personality routine 0 supported in the index */
ctrl.insn = &idx->insn;
else {
- pr_warning("unwind: Unsupported personality routine %08lx in the index at %p\n",
+ eprintf("unwind: Unsupported personality routine %08lx in the index at %p\n",
idx->insn, idx);
return -URC_FAILURE;
}
@@ -277,7 +335,7 @@ int unwind_frame(struct stackframe *frame)
ctrl.byte = 1;
ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
} else {
- pr_warning("unwind: Unsupported personality routine %08lx at %p\n",
+ eprintf("unwind: Unsupported personality routine %08lx at %p\n",
*ctrl.insn, ctrl.insn);
return -URC_FAILURE;
}
@@ -340,15 +398,3 @@ void dump_stack(void)
{
unwind_backtrace(NULL);
}
-
-static int unwind_init(void)
-{
- struct unwind_idx *idx;
-
- /* Convert the symbol addresses to absolute values */
- for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
- idx->addr = prel31_to_addr(&idx->addr);
-
- return 0;
-}
-core_initcall(unwind_init);