为什么我们需要在微控制器的相同闪存程序存储器(特别是STM32F103,称为引导加载程序)中使用单独的程序?
将其与主应用程序分开有何特殊之处?
一般而言,基于微处理器的系统(例如PowerPC MPC8270)的引导程序是否与微控制器(例如ARM STM32F103)的引导程序完成相同的工作,或者它们在根本上是互不相同的工作,但两者都称为“引导程序” ?
为什么我们需要在微控制器的相同闪存程序存储器(特别是STM32F103,称为引导加载程序)中使用单独的程序?
将其与主应用程序分开有何特殊之处?
一般而言,基于微处理器的系统(例如PowerPC MPC8270)的引导程序是否与微控制器(例如ARM STM32F103)的引导程序完成相同的工作,或者它们在根本上是互不相同的工作,但两者都称为“引导程序” ?
Answers:
微控制器上的引导加载程序负责通过编程头以外的通信通道更新主固件。这对于通过BLE,UART,I2C,SD卡,USB等在现场更新固件非常有用。要求客户购买编程器仅用于更新其设备上的固件将非常不便。
引导加载程序与众不同的原因是出于可靠性考虑。引导加载程序和应用程序代码放置在闪存的不同部分中,因此引导加载程序可以擦除和重写应用程序代码,而无需更改与引导加载程序代码相关的任何内容。
如果将引导加载程序和应用程序放在一起,则必须将引导加载程序代码复制到RAM才能运行,因为任何固件更新都会擦除闪存中的引导加载程序代码。如果通过RAM中的引导加载程序代码断电并且擦除了闪存,则设备将变砖。
main()
功能。开机时,引导加载程序的启动代码将运行并调用引导加载程序的main()
。引导加载程序会检查有效的应用程序,然后跳转到应用程序的启动代码,该启动代码调用应用程序的main()
。每个程序的启动代码都会为相应的程序初始化C运行时环境(即,初始化变量,堆栈等),通常,任何程序main()
都不会返回到启动代码。
main
。
这样加载过程可以从错误中恢复。假设升级期间出现通信错误或电源断开。如果引导加载程序是您要升级的应用程序的一部分,那么用户将无法在不使用特殊硬件重新刷新到引导加载程序的情况下再次尝试。
某些微控制器无法从RAM执行代码。如果引导加载程序与软件的其余部分混合在一起,那么您实际上将无法升级软件,因为您无法擦除当前正在执行的闪存页面。解决方法是先将新代码刻录到闪存的后半部分,然后再跳转到闪存的后半部分。然后,新代码将自身复制到闪存的前半部分。当然,不利的一面是,刻录闪存通常速度较慢,而现在您必须这样做两次,因此加载过程可能要花两倍的时间。同样,此变通办法将您的应用程序大小限制为不大于总闪存的一半。
编写良好的引导加载程序会尝试在执行设备之前验证设备上是否存在有效的代码。如果将引导加载程序和其他代码混合在一起,那么如何确定在所有代码未加载的情况下验证例程仍能正常工作?
身份验证。安全启动加载程序会在执行之前尝试验证加载的应用程序是否与数字签名匹配。但是,如果将引导加载程序和其他代码混合在一起,那么您将无法控制设备上运行的内容,因为一旦用户加载了新代码,您就无法控制启动时会发生什么。
除了关于允许从引导加载程序对主固件进行重新编程的其他正确答案之外,使引导加载程序分离的另一个好处是,您可以在逻辑上将“启动时执行一次”任务与运行时所需的代码分开。然后,在引导加载程序完成其初始配置任务之后,主固件可以使用其所有不再需要的代码从内存中逐出引导加载程序,从而节省了大量的RAM空间。可以通过其他方式实现此目的,但是引导加载程序/固件的拆分使它在许多体系结构上都变得更加容易。
简短的答案是因为软件很棒。
您可以使Bootloader成为“纯硬件”。但是,将引导加载程序确实以软件编写然后由硬件解释的任务要容易得多。
这些任务可能涉及为要运行的“实际”软件设置硬件(例如,在Raspberry Pi上(通过@ErikF)),并具有在运行之前替换“实际”程序的协议(检查引脚,如果设置该引脚,然后重新刷新真实程序),甚至为“真实”程序设置软件环境。
在较小规模的软件上,当您运行可执行文件时,应用程序加载器会执行一些操作,例如将部分数据加载到内存中,有时修复地址,设置主要或其他全局变量的参数,启动OS提供的库,以及然后跳到 _main
代码。其中一些事情可以由引导加载程序完成。
在微控制器中,引导加载程序执行的某些任务可以分解为程序。您平台的编译器可以自动将“设置”代码注入每个可执行文件中。
但是,在引导加载程序中包含它意味着同一个编译器可能在不同的硬件上运行,因为引导加载程序可以“隐藏”平台之间的差异。
最重要的是,刷新主程序不会冒引导程序的风险(以及重新刷新主程序的能力)的事实,拥有一个普通的引导程序是一件很了不起的事情。
到目前为止,尚未解决的问题之一是微控制器和微处理器系统上的引导加载程序之间的区别。
微控制器
大多数微控制器都有内置的ROM存储器,其中包含其程序代码。更改此代码通常需要连接到微控制器编程接口的编程器设备(例如,ATMega上的ISP)。但是,与其他接口相比,这些编程接口通常通常使用起来不太方便,因为在给定的上下文中它们可能不容易使用。因此,例如,尽管几乎每台计算机都具有USB端口,但ISP所需的SPI接口要少得多,而其他接口(如ATXMega上使用的PID接口)仅受专用编程硬件支持。
因此,例如,如果您想从没有任何外部硬件的常规计算机上更新软件,则可以使用从不同类型的接口(例如,像Arduino上的RS232,USB或USB上的RS232)读取的引导加载程序对设备进行编程通过通用接口。
就是说,如果您不需要此功能,则引导加载程序是完全可选的。无需引导加载程序,微控制器仍可以完全运行其代码。
微处理器
在微处理器上,情况有所不同。尽管大多数微处理器的ROM足够用于引导加载程序,但这些ROM的容量不足以容纳完整的OS。因此,引导加载程序的目的是初始化硬件,寻找可引导的操作系统,加载并运行它。因此,引导加载程序对于每次引导都至关重要。
在x86 / x64系统上,此引导程序是BIOS或UEFI(基本上是BIOS的较新版本)。
有时,您甚至可能有多个引导程序在链中运行。例如,如果您具有使用Windows和Linux的双引导系统,则可能会得到以下结果:
因此,在这种情况下,可以将三个软件视为引导加载程序。GRUB和Windows Bootloader大多都在这里,为用户提供比BIOS / UEFI提供的更为方便的启动选择选项。它还允许从同一硬盘驱动器甚至同一分区启动多个操作系统。
TLDR
因此,尽管在这两个系统中,引导加载程序都做了类似的事情(帮助用户选择要引导的代码),但是两者在实现方式和确切执行方式上都存在很大差异。