diff options
Diffstat (limited to 'arch/arm/lib32')
-rw-r--r-- | arch/arm/lib32/.gitignore | 2 | ||||
-rw-r--r-- | arch/arm/lib32/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/lib32/arm_architected_timer.c | 17 | ||||
-rw-r--r-- | arch/arm/lib32/armlinux.c | 7 | ||||
-rw-r--r-- | arch/arm/lib32/barebox.lds.S | 14 | ||||
-rw-r--r-- | arch/arm/lib32/bootm.c | 10 | ||||
-rw-r--r-- | arch/arm/lib32/bootu.c | 7 | ||||
-rw-r--r-- | arch/arm/lib32/bootz.c | 5 | ||||
-rw-r--r-- | arch/arm/lib32/io.c | 69 | ||||
-rw-r--r-- | arch/arm/lib32/module.c | 2 | ||||
-rw-r--r-- | arch/arm/lib32/optee-early.c | 1 | ||||
-rw-r--r-- | arch/arm/lib32/runtime-offset.S | 2 | ||||
-rw-r--r-- | arch/arm/lib32/setjmp.S | 1 | ||||
-rw-r--r-- | arch/arm/lib32/start-kernel-optee.S | 2 | ||||
-rw-r--r-- | arch/arm/lib32/unwind.c | 138 |
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); |