This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
u-boot_boot_sequence [2019/12/27 17:43] rpjday |
u-boot_boot_sequence [2019/12/28 08:33] rpjday [1.] |
||
---|---|---|---|
Line 19: | Line 19: | ||
===== arch/arm/lib/crt0_64.S [ENTRY(_main)] ===== | ===== arch/arm/lib/crt0_64.S [ENTRY(_main)] ===== | ||
- | ==== 1. ==== | + | ==== Prologue ==== |
<code> | <code> | ||
Line 25: | Line 25: | ||
* start-up where a C runtime environment is needed. Its entry point | * start-up where a C runtime environment is needed. Its entry point | ||
* is _main and is branched into from the target's start.S file. | * is _main and is branched into from the target's start.S file. | ||
- | * | + | </code> |
- | * _main execution sequence is: | + | |
- | * | + | ==== 1. ==== |
+ | |||
+ | <code> | ||
* 1. Set up initial environment for calling board_init_f(). | * 1. Set up initial environment for calling board_init_f(). | ||
* This environment only provides a stack and a place to store | * This environment only provides a stack and a place to store | ||
Line 35: | Line 37: | ||
* CONSTANT initialized data are available. GD should be zeroed | * CONSTANT initialized data are available. GD should be zeroed | ||
* before board_init_f() is called. | * before board_init_f() is called. | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | ENTRY(_main) | ||
+ | |||
+ | /* | ||
+ | * Set up initial C runtime environment and call board_init_f(0). | ||
+ | */ | ||
+ | #if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK) | ||
+ | ldr x0, =(CONFIG_TPL_STACK) | ||
+ | #elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) | ||
+ | ldr x0, =(CONFIG_SPL_STACK) | ||
+ | #elif defined(CONFIG_INIT_SP_RELATIVE) | ||
+ | adr x0, __bss_start | ||
+ | add x0, x0, #CONFIG_SYS_INIT_SP_BSS_OFFSET | ||
+ | #else | ||
+ | ldr x0, =(CONFIG_SYS_INIT_SP_ADDR) | ||
+ | #endif | ||
+ | bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */ | ||
+ | mov x0, sp | ||
+ | bl board_init_f_alloc_reserve | ||
+ | mov sp, x0 | ||
+ | /* set up gd here, outside any C code */ | ||
+ | mov x18, x0 | ||
+ | bl board_init_f_init_reserve | ||
</code> | </code> | ||
Line 46: | Line 73: | ||
* data include the relocation destination, the future stack, and | * data include the relocation destination, the future stack, and | ||
* the future GD location. | * the future GD location. | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | mov x0, #0 | ||
+ | bl board_init_f | ||
</code> | </code> | ||
Line 54: | Line 86: | ||
* ones allocated by board_init_f() in system RAM, but BSS and | * ones allocated by board_init_f() in system RAM, but BSS and | ||
* initialized non-const data are still not available. | * initialized non-const data are still not available. | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | #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 x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */ | ||
+ | bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */ | ||
+ | ldr x18, [x18, #GD_NEW_GD] /* x18 <- gd->new_gd */ | ||
+ | |||
+ | adr lr, relocation_return | ||
+ | #if CONFIG_POSITION_INDEPENDENT | ||
+ | /* Add in link-vs-runtime offset */ | ||
+ | adr x0, _start /* x0 <- Runtime value of _start */ | ||
+ | ldr x9, _TEXT_BASE /* x9 <- Linked value of _start */ | ||
+ | sub x9, x9, x0 /* x9 <- Run-vs-link offset */ | ||
+ | add lr, lr, x9 | ||
+ | #endif | ||
+ | /* Add in link-vs-relocation offset */ | ||
+ | ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd->reloc_off */ | ||
+ | add lr, lr, x9 /* new return address after relocation */ | ||
+ | ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */ | ||
</code> | </code> | ||
Line 62: | Line 119: | ||
* relocates U-Boot from its current location into the relocation | * relocates U-Boot from its current location into the relocation | ||
* destination computed by board_init_f(). | * destination computed by board_init_f(). | ||
+ | </code> | ||
+ | |||
+ | <code> | ||
+ | b relocate_code | ||
+ | |||
+ | relocation_return: | ||
</code> | </code> | ||
Line 87: | Line 150: | ||
* at this point regarding memory, so call c_runtime_cpu_setup. | * at this point regarding memory, so call c_runtime_cpu_setup. | ||
</code> | </code> | ||
- | |||
- | ==== 7. ==== | ||
<code> | <code> | ||
- | * 7. Branch to board_init_r(). | + | /* |
- | </code> | + | * Set up final (full) environment |
- | + | */ | |
- | ===== common/board_f.c ===== | + | bl c_runtime_cpu_setup /* still call old routine */ |
- | + | #endif /* !CONFIG_SPL_BUILD */ | |
- | ===== common/board_r.c (only most common) ===== | + | #if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK) |
- | + | #if defined(CONFIG_SPL_BUILD) | |
- | ==== initr_dm() [C] ==== | + | bl spl_relocate_stack_gd /* may return NULL */ |
- | ==== board_init() [A,B] ==== | + | /* set up gd here, outside any C code, if new stack is returned */ |
- | + | cmp x0, #0 | |
- | ==== board_early_init_r() (not for Zynq) ==== | + | csel x18, x0, x18, ne |
- | + | /* | |
- | ==== arch_early_init_r() [A] ==== | + | * Perform 'sp = (x0 != NULL) ? x0 : sp' while working |
- | + | * around the constraint that conditional moves can not | |
- | * arch/arm/mach-zynq/cpu.c | + | * have 'sp' as an operand |
- | * arch/arm/mach-zynq/spl.c | + | */ |
- | + | mov x1, sp | |
- | <code> | + | cmp x0, #0 |
- | #if defined(CONFIG_ARCH_EARLY_INIT_R) | + | csel x0, x0, x1, ne |
- | int arch_early_init_r(void) | + | mov sp, x0 |
- | { | + | |
- | #if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ | + | |
- | (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) | + | |
- | int cpu_id = cpu_desc_id(); | + | |
- | + | ||
- | if (cpu_id < 0) | + | |
- | return 0; | + | |
- | + | ||
- | fpga.size = zynq_fpga_descs[cpu_id].fpga_size; | + | |
- | fpga.name = zynq_fpga_descs[cpu_id].devicename; | + | |
- | fpga_init(); | + | |
- | fpga_add(fpga_xilinx, &fpga); | + | |
#endif | #endif | ||
- | return 0; | ||
- | } | ||
- | #endif | ||
- | </code> | ||
- | |||
- | ==== initr_mmc() [C] ==== | ||
- | |||
- | <code> | ||
- | #ifdef CONFIG_MMC | ||
- | static int initr_mmc(void) | ||
- | { | ||
- | puts("MMC: "); | ||
- | mmc_initialize(gd->bd); | ||
- | return 0; | ||
- | } | ||
- | #endif | ||
- | </code> | ||
- | |||
- | ==== initr_env() [C] ==== | ||
- | |||
- | <code> | ||
- | static int initr_env(void) | ||
- | { | ||
- | /* initialize environment */ | ||
- | if (should_load_env()) | ||
- | env_relocate(); | ||
- | else | ||
- | set_default_env(NULL, 0); | ||
- | #ifdef CONFIG_OF_CONTROL | ||
- | env_set_hex("fdtcontroladdr", | ||
- | (unsigned long)map_to_sysmem(gd->fdt_blob)); | ||
- | #endif | ||
- | |||
- | /* Initialize from environment */ | ||
- | load_addr = env_get_ulong("loadaddr", 16, load_addr); | ||
- | |||
- | return 0; | ||
- | } | ||
- | </code> | ||
- | |||
- | ==== show_board_info() [C] ==== | ||
- | |||
- | From ''common/board_info.c'': | ||
- | |||
- | <code> | ||
- | int __weak checkboard(void) | ||
- | { | ||
- | return 0; | ||
- | } | ||
/* | /* | ||
- | * If the root node of the DTB has a "model" property, show it. | + | * Clear BSS section |
- | * Then call checkboard(). | + | |
*/ | */ | ||
- | int __weak show_board_info(void) | + | ldr x0, =__bss_start /* this is auto-relocated! */ |
- | { | + | ldr x1, =__bss_end /* this is auto-relocated! */ |
- | #ifdef CONFIG_OF_CONTROL | + | clear_loop: |
- | DECLARE_GLOBAL_DATA_PTR; | + | str xzr, [x0], #8 |
- | const char *model; | + | cmp x0, x1 |
- | + | b.lo clear_loop | |
- | model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); | + | |
- | + | ||
- | if (model) | + | |
- | printf("Model: %s\n", model); | + | |
- | #endif | + | |
- | return checkboard(); | + | /* call board_init_r(gd_t *id, ulong dest_addr) */ |
- | } | + | mov x0, x18 /* gd_t */ |
+ | ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */ | ||
</code> | </code> | ||
- | + | ==== 7. ==== | |
- | For ''zynqmp.c'': | + | |
<code> | <code> | ||
- | int checkboard(void) | + | * 7. Branch to board_init_r(). |
- | { | + | |
- | puts("Board: Xilinx ZynqMP\n"); | + | |
- | return 0; | + | |
- | } | + | |
</code> | </code> | ||
- | |||
- | ==== arch_misc_init() ==== | ||
- | |||
- | Some arches and boards, not Zynq. | ||
<code> | <code> | ||
- | #ifdef CONFIG_ARCH_MISC_INIT | + | b board_init_r /* PC relative jump */ |
- | arch_misc_init, | + | |
- | #endif | + | |
- | </code> | + | |
- | ==== misc_init_r() ==== | + | /* NOTREACHED - board_init_r() does not return */ |
- | + | ||
- | <code> | + | |
- | #ifdef CONFIG_MISC_INIT_R | + | |
- | misc_init_r, | + | |
- | #endif | + | |
</code> | </code> | ||
- | ==== initr_enable_interrupts() ==== | + | ===== common/board_f.c ===== |
<code> | <code> | ||
- | #ifdef CONFIG_ARM | + | void board_init_f(ulong boot_flags) |
- | static int initr_enable_interrupts(void) | + | |
{ | { | ||
- | enable_interrupts(); | + | gd->flags = boot_flags; |
- | return 0; | + | gd->have_console = 0; |
- | } | + | |
- | #endif | + | if (initcall_run_list(init_sequence_f)) |
+ | hang(); | ||
+ | ... | ||
</code> | </code> | ||
- | From ''arch/arm/lib/interrupts.c'': | + | ===== common/board_r.c ===== |
<code> | <code> | ||
- | int interrupt_init (void) | + | void board_init_r(gd_t *new_gd, ulong dest_addr) |
{ | { | ||
/* | /* | ||
- | * setup up stacks if necessary | + | * Set up the new global data pointer. So far only x86 does this |
+ | * here. | ||
+ | * TODO(sjg@chromium.org): Consider doing this for all archs, or | ||
+ | * dropping the new_gd parameter. | ||
*/ | */ | ||
- | IRQ_STACK_START_IN = gd->irq_sp + 8; | + | #if CONFIG_IS_ENABLED(X86_64) |
+ | arch_setup_gd(new_gd); | ||
+ | #endif | ||
- | return 0; | + | #ifdef CONFIG_NEEDS_MANUAL_RELOC |
- | } | + | int i; |
- | + | ||
- | void enable_interrupts (void) | + | |
- | { | + | |
- | return; | + | |
- | } | + | |
- | int disable_interrupts (void) | + | |
- | { | + | |
- | return 0; | + | |
- | } | + | |
- | </code> | + | |
- | + | ||
- | ==== initr_ethaddr() [C] ==== | + | |
- | + | ||
- | <code> | + | |
- | #ifdef CONFIG_CMD_NET | + | |
- | initr_ethaddr, | + | |
#endif | #endif | ||
- | </code> | ||
- | <code> | + | #if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) |
- | #ifdef CONFIG_CMD_NET | + | gd = new_gd; |
- | static int initr_ethaddr(void) | + | |
- | { | + | |
- | bd_t *bd = gd->bd; | + | |
- | + | ||
- | /* kept around for legacy kernels only ... ignore the next section */ | + | |
- | eth_env_get_enetaddr("ethaddr", bd->bi_enetaddr); | + | |
- | #ifdef CONFIG_HAS_ETH1 | + | |
- | eth_env_get_enetaddr("eth1addr", bd->bi_enet1addr); | + | |
#endif | #endif | ||
- | #ifdef CONFIG_HAS_ETH2 | + | gd->flags &= ~GD_FLG_LOG_READY; |
- | eth_env_get_enetaddr("eth2addr", bd->bi_enet2addr); | + | |
- | #endif | + | |
- | #ifdef CONFIG_HAS_ETH3 | + | |
- | eth_env_get_enetaddr("eth3addr", bd->bi_enet3addr); | + | |
- | #endif | + | |
- | #ifdef CONFIG_HAS_ETH4 | + | |
- | eth_env_get_enetaddr("eth4addr", bd->bi_enet4addr); | + | |
- | #endif | + | |
- | #ifdef CONFIG_HAS_ETH5 | + | |
- | eth_env_get_enetaddr("eth5addr", bd->bi_enet5addr); | + | |
- | #endif | + | |
- | return 0; | + | |
- | } | + | |
- | #endif /* CONFIG_CMD_NET */ | + | |
- | </code> | + | |
- | ==== board_late_init() [B] ==== | + | #ifdef CONFIG_NEEDS_MANUAL_RELOC |
- | + | for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++) | |
- | (Defined in board/xilinx/zynq/board.c.) | + | init_sequence_r[i] += gd->reloc_off; |
- | + | ||
- | <code> | + | |
- | #ifdef CONFIG_BOARD_LATE_INIT | + | |
- | board_late_init, | + | |
#endif | #endif | ||
- | </code> | ||
- | ==== initr_net() ==== | + | if (initcall_run_list(init_sequence_r)) |
+ | hang(); | ||
- | <code> | + | /* NOTREACHED - run_main_loop() does not return */ |
- | #ifdef CONFIG_CMD_NET | + | hang(); |
- | static int initr_net(void) | + | |
- | { | + | |
- | puts("Net: "); | + | |
- | eth_initialize(); | + | |
- | #if defined(CONFIG_RESET_PHY_R) | + | |
- | debug("Reset Ethernet PHY\n"); | + | |
- | reset_phy(); | + | |
- | #endif | + | |
- | return 0; | + | |
- | } | + | |
- | #endif | + | |
</code> | </code> | ||
- |