mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-19 19:34:35 +00:00
microblaze: Add support for run time relocation
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> Link: https://lore.kernel.org/r/a845670b34925859b2e321875f7588a29f6655f9.1655299267.git.michal.simek@amd.com
This commit is contained in:
parent
034944b33b
commit
d58c007498
9 changed files with 216 additions and 4 deletions
|
@ -8,9 +8,6 @@ config CREATE_ARCH_SYMLINK
|
||||||
config HAVE_ARCH_IOREMAP
|
config HAVE_ARCH_IOREMAP
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config NEEDS_MANUAL_RELOC
|
|
||||||
bool
|
|
||||||
|
|
||||||
config SYS_CACHE_SHIFT_4
|
config SYS_CACHE_SHIFT_4
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
@ -76,7 +73,6 @@ config M68K
|
||||||
|
|
||||||
config MICROBLAZE
|
config MICROBLAZE
|
||||||
bool "MicroBlaze architecture"
|
bool "MicroBlaze architecture"
|
||||||
select NEEDS_MANUAL_RELOC
|
|
||||||
select SUPPORT_OF_CONTROL
|
select SUPPORT_OF_CONTROL
|
||||||
imply CMD_IRQ
|
imply CMD_IRQ
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ menu "M68000 architecture"
|
||||||
config SYS_ARCH
|
config SYS_ARCH
|
||||||
default "m68k"
|
default "m68k"
|
||||||
|
|
||||||
|
config NEEDS_MANUAL_RELOC
|
||||||
|
def_bool y
|
||||||
|
|
||||||
# processor family
|
# processor family
|
||||||
config MCF520x
|
config MCF520x
|
||||||
select OF_CONTROL
|
select OF_CONTROL
|
||||||
|
|
|
@ -4,6 +4,20 @@ menu "MicroBlaze architecture"
|
||||||
config SYS_ARCH
|
config SYS_ARCH
|
||||||
default "microblaze"
|
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
|
choice
|
||||||
prompt "Target select"
|
prompt "Target select"
|
||||||
optional
|
optional
|
||||||
|
|
|
@ -17,6 +17,11 @@ ifeq ($(CONFIG_SPL_BUILD),)
|
||||||
PLATFORM_CPPFLAGS += -fPIC
|
PLATFORM_CPPFLAGS += -fPIC
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_STATIC_RELA),y)
|
||||||
|
PLATFORM_CPPFLAGS += -fPIC
|
||||||
|
LDFLAGS_u-boot += -pic
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_SYS_LITTLE_ENDIAN),y)
|
ifeq ($(CONFIG_SYS_LITTLE_ENDIAN),y)
|
||||||
PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblazeel
|
PLATFORM_ELFFLAGS += -B microblaze $(OBJCOPYFLAGS) -O elf32-microblazeel
|
||||||
else
|
else
|
||||||
|
|
|
@ -6,4 +6,5 @@
|
||||||
extra-y = start.o
|
extra-y = start.o
|
||||||
obj-y = irq.o
|
obj-y = irq.o
|
||||||
obj-y += interrupts.o cache.o exception.o timer.o
|
obj-y += interrupts.o cache.o exception.o timer.o
|
||||||
|
obj-$(CONFIG_STATIC_RELA) += relocate.o
|
||||||
obj-$(CONFIG_SPL_BUILD) += spl.o
|
obj-$(CONFIG_SPL_BUILD) += spl.o
|
||||||
|
|
111
arch/microblaze/cpu/relocate.c
Normal file
111
arch/microblaze/cpu/relocate.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,16 @@
|
||||||
#include <asm-offsets.h>
|
#include <asm-offsets.h>
|
||||||
#include <config.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) \
|
#define SYM_ADDR(reg, reg_add, symbol) \
|
||||||
addi reg, reg_add, symbol
|
addi reg, reg_add, symbol
|
||||||
|
#endif
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.global _start
|
.global _start
|
||||||
|
@ -27,6 +35,39 @@ _start:
|
||||||
addi r1, r0, CONFIG_SPL_STACK_ADDR
|
addi r1, r0, CONFIG_SPL_STACK_ADDR
|
||||||
#else
|
#else
|
||||||
add r1, r0, r20
|
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
|
#endif
|
||||||
|
|
||||||
addi r1, r1, -4 /* Decrement SP to top of memory */
|
addi r1, r1, -4 /* Decrement SP to top of memory */
|
||||||
|
@ -297,6 +338,30 @@ relocate_code:
|
||||||
brlid r15, __setup_exceptions
|
brlid r15, __setup_exceptions
|
||||||
nop
|
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 */
|
/* Check if GOT exist */
|
||||||
addik r21, r23, _got_start
|
addik r21, r23, _got_start
|
||||||
addik r22, r23, _got_end
|
addik r22, r23, _got_end
|
||||||
|
@ -314,6 +379,7 @@ relocate_code:
|
||||||
cmpu r12, r21, r22 /* Check if this cross boundary */
|
cmpu r12, r21, r22 /* Check if this cross boundary */
|
||||||
bneid r12, 3b
|
bneid r12, 3b
|
||||||
addik r21. r21, 4
|
addik r21. r21, 4
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Flush caches to ensure consistency */
|
/* Flush caches to ensure consistency */
|
||||||
addik r5, r0, 0
|
addik r5, r0, 0
|
||||||
|
|
|
@ -46,6 +46,20 @@ SECTIONS
|
||||||
}
|
}
|
||||||
__init_end = . ;
|
__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 ALIGN(0x4):
|
||||||
{
|
{
|
||||||
__bss_start = .;
|
__bss_start = .;
|
||||||
|
|
|
@ -684,6 +684,8 @@ static int setup_reloc(void)
|
||||||
#ifdef CONFIG_SYS_TEXT_BASE
|
#ifdef CONFIG_SYS_TEXT_BASE
|
||||||
#ifdef ARM
|
#ifdef ARM
|
||||||
gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;
|
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)
|
#elif defined(CONFIG_M68K)
|
||||||
/*
|
/*
|
||||||
* On all ColdFire arch cpu, monitor code starts always
|
* On all ColdFire arch cpu, monitor code starts always
|
||||||
|
|
Loading…
Add table
Reference in a new issue