u-Boot启动部分
U-Boot启动到Linux的流程图如下所示:
board_init_r
U-Boot首先从u-bootarch/arm/lib/crt0.S
调用u-boot/arch/arm/lib/board.c
中的board_init_r
开始启动,函数board_init_r
的实现如下所示:
void board_init_r(gd_t *id, ulong dest_addr)
{
ulong malloc_start;
#if !defined(CONFIG_SYS_NO_FLASH)
ulong flash_size;
#endif
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
monitor_flash_len = (ulong)&__rel_dyn_end - (ulong)_start;
/* Enable caches */
enable_caches();
debug("monitor flash len: %08lX\n", monitor_flash_len);
board_init(); /* Setup chipselects */
/*
* 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
serial_initialize();
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
#else
debug("Now running in RAM - U-Boot at: %08lx\n", CONFIG_SYS_SDRAM_BASE);
#endif
#ifdef CONFIG_LOGBUFFER
logbuff_init_ptrs();
#endif
#ifdef CONFIG_POST
post_output_backlog();
#endif
/* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
#ifdef CONFIG_ARCH_EARLY_INIT_R
arch_early_init_r();
#endif
power_init_board();
#if !defined(CONFIG_SYS_NO_FLASH)
puts("Flash: ");
flash_size = flash_init();
if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
print_size(flash_size, "");
/*
* Compute and print flash CRC if flashchecksum is set to 'y'
*
* NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
*/
if (getenv_yesno("flashchecksum") == 1) {
printf(" CRC: %08X", crc32(0,
(const unsigned char *) CONFIG_SYS_FLASH_BASE,
flash_size));
}
putc('\n');
# else /* !CONFIG_SYS_FLASH_CHECKSUM */
print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
} else {
puts(failed);
hang();
}
#endif
#if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init(); /* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_GENERIC_MMC
puts("MMC: ");
mmc_initialize(gd->bd);
#endif
#ifdef CONFIG_ROCKCHIP
board_storage_init();
#endif
#ifdef CONFIG_CMD_SCSI
puts("SCSI: ");
scsi_init();
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
if (should_load_env())
env_relocate();
else
set_default_env(NULL);
#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
arm_pci_init();
#endif
stdio_init(); /* get the devices list going. */
jumptable_init();
#if defined(CONFIG_API)
/* Initialize API */
api_init();
#endif
console_init_r(); /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
# ifdef CONFIG_OF_CONTROL
/* Put this here so it appears on the LCD, now it is ready */
display_fdt_model(gd->fdt_blob);
# else
checkboard();
# endif
#endif
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r();
#endif
#ifndef CONFIG_ROCKCHIP
/* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts();
#endif
/* Initialize from environment */
load_addr = getenv_ulong("loadaddr", 16, load_addr);
#ifdef CONFIG_BOARD_LATE_INIT
board_late_init();
#endif
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
puts("Net: ");
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
#ifdef CONFIG_POST
post_run(NULL, POST_RAM | post_bootmode_get(0));
#endif
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
/*
* Export available size of memory for Linux,
* taking into account the protected RAM at top of memory
*/
{
ulong pram = 0;
uchar memsz[32];
#ifdef CONFIG_PRAM
pram = getenv_ulong("pram", 10, CONFIG_PRAM);
#endif
#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
/* Also take the logbuffer into account (pram is in kB) */
pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
#endif
#endif
sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram);
setenv("mem", (char *)memsz);
}
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
}
/* NOTREACHED - no way out of command loop except booting */
}
函数board_init_r
事实上为初始化序列的第二部分,此时从内存启动并具有一个正常的C运行环境。如全局数据可以写入,BSS已被清除等,在其中最重要的部分就是调用函数board_late_init
准备启动Linux系统的环境变量。
board_late_init
函数board_late_init
实现在文件u-boot/board/rockchip/rk32xx/rk32xx.c
中:
extern char bootloader_ver[24];
int board_late_init(void)
{
debug("board_late_init\n");
#if (CONFIG_BOOTDELAY > 0)
setenv("bootdelay", simple_itoa(CONFIG_BOOTDELAY));
#endif
setenv("bootcmd", CONFIG_BOOTCOMMAND);
load_disk_partitions();
rkimage_prepare_fdt();
key_init();
#ifdef CONFIG_POWER_RK
pmic_init(0);
fg_init(0); /*fuel gauge init*/
#endif
//TODO:set those buffers in a better way, and use malloc?
rkidb_setup_space(gd->arch.rk_global_buf_addr);
/* after setup space, get id block data first */
rkidb_get_idblk_data();
/* Secure boot check after idb data get */
SecureBootCheck();
if (rkidb_get_bootloader_ver() == 0) {
printf("\n#Boot ver: %s\n", bootloader_ver);
}
char tmp_buf[32];
/* rk sn size 30bytes, zero buff */
memset(tmp_buf, 0, 32);
if (rkidb_get_sn(tmp_buf)) {
setenv("fbt_sn#", tmp_buf);
}
board_fbt_preboot();
return 0;
}
这里其实是在准备Linux系统的启动环境变量,其中核心的部分在于调用board_fbt_preboot
进入fastboot启动模式。
board_fbt_preboot
函数board_fbt_preboot
实现在文件u-boot/board/rockchip/common/rkboot/fastboot.c
中:
void board_fbt_preboot(void)
{
enum fbt_reboot_type frt;
#ifdef CONFIG_CMD_FASTBOOT
/* need to init this ASAP so we know the unlocked state */
fbt_fastboot_init();
#endif
frt = board_fbt_get_reboot_type();
if ((frt == FASTBOOT_REBOOT_UNKNOWN) || (frt == FASTBOOT_REBOOT_NORMAL)) {
FBTDBG("\n%s: no spec reboot type, check key press.\n", __func__);
frt = board_fbt_key_pressed();
} else {
//clear reboot type.
board_fbt_set_reboot_type(FASTBOOT_REBOOT_NORMAL);
}
#ifdef CONFIG_POWER_RK
board_fbt_low_power_check();
#endif
int logo_on = 0;
#ifdef CONFIG_LCD
if (gd->fdt_blob) {
int node = fdt_path_offset(gd->fdt_blob, "/fb");
logo_on = fdtdec_get_int(gd->fdt_blob, node, "rockchip,uboot-logo-on", 0);
}
printf("read logo_on switch from dts [%d]\n", logo_on);
if ((frt != FASTBOOT_REBOOT_MINIKERNEL || (is_power_low() && !is_charging())) && logo_on) {
drv_lcd_init(); //move backlight enable to board_init_r, for don't show logo in rockusb
}
#endif
#ifdef CONFIG_POWER_RK
board_fbt_low_power_off();
#endif
#ifdef CONFIG_UBOOT_CHARGE
//check charge mode when no key pressed.
int cold_boot = board_fbt_is_cold_boot();
if ((cold_boot && board_fbt_is_charging())
|| frt == FASTBOOT_REBOOT_CHARGE) {
#ifdef CONFIG_CMD_CHARGE_ANIM
char *charge[] = { "charge" };
if (logo_on && do_charge(NULL, 0, ARRAY_SIZE(charge), charge)) {
//boot from charge animation.
frt = FASTBOOT_REBOOT_NORMAL;
}
#else
return fbt_run_charge();
#endif
}
#endif //CONFIG_UBOOT_CHARGE
powerOn();
#ifdef CONFIG_LCD
if (frt != FASTBOOT_REBOOT_MINIKERNEL && logo_on) {
lcd_enable_logo(true);
lcd_standby(0);
mdelay(100);
rk_backlight_ctrl(-1); /*use defaut brightness in dts*/
}
#endif
#ifdef CONFIG_RK_PWM_REMOTE
if ((frt == FASTBOOT_REBOOT_UNKNOWN) || (frt == FASTBOOT_REBOOT_NORMAL)) {
frt = board_fbt_key_pressed();
}
RemotectlDeInit();
#endif
if (frt == FASTBOOT_REBOOT_RECOVERY) {
FBTDBG("\n%s: starting recovery img because of reboot flag\n", __func__);
return board_fbt_run_recovery();
} else if (frt == FASTBOOT_REBOOT_RECOVERY_WIPE_DATA) {
FBTDBG("\n%s: starting recovery img to wipe data "
"because of reboot flag\n", __func__);
/* we've not initialized most of our state so don't
* save env in this case
*/
return board_fbt_run_recovery_wipe_data();
}
#ifdef CONFIG_CMD_FASTBOOT
else if (frt == FASTBOOT_REBOOT_FASTBOOT) {
FBTDBG("\n%s: starting fastboot because of reboot flag\n", __func__);
board_fbt_request_start_fastboot();
}
#endif
else if (frt == FASTBOOT_REBOOT_MINIKERNEL) {
FBTDBG("\n%s: starting mini kernel because of reboot flag\n", __func__);
printf("mini kernel\n");
do_mini_kernel();
}
else {
FBTDBG("\n%s: check misc command.\n", __func__);
/* unknown reboot cause (typically because of a cold boot).
* check if we had misc command to boot recovery.
*/
rkloader_run_misc_cmd();
}
}
在该函数中,判断通过文件kernel/arch/arm/mach-rockchip/rk3288.c
中的函数rk3288_restart
调用writel_relaxed
写入寄存器RK3288_PMU_SYS_REG0
中的值来判断启动类型,对于recovery
模式来说,最终调用到函数board_fbt_run_recovery
。
board_fbt_run_recovery
函数board_fbt_run_recovery
实现在文件u-boot/board/rockchip/common/rkboot/fastboot.c
中:
static void board_fbt_run_recovery(void)
{
#ifdef CONFIG_CMD_BOOTRK
char *const boot_recovery_cmd[] = {"bootrk", "recovery"};
do_bootrk(NULL, 0, ARRAY_SIZE(boot_recovery_cmd), boot_recovery_cmd);
#endif
/* returns if recovery.img is bad */
FBTERR("\nfastboot: Error: Invalid recovery img\n");
}
很明显,这里调用的函数为do_bootrk(NULL, 0, 2, {"bootrk", "recovery"})
,
do_bootrk
函数do_bootrk
的实现在文件u-boot/common/cmd_bootrk.c
中:
int do_bootrk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
char *boot_source = "boot";
rk_boot_img_hdr *hdr = NULL;
const disk_partition_t* ptn = NULL;
bootm_headers_t images;
bool charge = false;
if (argc >= 2) {
if (!strcmp(argv[1], "charge")) {
charge = true;
} else {
boot_source = argv[1];
}
}
memset(&images, 0, sizeof(images));
if (rk_bootrk_start(&images)) { /*it returns 1 when failed.*/
puts("bootrk: failed to setup lmb!\n");
goto fail;
}
ptn = get_disk_partition(boot_source);
if (ptn) {
hdr = rk_load_image_from_storage(ptn, &images);
if (hdr == NULL) {
goto fail;
}
} else {
hdr = rk_load_image_from_ram(boot_source, &images);
if (hdr == NULL) {
goto fail;
}
}
#ifdef CONFIG_SECUREBOOT_CRYPTO
if ((SecureMode != SBOOT_MODE_NS) && (SecureBootCheckOK == 0)) {
puts("Not allow to boot no secure sign image!");
while(1);
}
#endif /* CONFIG_SECUREBOOT_CRYPTO */
rk_commandline_setenv(boot_source, hdr, charge);
#if defined(CONFIG_UBOOT_CHARGE) && defined(CONFIG_POWER_FG_ADC)
fg_adc_storage_flag_store(0);
fg_adc_storage_store(0);
#endif
rk_module_deinit();
/* Secure boot state will set drm, sn and others information in the nanc ram,
* so, after set, PLS notice do not read/write nand flash.
*/
SecureBootSecureState2Kernel(SecureBootCheckOK);
/* after here, make sure no read/write storate */
bootimg_print_image_hdr(hdr);
printf("kernel @ 0x%08x (0x%08x)\n", hdr->kernel_addr, hdr->kernel_size);
printf("ramdisk @ 0x%08x (0x%08x)\n", hdr->ramdisk_addr, hdr->ramdisk_size);
images.ep = hdr->kernel_addr;
images.rd_start = hdr->ramdisk_addr;
images.rd_end = hdr->ramdisk_addr + hdr->ramdisk_size;
#ifdef CONFIG_IMPRECISE_ABORTS_CHECK
puts("enable imprecise aborts check.");
enable_imprecise_aborts();
#endif
#ifdef CONFIG_BOOTM_LINUX
puts("bootrk: do_bootm_linux...\n");
do_bootm_linux(0, 0, NULL, &images);
#endif /* CONFIG_BOOTM_LINUX */
fail:
board_fbt_boot_failed(boot_source);
puts("bootrk: Control returned to monitor - resetting...\n");
do_reset(cmdtp, flag, argc, argv);
return 1;
}
这里的主要任务就是确认了所要加载的镜像的位置,然后通过函数do_bootm_linux(0, 0, NULL, &images)
启动对应的镜像,对于recovery
模式来说,就是镜像recovery.img
了。
do_bootm_linux
函数do_bootm_linux(0, 0, NULL, &images)
来实现在文件u-boot/arch/arm/lib/bootm.c
中:
int do_bootm_linux(int flag, int argc, char * const argv[],
bootm_headers_t *images)
{
/* No need for those on ARM */
if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
return -1;
if (flag & BOOTM_STATE_OS_PREP) {
boot_prep_linux(images);
return 0;
}
if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
boot_jump_linux(images, flag);
return 0;
}
boot_prep_linux(images);
boot_jump_linux(images, flag);
return 0;
}
最终到这里,通过boot_prep_linux
设置参数,并以boot_jump_linux
来启动linux内核。接下来的任务,就是Linux系统启动的事情了。