At arch level: add linker flag -pie 添加链接标识 -pie用于生成位置无关代码
1 2 3 4 5 6
This causes the linker to generate fixup tables .rel.dyn and .dynsym, which must be applied to the relocated image before transferring control to it. These fixups are described in the ARM ELF documentation as type 23 (program-base-relative) and 2 (symbol-relative)
At cpu level: modify linker file and add a relocation and fixup loop
1 2 3 4 5 6 7
the linker file must be modified to include the .rel.dyn and .dynsym tables in the binary image, and to provide symbols for the relocation code to access these tables The relocation and fixup loop must be executed after executing board_init_f at initial location and before executing board_init_r at final location.
At board level:
1 2 3
dram_init(): bd pointer is now at this point NOT accessible, so only detect the real dramsize, and store it in gd->ram_size. Bst detected with get_ram_size().
TODO: move also dram initialization there on boards where it is possible.
1 2
Setup of the the bd_t dram bank info is done in the new function dram_init_banksize() called after bd is accessible.
At lib level:
1
Board.c code is adapted from ppc code
** WARNING ** Boards which are not fixed to support relocation will be REMOVED!
For boards which boot from spl, it is possible to save one copy 对于从SPL启动的,当CONFIG_SYS_TEXT_BASE和relocate目标地址相等时,可以不进行再次拷贝
if CONFIG_SYS_TEXT_BASE == relocation address! This prevents that uboot code is copied again in relocate_code().
#arch/arm/config.mk # The movt / movw can hardcode 16 bit parts of the addresses in the # instruction. Relocation is not supported for that case, so disable # such usage by requiring word relocations. PLATFORM_CPPFLAGS += $(call cc-option, -mword-relocations) PLATFORM_CPPFLAGS += $(call cc-option, -fno-pic)
//common/init/board_init.c /* * Allocate reserved space for use as 'globals' from 'top' address and * return 'bottom' address of allocated space * * Notes: * * Actual reservation cannot be done from within this function as * it requires altering the C stack pointer, so this will be done by * the caller upon return from this function. * * IMPORTANT: * * Alignment constraints may differ for each 'chunk' allocated. For now: * * - GD is aligned down on a 16-byte boundary * * - the early malloc arena is not aligned, therefore it follows the stack * alignment constraint of the architecture for which we are bulding. * * - GD is allocated last, so that the return value of this functions is * both the bottom of the reserved area and the address of GD, should * the calling context need it. */ /* * 以手头的OK6410板子分析: * CONFIG_SYS_TEXT_BASE = 0x5FE00000 * CONFIG_SYS_INIT_SP_ADDR = (CONFIG_SYS_TEXT_BASE - 0x80) * SYS_MALLOC_F_LEN宏没有定义 */ ulong board_init_f_alloc_reserve(ulong top) { /* Reserve early malloc arena */ #if CONFIG_VAL(SYS_MALLOC_F_LEN) top -= CONFIG_VAL(SYS_MALLOC_F_LEN); #endif /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */ //保留出了用于存放gd的空间,并使新sp地址16字节对齐,这里gd_size=208=0xd0 top = rounddown(top-sizeof(struct global_data), 16); return top; }
//common/init/board_init.c /* * Initialize reserved space (which has been safely allocated on the C * stack from the C runtime environment handling code). * * Notes: * * Actual reservation was done by the caller; the locations from base * to base+size-1 (where 'size' is the value returned by the allocation * function above) can be accessed freely without risk of corrupting the * C runtime environment. * * IMPORTANT: * * Upon return from the allocation function above, on some architectures * the caller will set gd to the lowest reserved location. Therefore, in * this initialization function, the global data MUST be placed at base. * * ALSO IMPORTANT: * * On some architectures, gd will already be good when entering this * function. On others, it will only be good once arch_setup_gd() returns. * Therefore, global data accesses must be done: * * - through gd_ptr if before the call to arch_setup_gd(); * * - through gd once arch_setup_gd() has been called. * * Do not use 'gd->' until arch_setup_gd() has been called! * * IMPORTANT TOO: * * Initialization for each "chunk" (GD, early malloc arena...) ends with * an incrementation line of the form 'base += <some size>'. The last of * these incrementations seems useless, as base will not be used any * more after this incrementation; but if/when a new "chunk" is appended, * this increment will be essential as it will give base right value for * this new chunk (which will have to end with its own incrementation * statement). Besides, the compiler's optimizer will silently detect * and remove the last base incrementation, therefore leaving that last * (seemingly useless) incrementation causes no code increase. */ voidboard_init_f_init_reserve(ulong base) { structglobal_data *gd_ptr; /* * clear GD entirely and set it up. * Use gd_ptr, as gd may not be properly set yet. */ gd_ptr = (struct global_data *)base; /* zero the area */ memset(gd_ptr, '\0', sizeof(*gd)); /* set GD unless architecture did it already */ #if !defined(CONFIG_ARM) arch_setup_gd(gd_ptr); #endif /* next alloc will be higher by one GD plus 16-byte alignment */ base += roundup(sizeof(struct global_data), 16); /* * record early malloc arena start. * Use gd as it is now properly set for all architectures. */ #if CONFIG_VAL(SYS_MALLOC_F_LEN) /* go down one 'early malloc arena' */ gd->malloc_base = base; /* next alloc will be higher by one 'early malloc arena' size */ base += CONFIG_VAL(SYS_MALLOC_F_LEN); #endif }
//common/board_f.c staticintsetup_dest_addr(void) { /*表示u-boot的大小,在uboot代码空间relocate的时候, * relocate的size就是由这里决定 * gd->mon_len = (ulong)&__bss_end - (ulong)_start; */ debug("Monitor len: %08lX\n", gd->mon_len); /* * Ram is setup, size stored in gd !! * 表示ram的大小,对于ok6410,在smdk6410.c中由dram_init()初始化 * gd->bd->bi_dram[0].start = 0x50000000; * gd->bd->bi_dram[0].size = 0x10000000; //256M */ debug("Ram size: %08lX\n", (ulong)gd->ram_size); #if defined(CONFIG_SYS_MEM_TOP_HIDE) /* * Subtract specified amount of memory to hide so that it won't * get "touched" at all by U-Boot. By fixing up gd->ram_size * the Linux kernel should now get passed the now "corrected" * memory size and won't touch it either. This should work * for arch/ppc and arch/powerpc. Only Linux board ports in * arch/powerpc with bootwrapper support, that recalculate the * memory size from the SDRAM controller setup will have to * get fixed. */ gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE; #endif #ifdef CONFIG_SYS_SDRAM_BASE gd->ram_base = CONFIG_SYS_SDRAM_BASE; #endif /* * 计算dram的顶端地址:gd->ram_top = gd->ram_base + gd->ram_size; * relocate地址(新u-boot的起始地址):gd->relocaddr = gd->ram_top; */ gd->ram_top = gd->ram_base + get_effective_memsize(); gd->ram_top = board_get_usable_ram_top(gd->mon_len); gd->relocaddr = gd->ram_top; debug("Ram top: %08lX\n", (ulong)gd->ram_top); #if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500)) /* * We need to make sure the location we intend to put secondary core * boot code is reserved and not used by any part of u-boot */ if (gd->relocaddr > determine_mp_bootpg(NULL)) { gd->relocaddr = determine_mp_bootpg(NULL); debug("Reserving MP boot page to %08lx\n", gd->relocaddr); } #endif return0; }
//common/board_f.c staticintsetup_reloc(void) { if (gd->flags & GD_FLG_SKIP_RELOC) { debug("Skipping relocation due to flag\n"); return0; }
#ifdef CONFIG_SYS_TEXT_BASE #ifdef ARM /* * 对于arm * 偏移量gd->reloc_off=gd->relocaddr-(unsigned long)__image_copy_start * gd->relocaddr为新u-boot的起始地址 * __image_copy_start在u-boot.lds链接器脚本文件中定义,是旧u-boot的起始地址 */ gd->reloc_off = gd->relocaddr - (unsignedlong)__image_copy_start; #elif defined(CONFIG_M68K) /* * On all ColdFire arch cpu, monitor code starts always * just after the default vector table location, so at 0x400 */ gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400); #else gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; #endif #endif //relocate旧的global_data到新的global_data的空间上 memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
debug("Relocation Offset is: %08lx\n", gd->reloc_off); debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n", gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd), gd->start_addr_sp);
/* * arch/arm/lib/relocate.S * * void relocate_code(addr_moni) * * This function relocates the monitor code. * * NOTE: * To prevent the code below from containing references with an R_ARM_ABS32 * relocation record type, we never refer to linker-defined symbols directly. * Instead, we declare literals which contain their relative location with * respect to relocate_code, and at run time, add relocate_code back to them. */
/* ************************************************************************* * * Indirect vectors table * * Symbols referenced here must be defined somewhere else * ************************************************************************* */
/* * Default/weak exception vectors relocation routine * * This routine covers the standard ARM cases: normal (0x00000000), * high (0xffff0000) and VBAR. SoCs which do not comply with any of * the standard cases must provide their own, strong, version. */