u-boot分析(三):main函数分析、uboot自拷贝和重定位
uboot分析三
1、main函数
main函数代码如下。sp = CONFIG_SYS_INIT_SP_ADDR = 0X0091FF00, 未定义CONFIG_CPU_V7M,sp 8字节对齐,r0 = sp,执行 board_init_f_alloc_reserve函数。
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
#endif
mov r0, sp
bl board_init_f_alloc_reserve
mov sp, r0
/* set up gd here, outside any C code */
mov r9, r0
bl board_init_f_init_reserve
mov r0, #0
bl board_init_f
#if ! defined(CONFIG_SPL_BUILD)
/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
#endif
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
#if defined(CONFIG_CPU_V7M)
orr lr, #1 /* As required by Thumb-only */
#endif
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code
here:
/*
* now relocate vectors
*/
bl relocate_vectors
/* Set up final (full) environment */
bl c_runtime_cpu_setup /* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
# ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl spl_relocate_stack_gd
cmp r0, #0
movne sp, r0
movne r9, r0
# endif
ldr r0, =__bss_start /* this is auto-relocated! */
#ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end /* this is auto-relocated! */
mov r1, #0x00000000 /* prepare zero to clear BSS */
subs r2, r3, r0 /* r2 = memset len */
bl memset
#else
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
#if defined(CONFIG_CPU_V7M)
itt lo
#endif
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
#endif
#if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
bl red_led_on
#endif
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
#if defined(CONFIG_SYS_THUMB_BUILD)
ldr lr, =board_init_r /* this is auto-relocated! */
bx lr
#else
ldr pc, =board_init_r /* this is auto-relocated! */
#endif
/* we should not return here. */
#endif
ENDPROC(_main)
1.1 board_init_f_alloc_reserve函数
board_init_f_alloc_reserve函数如下,在main函数部分r0 = sp,board_init_f_alloc_reserve 的top = r0,执行完之后,sp = r0 = (0X0091FB00 -248 ) - (0X0091FB00 -248 )%16 = 0X0091FA00, r9 = r0,将gdata地址设置成0X0091FA00,此时去执行board_init_f_init_reserve函数。base = r0 = 0X0091FA00,执行完base = base +roundup(248,16) =0X0091FA00 + 0X100 = 0X0091FB00
ulong board_init_f_alloc_reserve(ulong top)
{
/* Reserve early malloc arena */
#if defined(CONFIG_SYS_MALLOC_F)
top -= CONFIG_SYS_MALLOC_F_LEN;
#endif
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
top = rounddown(top-sizeof(struct global_data), 16);
return top;
}
#define rounddown(x, y) ( \
{ \
typeof(x) __x = (x); \
__x - (__x % (y)); \
} \
)
1.2 board_init_f_init_reserve函数
board_init_f_init_reserve函数代码如下。gd 这个变量通过 DECLARE_GLOBAL_DATA_PTR 定义,这个变量的作用是用来存储 uboot 需要使用到的全局变量,这样可以减少全局变量的数量,方便他人阅读代码。具体的作用可以从结构体成员中得知。 bd 这个成员变量的主要作用是用来保存一些和板级相关的信息,如波特率、ip 地址等。
void board_init_f_init_reserve(ulong base)
{
struct global_data *gd_ptr;
#ifndef _USE_MEMCPY
int *ptr;
#endif
/*
* 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 */
#ifdef _USE_MEMCPY
memset(gd_ptr, '\0', sizeof(*gd));
#else
for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
*ptr++ = 0;
#endif
/* 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 defined(CONFIG_SYS_MALLOC_F)
/* go down one 'early malloc arena' */
gd->malloc_base = base;
/* next alloc will be higher by one 'early malloc arena' size */
base += CONFIG_SYS_MALLOC_F_LEN;
#endif
}
1.3 board_init_f函数
board_init_f_init_reserve函数执行完后,r0 = 0;board_init_f函数代码如下。主要运行initcall_run_list函数初始化序列init_sequence_f里面男的一系列函数
void board_init_f(ulong boot_flags)
{
#ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA
/*
* For some archtectures, global data is initialized and used before
* calling this function. The data should be preserved. For others,
* CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
* here to host global data until relocation.
*/
gd_t data;
gd = &data;
/*
* Clear global data before it is accessed at debug print
* in initcall_run_list. Otherwise the debug print probably
* get the wrong vaule of gd->have_console.
*/
zero_global_data();
#endif
gd->flags = boot_flags;
gd->have_console = 0;
if (initcall_run_list(init_sequence_f))
hang();
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP)
/* NOTREACHED - jump_to_copy() does not return */
hang();
#endif
}
1.3.1 initcall_run_list函数
函数代码如下,遍历执行init_sequence里面的函数。
int initcall_run_list(const init_fnc_t init_sequence[])
{
const init_fnc_t *init_fnc_ptr;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
unsigned long reloc_ofs = 0;
int ret;
if (gd->flags & GD_FLG_RELOC)
reloc_ofs = gd->reloc_off;
#ifdef CONFIG_EFI_APP
reloc_ofs = (unsigned long)image_base;
#endif
debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);
if (gd->flags & GD_FLG_RELOC)
debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);
else
debug("\n");
ret = (*init_fnc_ptr)();
if (ret) {
printf("initcall sequence %p failed at call %p (err=%d)\n",
init_sequence,
(char *)*init_fnc_ptr - reloc_ofs, ret);
return -1;
}
}
return 0;
}
init_sequence_f序列里面包含了一些列的函数,代码如下。
static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
setup_ram_buf,
#endif
setup_mon_len,
#ifdef CONFIG_OF_CONTROL
fdtdec_setup,
#endif
#ifdef CONFIG_TRACE
trace_early_init,
#endif
initf_malloc,
initf_console_record,
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
/* TODO: can this go into arch_cpu_init()? */
probecpu,
#endif
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
x86_fsp_init,
#endif
arch_cpu_init, /* basic arch cpu dependent setup */
initf_dm,
arch_cpu_init_dm,
mark_bootstage, /* need timer, go after init dm */
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
/* TODO: can any of this go into arch_cpu_init()? */
#if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
get_clocks, /* get CPU and bus clocks (etc.) */
#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
&& !defined(CONFIG_TQM885D)
adjust_sdram_tbs_8xx,
#endif
/* TODO: can we rename this to timer_init()? */
init_timebase,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || \
defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || \
defined(CONFIG_SPARC)
timer_init, /* initialize timer */
#endif
#ifdef CONFIG_SYS_ALLOC_DPRAM
#if !defined(CONFIG_CPM2)
dpram_init,
#endif
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
board_postclk_init,
#endif
#if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
get_clocks,
#endif
env_init, /* initialize environment */
#if defined(CONFIG_8xx_CPUCLK_DEFAULT)
/* get CPU and bus clocks according to the environment variable */
get_clocks_866,
/* adjust sdram refresh rate according to the new clock */
sdram_adjust_866,
init_timebase,
#endif
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
#ifdef CONFIG_SANDBOX
sandbox_early_getopt_check,
#endif
#ifdef CONFIG_OF_CONTROL
fdtdec_prepare_fdt,
#endif
display_options, /* say that we are here */
display_text_info, /* show debugging info if required */
#if defined(CONFIG_MPC8260)
prt_8260_rsr,
prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx)
prt_83xx_rsr,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
checkcpu,
#endif
print_cpuinfo, /* display cpu info (and speed) */
#if defined(CONFIG_MPC5xxx)
prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)
show_board_info,
#endif
INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
misc_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)
init_func_spi,
#endif
announce_dram_init,
/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \
defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)
dram_init, /* configure available RAM banks */
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)
init_func_ram,
#endif
#ifdef CONFIG_POST
post_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
testdram,
#endif /* CONFIG_SYS_DRAM_TEST */
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_POST
init_post,
#endif
INIT_FUNC_WATCHDOG_RESET
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*
* Reserve memory at end of RAM for (top down in that order):
* - area that won't get touched by U-Boot and Linux (optional)
* - kernel log buffer
* - protected RAM
* - LCD framebuffer
* - monitor code
* - board info struct
*/
setup_dest_addr,
#if defined(CONFIG_BLACKFIN)
/* Blackfin u-boot monitor should be on top of the ram */
reserve_uboot,
#endif
#if defined(CONFIG_SPARC)
reserve_prom,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM
reserve_pram,
#endif
reserve_round_4k,
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
defined(CONFIG_ARM)
reserve_mmu,
#endif
#ifdef CONFIG_DM_VIDEO
reserve_video,
#else
# ifdef CONFIG_LCD
reserve_lcd,
# endif
/* TODO: Why the dependency on CONFIG_8xx? */
# if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
!defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
reserve_legacy_video,
# endif
#endif /* CONFIG_DM_VIDEO */
reserve_trace,
#if !defined(CONFIG_BLACKFIN)
reserve_uboot,
#endif
#ifndef CONFIG_SPL_BUILD
reserve_malloc,
reserve_board,
#endif
setup_machine,
reserve_global_data,
reserve_fdt,
reserve_arch,
reserve_stacks,
setup_dram_config,
show_dram_config,
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
INIT_FUNC_WATCHDOG_RESET
setup_board_part2,
#endif
display_new_sp,
#ifdef CONFIG_SYS_EXTBDINFO
setup_board_extra,
#endif
INIT_FUNC_WATCHDOG_RESET
reloc_fdt,
setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
copy_uboot_to_ram,
clear_bss,
do_elf_reloc_fixups,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
jump_to_copy,
#endif
NULL,
};
(1)setup_mon_len :函数设置 gd 的 mon_len 成员变量即代码长度 = __bss_end -_start =0X878A8E74-0x87800000=0XA8E74;
(2)initf_malloc: 函数初始化 gd 中跟 malloc 有关的成员变量,比如 malloc_limit,gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN=0X400 内存池大小为0x400;
(3)timer_init :初始化A7内核定时器,类似于M内核SysTick
(4)env_init: 设置 gd 的成员变量 env_addr,也就是环境变量的保存地址
(5)init_baud_rate :函数用于初始化波特率,根据环境变量 baudrate 来初始化 gd->baudrate。
(6)dram_init :设置 gd->ram_size 的值 512MB
(7)setup_dest_addr函数,设置目的地址,设置gd->ram_size,gd->ram_top,gd->relocaddr 等
(8)reserve_uboot, 留出重定位后的 uboot 所占用的内存区域
(9)reserve_mmu:留出 MMU 的 TLB 表的位置
(10)reserve_malloc:reserve_malloc,留出 malloc 区域,调整 gd->start_addr_sp 位置,malloc 区域由宏TOTAL_MALLOC_LEN 定义:#define TOTAL_MALLOC_LEN (CONFIG_SYS_MALLOC_LEN +
CONFIG_ENV_SIZE),宏 CONFIG_SYS_MALLOC_LEN 为 16MB=0X1000000, 宏CONFIG_ENV_SIZE=8KB=0X2000,因此 TOTAL_MALLOC_LEN=0X1002000。调整以后
gd->start_addr_sp=0X9EF45000 //0X9FF47000-16MB-8KB=0X9EF45000
(11)reserve_board :留出板子 bd 所占的内存区,bd 是结构体 bd_t,bd_t 大小为
80 字节
(12)reserve_global_data:保留出 gd_t 的内存区域
(13)reserve_stacks 留出栈空间,先对 gd->start_addr_sp 减去 16,然后做 16 字节对齐
(14)setup_dram_config 函数设置 dram 信息,就是设置 gd->bd->bi_dram[0].start 和 gd->bd->bi_dram[0].size,后面会传递给 linux 内核,告诉 linux DRAM 的起始地址和大小。
(15)setup_reloc,设置 gd 的其他一些成员变量,供后面重定位的时候使用,并且将以
前的 gd 拷贝到 gd->new_gd 处。
最终的DRAM内存分配图如下图所示:
1.4 relocate_code函数
执行完board_init_f函数之后,ldr sp, [r9, #GD_START_ADDR_SP] 这句话会将sp = gd->start_addr_sp = 0X9EF44E90。下面三条指令,将here函数采用adr相对寻址的方式,将地址给lr,因为下面要调用relocate_code进行重定位。
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
然后设置 r0 =gd->relocaddr = 0X9FF47000,调用 relocate_code函数,代码如下
/*
* 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.
*/
ENTRY(relocate_code)
ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
subs r4, r0, r1 /* r4 <- relocation offset */
beq relocate_done /* skip relocation */
ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */
copy_loop:
ldmia r1!, {r10-r11} /* copy from source address [r1] */
stmia r0!, {r10-r11} /* copy to target address [r0] */
cmp r1, r2 /* until source end address [r2] */
blo copy_loop
/*
* fix .rel.dyn relocations
*/
ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */
ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */
fixloop:
ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */
and r1, r1, #0xff
cmp r1, #23 /* relative fixup? */
bne fixnext
/* relative fix: increase location by offset */
add r0, r0, r4
ldr r1, [r0]
add r1, r1, r4
str r1, [r0]
fixnext:
cmp r2, r3
blo fixloop
relocate_done:
#ifdef __XSCALE__
/*
* On xscale, icache must be invalidated and write buffers drained,
* even with cache disabled - 4.2.7 of xscale core developer's manual
*/
mcr p15, 0, r0, c7, c7, 0 /* invalidate icache */
mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
#endif
/* ARMv4- don't know bx lr but the assembler fails to see that */
#ifdef __ARM_ARCH_4__
mov pc, lr
#else
bx lr
#endif
ENDPROC(relocate_code)
uboot拷贝:r1 = __image_copy_start=0X87800000;r0=0X9FF47000,这个地址就是 uboot 拷贝的目标首地址;r0-r1 等于 0,说明 r0 和 r1 相等,也就是源地址和目的地址是一样的,那肯定就不需要拷贝了!执行 relocate_done 函数。
如果r0与r1不相等,读取 uboot 代码保存到 r10 和 r11 中,一次就只拷贝这 2 个 32 位的数据。拷贝完成以后 r1 的值会更新,保存下一个要拷贝的数据地址。然后将 r10 和 r11 的数据写到 r0 开始的地方,也就是目的地址。写完以后 r0 的值会更新,更新为下一个要写入的数据地址。
重定位:
r2=__rel_dyn_start,也就是.rel.dyn 段的起始地址
r3=__rel_dyn_end,也就是.rel.dyn 段的终止地址。
从.rel.dyn 段起始地址开始,每次读取两个 4 字节的数据存放到 r0 和 r1 寄存器中,r0 存放低 4 字节的数据,也就是 Label 地址;
r1 存放高 4 字节的数据,也就是 Label 标志。r1 中给的值与 0xff 进行与运算,其实就是取 r1 的低 8 位,判断 r1 中的值是否等于 23(0X17),如果 r1 不等于 23 的话就说明不是描述 Label 的,执行函数 fixnext。否则的话,r0 保存着 Label 值,r4 保存着重定位后的地址偏移,r0+r4 就得到了重定位后的Label 值。此时 r0 保存着重定位后的 Label 值,相当于0X87804198+0X18747000=0X9FF4B198。ldr r1, [r0]这条指定读取r0数据,这个数据就是记录原来的变量地址,由于重定位了,所以add r1, r1, r4,将原来记录的变量的存储地址也加上偏移,并将新的值写入r0,所以执行str r1, [r0]。
1.5 relocate_vectors函数
relocate_vectors函数代码如下。 在.config 里面定义了 CONFIG_HAS_VBAR,因此会执行CONFIG_HAS_VBAR这个分支。,r0=gd->relocaddr,也就是重定位后 uboot 的首地址,将 r0 的值写入到 CP15 的 VBAR 寄存器中,也就是将新的向量表首地址写入到寄存器 VBAR 中,设置向量表偏移。
ENTRY(relocate_vectors)
#ifdef CONFIG_CPU_V7M
/*
* On ARMv7-M we only have to write the new vector address
* to VTOR register.
*/
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
ldr r1, =V7M_SCB_BASE
str r0, [r1, V7M_SCB_VTOR]
#else
#ifdef CONFIG_HAS_VBAR
/*
* If the ARM processor has the security extensions,
* use VBAR to relocate the exception vectors.
*/
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
mcr p15, 0, r0, c12, c0, 0 /* Set VBAR */
#else
/*
* Copy the relocated exception vectors to the
* correct address
* CP15 c1 V bit gives us the location of the vectors:
* 0x00000000 or 0xFFFF0000.
*/
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
mrc p15, 0, r2, c1, c0, 0 /* V bit (bit[13]) in CP15 c1 */
ands r2, r2, #(1 << 13)
ldreq r1, =0x00000000 /* If V=0 */
ldrne r1, =0xFFFF0000 /* If V=1 */
ldmia r0!, {r2-r8,r10}
stmia r1!, {r2-r8,r10}
ldmia r0!, {r2-r8,r10}
stmia r1!, {r2-r8,r10}
#endif
#endif
bx lr
ENDPROC(relocate_vectors)
1.6 c_runtime_cpu_setup 函数
c_runtime_cpu_setup 函数代码如下,不使用icache。
ENTRY(c_runtime_cpu_setup)
/*
* If I-cache is enabled invalidate it
*/
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
#endif
bx lr
ENDPROC(c_runtime_cpu_setup)
1.7 board_init_r 函数
在执行board_init_r 函数之前,首先执行mov r0, r9 ;ldr r1, [r9, #GD_RELOCADDR];r0 = gd_t ,r1 = gd->relocadd。board_init_r函数代码如下。也是initcall_run_list函数对序列init_sequence_r里面的函数进行调用初始化。
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
int i;
#endif
#ifdef CONFIG_AVR32
mmu_init_r(dest_addr);
#endif
#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
gd = new_gd;
#endif
#ifdef CONFIG_NEEDS_MANUAL_RELOC
for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
init_sequence_r[i] += gd->reloc_off;
#endif
if (initcall_run_list(init_sequence_r))
hang();
/* NOTREACHED - run_main_loop() does not return */
hang();
}
1.7.1 init_sequence_r
init_sequence_r里面的函数集合如下。
init_fnc_t init_sequence_r[] = {
initr_trace,
initr_reloc,
/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
initr_caches,
/* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
* A temporary mapping of IFC high region is since removed,
* so environmental variables in NOR flash is not availble
* until board_init() is called below to remap IFC to high
* region.
*/
#endif
initr_reloc_global_data,
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
initr_unlock_ram_in_cache,
#endif
initr_barrier,
initr_malloc,
initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORY
initr_noncached,
#endif
bootstage_relocate,
#ifdef CONFIG_DM
initr_dm,
#endif
initr_bootstage,
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)
board_init, /* Setup chipselects */
#endif
/*
* TODO: printing of the clock inforamtion of the board is now
* implemented as part of bdinfo command. Currently only support for
* davinci SOC's is added. Remove this check once all the board
* implement this.
*/
#ifdef CONFIG_CLOCKS
set_cpu_clk_info, /* Setup clock information */
#endif
stdio_init_tables,
initr_serial,
initr_announce,
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_NEEDS_MANUAL_RELOC
initr_manual_reloc_cmdtable,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
initr_trap,
#endif
#ifdef CONFIG_ADDR_MAP
initr_addr_map,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_R)
board_early_init_r,
#endif
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_LOGBUFFER
initr_logbuffer,
#endif
#ifdef CONFIG_POST
initr_post_backlog,
#endif
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_SYS_DELAYED_ICACHE
initr_icache_enable,
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)
/*
* Do early PCI configuration _before_ the flash gets initialised,
* because PCU ressources are crucial for flash access on some boards.
*/
initr_pci,
#endif
#ifdef CONFIG_WINBOND_83C553
initr_w83c553f,
#endif
#ifdef CONFIG_ARCH_EARLY_INIT_R
arch_early_init_r,
#endif
power_init_board,
#ifndef CONFIG_SYS_NO_FLASH
initr_flash,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86) || \
defined(CONFIG_SPARC)
/* initialize higher level parts of CPU like time base and timers */
cpu_init_r,
#endif
#ifdef CONFIG_PPC
initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
initr_onenand,
#endif
#ifdef CONFIG_GENERIC_MMC
initr_mmc,
#endif
#ifdef CONFIG_HAS_DATAFLASH
initr_dataflash,
#endif
initr_env,
#ifdef CONFIG_SYS_BOOTPARAMS_LEN
initr_malloc_bootparams,
#endif
INIT_FUNC_WATCHDOG_RESET
initr_secondary_cpu,
#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
mac_read_from_eeprom,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
/*
* Do pci configuration
*/
initr_pci,
#endif
stdio_add_devices,
initr_jumptable,
#ifdef CONFIG_API
initr_api,
#endif
console_init_r, /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INIT
arch_misc_init, /* miscellaneous arch-dependent init */
#endif
#ifdef CONFIG_MISC_INIT_R
misc_init_r, /* miscellaneous platform-dependent init */
#endif
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDB
initr_kgdb,
#endif
interrupt_init,
#if defined(CONFIG_ARM) || defined(CONFIG_AVR32)
initr_enable_interrupts,
#endif
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || defined(CONFIG_M68K)
timer_init, /* initialize timer */
#endif
#if defined(CONFIG_STATUS_LED)
initr_status_led,
#endif
/* PPC has a udelay(20) here dating from 2002. Why? */
#ifdef CONFIG_CMD_NET
initr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init,
#endif
#ifdef CONFIG_FSL_FASTBOOT
initr_fastboot_setup,
#endif
#if defined(CONFIG_CMD_AMBAPP)
ambapp_init_reloc,
#if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP)
initr_ambapp_print,
#endif
#endif
#ifdef CONFIG_CMD_SCSI
INIT_FUNC_WATCHDOG_RESET
initr_scsi,
#endif
#ifdef CONFIG_CMD_DOC
INIT_FUNC_WATCHDOG_RESET
initr_doc,
#endif
#ifdef CONFIG_BITBANGMII
initr_bbmii,
#endif
#ifdef CONFIG_CMD_NET
INIT_FUNC_WATCHDOG_RESET
initr_net,
#endif
#ifdef CONFIG_POST
initr_post,
#endif
#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
initr_pcmcia,
#endif
#if defined(CONFIG_CMD_IDE)
initr_ide,
#endif
#ifdef CONFIG_LAST_STAGE_INIT
INIT_FUNC_WATCHDOG_RESET
/*
* Some parts can be only initialized if all others (like
* Interrupts) are up and running (i.e. the PC-style ISA
* keyboard).
*/
last_stage_init,
#endif
#ifdef CONFIG_CMD_BEDBUG
INIT_FUNC_WATCHDOG_RESET
initr_bedbug,
#endif
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
initr_mem,
#endif
#ifdef CONFIG_PS2KBD
initr_kbd,
#endif
#if defined(CONFIG_SPARC)
prom_init,
#endif
#ifdef CONFIG_FSL_FASTBOOT
initr_check_fastboot,
#endif
run_main_loop,
};
(1)initr_trace 函数:初始化和调试跟踪有关的内容
(2)initr_caches 函数:初始化 cache,使能 cache
(3)initr_malloc 函数:初始化 malloc
(4)initr_serial 函数:初始化串口
(5)initr_nand函数:初始化NAND
(6)initr_mmc 函数:初始化 EMMC
()run_main_loop:这个函数后面再分析