• u-boot 源码分析(1) 启动过程分析


    u-boot 源码分析(1) 启动过程分析

    前言

    对于uboot,我一直是云里雾里的一个状态,这部分让我感到自己很菜,不用纵向深入地掌握uboot整个细节,但是相对它有一个整体流程上的把握,包括uboot的启动启动过程,在整个启动过程中会涉及到哪些文件,以此的调用过程是什么?抱着这几个问题,大量搜集资料,包括阅读了uboot源码,在一知半解的基础上,有了进一步的认识。本文写的并不深入,因为能力有限,从最快速的方式对Uboot启动有一个整体的了解。

    配置

    uboot:201709

    paltform:rockchip

    arch:arm64

    download:ftp://ftp.denx.de/pub/u-boot/

    在这里插入图片描述

    源码结构

    api

    硬件无关的功能函数的API。uboot移植时基本不用管,这些函数是uboot本身使用的。

    arch

    CPU架构的目录。里面放着很多子目录,都是各种cpu架构。

    board

    板级相关配置文件,针对不同平台的功能下具体的实现。

    common

    文件夹下放的是一些与具体硬件无关的普遍适用的一些代码。譬如控制台实现、crc校验的。但是更多的主要是两类:一类是cmd开头的,是用来实现uboot的命令系统的;另一类是env开头的,是用来实现环境变量的。

    cmd

    实现uboot命令行下支持的命令,每一条命令都对应一个文件。例如bootm命令对应就是cmd_bootm.c

    drivers

    板级的驱动。这里面放的就是从linux源代码中移植过来的linux设备驱动,主要是开发板上必须用到的一些驱动,如网卡驱动、Inand/SD卡、NandFlash等的驱动。要知道:uboot中的驱动其实就是linux中的驱动,uboot在一定程度上移植了linux的驱动给自己用。但是linux是操作系统而uboot只是个裸机程序,因此这种移植会有不同,让我说:uboot中的驱动其实是linux中的驱动的一部分。同样的uboot中的驱动也支持设备树。

    fs

    文件系统相关的代码,这个也是从linux源代码中移植过来的,用来管理Flash等资源。

    Kbuild

    可以通过make menuconfig进行uboot的基本配置。

    启动过程

    uboot启动主要分为两个阶段。

    第一阶段主要由start.s运行并实现相应的初始化,定义程序入口地址,初始化CPU,初始化内存,最后调用_main到第二阶段的板级别初始化部分。

    第二阶段主要是C语言编写,对于硬件内存分配,初始化硬件设备,串口初始化,显示设备初始化,运行环境初始化等等,最后启动内核。

    第一阶段

    这里主要会涉及到两个汇编文件,完成最底层的初始化。

    start.S

    路径:arch/yourplatform/cpu/start.S

    yourplatform按照实际使用的平台进行选择,如arm,x86,mips

    这是一个汇编文件,如果分析的是arm的平台,需要对arm的指令集有简单的了解。

    crt0_64.S

    路径:arch/arm/lib/crt0_64.S

    crt0C Runtime Startup的简称,这部分程序主要完成C语言环境的初始化,最终会运行_main函数,由于水平有限,这里暂不对细节进行分析。

    第二阶段

    由于需要适配不同的硬件平台,提高可移植性和代码的复用,这部分使用基本使用C语言,在common下,board_f.cboard_r.c这两个文件基本包括了通用实现。初始化主要包括两个部分,前置的初始化在board_f.c中实现,后置的初始化在board_r.c中实现。

    board_f.c

    主要分析一下board_init_f函数,具体的代码

    void board_init_f(ulong boot_flags)
    {
        ...
    	if(initcall_run_list(init_sequence_f))    
            hang();
        ...
    }
    

    init_sequence_f数组中保存了需要初始化的函数指针,所以板级初始化。

    board_r.c

    这里和board_f.c类似,主要有board_init_r这个函数,完成板级的后置初始化,代码如下:

    void board_init_r(gd_t *new_gd, ulong dest_addr)
    {
    #ifdef CONFIG_NEEDS_MANUAL_RELOC
            int i;
    #endif
    
    #if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
            gd = new_gd;
    #endif
    
    #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();
    }
    

    函数中通过initcall_run_list运行initcall_run_list列表中的函数,可以看一下init_sequence_r包括了各种板级的初始化,最终运行run_main_loop

    init_fnc_t init_sequence_r[] = {
    	initr_trace,
    	initr_reloc,
    	/* TODO: could x86/PPC have this also perhaps? */
    #ifdef CONFIG_ARM
    	initr_caches,
    #endif
    	initr_reloc_global_data,
    #if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
    	initr_unlock_ram_in_cache,
    #endif
    	initr_barrier,
    	initr_malloc,
    	bootstage_relocate,
    #ifdef CONFIG_DM
    	initr_dm,
    #endif
    #ifdef CONFIG_ARM
    	board_init,	/* Setup chipselects */
    #endif
    	/*
    	 * 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
    	stdio_init_tables,
    	initr_serial,
    	initr_announce,
    	INIT_FUNC_WATCHDOG_RESET
    #ifdef CONFIG_PPC
    	initr_trap,
    #endif
    #ifdef CONFIG_ADDR_MAP
    	initr_addr_map,
    #endif
    #if defined(CONFIG_BOARD_EARLY_INIT_R)
    	board_early_init_r,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #ifdef CONFIG_LOGBUFFER
    	initr_logbuffer,
    #endif
    #ifdef CONFIG_POST
    	initr_post_backlog,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #ifdef CONFIG_SYS_DELAYED_ICACHE
    	initr_icache_enable,
    #endif
    #if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)
    	/*
    	 * Do early PCI configuration _before_ the flash gets initialised,
    	 * because PCU ressources are crucial for flash access on some boards.
    	 */
    	initr_pci,
    #endif
    #ifdef CONFIG_WINBOND_83C553
    	initr_w83c553f,
    #endif
    #ifdef CONFIG_ARCH_EARLY_INIT_R
    	arch_early_init_r,
    #endif
    	power_init_board,
    #ifndef CONFIG_SYS_NO_FLASH
    	initr_flash,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_PPC) || defined(CONFIG_X86)
    	/* initialize higher level parts of CPU like time base and timers */
    	cpu_init_r,
    #endif
    #ifdef CONFIG_PPC
    	initr_spi,
    #endif
    #if defined(CONFIG_X86) && defined(CONFIG_SPI)
    	init_func_spi,
    #endif
    #ifdef CONFIG_CMD_NAND
    	initr_nand,
    #endif
    #ifdef CONFIG_CMD_ONENAND
    	initr_onenand,
    #endif
    #ifdef CONFIG_GENERIC_MMC
    	initr_mmc,
    #endif
    #ifdef CONFIG_HAS_DATAFLASH
    	initr_dataflash,
    #endif
    #ifdef CONFIG_ROCKCHIP
    	initr_rk_storage,
    #endif
    	initr_env,
    	INIT_FUNC_WATCHDOG_RESET
    	initr_secondary_cpu,
    #ifdef CONFIG_SC3
    	initr_sc3_read_eeprom,
    #endif
    #ifdef	CONFIG_HERMES
    	initr_hermes,
    #endif
    #if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
    	mac_read_from_eeprom,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
    	/*
    	 * Do pci configuration
    	 */
    	initr_pci,
    #endif
    	stdio_add_devices,
    	initr_jumptable,
    #ifdef CONFIG_API
    	initr_api,
    #endif
    	console_init_r,		/* fully init console as a device */
    #ifdef CONFIG_DISPLAY_BOARDINFO_LATE
    	show_board_info,
    #endif
    #ifdef CONFIG_ARCH_MISC_INIT
    	arch_misc_init,		/* miscellaneous arch-dependent init */
    #endif
    #ifdef CONFIG_MISC_INIT_R
    	misc_init_r,		/* miscellaneous platform-dependent init */
    #endif
    #ifdef CONFIG_HERMES
    	initr_hermes_start,
    #endif
    	INIT_FUNC_WATCHDOG_RESET
    #ifdef CONFIG_CMD_KGDB
    	initr_kgdb,
    #endif
    #ifdef CONFIG_X86
    	board_early_init_r,
    #endif
    	interrupt_init,
    #if defined(CONFIG_ARM) || defined(CONFIG_x86)
    	initr_enable_interrupts,
    #endif
    #ifdef CONFIG_X86
    	timer_init,		/* initialize timer */
    #endif
    #if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
    	initr_status_led,
    #endif
    	/* PPC has a udelay(20) here dating from 2002. Why? */
    #ifdef CONFIG_CMD_NET
    	initr_ethaddr,
    #endif
    #ifdef CONFIG_BOARD_LATE_INIT
    	board_late_init,
    #endif
    #ifdef CONFIG_CMD_SCSI
    	INIT_FUNC_WATCHDOG_RESET
    	initr_scsi,
    #endif
    #ifdef CONFIG_CMD_DOC
    	INIT_FUNC_WATCHDOG_RESET
    	initr_doc,
    #endif
    #ifdef CONFIG_BITBANGMII
    	initr_bbmii,
    #endif
    #ifdef CONFIG_CMD_NET
    	INIT_FUNC_WATCHDOG_RESET
    	initr_net,
    #endif
    #ifdef CONFIG_POST
    	initr_post,
    #endif
    #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
    	initr_pcmcia,
    #endif
    #if defined(CONFIG_CMD_IDE)
    	initr_ide,
    #endif
    #ifdef CONFIG_LAST_STAGE_INIT
    	INIT_FUNC_WATCHDOG_RESET
    	/*
    	 * Some parts can be only initialized if all others (like
    	 * Interrupts) are up and running (i.e. the PC-style ISA
    	 * keyboard).
    	 */
    	last_stage_init,
    #endif
    #ifdef CONFIG_CMD_BEDBUG
    	INIT_FUNC_WATCHDOG_RESET
    	initr_bedbug,
    #endif
    #if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
    	initr_mem,
    #endif
    #ifdef CONFIG_PS2KBD
    	initr_kbd,
    #endif
    	run_main_loop,
    };
    

    总结

    按照最快的方式熟悉UBoot的源码,实现从UBoot源码入门到入门,但是目前对于Kbuild 中的配置和源码的对应关系并未做到有效的认识,所以如果需要进行UBoot源码移植,单纯掌握这些还是远远不够的。以上的分析基本都是一笔带过,没有参杂任何的细节,后面需要通过实战移植一波Uboot然后加深对这块知识的掌握和认识。

    参考

    http://blog.chinaunix.net/uid-22979746-id-2590215.html

    http://www.wowotech.net/sort/u-boot

  • 相关阅读:
    深度学习之 TensorFlow(一):基础库包的安装
    爬取网易云音乐评论并使用词云展示
    MySQL学习笔记(一):查询
    【linux】查看linux系统版本信息(Oracle Linux、Centos Linux、Redhat Linux、Debian、Ubuntu)
    【php】PHP中Session ID的实现原理
    VMware安装VMwareTolls
    退耦、旁路电容
    SPI笔记
    旧板与IO板之间的连接
    S3C2440启动方式
  • 原文地址:https://www.cnblogs.com/unclemac/p/12783412.html
Copyright © 2020-2023  润新知