This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Last revision Both sides next revision | ||
u-boot_boot_sequence [2019/12/27 17:40] rpjday [arch/arm/lib/crt0_64.S [ENTRY(_main)]] |
u-boot_boot_sequence [2019/12/27 17:55] rpjday [common/board_f.c] |
||
---|---|---|---|
Line 21: | Line 21: | ||
==== 1. ==== | ==== 1. ==== | ||
- | ==== 2. ==== | + | <code> |
- | + | * This file handles the target-independent stages of the U-Boot | |
- | ==== 3. ==== | + | * 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. | |
- | ==== 4a. ==== | + | * |
- | + | * _main execution sequence is: | |
- | ==== 4b. ==== | + | * |
- | + | * 1. Set up initial environment for calling board_init_f(). | |
- | ==== 5. ==== | + | * This environment only provides a stack and a place to store |
- | + | * the GD ('global data') structure, both located in some readily | |
- | ==== 6. ==== | + | * available RAM (SRAM, locked cache...). In this context, VARIABLE |
- | + | * global data, initialized or not (BSS), are UNAVAILABLE; only | |
- | ==== 7. ==== | + | * CONSTANT initialized data are available. GD should be zeroed |
- | + | * before board_init_f() is called. | |
- | ===== common/board_f.c ===== | + | </code> |
- | + | ||
- | ===== common/board_r.c (only most common) ===== | + | |
- | + | ||
- | ==== initr_dm() [C] ==== | + | |
- | ==== board_init() [A,B] ==== | + | |
- | + | ||
- | ==== board_early_init_r() (not for Zynq) ==== | + | |
- | + | ||
- | ==== arch_early_init_r() [A] ==== | + | |
- | + | ||
- | * arch/arm/mach-zynq/cpu.c | + | |
- | * arch/arm/mach-zynq/spl.c | + | |
<code> | <code> | ||
- | #if defined(CONFIG_ARCH_EARLY_INIT_R) | + | ENTRY(_main) |
- | int arch_early_init_r(void) | + | |
- | { | + | |
- | #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; | + | * Set up initial C runtime environment and call board_init_f(0). |
- | + | */ | |
- | fpga.size = zynq_fpga_descs[cpu_id].fpga_size; | + | #if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK) |
- | fpga.name = zynq_fpga_descs[cpu_id].devicename; | + | ldr x0, =(CONFIG_TPL_STACK) |
- | fpga_init(); | + | #elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) |
- | fpga_add(fpga_xilinx, &fpga); | + | ldr x0, =(CONFIG_SPL_STACK) |
- | #endif | + | #elif defined(CONFIG_INIT_SP_RELATIVE) |
- | return 0; | + | adr x0, __bss_start |
- | } | + | add x0, x0, #CONFIG_SYS_INIT_SP_BSS_OFFSET |
+ | #else | ||
+ | ldr x0, =(CONFIG_SYS_INIT_SP_ADDR) | ||
#endif | #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> | ||
- | ==== initr_mmc() [C] ==== | + | ==== 2. ==== |
<code> | <code> | ||
- | #ifdef CONFIG_MMC | + | * 2. Call board_init_f(). This function prepares the hardware for |
- | static int initr_mmc(void) | + | * execution from system RAM (DRAM, DDR...) As system RAM may not |
- | { | + | * be available yet, , board_init_f() must use the current GD to |
- | puts("MMC: "); | + | * store any data which must be passed on to later stages. These |
- | mmc_initialize(gd->bd); | + | * data include the relocation destination, the future stack, and |
- | return 0; | + | * the future GD location. |
- | } | + | |
- | #endif | + | |
</code> | </code> | ||
- | |||
- | ==== initr_env() [C] ==== | ||
<code> | <code> | ||
- | static int initr_env(void) | + | mov x0, #0 |
- | { | + | bl board_init_f |
- | /* initialize environment */ | + | </code> |
- | 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 */ | + | ==== 3. ==== |
- | load_addr = env_get_ulong("loadaddr", 16, load_addr); | + | |
- | return 0; | + | <code> |
- | } | + | * 3. Set up intermediate environment where the stack and GD are the |
+ | * ones allocated by board_init_f() in system RAM, but BSS and | ||
+ | * initialized non-const data are still not available. | ||
</code> | </code> | ||
- | |||
- | ==== show_board_info() [C] ==== | ||
- | |||
- | From ''common/board_info.c'': | ||
<code> | <code> | ||
- | int __weak checkboard(void) | + | #if !defined(CONFIG_SPL_BUILD) |
- | { | + | |
- | return 0; | + | |
- | } | + | |
/* | /* | ||
- | * If the root node of the DTB has a "model" property, show it. | + | * Set up intermediate environment (new sp and gd) and call |
- | * Then call checkboard(). | + | * relocate_code(addr_moni). Trick here is that we'll return |
+ | * 'here' but relocated. | ||
*/ | */ | ||
- | int __weak show_board_info(void) | + | ldr x0, [x18, #GD_START_ADDR_SP] /* x0 <- gd->start_addr_sp */ |
- | { | + | bic sp, x0, #0xf /* 16-byte alignment for ABI compliance */ |
- | #ifdef CONFIG_OF_CONTROL | + | ldr x18, [x18, #GD_NEW_GD] /* x18 <- gd->new_gd */ |
- | DECLARE_GLOBAL_DATA_PTR; | + | |
- | const char *model; | + | |
- | model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); | + | adr lr, relocation_return |
- | + | #if CONFIG_POSITION_INDEPENDENT | |
- | if (model) | + | /* Add in link-vs-runtime offset */ |
- | printf("Model: %s\n", model); | + | 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 | #endif | ||
- | + | /* Add in link-vs-relocation offset */ | |
- | return checkboard(); | + | 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> | ||
+ | ==== 4a. ==== | ||
- | For ''zynqmp.c'': | + | <code> |
+ | * 4a.For U-Boot proper (not SPL), call relocate_code(). This function | ||
+ | * relocates U-Boot from its current location into the relocation | ||
+ | * destination computed by board_init_f(). | ||
+ | </code> | ||
<code> | <code> | ||
- | int checkboard(void) | + | b relocate_code |
- | { | + | |
- | puts("Board: Xilinx ZynqMP\n"); | + | relocation_return: |
- | return 0; | + | |
- | } | + | |
</code> | </code> | ||
- | ==== arch_misc_init() ==== | + | ==== 4b. ==== |
- | + | ||
- | Some arches and boards, not Zynq. | + | |
<code> | <code> | ||
- | #ifdef CONFIG_ARCH_MISC_INIT | + | * 4b.For SPL, board_init_f() just returns (to crt0). There is no |
- | arch_misc_init, | + | * code relocation in SPL. |
- | #endif | + | |
</code> | </code> | ||
- | ==== misc_init_r() ==== | + | ==== 5. ==== |
<code> | <code> | ||
- | #ifdef CONFIG_MISC_INIT_R | + | * 5. Set up final environment for calling board_init_r(). This |
- | misc_init_r, | + | * environment has BSS (initialized to 0), initialized non-const |
- | #endif | + | * data (initialized to their intended value), and stack in system |
+ | * RAM (for SPL moving the stack and GD into RAM is optional - see | ||
+ | * CONFIG_SPL_STACK_R). GD has retained values set by board_init_f(). | ||
</code> | </code> | ||
- | ==== initr_enable_interrupts() ==== | + | ==== 6. ==== |
<code> | <code> | ||
- | #ifdef CONFIG_ARM | + | * 6. For U-Boot proper (not SPL), some CPUs have some work left to do |
- | static int initr_enable_interrupts(void) | + | * at this point regarding memory, so call c_runtime_cpu_setup. |
- | { | + | |
- | enable_interrupts(); | + | |
- | return 0; | + | |
- | } | + | |
- | #endif | + | |
</code> | </code> | ||
- | |||
- | From ''arch/arm/lib/interrupts.c'': | ||
<code> | <code> | ||
- | int interrupt_init (void) | + | /* |
- | { | + | * Set up final (full) environment |
+ | */ | ||
+ | bl c_runtime_cpu_setup /* still call old routine */ | ||
+ | #endif /* !CONFIG_SPL_BUILD */ | ||
+ | #if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK) | ||
+ | #if defined(CONFIG_SPL_BUILD) | ||
+ | bl spl_relocate_stack_gd /* may return NULL */ | ||
+ | /* set up gd here, outside any C code, if new stack is returned */ | ||
+ | cmp x0, #0 | ||
+ | csel x18, x0, x18, ne | ||
/* | /* | ||
- | * setup up stacks if necessary | + | * Perform 'sp = (x0 != NULL) ? x0 : sp' while working |
+ | * around the constraint that conditional moves can not | ||
+ | * have 'sp' as an operand | ||
*/ | */ | ||
- | IRQ_STACK_START_IN = gd->irq_sp + 8; | + | mov x1, sp |
+ | cmp x0, #0 | ||
+ | csel x0, x0, x1, ne | ||
+ | mov sp, x0 | ||
+ | #endif | ||
- | return 0; | + | /* |
- | } | + | * Clear BSS section |
+ | */ | ||
+ | ldr x0, =__bss_start /* this is auto-relocated! */ | ||
+ | ldr x1, =__bss_end /* this is auto-relocated! */ | ||
+ | clear_loop: | ||
+ | str xzr, [x0], #8 | ||
+ | cmp x0, x1 | ||
+ | b.lo clear_loop | ||
- | void enable_interrupts (void) | + | /* call board_init_r(gd_t *id, ulong dest_addr) */ |
- | { | + | mov x0, x18 /* gd_t */ |
- | return; | + | ldr x1, [x18, #GD_RELOCADDR] /* dest_addr */ |
- | } | + | |
- | int disable_interrupts (void) | + | |
- | { | + | |
- | return 0; | + | |
- | } | + | |
</code> | </code> | ||
- | ==== initr_ethaddr() [C] ==== | + | ==== 7. ==== |
<code> | <code> | ||
- | #ifdef CONFIG_CMD_NET | + | * 7. Branch to board_init_r(). |
- | initr_ethaddr, | + | |
- | #endif | + | |
</code> | </code> | ||
<code> | <code> | ||
- | #ifdef CONFIG_CMD_NET | + | b board_init_r /* PC relative jump */ |
- | static int initr_ethaddr(void) | + | |
- | { | + | |
- | bd_t *bd = gd->bd; | + | |
- | /* kept around for legacy kernels only ... ignore the next section */ | + | /* NOTREACHED - board_init_r() does not return */ |
- | eth_env_get_enetaddr("ethaddr", bd->bi_enetaddr); | + | |
- | #ifdef CONFIG_HAS_ETH1 | + | |
- | eth_env_get_enetaddr("eth1addr", bd->bi_enet1addr); | + | |
- | #endif | + | |
- | #ifdef CONFIG_HAS_ETH2 | + | |
- | 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> | </code> | ||
- | ==== board_late_init() [B] ==== | + | ===== common/board_f.c ===== |
- | (Defined in board/xilinx/zynq/board.c.) | + | <code> |
+ | void board_init_f(ulong boot_flags) | ||
+ | { | ||
+ | gd->flags = boot_flags; | ||
+ | gd->have_console = 0; | ||
- | <code> | + | if (initcall_run_list(init_sequence_f)) |
- | #ifdef CONFIG_BOARD_LATE_INIT | + | hang(); |
- | board_late_init, | + | ... |
- | #endif | + | |
</code> | </code> | ||
- | ==== initr_net() ==== | + | ===== common/board_r.c ===== |
<code> | <code> | ||
- | #ifdef CONFIG_CMD_NET | + | void board_init_r(gd_t *new_gd, ulong dest_addr) |
- | static int initr_net(void) | + | |
{ | { | ||
- | puts("Net: "); | + | /* |
- | eth_initialize(); | + | * Set up the new global data pointer. So far only x86 does this |
- | #if defined(CONFIG_RESET_PHY_R) | + | * here. |
- | debug("Reset Ethernet PHY\n"); | + | * TODO(sjg@chromium.org): Consider doing this for all archs, or |
- | reset_phy(); | + | * dropping the new_gd parameter. |
+ | */ | ||
+ | #if CONFIG_IS_ENABLED(X86_64) | ||
+ | arch_setup_gd(new_gd); | ||
#endif | #endif | ||
- | return 0; | + | |
- | } | + | #ifdef CONFIG_NEEDS_MANUAL_RELOC |
+ | int i; | ||
#endif | #endif | ||
- | </code> | ||
+ | #if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) | ||
+ | gd = new_gd; | ||
+ | #endif | ||
+ | gd->flags &= ~GD_FLG_LOG_READY; | ||
+ | |||
+ | #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(); | ||
+ | </code> |