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. Daily Scrum 12/25/2015

    Process: Zhaoyang: Implement the Alex 50M model in the Caffe framework. Yandong: The Azure Back end ...

  2. stand up meeting 12/23/2015

    part 组员                工作              工作耗时/h 明日计划 工作耗时/h    UI 冯晓云  基本完成单词本显示页面的设计和实现    4 完善页面切换   ...

  3. 01、WireShark——ARP 协议包分析

     1. 什么是ARP ARP(Address Resolution Protocol)协议,即地址解析协议.该协议的功能就是将 IP 地 址解析成 MAC 地址. ARP(Address Resolu ...

  4. [转+自]关于PHP7的新特性(涉及取反和disabled_functions绕过)

    PHP7和PHP5上的安全区别 preg_replace()不再支持/e修饰符 利用\e修饰符执行代码的后门大家也用了不少了,具体看官方的这段描述: 如果设置了这个被弃用的修饰符, preg_repl ...

  5. 为什么选择python?

    Why python? 那些最好的程序员不是为了得到更高的薪水或者得到公众的仰慕而编程,他们只是觉得这是一件有趣的事情. —— Linux 之父 Linux Torvalds 作为一个使用主义的学习者 ...

  6. PHP反序列化漏洞总结

    写在前边 做了不少PHP反序列化的题了,是时候把坑给填上了.参考了一些大佬们的博客,自己再做一下总结 1.面向对象 2.PHP序列化和反序列化 3.PHP反序列化漏洞实例 1.面向对象 在了解序列化和 ...

  7. Docker 安装 Jenkins , 并解决初始安装插件失败

    安装 Jenkins 后,初始化下载插件总是失败,导致安装不成功,重试好几次都是卡在安装插件那. 这里记录下 Docker 下怎么安装 Jenkins ,并解决初始安装插件失败问题. 安装插件失败,其 ...

  8. 进阶 Linux基本命令-1

    vmware三种网络模式1,桥接虚拟机直接连接外网,局域网.宿主机电脑不提供路由. 2,NAT网络地址转换,家庭网 3,host only 只能和宿主电脑打交道 Linux命令形式 命令 +[参数]+ ...

  9. python小白入门之导入指定的模块

    在python中导入模块是通过关键字import进行导入的,下面演示一下,模块的导入,指定模块别名,指定函数别名,调用模块中所有的函数运行结果:  1.模块的导入Study.py文件里面的内容是:形式 ...

  10. Springboot以Jetty为容器实现http重定向到https

    1 简介 之前讲解的Springboot整合https用的是tomcat作为容器,tomcat也是一个流行多年的老牌Java容器了.但针对不同的场景,还是会有不同的选择,如Jetty.Jetty是架构 ...