U-boot引导内核流程分析

标签: geek | 发表时间:2018-12-23 00:00 | 作者:
出处:http://itindex.net/relian

U-boot引导内核流程分析
1. 加载内核
当U-boot完成重定位和初始化外设后,它将正式进入工作状态,可以加载内核镜像到DDR的链接地址中了,具体的地址也可以通过bootcmd这个环境变量来指定,内核镜像有两种加载方式:

一种是通过tftp将镜像文件直接引导入DDR中内核的链接地址(对于s5pv210来说是30008000),这种方法很适合调试
另一种是从存储介质中的特定扇区读取,这个扇区可以通过分区表来确定(关于分区表以后再续)
2.判断镜像
加载内核到DDR的链接地址后,U-boo将读取镜像的头信息,然后在头信息的特定位置找到MAGIC_NUM,由此来判断镜像的种类。这里就要说一下内核镜像的种类了,内核镜像主要分为zImage和uImage 
zImage:当内核编译完成之后首先生成的是一个elf文件,此文件类似于windows下的exe,是可以在操作系统下运行的,故里面有许多的信息;可是我们的kernel是个裸机程序,不需要在操作系统下运行,删除这些信息后体积便能缩为1/10,这就成了我们熟悉的.bin文件,但是因为一些原因这个文件名字起成了Image…而不是Image.bin….;其实这个Image文件已经能用了,但是由于一些历史原因,Image一般要经过压缩变成zImage再使用,这个zImage文件比Image文件更小,它是自解压的,它的头部是一段信息和解压程序,解压程序可以把后面真正的代码自动解压出来,并不需要U-boot的协助
uImage:uImage是U-boot自己发明的一种内核镜像格式,是在zImage的基础上在加上一段信息和一段校验头,共64字节。那么将zImage加工为uImage的工具在哪呢,在U-boot根目录下/tools中的mkimage程序,只需将其复制到/usr/local/bin/,编译内核时输入make uImage,然后就能产生uImage了
判断完镜像种类后U-boot将对镜像头进行校验,然后再次读取头信息,从头信息的特定位置找到这个镜像的各种信息(镜像长度,镜像种类,入口地址)
4.相关环境变量
引导内核有关的环境变量有bootcmd和bootargs。之所以要有这两个环境变量其实是为了灵活,为了在U-boot不重新编译的情况下可以用不同的方式启动

关于bootcmd,其实是U-boot内部好几个命令组成的命令集,负责引导内核的操作,以x210板载的bootcmd为例,bootcmd=movi read kernel 30008000;bootm 30008000;这其实是两句命令,第一句的意思是从inand的kernel分区读取内容到DDR内的地址30008000,第二句的意思是使用bootm启动命令到DDR的地址30008000处执行内核。其中,这个30008000是由内核的链接地址所确定的
关于bootargs,其实是U-boot传递给内核的参数,以x210板载的bootargs为例,bootargs=console=ttySAC2,115200 root=dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3,其中,console=ttySAC2,115200意思是引导后的控制台使用串口2,波特率115200;root=/dev/mmcblk0p2 rw意思是根文件系统在SD卡端口0设备(inand)第二分区,并且可读可写;init=/linuxrc意思是linux的进程1(init)进程的路径;rootfstype=ext3 意思是根文件系统的类型是ext3
5.传参及引导
最后把入口地址(ep)转化为一个函数指针theKernel = (void (*)(int, int, 
uint))ep,然后通过函数指针去执行镜像(即执行内核的第一句代码)。至此一去不复返,U-boot彻底结束了它的使命
    void    (*theKernel)(int zero, int arch, uint params);//定义了一个函数指针
    //中间代码略过
    theKernel = (void (*)(int, int, uint))ep;//把入口地址赋给函数指针
    //中间代码略过
    theKernel (0, machid, bd->bi_boot_params);//跳到内核入口执行内核,再也不返回

    void    (*theKernel)(int zero, int arch, uint params);//定义了一个函数指针
    //中间代码略过
    theKernel = (void (*)(int, int, uint))ep;//把入口地址赋给函数指针
    //中间代码略过
    theKernel (0, machid, bd->bi_boot_params);//跳到内核入口执行内核,再也不返回

--------------------- 
作者:XiaoBaWu 
来源:CSDN 
原文:https://blog.csdn.net/qq_28992301/article/details/51873201 
版权声明:本文为博主原创文章,转载请附上博文链接!


执行前传递给内核三个参数:

0:这个参数固定为0
机器码:只有uboot的机器码和内核镜像中的机器码相同时,内核才能被正确启动,机器码的值第一顺序备选是环境变量machid,如果环境变量里面没有,则第二顺序备选是gd->bd->bi_arch_num(x210_sd.h中硬编码配置的)
bd->bi_boot_params:这是全局变量结构体gd中的硬件信息结构体bd中的变量bi_boot_params,它的值为U-boot传给kernel的众多参数数据结构——tag的首地址。各个tag里面分别有许多有用的信息,比如环境变量bootargs的各种参数就在tag里,一般来说有关tag的代码是不用动的,只要考虑那些用来创建tag的宏(x210.h内)就行了
6.补充:新版uboot与内核的传参与引导
近年来的内核在启动时还需要dts文件,于是比较新的uboot都实现了传递dtb的功能,为了使能设备树,需要在编译U-boot的时候在config文件中加入:#define CONFIG_OF_LIBFDT

一般分为三种情况:

利用U-boot的命令,在引导kernel时将dts传入。这种方式需要将dtb的地址写到uboot中(一般是环境变量),比如:首先将kernel载入内存,然后用fdt addr ${fdtaddr}命令将dtb载入内存,最后使用bootz ${loadaddr} ${initrdaddr} ${fdtaddr}来引导内核,(其中initrd是临时文件系统,嵌入式中用得极少)实际使用时用“-”代替:bootz ${loadaddr} - ${fdtaddr}。总之,U-boot中的命令和环境变量是很灵活的,可以随意组合

将dts和kernel打包为pImage。这种方式无需将dtb的地址写到uboot中(但uboot中要实现读pImage头部的功能),uboot可以去pImage的头部信息处读取到dtb的地址,然后传给传递给kernel

启用kernel中”ARM_APPENDED_DTB”选项,该选项的意思是将dtb和kernel打包在一起,如此一来kernel启动时会去紧挨着它的地方寻找dtb,这样就不需要uboot来传递dtb地址了
7.引导时可能出现的问题
最后强调一下,如果U-boot确认无误可以启动起来,而kernel的启动却出现了问题,那么一般是三种情况

对于老版本的U-boot,有大概率是U-boot传给kernel参数的时候出了问题,着重注意一下创建tag的宏有没有正常定义,如CONFIG_CMDLINE_TAG、CONFIG_MTDPARTITION等
kernel的链接地址与加载地址不符,链接地址可以通过kernel的head.S获知,详见kernel启动汇编阶段分析
kernel的自解压地址与链接地址不符,zImage这类kernel格式必须把自己解压到自己的链接地址,自解压地址在kernel源码目录arch/arm/mach-xxxx/Makefile.boot文件中
环境变量未被正常设置
--------------------- 
作者:XiaoBaWu 
来源:CSDN 
原文:https://blog.csdn.net/qq_28992301/article/details/51873201 
版权声明:本文为博主原创文章,转载请附上博文链接!

相关 [boot 引导 内核] 推荐:

U-boot引导内核流程分析

- - IT瘾-geek
U-boot引导内核流程分析. 当U-boot完成重定位和初始化外设后,它将正式进入工作状态,可以加载内核镜像到DDR的链接地址中了,具体的地址也可以通过bootcmd这个环境变量来指定,内核镜像有两种加载方式:. 一种是通过tftp将镜像文件直接引导入DDR中内核的链接地址(对于s5pv210来说是30008000),这种方法很适合调试.

"Boot-Repair":轻松解决Ubuntu引导问题[译]

- gbcwbz - 〖好记性不如烂笔头─Ubuntu Note〗
原文:《"Boot-Repair": Fix Ubuntu Boot Issues (After Installing Another OS Or Faulty GRUB Upgrade)》作者: Andrew. Boot-Repair是一个用于处理可能在Ubuntu中碰到的各种启动问题的图形界面工具.

用Grub Rescue手动引导来启动内核

- - Harttle Land
GNU Grub是一个来自GNU项目的启动引导程序. GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统. GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数. 几乎所有人的Linux都是一个双系统,所以Grub也是几乎所有Linux用户熟知的东西.

Spring boot传统部署

- - 企业架构 - ITeye博客
使用spring boot很方便,一个jar包就可以启动了,因为它里面内嵌了tomcat等服务器. 但是spring boot也提供了部署到独立服务器的方法. 如果你看文档的话,从jar转换为war包很简单,pom.xml的配置修改略去不讲. 只看source的修改,很简单,只要一个配置类,继承自SpringBootServletInitializer, 并覆盖configure方法.

值得使用的Spring Boot

- - ImportNew
2013年12月12日,Spring发布了4.0版本. 这个本来只是作为Java平台上的控制反转容器的库,经过将近10年的发展已经成为了一个巨无霸产品. 不过其依靠良好的分层设计,每个功能模块都能保持较好的独立性,是Java平台不可多得的好用的开源应用程序框架. Spring的4.0版本可以说是一个重大的更新,其全面支持Java8,并且对Groovy语言也有良好的支持.

Spring Boot配置多个DataSource

- - 廖雪峰的官方网站
使用Spring Boot时,默认情况下,配置 DataSource非常容易. Spring Boot会自动为我们配置好一个 DataSource. 如果在 application.yml中指定了 spring.datasource的相关配置,Spring Boot就会使用该配置创建一个 DataSource.

Spring boot executable jar/war 原理

- - ImportNew
spring boot里其实不仅可以直接以 Java -jar demo.jar的方式启动,还可以把jar/war变为一个可以执行的脚本来启动,比如./demo.jar. 把这个executable jar/war 链接到/etc/init.d下面,还可以变为Linux下的一个service. 只要在spring boot maven plugin里配置:.

Spring Boot Starter是什么?

- - 技术,永无止境
在工作中我们经常能看到各种各样的springboot starter,如spring-cloud-netflix、spring-cloud-alibaba等等. 这些starter究竟有什么作用呢. 在了解这些starter之前,我们需要先大概知道Spring MVC与Spring Boot的关系.

SPRING BOOT OAUTH2 + KEYCLOAK - service to service call

- - BlogJava-首页技术区
employee-service调用department-service,如果要按OAUTH2.0流程,只需要提供client-id和client-secrect即可. 在KEYCLOAK中引入service-account,即配置该employee-service时,取消standard-flow,同时激活service-account.

UEFI Secure Boot 对 Linux 的影响

- SotongDJ - LinuxTOY
Red Hat 协同 Linux 基金会以及 Canonical 发布了针对 UEFI 中安全启动对于 Linux 系统影响的评估白皮书. 前段时间某些朝内站点上关于 UEFI 将禁止其他非 Win 系统的谣言总算以 M$ 方面澄清的方式告一段落. 现在来自 Linux 阵营的参与者们作出了自己的回应,对于 Secure Boot 进行了评估.