Android4.4.2恢复出厂设置(四)

u-Boot启动部分

U-Boot启动到Linux的流程图如下所示:


Android4.4.2恢复出厂设置(四)_第1张图片
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系统启动的事情了。

你可能感兴趣的:(Android4.4.2恢复出厂设置(四))