diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/riscv/Makefile | 1 | ||||
-rw-r--r-- | arch/riscv/boot/Makefile | 3 | ||||
-rw-r--r-- | arch/riscv/boot/entry.c | 29 | ||||
-rw-r--r-- | arch/riscv/boot/entry.h | 15 | ||||
-rw-r--r-- | arch/riscv/boot/start.c | 185 | ||||
-rw-r--r-- | arch/riscv/boot/uncompress.c | 74 | ||||
-rw-r--r-- | arch/riscv/include/asm/barebox-riscv.h | 104 | ||||
-rw-r--r-- | arch/riscv/include/asm/common.h | 10 | ||||
-rw-r--r-- | arch/riscv/include/asm/elf.h | 7 | ||||
-rw-r--r-- | arch/riscv/include/asm/linkage.h | 4 | ||||
-rw-r--r-- | arch/riscv/include/asm/sections.h | 15 | ||||
-rw-r--r-- | arch/riscv/lib/Makefile | 3 | ||||
-rw-r--r-- | arch/riscv/lib/barebox.lds.S | 14 | ||||
-rw-r--r-- | arch/riscv/lib/pbl.lds.S | 80 | ||||
-rw-r--r-- | arch/riscv/lib/reloc.c | 66 | ||||
-rw-r--r-- | arch/riscv/lib/runtime-offset.S | 12 | ||||
-rw-r--r-- | arch/riscv/lib/sections.c | 9 | ||||
-rw-r--r-- | arch/riscv/lib/setupc.S | 55 |
18 files changed, 682 insertions, 4 deletions
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index d9cefe32c0..df2b5bb681 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 0000000000..70e5b11beb --- /dev/null +++ b/arch/riscv/boot/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += start.o +pbl-y += entry.o uncompress.o diff --git a/arch/riscv/boot/entry.c b/arch/riscv/boot/entry.c new file mode 100644 index 0000000000..eb286423d8 --- /dev/null +++ b/arch/riscv/boot/entry.c @@ -0,0 +1,29 @@ +/* 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 __naked barebox_riscv_entry(unsigned long membase, + unsigned long memsize, void *boarddata) +{ + unsigned long stack_top = riscv_mem_stack_top(membase, membase + memsize); + asm volatile ("move sp, %0" : : "r"(stack_top)); + barebox_pbl_start(membase, memsize, boarddata); +} + diff --git a/arch/riscv/boot/entry.h b/arch/riscv/boot/entry.h new file mode 100644 index 0000000000..b3a24d2783 --- /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/start.c b/arch/riscv/boot/start.c new file mode 100644 index 0000000000..05f6c6231f --- /dev/null +++ b/arch/riscv/boot/start.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2010 Sascha Hauer <s.hauer@pengutronix.de>, 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 <compressed-dtb.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; + +void *barebox_riscv_boot_dtb(void) +{ + void *dtb; + void *data; + int ret; + struct barebox_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 (!fdt_blob_can_be_decompressed(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_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 0000000000..cf268bece1 --- /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@pengutronix.de>, Pengutronix +// SPDX-FileCopyrightText: 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + +/* 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 0000000000..980165dc8a --- /dev/null +++ b/arch/riscv/include/asm/barebox-riscv.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + */ + +#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 __naked 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); + +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 r0, ulong r1, ulong r2); \ + static void __##name(ulong, ulong, ulong); \ + void __naked __noreturn __section(.text_head_entry_##name) name \ + (ulong a0, ulong a1, ulong a2) \ + { \ + __barebox_riscv_head(); \ + __##name(a0, a1, a2); \ + } \ + static void __naked __noreturn noinline __##name \ + (ulong arg0, ulong arg1, ulong arg2) + + +/* + * 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 bc8a17e30b..a0982c548f 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 7134fa0582..adb8ec8f6e 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 9e88ba23cd..c6801294f3 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 2b8c516038..b5fbba8f16 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 b983ca8cdc..5f57d9fcd2 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 342769890b..c8a331c577 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 0000000000..881faac340 --- /dev/null +++ b/arch/riscv/lib/pbl.lds.S @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* SPDX-FileCopyrightText: 2012 Sascha Hauer <s.hauer@pengutronix.de>, 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*) + } + + 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 0000000000..2fc8818cd6 --- /dev/null +++ b/arch/riscv/lib/reloc.c @@ -0,0 +1,66 @@ +// 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(); + if (!offset) + return; + + 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 0000000000..f6a0406289 --- /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 0000000000..e23a41dcf5 --- /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 0000000000..5fdd81c2c3 --- /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 */ + + /* 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) + + beq a0, a1, copied /* skip if already at new address */ + + lla a2, copied + sub a2, a2, a1 + add a2, a2, a0 + REG_S a2, (SZREG * 1)(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) |