August 14, 2018

U-Boot flow of execution

The game here is to figure out exactly where the first instruction is that U-Boot executes and follow the execution path from there. It is important to realize that U-boot does not get started directly by processor reset. Maybe on some systems it does, but not on any I have ever had experience with. Processor reset will typically enter some kind of bootrom code delivered with the chip, and a variety of steps may be needed before a U-Boot image in DRAM can run. But we are going to start our game looking at that final stage of U-boot running from DRAM. On some systems a stripped down U-Boot called the SPL runs first, typically in some on chip memory and in turn loads the final U-boot into RAM after setting up DRAM clocks and such.

Apart from just using grep and starting at a sensible starting place, a couple of clues are very helpful. One is doing a build for the system of interest and using the object files as "breadcrumbs" to discern which files were actually used for the build. The other is to have on hand a log from the build, like this one:

On the S5P6818, several executables run before U-Boot itself, and I will ignore those. There is apparently no SPL. Also on some systems U-Boot gets loaded to one address then relocates itself to another. This does not seem to be the case on the S5P6818. In other words things are fairly simple once we get to the stage I intend to study.

Execution starts in arch/arm/cpu/armv8/start.S at _start. This branches to _reset (but don't be fooled) and after a fair bit of initialization this branches to _main. The symbol _main is in arch/arm/lib/crt0_64.S

There is a nice comment at the start of crt0_64.S describing what happens next. Two routines are involved in the next stage. They are board_init_f() and board_init_r(). Remember, F first, then R.

The routine board_init_f() is called first and does what it can. (This calls arch_cpu_init() -- just for the record). Then relocate_code() is called and ultimately board_init_r() is called. Reading doc/README.arm-relocation may provide more details. See common/board_f.c for board_init_f(). The routine relocate_code() would seem to be in arch/arm/lib/relocate_64.S. See common/board_r.c for board_init_r().

An interesting aspect of board_init_f() as well as board_init_r() is the use of a table driven list of initialization routines. In the case of board_init_f(), the table is static init_fnc_t init_sequence_f[]. This table is processed by the following call:

if (initcall_run_list(init_sequence_f))
	hang();
See lib/initcall.c (only 40 lines of code). board_init_r also uses this scheme, with the last entry in the list being run_main_loop(), which is where U-Boot executes when initialization is finished and it finally gets to work. The code is in common_board_r.c as well and looks like this:
for (;;)
	main_loop();
Wrapping it in a loop allows it to retry if autoboot fails. The file common/main.c contains main_loop() and is pretty short. The critical parts look more or less like this:
        cli_init();

        run_preboot_environment_command();

        s = bootdelay_process();
        if (cli_process_fdt(&s))
                cli_secure_boot_cmd(s);

        autoboot_command(s);

        cli_loop();
Note that "fdt" is the "flat device tree", which is a whole 'nuther bundle of snakes I am not getting into here.

The file common/cli.c contains cli_init() and cli_loop(). The file common/autoboot.c contains autoboot_command(). The meat of autoboot.c is calles to run_command_list() which is also in common/cli.c.

So, where does the network get initialized?

This would seem to be done from board_init_r() via the list of initialization routines. Two sections are of interest:
#ifdef CONFIG_CMD_NET
        initr_ethaddr,
#endif
....
#ifdef CONFIG_CMD_NET
        INIT_FUNC_WATCHDOG_RESET
        initr_net,
#endif
The initr_ethaddr() routine, does this:
eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
The initr_net() routine, does this:
puts("Net:   ");
eth_initialize();
The routine eth_initialize() is in net/eth.c


Have any comments? Questions? Drop me a line!

Tom's electronics pages / [email protected]