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

u-boot 源码分析(1) 启动过程分析的更多相关文章

  1. 精尽Spring Boot源码分析 - SpringApplication 启动类的启动过程

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  2. Disconf源码分析之启动过程分析下(2)

    接上文,下面是第二次扫描的XML配置. <bean id="disconfMgrBean2" class="com.baidu.disconf.client.Dis ...

  3. Disconf源码分析之启动过程分析上(1)

    Disconf的启动,主要是包括两次扫描和XML非注解式配置,总共分为上下两篇,上篇先主要介绍第一次静态扫描过程. 先从入口分析,通过Disconf帮助文档,可以看到xml必须添加如下配置. < ...

  4. 精尽Spring Boot源码分析 - 文章导读

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  5. Spring Boot源码分析-启动过程

    Spring Boot作为目前最流行的Java开发框架,秉承"约定优于配置"原则,大大简化了Spring MVC繁琐的XML文件配置,基本实现零配置启动项目. 本文基于Spring ...

  6. 精尽Spring Boot源码分析 - Jar 包的启动实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  7. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  8. Spring Boot源码分析-配置文件加载原理

    在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...

  9. 精尽Spring Boot源码分析 - 序言

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

随机推荐

  1. 取代 Python 多进程!伯克利开源分布式框架 Ray

    Ray 由伯克利开源,是一个用于并行计算和分布式 Python 开发的开源项目.本文将介绍如何使用 Ray 轻松构建可从笔记本电脑扩展到大型集群的应用程序. 并行和分布式计算是现代应用程序的主要内容. ...

  2. tensorflow1.0 数据队列FIFOQueue的使用

    import tensorflow as tf #模拟一下同步先处理数据,然后才能取数据训练 #tensorflow当中,运行操作有依赖性 #1.首先定义队列 Q = tf.FIFOQueue(3,t ...

  3. Java中Double保留小数位

    1.能四舍五入 double d = 114.145; d = (double) Math.round(d * 100) / 100; System.out.println(d); 2. BigDec ...

  4. LDA概率主题模型

    目录 LDA 主题模型 几个重要分布 模型 Unigram model Mixture of unigrams model PLSA模型 LDA 怎么确定LDA的topic个数? 如何用主题模型解决推 ...

  5. MySQL主从数据库配置与原理

    1.为什么要搭建主从数据库 (1)通过增加从库实现读写分离,提高系统负载能力 (2)将从库作为数据库备份库,实现数据热备份,为数据恢复提供机会 (3)根据业务将不同服务部署在不同机器同时又共享相同的数 ...

  6. Python数据分析:大众点评数据进行选址

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:砂糖侠 如果你处于想学Python或者正在学习Python,Pyth ...

  7. sql语句------合并结果集

    select id,max(val) FROM (select id,a 列名 val from 表名unionselect id,b 列名 val from 表名unionselect id,c 列 ...

  8. 2019-2020-1 20199308《Linux内核原理与分析》第三周作业

    <Linux内核分析> 第二章 操作系统是如何工作的 2.1 函数调用堆栈 3个关键性的方法机制(3个法宝) 存储程序计算机 函数调用堆栈机制 中断 堆栈相关的寄存器 ESP:堆栈指针(s ...

  9. DMTF 关于 CIM-XML 的幻灯片介绍

    https://members.dmtf.org/data/presentations/devcon02/JimDavis-IntroductiontoCIM-XML.pdf

  10. JVM原理与深度调优(一)

    什么是jvm jvm是java虚拟机 运行在用户态.通过应用程序实现java代码跨平台.与平台无关.实际上是"一次编译,到处执行" 1.从微观来说编译出来的是字节码!去到哪个平台都 ...