Linux内核学习(二):Bootloader

Linux内核学习(二):UBOOT

在上一篇的文章中通过图片介绍了linux镜像的生成与加载,引出了一个东西叫uboot,是这个玩意一手把生成的内核镜像加载进去的。于是在进一步之前,我们得看看学习一下什么是Uboot,以及其工作流程和逻辑。

本文内容全部来自于《嵌入式Linux应用开发完全手册》:韦神的书

不过在这之前,我们首先得来看看什么BootLoader?因为Uboot可以说就是一种特别的bootloader。

1、BootLoader

其实我们大概还是知道,在设备上电后会先运行硬件提前设计好的,规划好的要执行的一段程序,来进行初始化,一般叫做chip rom,在x86里面也叫bias,而在嵌入式设备中叫bootloader。

1.2、BootLoader做了什么?

系统上电之后,需要一段程序来进行初始化:关闭WATCHDOG、改变系统时钟、初始化存储控制器、将更多的代码复制到内存中等。如果它能将操作系统内核复制到内存中运行,无论从本地(比如Flash)还是从远端(比如通过网络),就称这段程序为 Bootloader。
简单地说,Bootloader 就是这么一小段程序,它在系统上电时开始执行,初始化硬件设备、准备好软件环境,最后调用操作系统内核。

可以增强 Bootloader 的功能,比如增加网络功能、从PC上通过串口或网络下载文件、烧写文件、将Flash 上压缩的文件解压后再运行等,这就是一个功能更为强大的Bootloader,也称为Monitor。实际上,在最终产品中用户并不需要这些功能,它们只是为了方便开发。

Bootloader的实现非常依赖于具体硬件,在嵌入式系统中硬件配置千差万别,即使是相同的CPU,它的外设(比如 Flash)也可能不同,**所以不可能有一个 Bootloader 支持所有的CPU、所有的电路板。**即使是支持CPU架构比较多的U-Boot,也不是一拿来就可以使用的(除非里面的配置刚好与你的板子相同),需要进行一些移植。

1.2、BootLoader怎么工作?

1 X86 性能高,速度快,兼容性好 英特尔,AMD 英特尔 1978年

2 ARM 成本低,低功耗 苹果,谷歌,IBM,华为 英国ARM公司 1983年

3 RISC-V 模块化,极简,可拓展 三星,英伟达,西部数据 RISC-V基金会 2014年

4 MIPS 简洁,优化方便,高拓展性 龙芯 MIPS科技公司 1981年

CPU上电后,会从某个地址开始执行。(这个地方是在硬件的设计时设计好的,一上电它就开始执行这个位置的程序。)

MIPS结构的CPU会从0xBFCO0000取第一条指令

ARM结构的CPU则从地址0x0000000开始

嵌入式开发板中,需要把存储器件ROM或Flash等映射到这个地址,Bootloader 就存放在这个地址开始处,这样一上电就可以执行。

在开发时,通常需要使用各种命令操作Bootloader,一般通过串口来连接PC和开发板,可以在串口上输入各种命令、观察运行结果等。这也只是对开发人员才有意义,用户使用产品时是不用接串口来控制Bootloader 的。从这个观点来看,Bootloader可以
分为以下两种操作模式(Operation Mode)。
( 1)启动加载(Boot loading〉模式。
上电后,Bootloader 从板子上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。产品发布时,Bootloader 工作在这种模式下。
(2)下载( Downloading)模式。
在这种模式下,开发人员可以使用各种命令,通过串口连接或网络连接等通信手段从主机(Host)下载文件(比如内核映象、文件系统映象),将它们直接放在内存运行或是烧入Flash类固态存储设备中。

板子与主机间传输文件时,可以使用串口的 xmodem/ymodem/zmodem 协议,它们使用简单,只是速度比较慢;还可以使用网络通过tfip、nfs协议来传输,这时,主机上要开启tftp,nfs服务:还有其他方法,比如 USB等。

像Blob或U-Boot等这样功能强大的Bootloader通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。比如,U-Boot在启动时处于正常的启动加载模式,但是它会延时若干秒(这可以设置),等待终端用户按下任意键,而将U-Boot 切换到下载模式。如果在指定时间内没有用户按键,则U-Boot继续启动Linux内核。
(这里想起PC机进入bias界面,在一开机多少s内按住F10,很多底层的逻辑是相通的,当然也有别致的地方)

1.3、Bootloader的结构和启动过程

了解 Bootloader 的一些通用概念,对理解它的代码会有所帮助。

嵌入式Linux系统从软件的角度通常可以分为以下4个层次。

(1)引导加载程序

包括固化在固件( firmware)中的 boot 代码(可选)和 Bootloader两大部分。

**有些CPU在运行Bootloader 之前先运行一段固化的程序(固件,firmware),比如 x86结构的CPU就是先运行BIOS中的固件,**然后才运行硬盘第一个分区(MBR)中的Bootloader。在大多嵌入式系统中并没有固件,Bootloader是上电后执行的第一个程序。

(所以bootloader也不一定是第一个运行的程序,可能存在一些更加前面的继续的初始化)

(2) Linux内核。

特定于嵌入式板子的定制内核以及内核的启动参数。内核的启动参数可以是内核默认的,或是由Bootloader传递给它的。

(3)文件系统。

包括根文件系统和建立于Flash 内存设备之上的文件系统。里面包含了Linux系统能够运行所必需的应用程序、库等,比如可以给用户提供操作Linux的控制界面的shell程序、动态连接的程序运行时需要的glibc 或uClibc库等。

(4)用户应用程序。

特定于用户的应用程序,它们也存储在文件系统中。有时在用户应用程序和内核层之间可能还会包括一个嵌入式图形用户界面。
常用的嵌入式GUI有:Qtopia和MiniGUI等。显然,在嵌入系统的固态存储设备上有相应的分区来存储它们,如图15.1所示为一个典型的分区结构。

在这里插入图片描述
(最近在看内核的编译文件,其中会有个kernel_args,为传递给内核的参数)

“Boot parameters”分区中存放一些可设置的参数,比如IP地址、串口波特率、要传递给内核的命令行参数等。

正常启动过程中,Bootloader首先运行,然后它将内核复制到内存中(也有些内核可以在固态存储设备上直接运行), 并且在内存某个固定的地址设置好要传递给内核的参数,最后运行内核。 内核启动之后,它会挂接( mount)根文件系统(“Rootfilesystem”),启动文件系统中的应用程序。

2. Bootloader的两个阶段

Bootloader的启动过程可以分为单阶段(Single Stage)、多阶段(Multi-Stage〉两种。

通常多阶段的Bootloader 能提供更为复杂的功能以及更好的可移植性。

从固态存储设备上启动的 Bootloader大多都是两阶段的启动过程。

第一阶段使用汇编来实现,它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码;

第二阶段则通常使用C语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。

(1 ) Bootloader第一阶段的功能。

  • 硬件设备初始化。
  • 为加载Bootloader 的第二阶段代码准备RAM空间
  • 复制 Bootloader 的第二阶段代码到RAM空间中。
  • 设置好栈。
  • 跳转到第二阶段代码的C入口点。

在第一阶段进行的硬件初始化一般包括:关闭WATCHDOG、关中断、设置CPU的速度和时钟频率、RAM初始化等。这些并不都是必需的,比如 S3C2410/S3C2440的开发板所使用的U-Boot中,就将CPU的速度和时钟频率的设置放在第二阶段。
甚至,将第二阶段的代码复制到RAM空间中也不是必需的,对于NOR Flash等存储设备,完全可以在上面直接执行代码,只不过相比在RAM中执行效率大为降低。

(2)Bootloader第二阶段的功能。

  • 初始化本阶段要使用到的硬件设备。
  • 检测系统内存映射( memory map ).
  • 将内核映象和根文件系统映象从Flash 上读到RAM空间中。
  • ·为内核设置启动参数。
  • 调用内核

为了方便开发,至少要初始化一个串口以便程序员与Bootloader进行交互。

所谓检测内存映射,就是确定板上使用了多少内存、它们的地址空间是什么。

由于嵌入式开发中 Bootloader 多是针对某类板子进行编写,所以可以根据板子的情况直接设置,不需要考虑可以适用于各类情况的复杂算法。

Flash 上的内核映象有可能是经过压缩的,在读到RAM之后,还需要进行解压。当然,对于有自解压功能的内核,不需要Bootloader 来解压。

将根文件系统映象复制到RAM中,这不是必需的。这取决于是什么类型的根文件系统,以及内核访问它的方法。

将内核存放在适当的位置后,直接跳到它的入口点即可调用内核。调用内核之前,下列条件要满足。

( 1)CPU寄存器的设置。

  • RO=0。
  • Rl=机器类型ID;对于ARM 结构的CPU,其机器类型ID可以参见 linux/arch/arml/tools/mach-types。
  • R2=启动参数标记列表在RAM中起始基地址。

(2)CPU工作模式。
必须禁止中断(IRQs和FIQs )…CPU必须为SVC模式。

(3 )Cache和 MMU的设置。

  • MMU必须关闭。
  • 指令Cache可以打开也可以关闭。·
  • 数据Cache 必须关闭。

如果用C语言,可以像下列示例代码一样来调用内核:

void (*theKernel) (int zero,int arch,u32 params_add)= (void (*)(int,int,u32))KERNEL_RAM_BASE;
...
theKernel(0, ARCH_NUMBER, (u32) kernel_params_start);

3、Bootloader 与内核的交互

Bootloader 与内核的交互是单向的,Bootloader将各类参数传给内核。

由于它们不能同时运行,传递办法只有一个:Bootloader 将参数放在某个约定的地方之后,再启动内核,内核启动后从这个地方获得参数。

除了约定好参数存放的地址外,还要规定参数的结构。

Linux 2.4.x以后的内核都期望**以标记列表(tagged list〉的形式来传递启动参数。**标记,就是一种数据结构;标记列表,就是挨着存放的多个标记。标记列表以标记ATAG_CORE 开始,以标记ATAG_NONE结束。

标记的数据结构为tag,它由一个tag_header结构和一个联合(union)组成。
tag_header结构表示标记的类型及长度,比如是表示内存还是表示命令行参数等。
对于不同类型的标记使用不同的联合(union),比如表示内存时使用tag_mem32,表示命令行时使用tag_cmdline。

数据结构tag 和 tag_header定义在Linux内核源码的include/asm/setup.h头文件中,如下所示:

在这里插入图片描述
下面以设置内存标记、命令行标记为例说明参数的传递。

(1)设置标记ATAG_CORE。

标记列表以标记ATAG_CORE 开始,假设Bootloader 与内核约定的参数存放地址为0x30000100,则可以以如下代码设置标记ATAG_CORE:
在这里插入图片描述
在这里插入图片描述
(u是联合体,core是里面的一个结构体)

其中,tag_next定义如下,它指向当前标记的末尾:

#define tag_next (t) ((struct tag *)((u32*)(t)+ (t) ->hdr.size))

(2)设置内存标记。
假设开发板使用的内存起始地址为0x30000000,大小为0x4000000,则内存标记可以如下设置:在这里插入图片描述
(3)设置命令行标记。
命令行就是一个字符串,它被用来控制内核的一些行为。

比如"root=/dev/mtdblock 2init=/linuxrc console=ttySACO"

表示根文件系统在MTD2分区上,

系统启动后执行的第一个程序为/linuxrc,

控制台为ttySACO(即第一个串口)。

命令行可以在 Bootloader中通过命令设置好,然后按如下构造标记传给内核。

在这里插入图片描述
(4)设置标记ATAG_NONE。

标记列表以标记ATAG_NONE结束,如下设置:

在这里插入图片描述
结束啦,也没有tag_next(params)了

小结

本来打算这个部门直接将uboot的,但是韦神这个部分写的内容很精彩,觉得还是慢慢来。

现在常见的Bootloader种类很多:

  • 对于x86:LILO、GRUB等
  • 对于ARM:U-Boot、Vivi等

这些都各有特点,下面列出 Linux 的开放源代码的 Bootloader 及其支持的体系架构。
在这里插入图片描述
在这里插入图片描述
下一篇一定一定一定来讲讲关于U-Boot的东西。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TrustZone_Hcoco

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值