[PATCH v2 00/23] microblaze: Add support for full relocation

Hi,
this series is adding support for full rela relocation. Origin NEEDS_MANUAL_RELOC option is still there as default.
Code has been tested with multiple configurations on QEMU. - Origin behavior - u-boot - Relocated version - u-boot.elf - Loading u-boot.bin to higher address than TEXT_BASE - Loading u-boot.bin to lower address than TEXT_BASE
In v2 I fixed Kconfig issue reported in v1 series.
Thanks, Michal
Changes in v2: - new patch in series to solve Kconfig warning - Fix endian selection
Michal Simek (23): tools: relocate-rela: Open binary u-boot file later Makefile: Fix description for relocate-rela parameters tools: relocate-rela: Use global variables tools: relocate-rela: Read rela start/end directly from ELF microblaze: Switch absolute branches to relative microblaze: Fix stack protection behavior microblaze: Fix early stack allocation microblaze: Remove CONFIG_TEXT_BASE from code microblaze: Fix typo in exception.c mips: Move endianness selection to arch/Kconfig microblaze: Enable REMAKE_ELF microblaze: Separate code end substraction microblaze: Change stack protection address to new stack address microblaze: Optimize register usage in relocate_code microblaze: Remove code around r20 in relocate_code() microblaze: Remove _start symbol handling at U-Boot start microblaze: Add comment about reset location microblaze: Create SYM_ADDR macro to deal with symbols tools: relocate-rela: Extract elf64 reloc to special function tools: relocate-rela: Check that relocation works only for EM_AARCH64 tools: relocate-rela: Add support for elf32 decoding tools: relocate-rela: Add support for 32bit Microblaze relocation microblaze: Add support for run time relocation
Makefile | 6 +- arch/Kconfig | 23 +- arch/microblaze/Kconfig | 14 + arch/microblaze/config.mk | 11 + arch/microblaze/cpu/Makefile | 1 + arch/microblaze/cpu/exception.c | 2 +- arch/microblaze/cpu/relocate.c | 111 ++++++ arch/microblaze/cpu/start.S | 130 +++++-- arch/microblaze/cpu/u-boot.lds | 14 + arch/mips/Kconfig | 18 - common/board_f.c | 2 + configs/microblaze-generic_defconfig | 1 + include/configs/microblaze-generic.h | 4 - tools/relocate-rela.c | 545 +++++++++++++++++++++++++-- 14 files changed, 786 insertions(+), 96 deletions(-) create mode 100644 arch/microblaze/cpu/relocate.c

There is no value to open u-boot binary file so early. Better to check all values first and then open binary file.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
tools/relocate-rela.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index f0bc548617a4..883987111869 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -73,13 +73,6 @@ int main(int argc, char **argv) return 1; }
- f = fopen(argv[1], "r+b"); - if (!f) { - fprintf(stderr, "%s: Cannot open %s: %s\n", - argv[0], argv[1], strerror(errno)); - return 2; - } - if (!read_num(argv[2], &text_base) || !read_num(argv[3], &rela_start) || !read_num(argv[4], &rela_end)) { @@ -95,6 +88,13 @@ int main(int argc, char **argv) rela_start -= text_base; rela_end -= text_base;
+ f = fopen(argv[1], "r+b"); + if (!f) { + fprintf(stderr, "%s: Cannot open %s: %s\n", + argv[0], argv[1], strerror(errno)); + return 2; + } + fseek(f, 0, SEEK_END); file_size = ftell(f); rewind(f);

Numbers in comment are shifter which is visible from command which calls them. Also relocate-rela usage is describing them. "Usage: %s <bin file> <text base> <rela start> <rela end>"
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 2fa3a3b488e6..2270ec5c7938 100644 --- a/Makefile +++ b/Makefile @@ -922,7 +922,7 @@ endif # the raw binary, but certain simulators only accept an ELF file (but don't # do the relocation). ifneq ($(CONFIG_STATIC_RELA),) -# $(1) is u-boot ELF, $(2) is u-boot bin, $(3) is text base +# $(2) is u-boot ELF, $(3) is u-boot bin, $(4) is text base quiet_cmd_static_rela = RELOC $@ cmd_static_rela = \ start=$$($(NM) $(2) | grep __rel_dyn_start | cut -f 1 -d ' '); \

Declare rela_start/end and text_base as global variables. It will help with using these variables for ELF decoding.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
tools/relocate-rela.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index 883987111869..67a138aa67d7 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -20,6 +20,8 @@ #define R_AARCH64_RELATIVE 1027 #endif
+static uint64_t rela_start, rela_end, text_base; + static const bool debug_en;
static void debug(const char *fmt, ...) @@ -63,7 +65,7 @@ int main(int argc, char **argv) { FILE *f; int i, num; - uint64_t rela_start, rela_end, text_base, file_size; + uint64_t file_size;
if (argc != 5) { fprintf(stderr, "Statically apply ELF rela relocations\n");

There is no need to pass section information via parameters. Let's read text base and rela start/end directly from elf. It will help with reading other information from ELF for others architecture. Input to relocate-rela is u-boot binary and u-boot ELF.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
Makefile | 4 +- tools/relocate-rela.c | 181 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 168 insertions(+), 17 deletions(-)
diff --git a/Makefile b/Makefile index 2270ec5c7938..55c55dbb7e2b 100644 --- a/Makefile +++ b/Makefile @@ -925,9 +925,7 @@ ifneq ($(CONFIG_STATIC_RELA),) # $(2) is u-boot ELF, $(3) is u-boot bin, $(4) is text base quiet_cmd_static_rela = RELOC $@ cmd_static_rela = \ - start=$$($(NM) $(2) | grep __rel_dyn_start | cut -f 1 -d ' '); \ - end=$$($(NM) $(2) | grep __rel_dyn_end | cut -f 1 -d ' '); \ - tools/relocate-rela $(3) $(4) $$start $$end + tools/relocate-rela $(3) $(2) else quiet_cmd_static_rela = cmd_static_rela = diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index 67a138aa67d7..36065edb3f01 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -20,6 +20,8 @@ #define R_AARCH64_RELATIVE 1027 #endif
+static int ei_class; + static uint64_t rela_start, rela_end, text_base;
static const bool debug_en; @@ -54,32 +56,183 @@ static bool supported_rela(Elf64_Rela *rela) } }
-static bool read_num(const char *str, uint64_t *num) +static int decode_elf64(FILE *felf, char **argv) +{ + size_t size; + Elf64_Ehdr header; + uint64_t section_header_base, section_header_size, sh_offset, sh_size; + Elf64_Shdr *sh_table; /* Elf symbol table */ + int ret, i, machine; + char *sh_str; + + debug("64bit version\n"); + + /* Make sure we are at start */ + rewind(felf); + + size = fread(&header, 1, sizeof(header), felf); + if (size != sizeof(header)) { + fclose(felf); + return 25; + } + + machine = header.e_machine; + debug("Machine\t%d\n", machine); + + text_base = header.e_entry; + section_header_base = header.e_shoff; + section_header_size = header.e_shentsize * header.e_shnum; + + sh_table = malloc(section_header_size); + if (!sh_table) { + fprintf(stderr, "%s: Cannot allocate space for section header\n", + argv[0]); + fclose(felf); + return 26; + } + + ret = fseek(felf, section_header_base, SEEK_SET); + if (ret) { + fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n", + argv[0], ret, section_header_base); + free(sh_table); + fclose(felf); + return 26; + } + + size = fread(sh_table, 1, section_header_size, felf); + if (size != section_header_size) { + fprintf(stderr, "%s: Can't read section header: %lx/%lx\n", + argv[0], size, section_header_size); + free(sh_table); + fclose(felf); + return 27; + } + + sh_size = sh_table[header.e_shstrndx].sh_size; + debug("e_shstrndx\t0x%08x\n", header.e_shstrndx); + debug("sh_size\t\t0x%08lx\n", sh_size); + + sh_str = malloc(sh_size); + if (!sh_str) { + fprintf(stderr, "malloc failed\n"); + free(sh_table); + fclose(felf); + return 28; + } + + /* + * Specifies the byte offset from the beginning of the file + * to the first byte in the section. + */ + sh_offset = sh_table[header.e_shstrndx].sh_offset; + + debug("sh_offset\t0x%08x\n", header.e_shnum); + + ret = fseek(felf, sh_offset, SEEK_SET); + if (ret) { + fprintf(stderr, "Setting up sh_offset failed\n"); + free(sh_str); + free(sh_table); + fclose(felf); + return 29; + } + + size = fread(sh_str, 1, sh_size, felf); + if (size != sh_size) { + fprintf(stderr, "%s: Can't read section: %lx/%lx\n", + argv[0], size, sh_size); + free(sh_str); + free(sh_table); + fclose(felf); + return 30; + } + + for (i = 0; i < header.e_shnum; i++) { + /* fprintf(stderr, "%s\n", sh_str + sh_table[i].sh_name); Debug only */ + if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) { + debug("Found section\t".rela_dyn"\n"); + debug(" at addr\t0x%08x\n", + (unsigned int)sh_table[i].sh_addr); + debug(" at offset\t0x%08x\n", + (unsigned int)sh_table[i].sh_offset); + debug(" of size\t0x%08x\n", + (unsigned int)sh_table[i].sh_size); + rela_start = sh_table[i].sh_addr; + rela_end = rela_start + sh_table[i].sh_size; + break; + } + } + + /* Clean up */ + free(sh_str); + free(sh_table); + fclose(felf); + + debug("text_base\t0x%08lx\n", text_base); + debug("rela_start\t0x%08lx\n", rela_start); + debug("rela_end\t0x%08lx\n", rela_end); + + if (!rela_start) + return 1; + + return 0; +} + +static int decode_elf(char **argv) { - char *endptr; - *num = strtoull(str, &endptr, 16); - return str[0] && !endptr[0]; + FILE *felf; + size_t size; + unsigned char e_ident[EI_NIDENT]; + + felf = fopen(argv[2], "r+b"); + if (!felf) { + fprintf(stderr, "%s: Cannot open %s: %s\n", + argv[0], argv[5], strerror(errno)); + return 2; + } + + size = fread(e_ident, 1, EI_NIDENT, felf); + if (size != EI_NIDENT) { + fclose(felf); + return 25; + } + + /* Check if this is really ELF file */ + if (e_ident[0] != 0x7f && + e_ident[1] != 'E' && + e_ident[2] != 'L' && + e_ident[3] != 'F') { + fclose(felf); + return 1; + } + + ei_class = e_ident[4]; + debug("EI_CLASS(1=32bit, 2=64bit) %d\n", ei_class); + + if (ei_class == 2) + return decode_elf64(felf, argv); + + return 1; }
int main(int argc, char **argv) { FILE *f; - int i, num; + int i, num, ret; uint64_t file_size;
- if (argc != 5) { + if (argc != 3) { fprintf(stderr, "Statically apply ELF rela relocations\n"); - fprintf(stderr, "Usage: %s <bin file> <text base> " \ - "<rela start> <rela end>\n", argv[0]); - fprintf(stderr, "All numbers in hex.\n"); + fprintf(stderr, "Usage: %s <bin file> <u-boot ELF>\n", + argv[0]); return 1; }
- if (!read_num(argv[2], &text_base) || - !read_num(argv[3], &rela_start) || - !read_num(argv[4], &rela_end)) { - fprintf(stderr, "%s: bad number\n", argv[0]); - return 3; + ret = decode_elf(argv); + if (ret) { + fprintf(stderr, "ELF decoding failed\n"); + return ret; }
if (rela_start > rela_end || rela_start < text_base) {

There is no reason to use absolute branches and use just relative. This change helps with moving binary to different location and start it from there.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 645f7cb0389d..9e00eef1f4b6 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -29,7 +29,7 @@ _start: /* Call board_init_f_alloc_reserve with the current stack pointer as * parameter. */ add r5, r0, r1 - bralid r15, board_init_f_alloc_reserve + brlid r15, board_init_f_alloc_reserve nop
/* board_init_f_alloc_reserve returns a pointer to the allocated area @@ -41,20 +41,20 @@ _start: /* Call board_init_f_init_reserve with the address returned by * board_init_f_alloc_reserve as parameter. */ add r5, r0, r3 - bralid r15, board_init_f_init_reserve + brlid r15, board_init_f_init_reserve nop
#if !defined(CONFIG_SPL_BUILD) /* Setup vectors with pre-relocation symbols */ or r5, r0, r0 - bralid r15, __setup_exceptions + brlid r15, __setup_exceptions nop #endif
/* Flush cache before enable cache */ addik r5, r0, 0 addik r6, r0, XILINX_DCACHE_BYTE_SIZE - bralid r15, flush_cache + brlid r15, flush_cache nop
/* enable instruction and data cache */ @@ -75,14 +75,14 @@ clear_bss: bnei r6, 2b 3: /* jumping to board_init */ #ifdef CONFIG_DEBUG_UART - bralid r15, debug_uart_init + brlid r15, debug_uart_init nop #endif #ifndef CONFIG_SPL_BUILD or r5, r0, r0 /* flags - empty */ - brai board_init_f + bri board_init_f #else - brai board_init_r + bri board_init_r #endif 1: bri 1b
@@ -289,7 +289,7 @@ relocate_code:
/* Setup vectors with post-relocation symbols */ add r5, r0, r23 /* load gd->reloc_off to r5 */ - bralid r15, __setup_exceptions + brlid r15, __setup_exceptions nop
/* Check if GOT exist */ @@ -318,7 +318,7 @@ relocate_code: /* Flush caches to ensure consistency */ addik r5, r0, 0 addik r6, r0, XILINX_DCACHE_BYTE_SIZE - bralid r15, flush_cache + brlid r15, flush_cache nop
2: addi r5, r31, 0 /* gd is initialized in board_r.c */

When U-Boot starts stack protection can be already enabled that's why setup the lowest possible SLR value which is address 0. And the highest possible stack in front of U-Boot. That's why you should never load U-Boot to the beginning of DDR. There must be some space reserved. Code is using this location for early malloc space, early global data and stack.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 9e00eef1f4b6..715ef37b39d9 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -15,8 +15,9 @@ _start: mts rmsr, r0 /* disable cache */
- addi r8, r0, _end - mts rslr, r8 + mts rslr, r0 + addi r8, r0, _start + mts rshr, r8
#if defined(CONFIG_SPL_BUILD) addi r1, r0, CONFIG_SPL_STACK_ADDR

CONFIG_SYS_INIT_SP_OFFSET macro place stack to TEXT_BASE - SYS_MALLOC_F_LEN but there is no reason to do it now because board_init_f_alloc_reserve() returns exact location where stack should be. That's why stack location is calculated at run time and there is no need to hardcode it via macro. This change will help with placing U-Boot to any address.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 2 +- include/configs/microblaze-generic.h | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 715ef37b39d9..1acac5faf428 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -22,7 +22,7 @@ _start: #if defined(CONFIG_SPL_BUILD) addi r1, r0, CONFIG_SPL_STACK_ADDR #else - addi r1, r0, CONFIG_SYS_INIT_SP_OFFSET + add r1, r0, r8 #endif
addi r1, r1, -4 /* Decrement SP to top of memory */ diff --git a/include/configs/microblaze-generic.h b/include/configs/microblaze-generic.h index 663837f33dc4..60ceb2c817e9 100644 --- a/include/configs/microblaze-generic.h +++ b/include/configs/microblaze-generic.h @@ -18,10 +18,6 @@ # define CONFIG_SYS_BAUDRATE_TABLE \ {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400}
-/* Stack location before relocation */ -#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_TEXT_BASE - \ - CONFIG_SYS_MALLOC_F_LEN) - #ifdef CONFIG_CFI_FLASH /* ?empty sector */ # define CONFIG_SYS_FLASH_EMPTY_INFO 1

Use symbol instead macro to find where U-Boot starts.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 1acac5faf428..205d5f384c38 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -142,7 +142,7 @@ __setup_exceptions: swi r2, r4, 0x0 /* reset address - imm opcode */ swi r3, r4, 0x4 /* reset address - brai opcode */
- addik r6, r0, CONFIG_SYS_TEXT_BASE + addik r6, r0, _start sw r6, r1, r0 lhu r7, r1, r10 rsubi r8, r10, 0x2 @@ -285,7 +285,7 @@ relocate_code:
/* R23 points to the base address. */ add r23, r0, r7 /* Move reloc addr to r23 */ - addi r24, r0, CONFIG_SYS_TEXT_BASE /* Get reloc offset */ + addi r24, r0, _start /* Get reloc offset */ rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */
/* Setup vectors with post-relocation symbols */ @@ -323,7 +323,7 @@ relocate_code: nop
2: addi r5, r31, 0 /* gd is initialized in board_r.c */ - addi r6, r0, CONFIG_SYS_TEXT_BASE + addi r6, r0, _start addi r12, r23, board_init_r bra r12 /* Jump to relocated code */

Trivial fix.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/exception.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/microblaze/cpu/exception.c b/arch/microblaze/cpu/exception.c index d3640d3903b8..9414776afa7f 100644 --- a/arch/microblaze/cpu/exception.c +++ b/arch/microblaze/cpu/exception.c @@ -16,7 +16,7 @@ void _hw_exception_handler (void)
/* loading address of exception EAR */ MFS(address, rear); - /* loading excetpion state register ESR */ + /* loading exception state register ESR */ MFS(state, resr); printf("Hardware exception at 0x%x address\n", address); R17(address);

This option will be used by Microblaze that's why move it to generic location to be able to use it.
Signed-off-by: Michal Simek michal.simek@amd.com ---
Changes in v2: - new patch in series to solve Kconfig warning
arch/Kconfig | 22 ++++++++++++++++++++++ arch/mips/Kconfig | 18 ------------------ 2 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig index 12de8a11650d..4851300e9bbe 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -447,3 +447,25 @@ source "arch/xtensa/Kconfig" source "arch/riscv/Kconfig"
source "board/keymile/Kconfig" + +if MIPS + +choice + prompt "Endianness selection" + help + Some MIPS boards can be configured for either little or big endian + byte order. These modes require different U-Boot images. In general there + is one preferred byteorder for a particular system but some systems are + just as commonly used in the one or the other endianness. + +config SYS_BIG_ENDIAN + bool "Big endian" + depends on SUPPORTS_BIG_ENDIAN + +config SYS_LITTLE_ENDIAN + bool "Little endian" + depends on SUPPORTS_LITTLE_ENDIAN + +endchoice + +endif diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 9b62764f4fe6..2e0793a7a7b8 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -180,24 +180,6 @@ source "arch/mips/mach-octeon/Kconfig"
if MIPS
-choice - prompt "Endianness selection" - help - Some MIPS boards can be configured for either little or big endian - byte order. These modes require different U-Boot images. In general there - is one preferred byteorder for a particular system but some systems are - just as commonly used in the one or the other endianness. - -config SYS_BIG_ENDIAN - bool "Big endian" - depends on SUPPORTS_BIG_ENDIAN - -config SYS_LITTLE_ENDIAN - bool "Little endian" - depends on SUPPORTS_LITTLE_ENDIAN - -endchoice - choice prompt "CPU selection" default CPU_MIPS32_R2

Enable u-boot.elf recreation from u-boot.bin to prepare for removing manul relocation. Enable option for big endian configuration but it is not used too much that's why it is completely untested. By supporting this system there is a need to define LITTLE/BIG endian Kconfig options to pass -EL/-EB flags.
Full command line for u-boot.elf recreation looks like this: microblazeel-xilinx-linux-gnu-objcopy -I binary -B microblaze \ -O elf32-microblazeel u-boot.bin u-boot-elf.o
Signed-off-by: Michal Simek michal.simek@amd.com ---
Changes in v2: - Fix endian selection
arch/Kconfig | 6 +++--- arch/microblaze/config.mk | 6 ++++++ configs/microblaze-generic_defconfig | 1 + 3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/Kconfig b/arch/Kconfig index 4851300e9bbe..02de32f9c77f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -448,7 +448,7 @@ source "arch/riscv/Kconfig"
source "board/keymile/Kconfig"
-if MIPS +if MIPS || MICROBLAZE
choice prompt "Endianness selection" @@ -460,11 +460,11 @@ choice
config SYS_BIG_ENDIAN bool "Big endian" - depends on SUPPORTS_BIG_ENDIAN + depends on (SUPPORTS_BIG_ENDIAN && MIPS) || MICROBLAZE
config SYS_LITTLE_ENDIAN bool "Little endian" - depends on SUPPORTS_LITTLE_ENDIAN + depends on (SUPPORTS_LITTLE_ENDIAN && MIPS) || MICROBLAZE
endchoice
diff --git a/arch/microblaze/config.mk b/arch/microblaze/config.mk index de5b97e719cc..3e84a832fc12 100644 --- a/arch/microblaze/config.mk +++ b/arch/microblaze/config.mk @@ -16,3 +16,9 @@ LDFLAGS_FINAL += --gc-sections ifeq ($(CONFIG_SPL_BUILD),) PLATFORM_CPPFLAGS += -fPIC endif + +ifeq ($(CONFIG_SYS_LITTLE_ENDIAN),y) +PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblazeel +else +PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblaze +endif diff --git a/configs/microblaze-generic_defconfig b/configs/microblaze-generic_defconfig index c0f5d4c9a1cf..c2d25ea460b2 100644 --- a/configs/microblaze-generic_defconfig +++ b/configs/microblaze-generic_defconfig @@ -18,6 +18,7 @@ CONFIG_XILINX_MICROBLAZE0_USE_DIV=1 CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=2 CONFIG_DEBUG_UART=y CONFIG_DISTRO_DEFAULTS=y +CONFIG_REMAKE_ELF=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_BOOTDELAY=-1

Follow up patch will convert symbol handling that's why it is necessary to separate logic around symbols to special instruction. It adds 4B for new instruction but it is worth to do it to have code ready for for full relocation.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 205d5f384c38..a35d8d8ea29a 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -273,7 +273,8 @@ relocate_code: add r23, r0, r7 /* Move reloc addr to r23 */ /* Relocate text and data - r12 temp value */ addi r21, r0, _start - addi r22, r0, _end - 4 /* Include BSS too */ + addi r22, r0, _end /* Include BSS too */ + addi r22, r22, -4
rsub r6, r21, r22 or r5, r0, r0

SLR low address is still setup to 0 that's why only high limit should be updated. STACK_SIZE macro is present and could be possible used for low address alignment but it is not done by this patch.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index a35d8d8ea29a..2aae4a0b7ccb 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -268,6 +268,7 @@ relocate_code: * r7 - reloc_addr */ addi r1, r5, 0 /* Start to use new SP */ + mts rshr, r1 addi r31, r6, 0 /* Start to use new GD */
add r23, r0, r7 /* Move reloc addr to r23 */

There are additional operations which can be done simpler that's why improve logic around relocation address r7 handling and _start symbol.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 2aae4a0b7ccb..f2d6d12deb73 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -271,7 +271,6 @@ relocate_code: mts rshr, r1 addi r31, r6, 0 /* Start to use new GD */
- add r23, r0, r7 /* Move reloc addr to r23 */ /* Relocate text and data - r12 temp value */ addi r21, r0, _start addi r22, r0, _end /* Include BSS too */ @@ -280,15 +279,13 @@ relocate_code: rsub r6, r21, r22 or r5, r0, r0 1: lw r12, r21, r5 /* Load u-boot data */ - sw r12, r23, r5 /* Write zero to loc */ + sw r12, r7, r5 /* Write zero to loc */ cmp r12, r5, r6 /* Check if we have reach the end */ bneid r12, 1b addi r5, r5, 4 /* Increment to next loc - relocate code */
/* R23 points to the base address. */ - add r23, r0, r7 /* Move reloc addr to r23 */ - addi r24, r0, _start /* Get reloc offset */ - rsub r23, r24, r23 /* keep - this is already here gd->reloc_off */ + rsub r23, r21, r7 /* keep - this is already here gd->reloc_off */
/* Setup vectors with post-relocation symbols */ add r5, r0, r23 /* load gd->reloc_off to r5 */

r20 is not used that's why remove logic around it.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index f2d6d12deb73..c3d925c1d151 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -310,11 +310,6 @@ relocate_code: bneid r12, 3b addik r21. r21, 4
- /* Update pointer to GOT */ - mfs r20, rpc - addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8 - addk r20, r20, r23 - /* Flush caches to ensure consistency */ addik r5, r0, 0 addik r6, r0, XILINX_DCACHE_BYTE_SIZE

Right now U-Boot runs all the time from the same address where it is loaded but going to full relocation code starting address doesn't need to be fixed and can be simply discovered from reading PC register. That's why use r20 to get PC address and subtract offset from the beginning to get starting address.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index c3d925c1d151..db3998f54505 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -14,15 +14,16 @@ .global _start _start: mts rmsr, r0 /* disable cache */ + mfs r20, rpc + addi r20, r20, -4
mts rslr, r0 - addi r8, r0, _start - mts rshr, r8 + mts rshr, r20
#if defined(CONFIG_SPL_BUILD) addi r1, r0, CONFIG_SPL_STACK_ADDR #else - add r1, r0, r8 + add r1, r0, r20 #endif
addi r1, r1, -4 /* Decrement SP to top of memory */

Better to add comment to explain why reset vector points all the time to origin U-Boot location. If reset happens U-Boot should start from it's origin location.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index db3998f54505..9aa5fd099361 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -144,6 +144,7 @@ __setup_exceptions: swi r3, r4, 0x4 /* reset address - brai opcode */
addik r6, r0, _start + /* Intentionally keep reset vector back to origin u-boot location */ sw r6, r1, r0 lhu r7, r1, r10 rsubi r8, r10, 0x2

Symbol handling depends on compilation flags. Right now manual relocation is used that's why symbols can be referenced just by name and there is no need to find them out. But when position independent code (PIC) is used symbols need to be described differently. That's why having one macro change is easier than changing the whole code.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/microblaze/cpu/start.S | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 9aa5fd099361..72b0f3354731 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -10,6 +10,9 @@ #include <asm-offsets.h> #include <config.h>
+#define SYM_ADDR(reg, reg_add, symbol) \ + addi reg, reg_add, symbol + .text .global _start _start: @@ -66,8 +69,8 @@ _start:
clear_bss: /* clear BSS segments */ - addi r5, r0, __bss_start - addi r4, r0, __bss_end + SYM_ADDR(r5, r0, __bss_start) + SYM_ADDR(r4, r0, __bss_end) cmp r6, r5, r4 beqi r6, 3f 2: @@ -143,7 +146,7 @@ __setup_exceptions: swi r2, r4, 0x0 /* reset address - imm opcode */ swi r3, r4, 0x4 /* reset address - brai opcode */
- addik r6, r0, _start + SYM_ADDR(r6, r0, _start) /* Intentionally keep reset vector back to origin u-boot location */ sw r6, r1, r0 lhu r7, r1, r10 @@ -157,7 +160,7 @@ __setup_exceptions: swi r2, r4, 0x8 /* user vector exception - imm opcode */ swi r3, r4, 0xC /* user vector exception - brai opcode */
- addik r6, r5, _exception_handler + SYM_ADDR(r6, r5, _exception_handler) sw r6, r1, r0 /* * BIG ENDIAN memory map for user exception @@ -190,7 +193,7 @@ __setup_exceptions: swi r2, r4, 0x10 /* interrupt - imm opcode */ swi r3, r4, 0x14 /* interrupt - brai opcode */
- addik r6, r5, _interrupt_handler + SYM_ADDR(r6, r5, _interrupt_handler) sw r6, r1, r0 lhu r7, r1, r10 rsubi r8, r10, 0x12 @@ -202,7 +205,7 @@ __setup_exceptions: swi r2, r4, 0x20 /* hardware exception - imm opcode */ swi r3, r4, 0x24 /* hardware exception - brai opcode */
- addik r6, r5, _hw_exception_handler + SYM_ADDR(r6, r5, _hw_exception_handler) sw r6, r1, r0 lhu r7, r1, r10 rsubi r8, r10, 0x22 @@ -274,8 +277,8 @@ relocate_code: addi r31, r6, 0 /* Start to use new GD */
/* Relocate text and data - r12 temp value */ - addi r21, r0, _start - addi r22, r0, _end /* Include BSS too */ + SYM_ADDR(r21, r0, _start) + SYM_ADDR(r22, r0, _end) /* Include BSS too */ addi r22, r22, -4
rsub r6, r21, r22 @@ -319,8 +322,8 @@ relocate_code: nop
2: addi r5, r31, 0 /* gd is initialized in board_r.c */ - addi r6, r0, _start - addi r12, r23, board_init_r + SYM_ADDR(r6, r0, _start) + SYM_ADDR(r12, r23, board_init_r) bra r12 /* Jump to relocated code */
.end relocate_code

Adding support for new type requires to change code layout that's why move elf64 code to own function for easier maintenance.
It also solves the problem with not calling fclose in case of error. Return value from rela_elf64 is saved to variable that's why fclose() is called all the time.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
tools/relocate-rela.c | 96 ++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 43 deletions(-)
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index 36065edb3f01..e62247d51e2a 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -216,49 +216,9 @@ static int decode_elf(char **argv) return 1; }
-int main(int argc, char **argv) +static int rela_elf64(char **argv, FILE *f) { - FILE *f; - int i, num, ret; - uint64_t file_size; - - if (argc != 3) { - fprintf(stderr, "Statically apply ELF rela relocations\n"); - fprintf(stderr, "Usage: %s <bin file> <u-boot ELF>\n", - argv[0]); - return 1; - } - - ret = decode_elf(argv); - if (ret) { - fprintf(stderr, "ELF decoding failed\n"); - return ret; - } - - if (rela_start > rela_end || rela_start < text_base) { - fprintf(stderr, "%s: bad rela bounds\n", argv[0]); - return 3; - } - - rela_start -= text_base; - rela_end -= text_base; - - f = fopen(argv[1], "r+b"); - if (!f) { - fprintf(stderr, "%s: Cannot open %s: %s\n", - argv[0], argv[1], strerror(errno)); - return 2; - } - - fseek(f, 0, SEEK_END); - file_size = ftell(f); - rewind(f); - - if (rela_end > file_size) { - // Most likely compiler inserted some section that didn't get - // objcopy-ed into the final binary - rela_end = file_size; - } + int i, num;
if ((rela_end - rela_start) % sizeof(Elf64_Rela)) { fprintf(stderr, "%s: rela size isn't a multiple of Elf64_Rela\n", argv[0]); @@ -316,11 +276,61 @@ int main(int argc, char **argv) } }
+ return 0; +} + +int main(int argc, char **argv) +{ + FILE *f; + int ret; + uint64_t file_size; + + if (argc != 3) { + fprintf(stderr, "Statically apply ELF rela relocations\n"); + fprintf(stderr, "Usage: %s <bin file> <u-boot ELF>\n", + argv[0]); + return 1; + } + + ret = decode_elf(argv); + if (ret) { + fprintf(stderr, "ELF decoding failed\n"); + return ret; + } + + if (rela_start > rela_end || rela_start < text_base) { + fprintf(stderr, "%s: bad rela bounds\n", argv[0]); + return 3; + } + + rela_start -= text_base; + rela_end -= text_base; + + f = fopen(argv[1], "r+b"); + if (!f) { + fprintf(stderr, "%s: Cannot open %s: %s\n", + argv[0], argv[1], strerror(errno)); + return 2; + } + + fseek(f, 0, SEEK_END); + file_size = ftell(f); + rewind(f); + + if (rela_end > file_size) { + // Most likely compiler inserted some section that didn't get + // objcopy-ed into the final binary + rela_end = file_size; + } + + if (ei_class == 2) + ret = rela_elf64(argv, f); + if (fclose(f) < 0) { fprintf(stderr, "%s: %s: close failed: %s\n", argv[0], argv[1], strerror(errno)); return 4; }
- return 0; + return ret; }

Relocation support is only for EM_AARCH64 that's why check machine type to make sure that the code will never run on any unsupported one.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
tools/relocate-rela.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index e62247d51e2a..2f7f1796a0ef 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -79,6 +79,11 @@ static int decode_elf64(FILE *felf, char **argv) machine = header.e_machine; debug("Machine\t%d\n", machine);
+ if (machine != EM_AARCH64) { + fprintf(stderr, "%s: Not supported machine type\n", argv[0]); + return 30; + } + text_base = header.e_entry; section_header_base = header.e_shoff; section_header_size = header.e_shentsize * header.e_shnum;

Add support for 32bit ELF format which is used by Microblaze. Also check that code runs only for Microblaze.
Function finds information about rela.dyn and dynsym which will be used later for relocation.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
tools/relocate-rela.c | 141 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-)
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index 2f7f1796a0ef..7c2a441a8e91 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -22,7 +22,7 @@
static int ei_class;
-static uint64_t rela_start, rela_end, text_base; +static uint64_t rela_start, rela_end, text_base, dyn_start;
static const bool debug_en;
@@ -184,6 +184,142 @@ static int decode_elf64(FILE *felf, char **argv) return 0; }
+static int decode_elf32(FILE *felf, char **argv) +{ + size_t size; + Elf32_Ehdr header; + uint64_t section_header_base, section_header_size, sh_offset, sh_size; + Elf32_Shdr *sh_table; /* Elf symbol table */ + int ret, i, machine; + char *sh_str; + + debug("32bit version\n"); + + /* Make sure we are at start */ + rewind(felf); + + size = fread(&header, 1, sizeof(header), felf); + if (size != sizeof(header)) { + fclose(felf); + return 25; + } + + machine = header.e_machine; + debug("Machine %d\n", machine); + + if (machine != EM_MICROBLAZE) { + fprintf(stderr, "%s: Not supported machine type\n", argv[0]); + return 30; + } + + text_base = header.e_entry; + section_header_base = header.e_shoff; + + debug("Section header base %x\n", section_header_base); + + section_header_size = header.e_shentsize * header.e_shnum; + + debug("Section header size %d\n", section_header_size); + + sh_table = malloc(section_header_size); + if (!sh_table) { + fprintf(stderr, "%s: Cannot allocate space for section header\n", + argv[0]); + fclose(felf); + return 26; + } + + ret = fseek(felf, section_header_base, SEEK_SET); + if (ret) { + fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n", + argv[0], ret, section_header_base); + free(sh_table); + fclose(felf); + return 26; + } + + size = fread(sh_table, 1, section_header_size, felf); + if (size != section_header_size) { + fprintf(stderr, "%s: Can't read section header: %lx/%lx\n", + argv[0], size, section_header_size); + free(sh_table); + fclose(felf); + return 27; + } + + sh_size = sh_table[header.e_shstrndx].sh_size; + debug("e_shstrndx %x, sh_size %lx\n", header.e_shstrndx, sh_size); + + sh_str = malloc(sh_size); + if (!sh_str) { + fprintf(stderr, "malloc failed\n"); + free(sh_table); + fclose(felf); + return 28; + } + + /* + * Specifies the byte offset from the beginning of the file + * to the first byte in the section. + */ + sh_offset = sh_table[header.e_shstrndx].sh_offset; + + debug("sh_offset %x\n", header.e_shnum); + + ret = fseek(felf, sh_offset, SEEK_SET); + if (ret) { + fprintf(stderr, "Setting up sh_offset failed\n"); + free(sh_str); + free(sh_table); + fclose(felf); + return 29; + } + + size = fread(sh_str, 1, sh_size, felf); + if (size != sh_size) { + fprintf(stderr, "%s: Can't read section: %lx/%lx\n", + argv[0], size, sh_size); + free(sh_str); + free(sh_table); + fclose(felf); + return 30; + } + + for (i = 0; i < header.e_shnum; i++) { + debug("%s\n", sh_str + sh_table[i].sh_name); + if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) { + debug("Found section\t".rela_dyn"\n"); + debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr); + debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset); + debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size); + rela_start = sh_table[i].sh_addr; + rela_end = rela_start + sh_table[i].sh_size; + } + if (!strcmp(".dynsym", (sh_str + sh_table[i].sh_name))) { + debug("Found section\t".dynsym"\n"); + debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr); + debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset); + debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size); + dyn_start = sh_table[i].sh_addr; + } + } + + /* Clean up */ + free(sh_str); + free(sh_table); + fclose(felf); + + debug("text_base\t0x%08lx\n", text_base); + debug("rela_start\t0x%08lx\n", rela_start); + debug("rela_end\t0x%08lx\n", rela_end); + debug("dyn_start\t0x%08lx\n", dyn_start); + + if (!rela_start) + return 1; + + return 0; +} + static int decode_elf(char **argv) { FILE *felf; @@ -218,7 +354,7 @@ static int decode_elf(char **argv) if (ei_class == 2) return decode_elf64(felf, argv);
- return 1; + return decode_elf32(felf, argv); }
static int rela_elf64(char **argv, FILE *f) @@ -310,6 +446,7 @@ int main(int argc, char **argv)
rela_start -= text_base; rela_end -= text_base; + dyn_start -= text_base;
f = fopen(argv[1], "r+b"); if (!f) {

Microblaze is 32bit that's why it is using elf32 format. Relocation code requires to get information about rela and dynsym senctions and also text base which was used for compilation. Code build with -fPIC and linked with -pic generates 4 relocation types. R_MICROBLAZE_NONE is the easiest one which doesn't require any action. R_MICROBLAZE_REL only requires write addend to r_offset address. R_MICROBLAZE_32/R_MICROBLAZE_GLOB_DAT are the most complicated. There is a need to find out symbol value with adding symbol value and write it to address pointed by r_offset. Calculation with addend is also added but only 0 addend values are generated now.
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
tools/relocate-rela.c | 166 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+)
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c index 7c2a441a8e91..090fb1acb20c 100644 --- a/tools/relocate-rela.c +++ b/tools/relocate-rela.c @@ -420,6 +420,170 @@ static int rela_elf64(char **argv, FILE *f) return 0; }
+static bool supported_rela32(Elf32_Rela *rela, uint32_t *type) +{ + uint32_t mask = 0xffULL; /* would be different on 32-bit */ + *type = rela->r_info & mask; + + debug("Type:\t"); + + switch (*type) { + case R_MICROBLAZE_32: + debug("R_MICROBLAZE_32\n"); + return true; + case R_MICROBLAZE_GLOB_DAT: + debug("R_MICROBLAZE_GLOB_DAT\n"); + return true; + case R_MICROBLAZE_NONE: + debug("R_MICROBLAZE_NONE - ignoring - do nothing\n"); + return false; + case R_MICROBLAZE_REL: + debug("R_MICROBLAZE_REL\n"); + return true; + default: + fprintf(stderr, "warning: unsupported relocation type %" + PRIu32 " at %" PRIx32 "\n", *type, rela->r_offset); + + return false; + } +} + +static int rela_elf32(char **argv, FILE *f) +{ + int i, num, index; + uint32_t value, type; + + if ((rela_end - rela_start) % sizeof(Elf32_Rela)) { + fprintf(stderr, "%s: rela size isn't a multiple of Elf32_Rela\n", argv[0]); + return 3; + } + + num = (rela_end - rela_start) / sizeof(Elf32_Rela); + + debug("Number of entries: %u\n", num); + + for (i = 0; i < num; i++) { + Elf32_Rela rela, swrela; + Elf32_Sym symbols; + uint32_t pos = rela_start + sizeof(Elf32_Rela) * i; + uint32_t addr, pos_dyn; + + debug("\nPossition:\t%d/0x%x\n", i, pos); + + if (fseek(f, pos, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" PRIx32 + " failed: %s\n", + argv[0], argv[1], pos, strerror(errno)); + } + + if (fread(&rela, sizeof(rela), 1, f) != 1) { + fprintf(stderr, "%s: %s: read rela failed at %" + PRIx32 "\n", + argv[0], argv[1], pos); + return 4; + } + + debug("Rela:\toffset:\t%" PRIx32 " r_info:\t%" + PRIu32 " r_addend:\t%" PRIx32 "\n", + rela.r_offset, rela.r_info, rela.r_addend); + + swrela.r_offset = cpu_to_le32(rela.r_offset); + swrela.r_info = cpu_to_le32(rela.r_info); + swrela.r_addend = cpu_to_le32(rela.r_addend); + + debug("SWRela:\toffset:\t%" PRIx32 " r_info:\t%" + PRIu32 " r_addend:\t%" PRIx32 "\n", + swrela.r_offset, swrela.r_info, swrela.r_addend); + + if (!supported_rela32(&swrela, &type)) + continue; + + if (swrela.r_offset < text_base) { + fprintf(stderr, "%s: %s: bad rela at %" PRIx32 "\n", + argv[0], argv[1], pos); + return 4; + } + + addr = swrela.r_offset - text_base; + + debug("Addr:\t0x%" PRIx32 "\n", addr); + + switch (type) { + case R_MICROBLAZE_REL: + if (fseek(f, addr, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx32 " failed: %s\n", + argv[0], argv[1], addr, strerror(errno)); + return 5; + } + + debug("Write addend\n"); + + if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) { + fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n", + argv[0], argv[1], addr); + return 4; + } + break; + case R_MICROBLAZE_32: + case R_MICROBLAZE_GLOB_DAT: + /* global symbols read it and add reloc offset */ + index = swrela.r_info >> 8; + pos_dyn = dyn_start + sizeof(Elf32_Sym) * index; + + debug("Index:\t%d\n", index); + debug("Pos_dyn:\t0x%x\n", pos_dyn); + + if (fseek(f, pos_dyn, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx32 " failed: %s\n", + argv[0], argv[1], pos_dyn, strerror(errno)); + return 5; + } + + if (fread(&symbols, sizeof(symbols), 1, f) != 1) { + fprintf(stderr, "%s: %s: read symbols failed at %" + PRIx32 "\n", + argv[0], argv[1], pos_dyn); + return 4; + } + + debug("Symbol description:\n"); + debug(" st_name:\t0x%x\n", symbols.st_name); + debug(" st_value:\t0x%x\n", symbols.st_value); + debug(" st_size:\t0x%x\n", symbols.st_size); + + value = swrela.r_addend + symbols.st_value; + + debug("Value:\t0x%x\n", value); + + if (fseek(f, addr, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx32 " failed: %s\n", + argv[0], argv[1], addr, strerror(errno)); + return 5; + } + + if (fwrite(&value, sizeof(rela.r_addend), 1, f) != 1) { + fprintf(stderr, "%s: %s: write failed at %" PRIx32 "\n", + argv[0], argv[1], addr); + return 4; + } + + break; + case R_MICROBLAZE_NONE: + debug("R_MICROBLAZE_NONE - skip\n"); + break; + default: + fprintf(stderr, "warning: unsupported relocation type %" + PRIu32 " at %" PRIx32 "\n", + type, rela.r_offset); + } + } + + return 0; +} + int main(int argc, char **argv) { FILE *f; @@ -467,6 +631,8 @@ int main(int argc, char **argv)
if (ei_class == 2) ret = rela_elf64(argv, f); + else + ret = rela_elf32(argv, f);
if (fclose(f) < 0) { fprintf(stderr, "%s: %s: close failed: %s\n",

Microblaze is using NEEDS_MANUAL_RELOC from the beginnging. This is causing issues with function pointer arrays which need to be updated manually after relocation. Building code with -fPIC and linking with -pic will remove this limitation and there is no longer need to run manual update.
By default still old option is enabled but by disabling NEEDS_MANUAL_RELOC code will be compiled for full relocation.
The patch does couple of things which are connected to each other. - Define STATIC_RELA dependency to call relocate-rela to fill sections. - REMAKE_ELF was already enabled but u-boot file can't be used because sections are empty. relocate-rela will fill them and output file is u-boot.elf which should be used. - Add support for full relocation (u-boot.elf) - Add support for early relocation when u-boot.bin is loaded to different address then CONFIG_SYS_TEXT_BASE - Add rela.dyn and dynsym sections
Disabling NEEDS_MANUAL_RELOC U-Boot size increased by 10% of it's original size (550kB to 608kB).
Signed-off-by: Michal Simek michal.simek@amd.com ---
(no changes since v1)
arch/Kconfig | 1 - arch/microblaze/Kconfig | 14 +++++ arch/microblaze/config.mk | 5 ++ arch/microblaze/cpu/Makefile | 1 + arch/microblaze/cpu/relocate.c | 111 +++++++++++++++++++++++++++++++++ arch/microblaze/cpu/start.S | 66 ++++++++++++++++++++ arch/microblaze/cpu/u-boot.lds | 14 +++++ common/board_f.c | 2 + 8 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 arch/microblaze/cpu/relocate.c
diff --git a/arch/Kconfig b/arch/Kconfig index 02de32f9c77f..6c8d295d66b2 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -76,7 +76,6 @@ config M68K
config MICROBLAZE bool "MicroBlaze architecture" - select NEEDS_MANUAL_RELOC select SUPPORT_OF_CONTROL imply CMD_IRQ
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index d7d1b219704e..6f45d19330a1 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -4,6 +4,20 @@ menu "MicroBlaze architecture" config SYS_ARCH default "microblaze"
+config NEEDS_MANUAL_RELOC + bool "Disable position-independent pre-relocation code" + default y + help + U-Boot expects to be linked to a specific hard-coded address, and to + be loaded to and run from that address. This option lifts that + restriction, thus allowing the code to be loaded to and executed from + almost any 4K aligned address. This logic relies on the relocation + information that is embedded in the binary to support U-Boot + relocating itself to the top-of-RAM later during execution. + +config STATIC_RELA + def_bool y if !NEEDS_MANUAL_RELOC + choice prompt "Target select" optional diff --git a/arch/microblaze/config.mk b/arch/microblaze/config.mk index 3e84a832fc12..d35b4f6db7a1 100644 --- a/arch/microblaze/config.mk +++ b/arch/microblaze/config.mk @@ -17,6 +17,11 @@ ifeq ($(CONFIG_SPL_BUILD),) PLATFORM_CPPFLAGS += -fPIC endif
+ifeq ($(CONFIG_STATIC_RELA),y) +PLATFORM_CPPFLAGS += -fPIC +LDFLAGS_u-boot += -pic +endif + ifeq ($(CONFIG_SYS_LITTLE_ENDIAN),y) PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblazeel else diff --git a/arch/microblaze/cpu/Makefile b/arch/microblaze/cpu/Makefile index f7a83d07b6f6..1feffc6a97c0 100644 --- a/arch/microblaze/cpu/Makefile +++ b/arch/microblaze/cpu/Makefile @@ -6,4 +6,5 @@ extra-y = start.o obj-y = irq.o obj-y += interrupts.o cache.o exception.o timer.o +obj-$(CONFIG_STATIC_RELA) += relocate.o obj-$(CONFIG_SPL_BUILD) += spl.o diff --git a/arch/microblaze/cpu/relocate.c b/arch/microblaze/cpu/relocate.c new file mode 100644 index 000000000000..b00d02b1dfcc --- /dev/null +++ b/arch/microblaze/cpu/relocate.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2022 Advanced Micro Devices, Inc + * Michal Simek michal.simek@amd.com + */ + +#include <common.h> +#include <elf.h> + +#define R_MICROBLAZE_NONE 0 +#define R_MICROBLAZE_32 1 +#define R_MICROBLAZE_REL 16 +#define R_MICROBLAZE_GLOB_DAT 18 + +/** + * mb_fix_rela - update relocation to new address + * @reloc_addr: new relocation address + * @verbose: enable version messages + * @rela_start: rela section start + * @rela_end: rela section end + * @dyn_start: dynamic section start + * @origin_addr: address where u-boot starts(doesn't need to be CONFIG_SYS_TEXT_BASE) + */ +void mb_fix_rela(u32 reloc_addr, u32 verbose, u32 rela_start, + u32 rela_end, u32 dyn_start, u32 origin_addr) +{ + u32 num, type, mask, i, reloc_off; + + /* + * Return in case u-boot.elf is used directly. + * Skip it when u-boot.bin is loaded to different address than + * CONFIG_SYS_TEXT_BASE. In this case relocation is necessary to run. + */ + if (reloc_addr == CONFIG_SYS_TEXT_BASE) { + debug_cond(verbose, + "Relocation address is the same - skip relocation\n"); + return; + } + + reloc_off = reloc_addr - origin_addr; + + debug_cond(verbose, "Relocation address:\t0x%08x\n", reloc_addr); + debug_cond(verbose, "Relocation offset:\t0x%08x\n", reloc_off); + debug_cond(verbose, "Origin address:\t0x%08x\n", origin_addr); + debug_cond(verbose, "Rela start:\t0x%08x\n", rela_start); + debug_cond(verbose, "Rela end:\t0x%08x\n", rela_end); + debug_cond(verbose, "Dynsym start:\t0x%08x\n", dyn_start); + + num = (rela_end - rela_start) / sizeof(Elf32_Rela); + + debug_cond(verbose, "Number of entries:\t%u\n", num); + + for (i = 0; i < num; i++) { + Elf32_Rela *rela; + u32 temp; + + rela = (Elf32_Rela *)(rela_start + sizeof(Elf32_Rela) * i); + + mask = 0xffULL; /* would be different on 32-bit */ + type = rela->r_info & mask; + + debug_cond(verbose, "\nRela possition:\t%d/0x%x\n", + i, (u32)rela); + + switch (type) { + case R_MICROBLAZE_REL: + temp = *(u32 *)rela->r_offset; + + debug_cond(verbose, "Type:\tREL\n"); + debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset); + debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info); + debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend); + debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp); + + rela->r_offset += reloc_off; + rela->r_addend += reloc_off; + + temp = *(u32 *)rela->r_offset; + temp += reloc_off; + *(u32 *)rela->r_offset = temp; + + debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset); + debug_cond(verbose, "New:Rela r_addend:\t0x%x\n", rela->r_addend); + debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp); + break; + case R_MICROBLAZE_32: + case R_MICROBLAZE_GLOB_DAT: + debug_cond(verbose, "Type:\t(32/GLOB) %u\n", type); + debug_cond(verbose, "Rela r_offset:\t\t0x%x\n", rela->r_offset); + debug_cond(verbose, "Rela r_info:\t\t0x%x\n", rela->r_info); + debug_cond(verbose, "Rela r_addend:\t\t0x%x\n", rela->r_addend); + debug_cond(verbose, "Value at r_offset:\t0x%x\n", temp); + + rela->r_offset += reloc_off; + + temp = *(u32 *)rela->r_offset; + temp += reloc_off; + *(u32 *)rela->r_offset = temp; + + debug_cond(verbose, "New:Rela r_offset:\t0x%x\n", rela->r_offset); + debug_cond(verbose, "New:Value at r_offset:\t0x%x\n", temp); + break; + case R_MICROBLAZE_NONE: + debug_cond(verbose, "R_MICROBLAZE_NONE - skip\n"); + break; + default: + debug_cond(verbose, "warning: unsupported relocation type %d at %x\n", + type, rela->r_offset); + } + } +} diff --git a/arch/microblaze/cpu/start.S b/arch/microblaze/cpu/start.S index 72b0f3354731..9a661e785f6d 100644 --- a/arch/microblaze/cpu/start.S +++ b/arch/microblaze/cpu/start.S @@ -10,8 +10,16 @@ #include <asm-offsets.h> #include <config.h>
+#if defined(CONFIG_STATIC_RELA) +#define SYM_ADDR(reg, reg_add, symbol) \ + mfs r20, rpc; \ + addik r20, r20, _GLOBAL_OFFSET_TABLE_ + 8; \ + lwi reg, r20, symbol@GOT; \ + addk reg, reg reg_add; +#else #define SYM_ADDR(reg, reg_add, symbol) \ addi reg, reg_add, symbol +#endif
.text .global _start @@ -27,6 +35,39 @@ _start: addi r1, r0, CONFIG_SPL_STACK_ADDR #else add r1, r0, r20 +#if defined(CONFIG_STATIC_RELA) + bri 1f + + /* Force alignment for easier ASM code below */ +#define ALIGNMENT_ADDR 0x20 + .align 4 +uboot_dyn_start: + .word __rel_dyn_start + +uboot_dyn_end: + .word __rel_dyn_end + +uboot_sym_start: + .word __dyn_sym_start +1: + + addi r5, r20, 0 + add r6, r0, r0 + + lwi r7, r20, ALIGNMENT_ADDR + addi r7, r7, -CONFIG_SYS_TEXT_BASE + add r7, r7, r5 + lwi r8, r20, ALIGNMENT_ADDR + 0x4 + addi r8, r8, -CONFIG_SYS_TEXT_BASE + add r8, r8, r5 + lwi r9, r20, ALIGNMENT_ADDR + 0x8 + addi r9, r9, -CONFIG_SYS_TEXT_BASE + add r9, r9, r5 + addi r10, r0, CONFIG_SYS_TEXT_BASE + + brlid r15, mb_fix_rela + nop +#endif #endif
addi r1, r1, -4 /* Decrement SP to top of memory */ @@ -297,6 +338,30 @@ relocate_code: brlid r15, __setup_exceptions nop
+#if defined(CONFIG_STATIC_RELA) + /* reloc_offset is current location */ + SYM_ADDR(r10, r0, _start) + + /* r5 new address where I should copy code */ + add r5, r0, r7 /* Move reloc addr to r5 */ + + /* Verbose message */ + addi r6, r0, 0 + + SYM_ADDR(r7, r0, __rel_dyn_start) + rsub r7, r10, r7 + add r7, r7, r5 + SYM_ADDR(r8, r0, __rel_dyn_end) + rsub r8, r10, r8 + add r8, r8, r5 + SYM_ADDR(r9, r0, __dyn_sym_start) + rsub r9, r10, r9 + add r9, r9, r5 + brlid r15, mb_fix_rela + nop + + /* end of code which does relocation */ +#else /* Check if GOT exist */ addik r21, r23, _got_start addik r22, r23, _got_end @@ -314,6 +379,7 @@ relocate_code: cmpu r12, r21, r22 /* Check if this cross boundary */ bneid r12, 3b addik r21. r21, 4 +#endif
/* Flush caches to ensure consistency */ addik r5, r0, 0 diff --git a/arch/microblaze/cpu/u-boot.lds b/arch/microblaze/cpu/u-boot.lds index 2b316cc7f5a5..821cc55d7b30 100644 --- a/arch/microblaze/cpu/u-boot.lds +++ b/arch/microblaze/cpu/u-boot.lds @@ -46,6 +46,20 @@ SECTIONS } __init_end = . ;
+ . = ALIGN(4); + __rel_dyn_start = .; + .rela.dyn : { + *(.rela.dyn) + } + __rel_dyn_end = .; + + . = ALIGN(4); + __dyn_sym_start = .; + .dynsym : { + *(.dynsym) + } + __dyn_sym_end = .; + .bss ALIGN(0x4): { __bss_start = .; diff --git a/common/board_f.c b/common/board_f.c index 51d2f3c365e9..a5666ca77c24 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -684,6 +684,8 @@ static int setup_reloc(void) #ifdef CONFIG_SYS_TEXT_BASE #ifdef ARM gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start; +#elif defined(CONFIG_MICROBLAZE) + gd->reloc_off = gd->relocaddr - (u32)_start; #elif defined(CONFIG_M68K) /* * On all ColdFire arch cpu, monitor code starts always
participants (1)
-
Michal Simek