BootLoader(引导加载器)是启动嵌入式系统时执行的第一个程序,位于固件中。它主要负责初始化系统硬件、加载操作系统,并将控制权转移到操作系统的启动过程。
关于Linux
引导加载程序的引入
嵌入式Linux系统从软件角度可以分为四个主要部分:引导加载程序(Bootloader)、Linux内核、文件系统和应用程序。这些部分共同构成了完整的嵌入式系统。
引导加载程序(Bootloader):引导加载程序是系统启动的第一个执行代码,负责系统的引导和初始化。它可以包括固化在固件中的boot代码和Bootloader程序。引导加载程序的主要任务是初始化硬件、加载Linux内核、配置系统参数,并将控制权传递给内核。
Linux内核:Linux内核是嵌入式系统的核心,负责管理系统的硬件资源、提供各种设备驱动程序和执行系统的核心功能。它提供了内存管理、进程调度、设备管理等基本功能,并提供了丰富的系统调用接口供应用程序使用。
文件系统:嵌入式系统通常会有一个或多个文件系统。根文件系统是其中最重要的,它包含了操作系统所需的基本文件和目录结构。此外,嵌入式系统还可以建立在闪存或其他存储设备上的文件系统,用于存储应用程序、配置文件和数据等。
应用程序:应用程序是嵌入式系统中运行在用户空间的程序,利用Linux内核提供的服务和资源完成特定的功能需求。应用程序可以包括各种应用、服务等用户程序,用于实现各种功能,如通信、控制、数据处理等。
启动阶段
通过这两个阶段的启动过程,引导加载程序能够在启动过程中对硬件进行初始化和配置,并加载操作系统,以使嵌入式系统能够正常运行。这种分阶段的启动过程为系统提供了灵活性和可扩展性,使Bootloader能够在不同的硬件平台和应用场景中进行自定义配置和操作。
预引导阶段(Pre-boot Stage):
第一阶段:该阶段也被称为硬件初始化阶段。在此阶段,Bootloader负责进行硬件初始化和基本系统设置。这包括检测和初始化处理器、内存、时钟、总线和其他外设的操作。
第二阶段:在此阶段,Bootloader负责加载第二阶段的Bootloader代码。此代码位于存储介质上(例如闪存、硬盘等),并负责执行更高级的系统配置和初始化,包括加载文件系统驱动程序等。这一阶段还可以提供用户界面、bootloader配置和固件升级等功能。
操作系统加载阶段(Operating System Load Stage):
该阶段是引导加载程序加载并启动操作系统(通常是Linux内核)的阶段。Bootloader会加载操作系统内核的映像文件,并执行一系列操作,例如设置内核参数、初始化设备树等。然后,它将控制权转移到操作系统的入口点,使操作系统(内核)接管系统的控制和管理。
如图为嵌入式Linux硬件上电到进入用户界面的全过程
下图为Linux(X86架构)硬件上电到进入用户界面的全过程
BootLoader的意义
最重要的是:Linux内核是由引导加载程序(Bootloader)装载到内存中的。在系统启动过程中,引导加载程序负责加载Linux内核(大的、独立的程序),将其从存储介质(如磁盘或闪存)读取到内存中的指定位置。
步骤如下:
(1)引导加载程序首先初始化硬件环境,例如处理器、内存和外设等。
(2)引导加载程序根据特定规则(如配置文件或参数)确定Linux内核的位置,通常是指定内核映像文件在存储介质上的位置。
(3)引导加载程序从存储介质中加载Linux内核的映像文件到内存中的指定位置。这个过程涉及到读取映像文件的内容,并将其复制到内存中的指定位置。引导加载程序还可能对内核进行一些预处理或修正,如设定内核启动参数、修改映像文件的头部信息等。
(4)加载完成后,引导加载程序将控制权转移到Linux内核的入口点,以开始内核的执行,随后完成创建/挂载文件系统、设置用户环境、内存和进程管理等各种工作。
(Linux不同于RTOS,它属于分时操作系统)
为什么需要BootLoader?
从其意义出发,总结如下:
(1)硬件初始化 (2)多引导选择 (3)系统配置和参数设置 (4)维护和固件升级 (5)加载操作系统
BootLoader的作用
BootLoader 作用 | 说明 |
硬件初始化 | 检测和初始化计算机或嵌入式系统的硬件设备,如处理器、内存、外部设备等。 |
加载操作系统 | 从存储设备中读取操作系统的引导程序,并将其加载到内存中。 |
启动操作系统 | 将控制权转移到操作系统的引导程序,以启动操作系统的执行。 |
提供启动选项 | 提供用户选择不同操作系统或不同启动模式的选项,支持多系统启动等。 |
提供固件升级 | 支持固件的更新和升级,以提供新功能、修复漏洞或提高系统性能。 |
处理错误检测 | 在启动过程中检测和处理硬件或软件错误,提供错误消息和故障排除功能。 |
支持设备引导 | 支持从不同的存储设备(如硬盘、闪存、网络等)引导操作系统。 |
自定义配置 | 允许用户自定义启动配置、参数和引导顺序,以满足特定需求。 |
下图为window与嵌入式Linux的启动区别
常用的Bootloader(ARM架构)
BootLoader | 特点 |
U-Boot | 开源,通用的Bootloader 支持多种处理器架构和嵌入式平台 功能丰富、灵活性高 用于启动操作系统、加载内核映像和文件系统等 |
Das U-Boot | 在U-Boot基础上进行定制和改进 提供更多功能和特定优化 快速启动、多协议支持和硬件平台兼容性等 |
barebox | 轻量级、模块化的Bootloader 小巧、可靠、高度可定制 适用于资源受限的嵌入式平台 |
TF-A (Trusted Firmware-A) | 开源的ARM架构下的Trusted Boot Firmware 提供安全启动和可信计算功能 用于ARM TrustZone技术的系统 确保系统启动过程的可信度和安全性 |
U-Boot(Universal BootLoader)是一个开源的通用BootLoader,究其开源和自由,功能丰富,平台支持广泛,可定制性强,开发社区活跃,是嵌入式系统中最广泛常用的BootLoader之一。
BootLoader的两种模式
(1)启动加载模式
启动加载模式又叫自主模式,指Bootloader从目标及某个固件存储设备上将操作系统加载到RAM运行,整个过程没有用户介入,是Bootloader的正常工作模式
(2)下载模式
目标机上的Bootloader将通过串口或网络或USB等其它通信手段从主机下载文件,如内核镜像,根文件系统镜像等,从主机下载的文件通常首先被Bootloader保存到目标机的RAM中,然后被Bootloader写到目标机的Flash内的固态存储设备中。这种模式通常在第一次安装内核和根文件系统时使用。系统更新也会使用这种工作模式。
BootLoader启动方式
方式 | 过程 |
引导加载程序(Bootloader) | 内部ROM启动:在芯片的内部ROM存储器中预装的引导加载程序,处理器上电或复位时直接执行。 外部存储器启动:引导加载程序存储在外部存储器(如Flash、SD卡等)中,处理器上电或复位时从外部存储器加载并执行。 刷写引导方式:通过工具或通信接口将引导加载程序刷写到目标设备的存储器中。 |
网络启动方式 | 网络引导启动:通过以太网接口远程下载内核映像或文件系统,实现通过网络启动设备。 PXE(Preboot Execution Environment)引导:通过网络引导服务器(如DHCP、TFTP、FTP等)提供的服务远程引导设备。 |
磁盘启动方式 | BIOS引导:使用电脑主板上的BIOS(基本输入/输出系统)进行引导,从硬盘、软盘或光盘中的引导扇区加载引导加载程序。 UEFI引导:使用统一的EFI(可扩展固件接口)进行引导,支持更大容量的硬盘、安全引导、图形界面等功能。 |
USB启动方式 | USB引导:通过连接到计算机的USB接口上的USB设备(如USB闪存驱动器)引导。 |
Flash启动方式 | 直接从Flash启动:引导加载程序存储在Flash存储器中,处理器上电或复位时直接执行Flash存储器中的引导加载程序。 从Flash复制并解压到RAM启动:将压缩的内存映像文件从Flash存储器复制到RAM中,再从RAM启动。 |
其他定制化启动方式 | SD卡启动:通过SD卡存储器中的引导加载程序和操作系统启动设备。 NAND启动:通过NAND闪存存储器中的引导加载程序和操作系统启动设备。 JTAG启动:通过JTAG接口进行调试和下载引导加载程序到目标设备中。 |
BootLoader依赖性
(1)硬件依赖性:每个硬件平台都有不同的架构、外设和寄存器配置。因此,Bootloader的实现必须与特定硬件平台的细节相匹配。这包括处理器类型、时钟频率、外设控制寄存器地址、中断和异常处理等。Bootloader需要正确地配置和操作硬件以实现正常的启动加载和初始化过程。
(2)设备配置依赖性:即使两个嵌入式板卡采用相同的处理器,它们的外设配置、内存映射和引导设备等可能仍然存在差异。因此,为了让Bootloader能够在不同的嵌入式板卡上运行,可能需要进行适当的参数配置和源代码的调整。这包括处理内存布局、引导设备的选择、时钟设置以及其他特定的硬件配置等。
(3)通信接口依赖性:根据具体的应用场景,Bootloader可能需要与主机或其他外部设备进行通信,如通过串口、以太网或USB接口。为了使Bootloader能够与这些接口正确交互,可能需要针对所用接口的规范和协议进行配置或开发相应的驱动程序。
(4)引导设备和文件系统依赖性:Bootloader通常从引导设备(如Flash、硬盘或SD卡)中加载映像文件(如操作系统内核或应用程序)。为了正确读取和加载这些文件,Bootloader需要了解并支持特定的引导设备类型和文件系统格式。
关于Baremetal
(1)硬件设备初始化:BootLoader的第一阶段负责初始化嵌入式系统的硬件设备,包括处理器、内存控制器、外部设备等。
(2)为加载Stage 2准备RAM空间:在Stage 1中,BootLoader会为加载Stage 2而准备好内存空间(RAM),通常通过栈(stack)的方式进行分配。
(3)加载Stage 2:BootLoader的Stage 1会从预定义的存储设备中读取Stage 2的引导程序,并将其加载到预先分配的内存空间(RAM)中。
(4)设置堆栈:BootLoader在加载Stage 2之前会设置好堆栈指针,以确保在后续的执行过程中能正确地进行函数调用和返回操作。
(5)跳转到Stage 2的C入口点:在加载完Stage 2之后,BootLoader会将控制权转移到Stage 2的C入口点,即Stage 2中的C语言代码执行的起始位置。
启动流程分析
上电之后,系统会取执行ROM或者Flash里面的Bootloader启动代码,启动代码是用来在初始化电路以及用来为高级语言编写的软件做好运行前准备的一小段汇编语言。商业实时操作系统中,启动代码部分一般叫板级支持包(BSP)。Bootloader启动具体流程如下:
1.第一步设置中断和异常向量
2.完成处理器芯片一些寄存器的系统启动的最初配置
3.设置看门狗
4.配置系统存储器,包括Flash、SRAM、和DRAM等,并为它们分配地址空间
5.为处理器的每个工作模式设置栈指针,ARM处理器有多种工作模式,每种工作模式都需要设置单独的占空间
6.变量初始化,软件中已经赋值的全局变量,启动过程把这部分变量从只读区域复制到读写区域,已经赋值的静态全局变量直接固化在只读Flash或EEPROM中
7.数据区准备,软件所有未赋值的全局变量,启动过程中需要把这部分变量所在区域清零
8.调用高级语言入口,main函数
总结:
BootLoader的启动方式基本如下:
stage1程序(汇编)在内存之外的存储介质中对内存空间进行初始化后,再将stage2程序(C)加载到内存中执行。
stage2加载内核(操作系统),由操作系统完成对整个操作系统的初始化或者无操作系统,则加载后进入口函数main。
可能有多种模式(涉及IAP升级)
例如STM32启动配置如下,支持不同的方案: