嵌入式linux开发uboot启动过程源码分析(一)
一、uboot启动流程简介
与大多数BootLoader一样,uboot的启动过程分为BL1和BL2两个阶段。BL1阶段通常是开发板的配置等设备初始化代码,需要依赖依赖于SoC体系结构,通常用汇编语言来实现;BL2阶段主要是对外部设备如网卡、Flash等的初始化以及uboot命令集等的自身实现,通常用C语言来实现。
1、BL1阶段
uboot的BL1阶段代码通常放在start.s文件中,用汇编语言实现,其主要代码功能如下:
(1) 指定uboot的入口。在链接脚本uboot.lds中指定uboot的入口为start.S中的_start。
(2)设置异常向量(exception vector)
(3)关闭IRQ、FIQ,设置SVC模式
(4)关闭L1 cache、设置L2 cache、关闭MMU
(5)根据OM引脚确定启动方式
(6)在SoC内部SRAM中设置栈
(7)lowlevel_init(主要初始化系统时钟、SDRAM初始化、串口初始化等)
(8)设置开发板供电锁存
(9)设置SDRAM中的栈
(10)将uboot从SD卡拷贝到SDRAM中
(11)设置并开启MMU
(12)通过对SDRAM整体使用规划,在SDRAM中合适的地方设置栈
(13)清除bss段,远跳转到start_armboot执行,BL1阶段执行完
2、BL2阶段
start_armboot函数位于lib_arm/board.c中,是C语言开始的函数,也是BL2阶段代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,BL2阶段的主要功能如下:
(1)规划uboot的内存使用
(2)遍历调用函数指针数组init_sequence中的初始化函数
(3)初始化uboot的堆管理器mem_malloc_init
(4)初始化SMDKV210开发板的SD/MMC控制器mmc_initialize
(5)环境变量重定位env_relocate
(6)将环境变量中网卡地址赋值给全局变量的开发板变量
(7)开发板硬件设备的初始化devices_init
(8)跳转表jumptable_init
(9)控制台初始化console_init_r
(10)网卡芯片初始化eth_initialize
(11)uboot进入主循环main_loop
二、uboot程序入口分析
1、link.lds链接脚本文件分析
u-boot.lds文件是uboot工程的链接脚本文件,位于board\samsung\smdkc110目录下,对于工程项目编译后期的链接阶段非常重要,决定了uboot程序的组装。
u-boot.lds链接文件中的ENTRY(_start)指定了uboot程序的入口地址为_start。
2、定位uboot程序入口地址
在SourceInsight建立uboot工程,利用索引功能查找_start,在搜索结果中找到与三星smdkv210开发板相关的代码,最终锁定cpu\s5pc11x\start.S文件,定位到文件中的_start标识符。
三、start.S文件分析
1、头文件分析
start.S有四个头文件:
#include <config.h>
config.h头文件在配置开发板时由mkconfig脚本创建的头文件,头文件内容即包含开发板的头文件:#include <configs/smdkv210single.h>
#include <version.h>
version.h头文件的内容为包含自动生成的版本头文件,头文件内容为:#include "version_autogenerated.h",version_autogenerated.h头文件定义了版本宏,宏定义为:#define U_BOOT_VERSION "U-Boot 1.3.4"。版本宏的值就是Makefile中定义的版本信息。
#include <asm/proc/domain.h>
domain.h头文件在定义了CONFIG_ENABLE_MMU宏时有效,为链接文件,实际指向的文件为include/asm-arm/proc-armv/domain.h。
#include <regs.h>
regs.h头文件为链接文件,指向s5pc110.h头文件,s5pc110.h文件内部使用宏定义了有关SoC内部寄存器的大量信息。
2、头校验信息的占位
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
#endif
定义uboot程序开头的16字节校验头信息填充空间,头校验信息块内的值需要在后面写入。
3、异常向量表的构建
.globl _start
_start:
b reset
ldrpc, _undefined_instruction
ldrpc, _software_interrupt
ldrpc, _prefetch_abort
ldrpc, _data_abort
ldrpc, _not_used
ldrpc, _irq
ldrpc, _fiq
uboot程序的入口点实际是定义了异常向量表,异常向量表由SoC硬件实现,因此uboot在开机上电复位时需要跳转到reset执行。
4、复位reset分析
SoC上电复位后运行的第一段代码就是reset。主要包括以下几部分:
A、关闭IRQ、FIQ,并将处理器模式设置为SVC模式
B、CPU关键寄存器的初始化cpu_init_crit:
关闭L2 cache
初始化L2 cache
开启L2 cache
关闭L1 cache
关闭MMU
读取OM启动引脚信息
确定从启动设备SD卡启动
设置SRAM中的栈为调用lowlevel_init做准备(lowlevel_init内部有嵌套调用)
调用lowlevel_init(主要初始化系统时钟、SDRAM初始化、串口初始化等)
设置开发板供电锁存
设置SDRAM中的栈
判断当前代码是否运行在SDRAM中,如果当前代码运行在SDRAM中,则跳过代码重定位。
判断启动方式,选择SD卡启动设备,跳转到mmcsd_boot
SD卡启动的准备工作,从SD卡拷贝uboot到SDRAM:movi_bl2_copy
C、设置MMU,开启MMU
D、通过对SDRAM整体使用规划,在SDRAM中合适的地方设置栈
E、清除bss段,远跳转到start_armboot执行,BL1阶段执行完
5、lowlevel_init分析
lowlevel_init位于\board\samsung\smdkc110\lowlevel_init.S中,主要功能如下:
A、检查复位状态,判断启动的方式
根据复位状态选择复位启动的方式,处于低功耗状态时复位启动可以跳过后续多个步骤。
B、IO状态恢复
C、关闭看门狗
D、外部SRAM的GPIO初始化、外部SROM初始化
E、开发板供电锁存设置
F、判断当前代码是否运行在SDRAM,如果当前代码运行在SDRAM,说明目前从低功耗状态复位,可以跳过系统时钟初始化、串口初始化、SDRAM初始化等
G、初始化系统时钟:system_clock_init
H、初始化SDRAM内存:mem_ctrl_asm_init
I、初始化串口,打印出’O’:uart_asm_init
J、初始化trustzone:tzpc_init
K、初始化nand或onenand
L、检查复位状态
M、关闭ABB
N、串口打印出‘K’
说明:”OK”是打印出的调试信息,如果打印出’O’则说明在串口初始化uart_asm_init前的所有代码是正确的。如果打印出”OK”则说明在开发板板级初始化lowlevel_init前的所有代码是正常工作的。
system_clock_init、uart_asm_init、tzpc_init、nand_asm_init都位于lowlevel_init.S文件内,mem_ctrl_asm_init位于cpu\s5pc11x\s5pc110\cpu_init.S文件中。
四、board.c文件分析
uboot在执行完BL1阶段后远跳转到start_armboot函数执行BL2,start_armboot函数位于lib_arm\board.c中。
1、重要变量的说明
typedef int (init_fnc_t) (void);函数类型
init_fnc_t **init_fnc_ptr;//二级函数指针
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
DECLARE_GLOBAL_DATA_PTR定义了一个存储在寄存器r8中的指向gd_t类型全局变量的指针gd。
全局变量结构体的定义:
typedefstructglobal_data {
bd_t*bd;//boardinfo结构体信息,存放和开发板有关的信息
unsigned longflags;//标志位
unsigned longbaudrate;//串口通信波特率
unsigned longhave_console;//控制台/* serial_init() was called */
unsigned longreloc_off;//重定位偏移量/* Relocation Offset */
unsigned longenv_addr;//环境变量结构体的地址/* Address of Environment struct */
unsigned longenv_valid;//环境变量使用标志/* Checksum of Environment valid? */
unsigned longfb_base;//fb基地址/* base address of frame buffer */
#ifdef CONFIG_VFD
unsigned charvfd_type;///* display type */
#endif
void**jt;//跳转表/* jump table */
} gd_t;
开发板信息结构体变量的定义:
typedef struct bd_info {
intbi_baudrate;//硬件串口波特率/* serial console baudrate */
unsigned longbi_ip_addr;//开发板IP地址/* IP Address */
unsigned charbi_enetaddr[6];//开发板网卡地址 /* Ethernet adress */
struct environment_s *bi_env;//环境变量指针
ulong bi_arch_number;//机器码/* unique id for this board */
ulong bi_boot_params;//uboot启动参数/* where this board expects params */
struct/* RAM configuration */
{
ulong start;
ulong size;
}bi_dram[CONFIG_NR_DRAM_BANKS];//内存插条信息
#ifdef CONFIG_HAS_ETH1
/* second onboard ethernet port */
unsigned char bi_enet1addr[6];//第二块网卡的地址
#endif
} bd_t;
2、uboot的内存规划
SDRAM_BASE被MMU映射在0xC0000000,CFG_UBOOT_BASE是0xC3E00000
在BL1段运行时,uboot镜像被拷贝到CFG_UBOOT_BASE开始的地址处。
gd的地址:
gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
bd的地址:
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
3、start_armboot函数分析
start_armboot函数的主要功能如下:
(1)、遍历调用函数指针数组init_sequence中的初始化函数
依次遍历调用函数指针数组init_sequence中的函数,如果有函数执行出错,则执行hang函数,打印出”### ERROR ### Please RESET the board ###”,进入死循环。
(2)、初始化uboot的堆管理器mem_malloc_init
(3)、初始化SMDKV210的SD/MMC控制器mmc_initialize
(4)、环境变量重定位env_relocate
(5)、将环境变量中网卡地址赋值给全局变量的开发板变量
(6)、开发板硬件设备的初始化devices_init
(7)、跳转表jumptable_init
(8)、控制台初始化console_init_r
(9)、网卡芯片初始化eth_initialize
(10)、uboot进入主循环main_loop
void start_armboot (void)
{
//全局数据变量指针gd占用r8。
DECLARE_GLOBAL_DATA_PTR;
/* 给全局数据变量gd安排空间*/
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
memset ((void*)gd, 0, sizeof (gd_t));
/* 给板子数据变量gd->bd安排空间*/
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;//u-boot长度。
/* 顺序执行init_sequence数组中的初始化函数 */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* 初始化堆空间 */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
/* 重新定位环境变量, */
env_relocate ();
/* 从环境变量中获取IP地址 */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* 以太网接口MAC 地址 */
devices_init (); /* 设备初始化 */
jumptable_init (); //跳转表初始化
console_init_r (); /* 完整地初始化控制台设备 */
enable_interrupts (); /* 使能中断处理 */
/* 通过环境变量初始化 */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
/* main_loop()循环不断执行 */
for (;;) {
main_loop (); /* 主循环函数处理执行用户命令 -- common/main.c */
}
}
4、函数指针数组init_sequence
函数指针数组init_sequence:
init_fnc_t *init_sequence[] = {
cpu_init,//CPU架构的初始化,为空cpu\s5pc11x\cpu.c
board_init,//开发板初始化board\samsung\smdkc110\smdkc110.c
interrupt_init,//定时器timer4初始化cpu\s5pc11x\interrupts.c
env_init,//环境变量初始化common\env_movi.c
init_baudrate,//波特率设置lib_arm\board.c
serial_init,//延时函数C,没有再次初始化串口cpu\s5pc11x\serial.c
console_init_f,//控制台第一阶段初始化,控制台未初始化好common\console.c
display_banner,//用串口发送uboot版本信息lib_arm\board.c
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,//串口打印系统时钟信息cpu\s5pc11x\s5pc110\speed.c
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,//打印开发板信Board:SMDKV210
//board\samsung\smdkc110\smdkc110.c
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,//SMDKV210未定义I2C,函数为空lib_arm\board.c
#endif
dram_init,//初始化gd->bd->bi_dram,开发板的SDRAM配置信息
board\samsung\smdkc110\smdkc110.c
display_dram_config,//串口打印出DRAM的大小信息,DRAM:xxxMB
lib_arm\board.c
NULL,
};
board_init函数:
dm9000_pre_init();//网卡初始化,GPIO和端口设置
gd->bd->bi_arch_number = MACH_TYPE;//开发板的机器码,uboot的机器码和linux的机器码之间必须适配
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);//uboot给内核的传参地址
display_banner函数:
打印uboot版本信息:uboot-1.3.4
print_cpuinfo函数:
打印CPU时钟系统的时钟信息
checkboard函数:
打印出开发板信息Board: SMDKV210
display_dram_config函数:
打印出DRAM的大小信息,DRAM:xxxMB
打印出的信息可以作为调试使用,依次遍历调用函数指针数组init_sequence中的函数,如果有函数执行出错,则执行hang函数,打印出”### ERROR ### Please RESET the board ###”,进入死循环。
嵌入式linux开发uboot启动过程源码分析(一)的更多相关文章
- 嵌入式linux开发uboot启动内核的机制(二)
一.嵌入式系统的分区 嵌入式系统部署在Flash设备上时,对于不同SoC和Flash设备,bootloader.kernel.rootfs的分区是不同的.三星S5PV210规定启动设备的分区方案如下: ...
- 10.4 android输入系统_框架、编写一个万能模拟输入驱动程序、reader/dispatcher线程启动过程源码分析
1. 输入系统框架 android输入系统官方文档 // 需FQhttp://source.android.com/devices/input/index.html <深入理解Android 卷 ...
- Spark(五十一):Spark On YARN(Yarn-Cluster模式)启动流程源码分析(二)
上篇<Spark(四十九):Spark On YARN启动流程源码分析(一)>我们讲到启动SparkContext初始化,ApplicationMaster启动资源中,讲解的内容明显不完整 ...
- Android系统默认Home应用程序(Launcher)的启动过程源码分析
在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还须要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...
- Android Content Provider的启动过程源码分析
本文參考Android应用程序组件Content Provider的启动过程源码分析http://blog.csdn.net/luoshengyang/article/details/6963418和 ...
- Flume-NG启动过程源码分析(二)(原创)
在上一节中讲解了——Flume-NG启动过程源码分析(一)(原创) 本节分析配置文件的解析,即PollingPropertiesFileConfigurationProvider.FileWatch ...
- Spark(四十九):Spark On YARN启动流程源码分析(一)
引导: 该篇章主要讲解执行spark-submit.sh提交到将任务提交给Yarn阶段代码分析. spark-submit的入口函数 一般提交一个spark作业的方式采用spark-submit来提交 ...
- Activity启动过程源码分析(Android 8.0)
Activity启动过程源码分析 本文来Activity的启动流程,一般我们都是通过startActivity或startActivityForResult来启动目标activity,那么我们就由此出 ...
- Netty入门一:服务端应用搭建 & 启动过程源码分析
最近周末也没啥事就学学Netty,同时打算写一些博客记录一下(写的过程理解更加深刻了) 本文主要从三个方法来呈现:Netty核心组件简介.Netty服务端创建.Netty启动过程源码分析 如果你对Ne ...
随机推荐
- echarts 中 柱图 、折线图、柱图层叠
app.title = '折柱混合'; option = { tooltip: { trigger: 'axis', axisPointer: { type: 'cross', crossStyle: ...
- CF1188C Array Beauty(DP)
日常降智. 不过还是第一次和 2700 的题正解这么近呢-- 由于排序后不影响答案,而且直觉告诉我们排序后会更好做,不妨排个序. 直觉告诉我们,变成求最小差 \(\ge v\) 的方案数会比最小差 \ ...
- printkd
#include <linux/fs.h> #include <asm/uaccess.h> #include <linux/namei.h> #include & ...
- 使用PAC文件来管理代理连接
生成PAC文件 谷歌浏览器插件商店安装SwitchyOmega,找到立即更新模式,然后导出PAC文件 使用PAC文件 pac采用js编写 Windows Windows上面使用PAC文件很简单,新建一 ...
- win10安装docker并结合Idea2018.1部署springboot项目
一.准备工作 1..工具:win10,idea2018,maven3.5,jdk8 二.win10安装docker 1.win10安装docker:http://www.runoob.com/dock ...
- Salesforce - 建立轮循机制的潜在客户分配规则
客服中心经常会遇到由多个客服轮流分配接进来的订单,例如你有100个订单进入系统,你希望五个客服每人分配20个,也就是一种小组的轮换机制,常被称为“轮询” 这种循环分配规需要保证平均分配给客服新的订单记 ...
- Jena Fuseki安装完成后不能添加数据库
问题描述:安装Jena成功后可以进入管理页面,无法通过界面选择和查询数据 解决方案: 进入 apache-jena-fuseki-3.12.0\run 修改 shiro.ini 配置文件 注释 /$/ ...
- CentOS7安装图形化界面方法
一.linux安装(root用户操作) 1. 安装vncserver; yum install tigervnc-server 2. 安装vncviewer; yum install vnc 3. 设 ...
- SourceTree 免登录
SourceTree 是 Windows 和Mac OS X 下免费的 Git 和 Hg 客户端,拥有可视化界面,容易上手操作.同时它也是Mercurial和Subversion版本控制系统工具.支持 ...
- Tomcat基础操作
1.在WebApps ROOT目录里,如果删除过ROOT从新创建,放置index.html,index.jsp即可访问. 2.修改默认8080端口,打开server.xml,将8080端口修改为80即 ...