澳门新葡亰平台游戏APP:嵌入式系统 Boot Loader 技术内幕

本文具体地先容了基于嵌入式系统中的OS启动加载法度榜样――BootLoader的观点、软件设计的主要义务以及布局框架等内容。1.小序在专用的嵌入式板子运行GNU/Linux系统已经变得越来越盛行。一个嵌入式Linux系统从软件的角度看平日可以分为四


当前位置: 主页 >


本文具体地先容了基于嵌入式系统中的 OS 启动加载法度榜样 ―― Boot Loader 的观点、软件设计的主要义务以及布局框架等内容。

1. 小序

在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越盛行。一个嵌入式 Linux 系统从软件的角度看平日可以分为四个层次:

1. 向导加载法度榜样。包括固化在固件(firmware)中的 boot 代码(可选),和 Boot Loader 两大年夜部分。

2. Linux 内核。特定于嵌入式板子的定制内核以及内核的启动参数。

3. 文件系统。包括根文件系统和建立于 Flash 内存设备之上文件系统。平日用 ram disk 来作为 root fs。

4. 用户利用法度榜样。特定于用户的利用法度榜样。无意偶尔在用户利用法度榜样和内核层之间可能还会包括一个嵌入式图形用户界面。常用的嵌入式 GUI 有:MicroWindows 和 MiniGUI 懂。

向导加载法度榜样是系统加电后运行的第一段软件代码。回忆一下 PC 的体系布局我们可以知道,PC 机中的向导加载法度榜样由 BIOS(其本色便是一段固件法度榜样)和位于硬盘 MBR 中的 OS Boot Loader(比如,LILO 和 GRUB 等)一路组成。BIOS 在完成硬件检测和资本分配后,将硬盘 MBR 中的 Boot Loader 读到系统的 RAM 中,然后将节制权交给 OS Boot Loader。Boot Loader 的主要运行义务便是将内核映象从硬盘上读到 RAM 中,然后跳转到内核的进口点去运行,也即开始启动操作系统。

而在嵌入式系统中,平日并没有像 BIOS 那样的固件法度榜样(注,有的嵌入式 CPU 也会内嵌一段短小的启动法度榜样),是以全部系统的加载启动义务就完全由 Boot Loader 来完成。比如在一个基于 ARM7TDMI core 的嵌入式系统中,系统在上电或复位时平日都从地址 0x00000000 处开始履行,而在这个地址处安排的平日便是系统的 Boot Loader 法度榜样。

本文将从 Boot Loader 的观点、Boot Loader 的主要义务、Boot Loader 的框架布局以及 Boot Loader 的安装等四个方面来评论争论嵌入式系统的 Boot Loader。

2. Boot Loader 的观点

简单地说,Boot Loader 便是在操作系统内核运行之前运行的一段小法度榜样。经由过程这段小法度榜样,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件情况带到一个相宜的状态,以便为终极调用操作系统内核筹备好精确的情况。

平日,Boot Loader 是严重地依附于硬件而实现的,分外是在嵌入式天下。是以,在嵌入式天下里建立一个通用的 Boot Loader 险些是弗成能的。只管如斯,我们仍旧可以对 Boot Loader 归纳出一些通用的观点来,以指示用户特定的 Boot Loader 设计与实现。

1. Boot Loader 所支持的 CPU 和嵌入式板

每种不合的 CPU 体系布局都有不合的 Boot Loader。有些 Boot Loader 也支持多种体系布局的 CPU,比如 U-Boot 就同时支持 ARM 体系布局和MIPS 体系布局。除了依附于 CPU 的体系布局外,Boot Loader 实际上也依附于详细的嵌入式板级设备的设置设置设备摆设摆设。这也便是说,对付两块不合的嵌入式板而言,纵然它们是基于同一种 CPU 而构建的,要想让运行在一块板子上的 Boot Loader 法度榜样也能运行在另一块板子上,平日也都必要改动 Boot Loader 的源法度榜样。

2. Boot Loader 的安装序言(Installation Medium)

系统加电或复位后,所有的 CPU 平日都从某个由 CPU 制造商预先安排的地址上取指令。比如,基于 ARM7TDMI core 的 CPU 在复位时平日都从地址 0x00000000 取它的第一条指令。而基于 CPU 构建的嵌入式系统平日都有某种类型的固态存储设备(比如:ROM、EEPROM 或 FLASH 等)被映射到这个预先安排的地址上。是以在系统加电后,CPU 将首先履行 Boot Loader 法度榜样。

像 Blob 或 U-Boot 等这样功能强大年夜的 Boot Loader 平日同时支持这两种事情模式,而且容许用户在这两种事情模式之间进行切换。比如,Blob 在启动时处于正常的启动加载模式,然则它会延时 10 秒等待终端用户按下随意率性键而将 blob 切换到下载模式。假如在 10 秒内没有用户按键,则 blob 继承启动 Linux 内核。

6. BootLoader 与主机之间进行文件传输所用的通信设备及协议

最常见的环境便是,目标机上的 Boot Loader 经由过程澳门新葡亰平台游戏APP串口与主机之间进行文件传输,传输协议平日是 xmodem/ymodem/zmodem 协议中的一种。然则,串口传输的速率是有限的,是以经由过程以太网连接并借助 TFTP 协议来下载文件是个更好的选择。

此外,在论及这个话题时,主机方所用澳门新葡亰平台游戏APP的软件也要斟酌。比如,在经由过程以太网连接和 TFTP 协议来下载文件时,主机方必须有一个软件用来的供给 TFTP 办事。

在评论争论了 BootLoader 的上述观点后,下面我们来详细看看 BootLoader 的应该完成哪些义务。

3. Boot Loader 的主要义务与范例布局框架

在继承本节的评论争论之前,首先我们做一个假定,那便是:假定内核映像与根文件系统映像都被加载到 RAM 中运行。之以是提出这样一个假设条件是由于,在嵌入式系统中内核映像与根文件系统映像也可以直接在 ROM 或 Flash 这样的固态存储设备中直接运行。但这种做法无疑因此运行速率的就义为价值的。

从操作系统的角度看,Boot Loader 的总目标便是精确地调用内核来履行。

别的,因为 Boot Loader 的实现依附于 CPU 的体系布局,是以大年夜多半 Boot Loader 都分为 stage1 和 stage2 两大年夜部分。依附于 CPU 体系布局的代码,比如设备初始化代码等,平日都放在 stage1 中,而且平日都用汇编说话来实现,以达到短小精悍的目的。而 stage2 则平日用C说话来实现,这样可以实现给繁杂的功能,而且代码会具有更好的可读性和可移植性。

为了得到更快的履行速率,平日把 stage2 加载到 RAM 空间中来履行,是以必须为加载 Boot Loader 的 stage2 筹备好一段可用的 RAM 空间范围。

因为 stage2 平日是 C 说话履行代码,是以在斟酌空间大年夜小时,除了 stage2 可履行映象的大年夜小外,还必须把客栈空间也斟酌进来。此外,空间大年夜小最好是 memory page 大年夜小(平日是 4KB)的倍数。一样平常而言,1M 的 RAM 空间已经足够了。详细的地址范围可以随意率性安排,比如 blob 就将它的 stage2 可履行映像安排到从系统 RAM 肇端地址 0xc0200000 开始的 1M 空间内履行。然则,将 stage2 安排到全部 RAM 空间的最顶 1MB(也即(RamEnd-1MB) - RamEnd)是一种值得保举的措施。

为了后面的论述方便,这里把所安排的 RAM 空间范围的大年夜小记为:stage2_size(字节),把肇端地址和终止地址分手记为:stage2_start 和 stage2_end(这两个地址均以 4 字节界限对齐)。是以:

stage2_end=stage2_start+stage2_size

别的,还必须确保所安排的地址范围的切实着实确是可读写的 RAM 空间,是以,必须对你所安排的地址范围进行测试。详细的测试措施可以采纳类似于 blob 的措施,也即:以 memory page 为被测试单位,测试每个 memory page 开始的两个字是否是可读写的。为了后面论述的方便,我们记这个检测算法为:test_mempage,其详细步骤如下:

1. 先保存 memory page 一开始两个字的内容。

2. 向这两个字中写入随意率性的数字。比如:向第一个字写入 0x55,第 2 个字写入 0xaa。

3. 然后,急速将这两个字的内容读回。显然,我们读到的内容应该分手是 0x55 和 0xaa。假如不是,则阐明这个 memory page 所盘踞的地址范围不是一段有效的 RAM 空间。

下面给出一个简单的 trampoline 法度榜样示例(来自blob):

.text

.globl _trampoline

_trampoline:

bl  main

/* if main ever returns we just call it again */

b  _trampoline

可以看出,当 main() 函数返回后,我们又用一条跳转指令从新履行 trampoline 法度榜样――当然也就从新履行 main() 函数,这也便是 trampoline(弹簧床)一词的意思所在。

3.2.1初始化本阶段澳门新葡亰平台游戏APP要应用到的硬件设备

这平日包括:(1)初始化至少一个串口,以便和终端用户进行 I/O 输出信息;(2)初始化计时器等。

在初始化这些设备之前,也可以从新把 LED 灯点亮,以注解我们已经进入 main() 函数履行。

设备初始化完成后,可以输出一些打印信息,法度榜样名字字符串、版本号等。

3.2.2 检测系统的内存映射(memory map)

所谓内存映射便是指在全部 4GB 物理地址空间中有哪些地址范围被分配用来寻址系统的 RAM 单元。比如,在 SA-1100 CPU 中,从 0xC000,0000 开始的 512M 地址空间被用作系统的 RAM 地址空间,而在 Samsung S3C44B0X CPU 中,从 0x0c00,0000 到 0x1000,0000 之间的 64M 地址空间被用作系统的 RAM 地址空间。虽然 CPU 平日预留出一大年夜段足够的地址空间给系统 RAM,然则在搭建详细的嵌入式系统时却不必然会实现 CPU 预留的整个 RAM 地址空间。也便是说,详细的嵌入式系统每每只把 CPU 预留的整个 RAM 地址空间中的一部分映射到 RAM 单元上,而让剩下的那部分预留 RAM 地址空间处于未应用状态。 因为上述这个事实,是以 Boot Loader 的 stage2 必须在它想干点什么 (比如,将存储在 flash 上的内核映像读到 RAM 空间中) 之前检测全部系统的内存映射环境,也即它必须知道 CPU 预留的整个 RAM 地址空间中的哪些被真正映射到 RAM 地址单元,哪些是处于 "unused" 状态的。

在用上述算法检测完系统的内存映射环境后,Boot Loader 也可以将内存映射的具体信息打印到串口。

3.2.3 加载内核映像和根文件系统映像

(1) 筹划内存占用的结构

这里包括两个方面:(1)内核映像所占用的内存范围;(2)根文件系统所占用的内存范围。在筹划内存占用的结构时,主要斟酌基地址和映像的大年夜小两个方面。

对付内核映像,一样平常将其拷贝到从(MEM_START+0x8000) 这个基地址开始的大年夜约1MB大年夜小的内存范围内(嵌入式 Linux 的内核一样平常都不操过 1MB)。为什么要把从 MEM_START 到 MEM_START+0x8000 这段 32KB 大年夜小的内存空出来呢?这是由于 Linux 内核要在这段内存中放置一些全局数据布澳门新葡亰平台游戏APP局,如:启动参数和内核页表等信息。

而对付根文件系统映像,则一样平常将其拷贝到 MEM_START+0x0010,0000 开始的地方。假如用 Ramdisk 作为根文件系统映像,则其解压后的大年夜小一样平常是1MB。

(2)从 Flash 上拷贝

因为像 ARM 这样的嵌入式 CPU 平澳门新葡亰平台游戏APP日都是在统一的内存地址空间中寻址 Flash 等固态存储设备的,是以从 Flash 上读取数据与从 RAM 单元中读取数据并没有什么不合。用一个简单的轮回就可以完成从 Flash 设备上拷贝映像的事情:

while(count) {

*dest++ = *src++; /* they are all aligned with word boundary */

count -= 4; /* byte number */

};

3.2.4 设置内核的启动参数

应该说,在将内核映像和根文件系统映像拷贝到 RAM 空间中后,就可以筹备启动 Linux 内核了。然则在调用内核之前,应该作一步筹备事情,即:设置 Linux 内核的启动参数。

Linux 2.4.x 今后的内核都期望以标记列表(tagged list)的形式来通报启动参数。启动参数标记列表以标记 ATAG_CORE 开始,以标记 ATAG_NONE 停止。每个标记由标识被通报参数的 tag_header 布局以及随后的参数值数据布局来组成。数据布局 tag 和 tag_header 定义在 Linux 内核源码的include/asm/setup.h 头文件中:

发表评论
加载中...

相关文章