On 14.03.21 13:27, Ahmad Fatoum wrote: > Given that we only support a single RISC-V board, this puts us in > a good position to make this a multi-image-only architecture. > > This commit adds the necessary bits. It's highly inspired by the ARM PBL > support. Notable difference is that for relocations to be generated, it > was necessary to compile with -fpic. The relocation code assumes the > relocation entries to preprocessed. This is done at build-time by > means of the prelink-riscv script imported from U-Boot. > > Actual migration to -fpic and prelinking is done along with porting > erizo in a follow-up commit. > > Cc: Masahiro Yamada <masahiroy@xxxxxxxxxx> > Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx> > > --- > Hello Masahiro, > > Do you know if Kernel Kbuild has a similiar prelink stage somewhere, > i.e. an optional architecture-specific rule that processes the ELF file > before continuing normally? I'd like for arch/risc/Makefile to define > PRELINK as a command that takes the ELF as an argument and for the > Makefiles to have no knowledge about PRELINK's content or architecture, > but I don't know how to best go about this. > > Thanks > --- > arch/riscv/Makefile | 1 + > arch/riscv/boot/Makefile | 3 + > arch/riscv/boot/entry.c | 33 +++++ > arch/riscv/boot/entry.h | 15 ++ > arch/riscv/boot/entry_ll.S | 15 ++ > arch/riscv/boot/start.c | 197 +++++++++++++++++++++++++ > arch/riscv/boot/uncompress.c | 74 ++++++++++ > arch/riscv/include/asm/barebox-riscv.h | 101 +++++++++++++ > arch/riscv/include/asm/common.h | 10 +- > arch/riscv/include/asm/elf.h | 7 + > arch/riscv/include/asm/linkage.h | 4 + > arch/riscv/include/asm/sections.h | 15 ++ > arch/riscv/lib/Makefile | 3 + > arch/riscv/lib/barebox.lds.S | 14 +- > arch/riscv/lib/pbl.lds.S | 83 +++++++++++ > arch/riscv/lib/reloc.c | 64 ++++++++ > arch/riscv/lib/runtime-offset.S | 12 ++ > arch/riscv/lib/sections.c | 9 ++ > arch/riscv/lib/setupc.S | 55 +++++++ > scripts/.gitignore | 1 + > scripts/Makefile | 1 + > scripts/Makefile.lib | 11 ++ > scripts/prelink-riscv.c | 122 +++++++++++++++ > scripts/prelink-riscv.inc | 123 +++++++++++++++ > 24 files changed, 969 insertions(+), 4 deletions(-) > create mode 100644 arch/riscv/boot/Makefile > create mode 100644 arch/riscv/boot/entry.c > create mode 100644 arch/riscv/boot/entry.h > create mode 100644 arch/riscv/boot/entry_ll.S > create mode 100644 arch/riscv/boot/start.c > create mode 100644 arch/riscv/boot/uncompress.c > create mode 100644 arch/riscv/include/asm/barebox-riscv.h > create mode 100644 arch/riscv/lib/pbl.lds.S > create mode 100644 arch/riscv/lib/reloc.c > create mode 100644 arch/riscv/lib/runtime-offset.S > create mode 100644 arch/riscv/lib/sections.c > create mode 100644 arch/riscv/lib/setupc.S > create mode 100644 scripts/prelink-riscv.c > create mode 100644 scripts/prelink-riscv.inc > > diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile > index d9cefe32c057..df2b5bb681a4 100644 > --- a/arch/riscv/Makefile > +++ b/arch/riscv/Makefile > @@ -43,6 +43,7 @@ endif > common-y += $(MACH) > common-y += arch/riscv/boards/ > common-y += arch/riscv/lib/ > +common-y += arch/riscv/boot/ > > common-$(CONFIG_OFTREE) += arch/riscv/dts/ > > diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile > new file mode 100644 > index 000000000000..954e9b602287 > --- /dev/null > +++ b/arch/riscv/boot/Makefile > @@ -0,0 +1,3 @@ > +# SPDX-License-Identifier: GPL-2.0 > +obj-y += start.o > +obj-pbl-y += entry.o entry_ll.o uncompress.o > diff --git a/arch/riscv/boot/entry.c b/arch/riscv/boot/entry.c > new file mode 100644 > index 000000000000..ec506acfa3b2 > --- /dev/null > +++ b/arch/riscv/boot/entry.c > @@ -0,0 +1,33 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#include <types.h> > + > +#include <asm/barebox-riscv.h> > + > +#include "entry.h" > +#include <debug_ll.h> > + > +/* > + * Main RISC-V entry point. Call this with the memory region you can > + * spare for barebox. This doesn't necessarily have to be the full > + * SDRAM. The currently running binary can be inside or outside of > + * this region. The PBL can be running inside or outside of this > + * region. > + * > + * -> membase + memsize > + * STACK_SIZE - stack > + * 128KiB - early memory space > + * -> maximum end of barebox binary > + */ > + > +void __noreturn __barebox_riscv_entry(unsigned long membase, > + unsigned long memsize, > + void *boarddata, > + unsigned long sp); > + > +void __noreturn barebox_riscv_entry(unsigned long membase, > + unsigned long memsize, void *boarddata) > +{ > + __barebox_riscv_entry(membase, memsize, boarddata, > + riscv_mem_stack_top(membase, membase + memsize)); > +} > + > diff --git a/arch/riscv/boot/entry.h b/arch/riscv/boot/entry.h > new file mode 100644 > index 000000000000..b3a24d2783f7 > --- /dev/null > +++ b/arch/riscv/boot/entry.h > @@ -0,0 +1,15 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef __ENTRY_H__ > +#define __ENTRY_H__ > + > +#include <common.h> > + > +void __noreturn barebox_non_pbl_start(unsigned long membase, > + unsigned long memsize, > + void *boarddata); > + > +void __noreturn barebox_pbl_start(unsigned long membase, > + unsigned long memsize, > + void *boarddata); > + > +#endif > diff --git a/arch/riscv/boot/entry_ll.S b/arch/riscv/boot/entry_ll.S > new file mode 100644 > index 000000000000..7011fefad865 > --- /dev/null > +++ b/arch/riscv/boot/entry_ll.S > @@ -0,0 +1,15 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#include <linux/linkage.h> > +#include <asm/sections.h> > + > +/* > + * a0: memory base > + * a1: memory size > + * a2: board data > + * a3: new value for SP > + */ > +.section .text.__barebox_riscv_entry > +ENTRY(__barebox_riscv_entry) > + move sp, a3 > + j barebox_pbl_start > +ENDPROC(__barebox_riscv_entry) > diff --git a/arch/riscv/boot/start.c b/arch/riscv/boot/start.c > new file mode 100644 > index 000000000000..7fcbafcc0758 > --- /dev/null > +++ b/arch/riscv/boot/start.c > @@ -0,0 +1,197 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +// SPDX-FileCopyrightText: 2010 Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>, Pengutronix > + > +#define pr_fmt(fmt) "start.c: " fmt > + > +#include <common.h> > +#include <init.h> > +#include <linux/sizes.h> > +#include <of.h> > +#include <asm/barebox-riscv.h> > +#include <asm-generic/memory_layout.h> > +#include <asm/sections.h> > +#include <asm/unaligned.h> > +#include <linux/kasan.h> > +#include <memory.h> > +#include <uncompress.h> > +#include <malloc.h> > + > +#include <debug_ll.h> > + > +#include "entry.h" > + > +unsigned long riscv_stack_top; > +static unsigned long riscv_barebox_size; > +static unsigned long riscv_endmem; > +static void *barebox_boarddata; > +static unsigned long barebox_boarddata_size; > + > +static bool blob_is_fdt(const void *blob) > +{ > + return get_unaligned_be32(blob) == FDT_MAGIC; > +} > + > +static bool blob_is_compressed_fdt(const void *blob) > +{ > + const struct barebox_riscv_boarddata_compressed_dtb *dtb = blob; > + > + return dtb->magic == BAREBOX_RISCV_BOARDDATA_COMPRESSED_DTB_MAGIC; > +} > + > +void *barebox_riscv_boot_dtb(void) > +{ > + void *dtb; > + void *data; > + int ret; > + struct barebox_riscv_boarddata_compressed_dtb *compressed_dtb; > + static void *boot_dtb; > + > + if (boot_dtb) > + return boot_dtb; > + > + if (barebox_boarddata && blob_is_fdt(barebox_boarddata)) { > + pr_debug("%s: using barebox_boarddata\n", __func__); > + return barebox_boarddata; > + } > + > + if (!IS_ENABLED(CONFIG_USE_COMPRESSED_DTB) || !barebox_boarddata > + || !blob_is_compressed_fdt(barebox_boarddata)) > + return NULL; > + > + compressed_dtb = barebox_boarddata; > + > + pr_debug("%s: using compressed_dtb\n", __func__); > + > + dtb = malloc(compressed_dtb->datalen_uncompressed); > + if (!dtb) > + return NULL; > + > + data = compressed_dtb + 1; > + > + ret = uncompress(data, compressed_dtb->datalen, NULL, NULL, dtb, NULL, NULL); > + if (ret) { > + pr_err("uncompressing dtb failed\n"); > + free(dtb); > + return NULL; > + } > + > + boot_dtb = dtb; > + > + return boot_dtb; > +} > + > +static inline unsigned long riscv_mem_boarddata(unsigned long membase, > + unsigned long endmem, > + unsigned long size) > +{ > + unsigned long mem; > + > + mem = riscv_mem_barebox_image(membase, endmem, riscv_barebox_size); > + mem -= ALIGN(size, 64); > + > + return mem; > +} > + > +unsigned long riscv_mem_ramoops_get(void) > +{ > + return riscv_mem_ramoops(0, riscv_stack_top); > +} > +EXPORT_SYMBOL_GPL(riscv_mem_ramoops_get); > + > +unsigned long riscv_mem_endmem_get(void) > +{ > + return riscv_endmem; > +} > +EXPORT_SYMBOL_GPL(riscv_mem_endmem_get); > + > +static int barebox_memory_areas_init(void) > +{ > + if(barebox_boarddata) > + request_sdram_region("board data", (unsigned long)barebox_boarddata, > + barebox_boarddata_size); > + > + return 0; > +} > +device_initcall(barebox_memory_areas_init); > + > +/* > + * First function in the uncompressed image. We get here from > + * the pbl. The stack already has been set up by the pbl. > + */ > +__noreturn __no_sanitize_address __section(.text_entry) > +void barebox_non_pbl_start(unsigned long membase, unsigned long memsize, void *boarddata) > +{ > + unsigned long endmem = membase + memsize; > + unsigned long malloc_start, malloc_end; > + unsigned long barebox_size = barebox_image_size + MAX_BSS_SIZE; > + unsigned long barebox_base = riscv_mem_barebox_image(membase, endmem, barebox_size); > + > + relocate_to_current_adr(); > + > + setup_c(); > + > + barrier(); > + > + pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize); > + > + riscv_endmem = endmem; > + riscv_stack_top = riscv_mem_stack_top(membase, endmem); > + riscv_barebox_size = barebox_size; > + malloc_end = barebox_base; > + > + if (boarddata) { > + uint32_t totalsize = 0; > + const char *name; > + > + if (blob_is_fdt(boarddata)) { > + totalsize = get_unaligned_be32(boarddata + 4); > + name = "DTB"; > + } else if (blob_is_compressed_fdt(boarddata)) { > + struct barebox_riscv_boarddata_compressed_dtb *bd = boarddata; > + totalsize = bd->datalen + sizeof(*bd); > + name = "Compressed DTB"; > + } > + > + if (totalsize) { > + unsigned long mem = riscv_mem_boarddata(membase, endmem, totalsize); > + pr_debug("found %s in boarddata, copying to 0x%08lx\n", name, mem); > + barebox_boarddata = memcpy((void *)mem, boarddata, totalsize); > + barebox_boarddata_size = totalsize; > + malloc_end = mem; > + } > + } > + > + /* > + * Maximum malloc space is the Kconfig value if given > + * or 1GB. > + */ > + if (MALLOC_SIZE > 0) { > + malloc_start = malloc_end - MALLOC_SIZE; > + if (malloc_start < membase) > + malloc_start = membase; > + } else { > + malloc_start = malloc_end - (malloc_end - membase) / 2; > + if (malloc_end - malloc_start > SZ_1G) > + malloc_start = malloc_end - SZ_1G; > + } > + > + pr_debug("initializing malloc pool at 0x%08lx (size 0x%08lx)\n", > + malloc_start, malloc_end - malloc_start); > + > + mem_malloc_init((void *)malloc_start, (void *)malloc_end - 1); > + > + pr_debug("starting barebox...\n"); > + > + start_barebox(); > +} > + > +void start(unsigned long membase, unsigned long memsize, void *boarddata); > +/* > + * First function in the uncompressed image. We get here from > + * the pbl. The stack already has been set up by the pbl. > + */ > +void __no_sanitize_address __section(.text_entry) start(unsigned long membase, > + unsigned long memsize, void *boarddata) > +{ > + barebox_non_pbl_start(membase, memsize, boarddata); > +} > diff --git a/arch/riscv/boot/uncompress.c b/arch/riscv/boot/uncompress.c > new file mode 100644 > index 000000000000..cf268bece1bf > --- /dev/null > +++ b/arch/riscv/boot/uncompress.c > @@ -0,0 +1,74 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +// SPDX-FileCopyrightText: 2010-2013 Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>, Pengutronix > +// SPDX-FileCopyrightText: 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx> > + > +/* uncompress.c - uncompressor code for self extracing pbl image */ > + > +#define pr_fmt(fmt) "uncompress.c: " fmt > + > +#include <common.h> > +#include <init.h> > +#include <linux/sizes.h> > +#include <pbl.h> > +#include <asm/barebox-riscv.h> > +#include <asm-generic/memory_layout.h> > +#include <asm/sections.h> > +#include <asm/unaligned.h> > + > +#include <debug_ll.h> > + > +#include "entry.h" > + > +unsigned long free_mem_ptr; > +unsigned long free_mem_end_ptr; > + > +extern unsigned char input_data[]; > +extern unsigned char input_data_end[]; > + > +void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize, > + void *fdt) > +{ > + uint32_t pg_len, uncompressed_len; > + void __noreturn (*barebox)(unsigned long, unsigned long, void *); > + unsigned long endmem = membase + memsize; > + unsigned long barebox_base; > + void *pg_start, *pg_end; > + unsigned long pc = get_pc(); > + > + pg_start = input_data + get_runtime_offset(); > + pg_end = input_data_end + get_runtime_offset(); > + > + /* > + * If we run from inside the memory just relocate the binary > + * 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) > + relocate_to_current_adr(); > + else > + relocate_to_adr(membase); > + > + pg_len = pg_end - pg_start; > + uncompressed_len = get_unaligned((const u32 *)(pg_start + pg_len - 4)); > + > + barebox_base = riscv_mem_barebox_image(membase, endmem, > + uncompressed_len + MAX_BSS_SIZE); > + > + setup_c(); > + > + pr_debug("memory at 0x%08lx, size 0x%08lx\n", membase, memsize); > + > + free_mem_ptr = riscv_mem_early_malloc(membase, endmem); > + free_mem_end_ptr = riscv_mem_early_malloc_end(membase, endmem); > + > + pr_debug("uncompressing barebox binary at 0x%p (size 0x%08x) to 0x%08lx (uncompressed size: 0x%08x)\n", > + pg_start, pg_len, barebox_base, uncompressed_len); > + > + pbl_barebox_uncompress((void*)barebox_base, pg_start, pg_len); > + > + barebox = (void *)barebox_base; > + > + pr_debug("jumping to uncompressed image at 0x%p. dtb=0x%p\n", barebox, fdt); > + > + barebox(membase, memsize, fdt); > +} > diff --git a/arch/riscv/include/asm/barebox-riscv.h b/arch/riscv/include/asm/barebox-riscv.h > new file mode 100644 > index 000000000000..05e076c4868b > --- /dev/null > +++ b/arch/riscv/include/asm/barebox-riscv.h > @@ -0,0 +1,101 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * (C) Copyright 2002 > + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> > + * Marius Groeger <mgroeger@xxxxxxxx> > + * > + * (C) Copyright 2002 > + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> > + * Alex Zuepke <azu@xxxxxxxx> > + */ > + > +#ifndef _BAREBOX_RISCV_H_ > +#define _BAREBOX_RISCV_H_ > + > +#include <linux/sizes.h> > +#include <asm-generic/memory_layout.h> > +#include <linux/kernel.h> > +#include <linux/types.h> > +#include <linux/compiler.h> > +#include <asm/sections.h> > + > +unsigned long get_runtime_offset(void); > + > +void setup_c(void); > +void relocate_to_current_adr(void); > +void relocate_to_adr(unsigned long target); > +void __noreturn barebox_riscv_entry(unsigned long membase, unsigned long memsize, void *boarddata); > + > +unsigned long riscv_mem_ramoops_get(void); > +unsigned long riscv_mem_endmem_get(void); > + > +struct barebox_riscv_boarddata_compressed_dtb { > +#define BAREBOX_RISCV_BOARDDATA_COMPRESSED_DTB_MAGIC 0x7b66bcbd > + u32 magic; > + u32 datalen; > + u32 datalen_uncompressed; > +}; > + > +void *barebox_riscv_boot_dtb(void); > + > +static inline unsigned long riscv_mem_stack_top(unsigned long membase, > + unsigned long endmem) > +{ > + return endmem - SZ_2M; > +} > + > +static inline unsigned long riscv_mem_stack(unsigned long membase, > + unsigned long endmem) > +{ > + return riscv_mem_stack_top(membase, endmem) - STACK_SIZE; > +} > + > +static inline unsigned long riscv_mem_early_malloc(unsigned long membase, > + unsigned long endmem) > +{ > + return riscv_mem_stack(membase, endmem) - SZ_128K; > +} > + > +static inline unsigned long riscv_mem_early_malloc_end(unsigned long membase, > + unsigned long endmem) > +{ > + return riscv_mem_stack(membase, endmem); > +} > + > +static inline unsigned long riscv_mem_ramoops(unsigned long membase, > + unsigned long endmem) > +{ > + endmem = riscv_mem_stack(membase, endmem); > +#ifdef CONFIG_FS_PSTORE_RAMOOPS > + endmem -= CONFIG_FS_PSTORE_RAMOOPS_SIZE; > + endmem = ALIGN_DOWN(endmem, SZ_4K); > +#endif > + > + return endmem; > +} > + > +static inline unsigned long riscv_mem_barebox_image(unsigned long membase, > + unsigned long endmem, > + unsigned long size) > +{ > + endmem = riscv_mem_ramoops(membase, endmem); > + > + return ALIGN_DOWN(endmem - size, SZ_1M); > +} > + > +#define ENTRY_FUNCTION(name, arg0, arg1, arg2) \ > + void name (ulong a0, ulong a1, ulong a2); \ > + void __section(.text_head_entry_##name) name (ulong a0, ulong a1, ulong a2) > + > +/* > + * When using compressed images in conjunction with relocatable images > + * the PBL code must pick a suitable place where to uncompress the barebox > + * image. For doing this the PBL code must know the size of the final > + * image including the BSS segment. The BSS size is unknown to the PBL > + * code, so define a maximum BSS size here. > + */ > +#define MAX_BSS_SIZE SZ_1M > + > +#define barebox_image_size (__image_end - __image_start) > + > +#endif /* _BAREBOX_RISCV_H_ */ > diff --git a/arch/riscv/include/asm/common.h b/arch/riscv/include/asm/common.h > index bc8a17e30bc5..a0982c548fe1 100644 > --- a/arch/riscv/include/asm/common.h > +++ b/arch/riscv/include/asm/common.h > @@ -1,6 +1,14 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* SPDX-FileCopyrightText: Copyright (c) 2021 Ahmad Fatoum, Pengutronix */ > #ifndef ASM_RISCV_COMMON_H > #define ASM_RISCV_COMMON_H > > -/* nothing special yet */ > +#include <linux/compiler.h> > + > +static __always_inline unsigned long get_pc(void) > +{ > +label: > + return (unsigned long)&&label; > +} > > #endif /* ASM_RISCV_COMMON_H */ > diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h > index 7134fa05820a..adb8ec8f6ece 100644 > --- a/arch/riscv/include/asm/elf.h > +++ b/arch/riscv/include/asm/elf.h > @@ -1,3 +1,4 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > #ifndef __ASM_RISCV_ELF_H__ > #define __ASM_RISCV_ELF_H__ > > @@ -8,4 +9,10 @@ > #define ELF_CLASS ELFCLASS32 > #endif > > +/* Relocation types used by the dynamic linker */ > +#define R_RISCV_NONE 0 > +#define R_RISCV_32 1 > +#define R_RISCV_64 2 > +#define R_RISCV_RELATIVE 3 > + > #endif /* __ASM_RISCV_ELF_H__ */ > diff --git a/arch/riscv/include/asm/linkage.h b/arch/riscv/include/asm/linkage.h > index 9e88ba23cd2b..c6801294f388 100644 > --- a/arch/riscv/include/asm/linkage.h > +++ b/arch/riscv/include/asm/linkage.h > @@ -9,4 +9,8 @@ > #define __ALIGN .balign 4 > #define __ALIGN_STR ".balign 4" > > +#define ENDPROC(name) \ > + .type name, %function; \ > + END(name) > + > #endif /* _ASM_RISCV_LINKAGE_H */ > diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h > index 2b8c5160388f..b5fbba8f165a 100644 > --- a/arch/riscv/include/asm/sections.h > +++ b/arch/riscv/include/asm/sections.h > @@ -1 +1,16 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +#ifndef __ASM_SECTIONS_H > +#define __ASM_SECTIONS_H > + > +#ifndef __ASSEMBLY__ > #include <asm-generic/sections.h> > +#include <linux/types.h> > + > +extern char __rel_dyn_start[]; > +extern char __rel_dyn_end[]; > +extern char __dynsym_start[]; > +extern char __dynsym_end[]; > + > +#endif > + > +#endif /* __ASM_SECTIONS_H */ > diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile > index b983ca8cdca0..5f57d9fcd2e2 100644 > --- a/arch/riscv/lib/Makefile > +++ b/arch/riscv/lib/Makefile > @@ -1,5 +1,8 @@ > +# SPDX-License-Identifier: GPL-2.0 > + > extra-y += barebox.lds > > obj-y += riscv_timer.o > +obj-pbl-y += sections.o setupc.o reloc.o sections.o runtime-offset.o > obj-$(CONFIG_HAS_ARCH_SJLJ) += setjmp.o longjmp.o > obj-$(CONFIG_RISCV_OPTIMZED_STRING_FUNCTIONS) += memcpy.o memset.o memmove.o > diff --git a/arch/riscv/lib/barebox.lds.S b/arch/riscv/lib/barebox.lds.S > index 342769890bb0..c8a331c577cf 100644 > --- a/arch/riscv/lib/barebox.lds.S > +++ b/arch/riscv/lib/barebox.lds.S > @@ -43,10 +43,18 @@ SECTIONS > > .barebox_imd : { BAREBOX_IMD } > > - . = ALIGN(8); > - .got : { *(.got*) } > + /DISCARD/ : { *(.rela.plt*) } > + .rela.dyn : { > + __rel_dyn_start = .; > + *(.rel*) > + __rel_dyn_end = .; > + } > > - .rela.dyn : { *(.rela*) } > + .dynsym : { > + __dynsym_start = .; > + *(.dynsym) > + __dynsym_end = .; > + } > > _edata = .; > . = ALIGN(8); > diff --git a/arch/riscv/lib/pbl.lds.S b/arch/riscv/lib/pbl.lds.S > new file mode 100644 > index 000000000000..33caab7b1024 > --- /dev/null > +++ b/arch/riscv/lib/pbl.lds.S > @@ -0,0 +1,83 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* SPDX-FileCopyrightText: 2012 Sascha Hauer <s.hauer@xxxxxxxxxxxxxx>, Pengutronix */ > + > +#include <linux/sizes.h> > +#include <asm-generic/barebox.lds.h> > +#include <asm-generic/memory_layout.h> > + > +OUTPUT_ARCH(riscv) > +SECTIONS > +{ > + . = 0x0; > + > + .image_start : { *(.__image_start) } > + > + . = ALIGN(4); > + ._text : { *(._text) } > + .text : > + { > + _stext = .; > + *(.text_head_entry*) > + __bare_init_start = .; > + *(.text_bare_init*) > + __bare_init_end = .; > + *(.text*) > + } > + > + /* Discard unwind if enable in barebox */ > + /DISCARD/ : { *(.ARM.ex*) } > + > + BAREBOX_BARE_INIT_SIZE > + BAREBOX_PBL_SIZE > + > + . = ALIGN(4); > + .rodata : { *(.rodata*) } > + > + .barebox_imd : { BAREBOX_IMD } > + > + _etext = .; /* End of text and rodata section */ > + > + .data : { *(.data*) } > + > + __shasum_start = .; > + .shasum : { > + KEEP(*(.shasum)) > + } > + __shasum_end = .; > + > + /DISCARD/ : { *(.rela.plt*) } > + .rela.dyn : { > + __rel_dyn_start = .; > + *(.rela*) > + __rel_dyn_end = .; > + } > + > + .dynsym : { > + __dynsym_start = .; > + *(.dynsym) > + __dynsym_end = .; > + } > + > + pbl_code_size = .; > + > + .__bss_start : { *(.__bss_start) } > + .bss : { *(.bss*) } > + .__bss_stop : { *(.__bss_stop) } > + _end = .; > + > + pbl_memory_size = .; > + > + . = ALIGN(4); > + __piggydata_start = .; > + .piggydata : { > + *(.piggydata) > + } > + __piggydata_end = .; > + > + .image_end : { KEEP(*(.__image_end)) } > + > + pbl_image_size = .; > + > + _barebox_image_size = __image_end; > + _barebox_pbl_size = __bss_start; > +} > diff --git a/arch/riscv/lib/reloc.c b/arch/riscv/lib/reloc.c > new file mode 100644 > index 000000000000..5e26c0be9c1c > --- /dev/null > +++ b/arch/riscv/lib/reloc.c > @@ -0,0 +1,64 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +// SPDX-FileCopyrightText: Copyright (c) 2021 Ahmad Fatoum, Pengutronix > + > +#include <common.h> > +#include <linux/linkage.h> > +#include <asm/sections.h> > +#include <asm/barebox-riscv.h> > +#include <debug_ll.h> > +#include <asm-generic/module.h> > + > +#include <elf.h> > + > +#if __riscv_xlen == 64 > +#define Elf_Rela Elf64_Rela > +#define R_RISCV_ABSOLUTE R_RISCV_64 > +#define DYNSYM_ENTRY(dynsym, rela) dynsym[ELF_R_SYM(rela->r_info) * 3 + 1] > +#elif __riscv_xlen == 32 > +#define Elf_Rela Elf32_Rela > +#define R_RISCV_ABSOLUTE R_RISCV_32 > +#define DYNSYM_ENTRY(dynsym, rela) dynsym[ELF_R_SYM(rela->r_info) * 4 + 1] > +#else > +#error unknown riscv target > +#endif > + > +#define RISC_R_TYPE(x) ((x) & 0xFF) > + > +void relocate_to_current_adr(void) > +{ > + unsigned long offset; > + unsigned long *dynsym; > + void *dstart, *dend; > + Elf_Rela *rela; > + > + /* Get offset between linked address and runtime address */ > + offset = get_runtime_offset(); > + > + dstart = __rel_dyn_start + offset; > + dend = __rel_dyn_end + offset; > + dynsym = (void *)__dynsym_start + offset; > + > + for (rela = dstart; (void *)rela < dend; rela++) { > + unsigned long *fixup; > + > + fixup = (unsigned long *)(rela->r_offset + offset); > + > + switch (RISC_R_TYPE(rela->r_info)) { > + case R_RISCV_RELATIVE: > + *fixup = rela->r_addend + offset; > + break; > + case R_RISCV_ABSOLUTE: > + *fixup = DYNSYM_ENTRY(dynsym, rela) + rela->r_addend + offset; > + break; > + default: > + putc_ll('>'); > + puthex_ll(rela->r_info); > + putc_ll(' '); > + puthex_ll(rela->r_offset); > + putc_ll(' '); > + puthex_ll(rela->r_addend); > + putc_ll('\n'); > + panic(""); > + } > + } > +} > diff --git a/arch/riscv/lib/runtime-offset.S b/arch/riscv/lib/runtime-offset.S > new file mode 100644 > index 000000000000..f6a040628963 > --- /dev/null > +++ b/arch/riscv/lib/runtime-offset.S > @@ -0,0 +1,12 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* SPDX-FileCopyrightText: Copyright (c) 2021 Ahmad Fatoum, Pengutronix */ > +#include <linux/linkage.h> > +#include <asm/sections.h> > + > +.section ".text_bare_init","ax" > +ENTRY(get_runtime_offset) > + lla a0, _text /* load addr */ > + la a1, _text /* link addr */ > + sub a0, a0, a1 > + ret > +ENDPROC(get_runtime_offset) > diff --git a/arch/riscv/lib/sections.c b/arch/riscv/lib/sections.c > new file mode 100644 > index 000000000000..e23a41dcf5d4 > --- /dev/null > +++ b/arch/riscv/lib/sections.c > @@ -0,0 +1,9 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#include <asm/sections.h> > +#include <linux/types.h> > + > +char _text[0] __attribute__((section("._text"))); > +char __bss_start[0] __attribute__((section(".__bss_start"))); > +char __bss_stop[0] __attribute__((section(".__bss_stop"))); > +char __image_start[0] __attribute__((section(".__image_start"))); > +char __image_end[0] __attribute__((section(".__image_end"))); > diff --git a/arch/riscv/lib/setupc.S b/arch/riscv/lib/setupc.S > new file mode 100644 > index 000000000000..6d824d00f7e0 > --- /dev/null > +++ b/arch/riscv/lib/setupc.S > @@ -0,0 +1,55 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* SPDX-FileCopyrightText: Copyright (c) 2021 Ahmad Fatoum, Pengutronix */ > + > +#include <linux/linkage.h> > +#include <asm/sections.h> > +#include <asm/asm.h> > + > +/* > + * setup_c: clear bss > + */ > +.section .text.setup_c > +ENTRY(setup_c) > + lla a0, __bss_start > + li a1, 0 > + lla a2, __bss_stop > + sub a2, a2, a0 > + j __memset > +ENDPROC(setup_c) > + > +/* > + * void relocate_to_adr(unsigned long targetadr) > + * > + * Copy binary to targetadr, relocate code and continue > + * executing at new address. > + */ > +.section .text.relocate_to_adr > +ENTRY(relocate_to_adr) > + /* a0: target address */ > + addi sp, sp, -SZREG * 2 > + lla a1, _text /* a1: source address */ > + > + beq a0, a1, copied /* skip if already at new address */ This needs to be moved after spilling ra onto stack. Will fix in v2. > + > + lla a2, copied > + sub a2, a2, a1 > + add a2, a2, a0 > + REG_S a2, (SZREG * 1)(sp) > + > + /* adjust return address */ > + sub ra, ra, a1 /* sub address where we are actually running */ > + add ra, ra, a0 /* add address where we are going to run */ > + REG_S ra, (SZREG * 2)(sp) > + > + lla a2, __bss_start > + sub a2, a2, a1 /* a2: size */ > + > + jal __memcpy > + > + REG_L a0, (SZREG * 1)(sp) > + jr a0 /* jump to relocated address */ > +copied: > + REG_L ra, (SZREG * 2)(sp) > + addi sp, sp, SZREG * 2 > + j relocate_to_current_adr /* relocate binary */ > +ENDPROC(relocate_to_adr) > diff --git a/scripts/.gitignore b/scripts/.gitignore > index 7c9a3f55715f..9577d568edd0 100644 > --- a/scripts/.gitignore > +++ b/scripts/.gitignore > @@ -32,3 +32,4 @@ mips-relocs > rsatoc > stm32image > mvebuimg > +prelink-riscv > diff --git a/scripts/Makefile b/scripts/Makefile > index 744f4dd0e7e6..4dc70815b7e6 100644 > --- a/scripts/Makefile > +++ b/scripts/Makefile > @@ -24,6 +24,7 @@ hostprogs-always-$(CONFIG_ARCH_SOCFPGA) += socfpga_mkimage > hostprogs-always-$(CONFIG_ARCH_MXS) += mxsimage mxsboot > hostprogs-always-$(CONFIG_ARCH_LAYERSCAPE) += pblimage > hostprogs-always-$(CONFIG_ARCH_STM32MP) += stm32image > +hostprogs-always-$(CONFIG_RISCV) += prelink-riscv > KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/ > HOSTLDLIBS_mxsimage = `pkg-config --libs openssl` > HOSTCFLAGS_omap3-usb-loader.o = `pkg-config --cflags libusb-1.0` > diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib > index 2844d29be600..319ac19975ed 100644 > --- a/scripts/Makefile.lib > +++ b/scripts/Makefile.lib > @@ -247,6 +247,17 @@ $(obj)/%:: $(src)/%_shipped > # and add target to extra-y so that we know we have to > # read in the saved command line > > +# Prelinking > +# --------------------------------------------------------------------------- > + > +ifneq ($(CONFIG_RISCV),) > +quiet_cmd_prelink__ = PRELINK $@ > + cmd_prelink__ = $(objtree)/scripts/prelink-riscv $@ > +endif > + > +quiet_cmd_prelink__ ?= > + cmd_prelink__ ?= > + > # Linking > # --------------------------------------------------------------------------- > > diff --git a/scripts/prelink-riscv.c b/scripts/prelink-riscv.c > new file mode 100644 > index 000000000000..c185d3981ca1 > --- /dev/null > +++ b/scripts/prelink-riscv.c > @@ -0,0 +1,122 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) 2017 Andes Technology > + * Chih-Mao Chen <cmchen@xxxxxxxxxxxxx> > + * > + * Statically process runtime relocations on RISC-V ELF images > + * so that it can be directly executed when loaded at LMA > + * without fixup. Both RV32 and RV64 are supported. > + */ > + > +#include <errno.h> > +#include <stdbool.h> > +#include <stdint.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > + > +#include <elf.h> > +#include <fcntl.h> > +#include <sys/mman.h> > +#include <sys/stat.h> > +#include <sys/types.h> > +#include <unistd.h> > +#include "compiler.h" > + > +#ifndef EM_RISCV > +#define EM_RISCV 243 > +#endif > + > +#ifndef R_RISCV_32 > +#define R_RISCV_32 1 > +#endif > + > +#ifndef R_RISCV_64 > +#define R_RISCV_64 2 > +#endif > + > +#ifndef R_RISCV_RELATIVE > +#define R_RISCV_RELATIVE 3 > +#endif > + > +const char *argv0; > + > +#define die(fmt, ...) \ > + do { \ > + fprintf(stderr, "%s: " fmt "\n", argv0, ## __VA_ARGS__); \ > + exit(EXIT_FAILURE); \ > + } while (0) > + > +#define PRELINK_BYTEORDER le > +#define PRELINK_INC_BITS 32 > +#include "prelink-riscv.inc" > +#undef PRELINK_BYTEORDER > +#undef PRELINK_INC_BITS > + > +#define PRELINK_BYTEORDER le > +#define PRELINK_INC_BITS 64 > +#include "prelink-riscv.inc" > +#undef PRELINK_BYTEORDER > +#undef PRELINK_INC_BITS > + > +#define PRELINK_BYTEORDER be > +#define PRELINK_INC_BITS 32 > +#include "prelink-riscv.inc" > +#undef PRELINK_BYTEORDER > +#undef PRELINK_INC_BITS > + > +#define PRELINK_BYTEORDER be > +#define PRELINK_INC_BITS 64 > +#include "prelink-riscv.inc" > +#undef PRELINK_BYTEORDER > +#undef PRELINK_INC_BITS > + > +int main(int argc, const char *const *argv) > +{ > + argv0 = argv[0]; > + > + if (argc < 2) { > + fprintf(stderr, "Usage: %s <u-boot>\n", argv0); > + exit(EXIT_FAILURE); > + } > + > + int fd = open(argv[1], O_RDWR, 0); > + > + if (fd < 0) > + die("Cannot open %s: %s", argv[1], strerror(errno)); > + > + struct stat st; > + > + if (fstat(fd, &st) < 0) > + die("Cannot stat %s: %s", argv[1], strerror(errno)); > + > + void *data = > + mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); > + > + if (data == MAP_FAILED) > + die("Cannot mmap %s: %s", argv[1], strerror(errno)); > + > + close(fd); > + > + unsigned char *e_ident = (unsigned char *)data; > + > + if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) > + die("Invalid ELF file %s", argv[1]); > + > + bool is64 = e_ident[EI_CLASS] == ELFCLASS64; > + bool isbe = e_ident[EI_DATA] == ELFDATA2MSB; > + > + if (is64) { > + if (isbe) > + prelink_be64(data); > + else > + prelink_le64(data); > + } else { > + if (isbe) > + prelink_be32(data); > + else > + prelink_le32(data); > + } > + > + return 0; > +} > diff --git a/scripts/prelink-riscv.inc b/scripts/prelink-riscv.inc > new file mode 100644 > index 000000000000..f2b5467f5b3c > --- /dev/null > +++ b/scripts/prelink-riscv.inc > @@ -0,0 +1,123 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) 2017 Andes Technology > + * Chih-Mao Chen <cmchen@xxxxxxxxxxxxx> > + * > + * Statically process runtime relocations on RISC-V ELF images > + * so that it can be directly executed when loaded at LMA > + * without fixup. Both RV32 and RV64 are supported. > + */ > + > +#define CONCAT_IMPL(x, y) x##y > +#define CONCAT(x, y) CONCAT_IMPL(x, y) > +#define CONCAT3(x, y, z) CONCAT(CONCAT(x, y), z) > + > +#define prelink_bonn CONCAT3(prelink_, PRELINK_BYTEORDER, PRELINK_INC_BITS) > +#define uintnn_t CONCAT3(uint, PRELINK_INC_BITS, _t) > +#define get_offset_bonn CONCAT3(get_offset_, PRELINK_BYTEORDER, PRELINK_INC_BITS) > +#define Elf_Ehdr CONCAT3(Elf, PRELINK_INC_BITS, _Ehdr) > +#define Elf_Phdr CONCAT3(Elf, PRELINK_INC_BITS, _Phdr) > +#define Elf_Rela CONCAT3(Elf, PRELINK_INC_BITS, _Rela) > +#define Elf_Sym CONCAT3(Elf, PRELINK_INC_BITS, _Sym) > +#define Elf_Dyn CONCAT3(Elf, PRELINK_INC_BITS, _Dyn) > +#define Elf_Addr CONCAT3(Elf, PRELINK_INC_BITS, _Addr) > +#define ELF_R_TYPE CONCAT3(ELF, PRELINK_INC_BITS, _R_TYPE) > +#define ELF_R_SYM CONCAT3(ELF, PRELINK_INC_BITS, _R_SYM) > +#define target16_to_cpu CONCAT(PRELINK_BYTEORDER, 16_to_cpu) > +#define target32_to_cpu CONCAT(PRELINK_BYTEORDER, 32_to_cpu) > +#define target64_to_cpu CONCAT(PRELINK_BYTEORDER, 64_to_cpu) > +#define targetnn_to_cpu CONCAT3(PRELINK_BYTEORDER, PRELINK_INC_BITS, _to_cpu) > +#define cpu_to_target32 CONCAT3(cpu_to_, PRELINK_BYTEORDER, 32) > +#define cpu_to_target64 CONCAT3(cpu_to_, PRELINK_BYTEORDER, 64) > + > +static void* get_offset_bonn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr) > +{ > + Elf_Phdr *p; > + > + for (p = phdrs; p < phdrs + phnum; ++p) > + if (targetnn_to_cpu(p->p_vaddr) <= addr && targetnn_to_cpu(p->p_vaddr) + targetnn_to_cpu(p->p_memsz) > addr) > + return data + targetnn_to_cpu(p->p_offset) + (addr - targetnn_to_cpu(p->p_vaddr)); > + > + return NULL; > +} > + > +static void prelink_bonn(void *data) > +{ > + Elf_Ehdr *ehdr = data; > + Elf_Phdr *p; > + Elf_Dyn *dyn; > + Elf_Rela *r; > + > + if (target16_to_cpu(ehdr->e_machine) != EM_RISCV) > + die("Machine type is not RISC-V"); > + > + Elf_Phdr *phdrs = data + targetnn_to_cpu(ehdr->e_phoff); > + > + Elf_Dyn *dyns = NULL; > + for (p = phdrs; p < phdrs + target16_to_cpu(ehdr->e_phnum); ++p) { > + if (target32_to_cpu(p->p_type) == PT_DYNAMIC) { > + dyns = data + targetnn_to_cpu(p->p_offset); > + break; > + } > + } > + > + if (dyns == NULL) > + die("No dynamic section found"); > + > + Elf_Rela *rela_dyn = NULL; > + size_t rela_count = 0; > + Elf_Sym *dynsym = NULL; > + for (dyn = dyns;; ++dyn) { > + if (targetnn_to_cpu(dyn->d_tag) == DT_NULL) > + break; > + else if (targetnn_to_cpu(dyn->d_tag) == DT_RELA) > + rela_dyn = get_offset_bonn(data, phdrs, target16_to_cpu(ehdr->e_phnum), + targetnn_to_cpu(dyn->d_un.d_ptr)); > + else if (targetnn_to_cpu(dyn->d_tag) == DT_RELASZ) > + rela_count = targetnn_to_cpu(dyn->d_un.d_val) / sizeof(Elf_Rela); > + else if (targetnn_to_cpu(dyn->d_tag) == DT_SYMTAB) > + dynsym = get_offset_bonn(data, phdrs, target16_to_cpu(ehdr->e_phnum), + targetnn_to_cpu(dyn->d_un.d_ptr)); > + > + } > + > + if (rela_dyn == NULL) > + die("No .rela.dyn found"); > + > + if (dynsym == NULL) > + die("No .dynsym found"); > + > + for (r = rela_dyn; r < rela_dyn + rela_count; ++r) { > + void* buf = get_offset_bonn(data, phdrs, target16_to_cpu(ehdr->e_phnum), targetnn_to_cpu(r->r_offset)); > + > + if (buf == NULL) > + continue; > + > + if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_RELATIVE) > + *((uintnn_t*) buf) = r->r_addend; > + else if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_32) > + *((uint32_t*) buf) = cpu_to_target32(targetnn_to_cpu(dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value) + targetnn_to_cpu(r->r_addend)); > + else if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_64) > + *((uint64_t*) buf) = cpu_to_target64(targetnn_to_cpu(dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value) + targetnn_to_cpu(r->r_addend)); > + } > +} > + > +#undef prelink_bonn > +#undef uintnn_t > +#undef get_offset_bonn > +#undef Elf_Ehdr > +#undef Elf_Phdr > +#undef Elf_Rela > +#undef Elf_Sym > +#undef Elf_Dyn > +#undef Elf_Addr > +#undef ELF_R_TYPE > +#undef ELF_R_SYM > +#undef target16_to_cpu > +#undef target32_to_cpu > +#undef target64_to_cpu > +#undef targetnn_to_cpu > +#undef cpu_to_target32 > +#undef cpu_to_target64 > + > +#undef CONCAT_IMPL > +#undef CONCAT > +#undef CONCAT3 > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox