为什么我们需要一个与我们的微控制器应用程序分开的引导程序?


28

为什么我们需要在微控制器的相同闪存程序存储器(特别是STM32F103,称为引导加载程序)中使用单独的程序?

将其与主应用程序分开有何特殊之处?

一般而言,基于微处理器的系统(例如PowerPC MPC8270)的引导程序是否与微控制器(例如ARM STM32F103)的引导程序完成相同的工作,或者它们在根本上是互不相同的工作,但两者都称为“引导程序” ?


2
同样的原因,您需要单独的芯片和零件,而不是一个巨型的整体结构
Emobe

你不知道 只需使用计算机控制台上的开关和指示灯输入程序即可。
热门点击

1
严格来说,您在微控制器上不需要单独的引导程序。但是我们通常会选择为其提供的其他实用程序功能使用一个。如果不需要这些功能,则可以删除引导加载程序。微控制器自举程序通常用于将新程序刻录到闪存中。有时可以将其用于调试功能,某些支持断点和其他功能强大的功能。在微型计算机上,引导加载程序通常从大容量存储器中加载程序,并且在那儿是必要的。
ghellquist

Answers:


55

微控制器上的引导加载程序负责通过编程头以外的通信通道更新主固件。这对于通过BLE,UART,I2C,SD卡,USB等在现场更新固件非常有用。要求客户购买编程器仅用于更新其设备上的固件将非常不便。

引导加载程序与众不同的原因是出于可靠性考虑。引导加载程序和应用程序代码放置在闪存的不同部分中,因此引导加载程序可以擦除和重写应用程序代码,而无需更改与引导加载程序代码相关的任何内容。

如果将引导加载程序和应用程序放在一起,则必须将引导加载程序代码复制到RAM才能运行,因为任何固件更新都会擦除闪存中的引导加载程序代码。如果通过RAM中的引导加载程序代码断电并且擦除了闪存,则设备将变砖。


3
我们的原因是相同的。它们位于同一闪存中,但引导加载程序对齐闪存时,其擦除擦除边界对齐且足够智能,仅能擦除比其自身地址高的闪存。
约书亚

3
在某些情况下,微处理器的编程标头实际上可能是不可访问的,而不必拆卸产品的底盘,因此无需额外的硬件就能够通过通信总线对其进行重新编程是可靠性的关键因素。
John Go-Soco

6
@ alt-rose引导加载程序和应用程序是单独编译的程序,每个程序都有自己的启动代码和main()功能。开机时,引导加载程序的启动代码将运行并调用引导加载程序的main()。引导加载程序会检查有效的应用程序,然后跳转到应用程序的启动代码,该启动代码调用应用程序的main()。每个程序的启动代码都会为相应的程序初始化C运行时环境(即,初始化变量,堆栈等),通常,任何程序main()都不会返回到启动代码。
kkrambo

1
@ alt-rose:与CPU获取引导加载程序的起始地址的方式相同-不会。取而代之的是,CPU指定它将用作引导加载程序的起始地址的内容,而引导加载器则指定它将用作应用程序的起始地址的内容。
MSalters

4
@kkrambo尽管通常是正确的,但也没有要求(也不是全球通用的事实)完全使用C或C派生的语言编写引导加载程序main
Yakk

26
  1. 这样加载过程可以从错误中恢复。假设升级期间出现通信错误或电源断开。如果引导加载程序是您要升级的应用程序的一部分,那么用户将无法在不使用特殊硬件重新刷新到引导加载程序的情况下再次尝试。

  2. 某些微控制器无法从RAM执行代码。如果引导加载程序与软件的其余部分混合在一起,那么您实际上将无法升级软件,因为您无法擦除当前正在执行的闪存页面。解决方法是先将新代码刻录到闪存的​​后半部分,然后再跳转到闪存的后半部分。然后,新代码将自身复制到闪存的前半部分。当然,不利的一面是,刻录闪存通常速度较慢,而现在您必须这样做两次,因此加载过程可能要花两倍的时间。同样,此变通办法将您的应用程序大小限制为不大于总闪存的一半。

  3. 编写良好的引导加载程序会尝试在执行设备之前验证设备上是否存在有效的代码。如果将引导加载程序和其他代码混合在一起,那么如何确定在所有代码未加载的情况下验证例程仍能正常工作?

  4. 身份验证。安全启动加载程序会在执行之前尝试验证加载的应用程序是否与数字签名匹配。但是,如果将引导加载程序和其他代码混合在一起,那么您将无法控制设备上运行的内容,因为一旦用户加载了新代码,您就无法控制启动时会发生什么。


4
作为第2点的一个例子,某些微控制器可能甚至不具有访问RAM在启动时:例如,树莓裨使用其GPU以从SD卡,然后使ARM处理器和存储器加载自举程序。
ErikF

11

它们通常在这里,使您可以更新主应用程序。

您需要一些知道如何擦除和重新编程一些内部闪存的代码,这些代码不能成为主程序,因为当其自身擦除时将无法重新编程。


9

引导加载程序允许MCU与其他设备进行通信,以接受新程序,对其进行存储并在重置后运行该程序。如果您没有引导加载程序,则需要使用程序员来访问内存并将程序放置到位。


2
就是这样。MCU只能通过特殊的编程子系统(例如AVRICE或JTAG)或已经在闪存中包含引导加载程序来获取代码。引导加载程序的复杂程度由应用程序决定,例如某些系统可以从WiFi加载代码。在像ATTiny这样的低端MCU上,引导加载程序(和串行引脚)的开销很大,因此您总是使用编程器。
Rich

7

除了关于允许从引导加载程序对主固件进行重新编程的其他正确答案之外,使引导加载程序分离的另一个好处是,您可以在逻辑上将“启动时执行一次”任务与运行时所需的代码分开。然后,在引导加载程序完成其初始配置任务之后,主固件可以使用其所有不再需要的代码从内存中逐出引导加载程序,从而节省了大量的RAM空间。可以通过其他方式实现此目的,但是引导加载程序/固件的拆分使它在许多体系结构上都变得更加容易。


1
在微控制器上,代码很可能永远不会存储在RAM中,因此无法将其逐出。您当然可以从RAM中丢弃引导加载程序的数据。
Ben Voigt

@BenVoigt,取决于微控制器。有些(主要是使用NOR闪存的)可以让您直接从闪存之外执行,而其他一些(通常是使用NAND闪存,这种情况越来越普遍)要求您在RAM之外执行。有时甚至没有板载闪存,您必须先将外部闪存芯片中的代码复制到本地SRAM中,然后才能执行任何操作。
Nate S-恢复莫妮卡

2

简短的答案是因为软件很棒。

您可以使Bootloader成为“纯硬件”。但是,将引导加载程序确实以软件编写然后由硬件解释的任务要容易得多。

这些任务可能涉及为要运行的“实际”软件设置硬件(例如,在Raspberry Pi上(通过@ErikF)),并具有在运行之前替换“实际”程序的协议(检查引脚,如果设置该引脚,然后重新刷新真实程序),甚至为“真实”程序设置软件环境。

在较小规模的软件上,当您运行可执行文件时,应用程序加载器会执行一些操作,例如将部分数据加载到内存中,有时修复地址,设置主要或其他全局变量的参数,启动OS提供的库,以及然后跳到 _main代码。其中一些事情可以由引导加载程序完成。

在微控制器中,引导加载程序执行的某些任务可以分解为程序。您平台的编译器可以自动将“设置”代码注入每个可执行文件中。

但是,在引导加载程序中包含它意味着同一个编译器可能在不同的硬件上运行,因为引导加载程序可以“隐藏”平台之间的差异。

最重要的是,刷新主程序不会冒引导程序的风险(以及重新刷新主程序的能力)的事实,拥有一个普通的引导程序是一件很了不起的事情。


-1

由于C语言的局限性,尚未涵盖的一个问题是需要将关注点分离。

通常,引导加载程序是用Assembly和C混合编写的,并且在Assembly的启动阶段很早。

这样做是为了设置某些特定内容,例如:

  • 分配C堆栈
  • 将堆栈指针读入寄存器
  • 将程序计数器读入寄存器
  • 声明重置向量
  • 将第二阶段(initramfs)加载到RAM中。

这与所采取的步骤非常近似,我正在描述ARM引导过程,对于x86和其他体系结构,情况又有所不同。

但是,原理仍然是相同的:分配C堆栈必须从汇编中完成。


为什么要下票?这既相关又准确。
BitShift

-1

到目前为止,尚未解决的问题之一是微控制器和微处理器系统上的引导加载程序之间的区别。

微控制器

大多数微控制器都有内置的ROM存储器,其中包含其程序代码。更改此代码通常需要连接到微控制器编程接口的编程器设备(例如,ATMega上的ISP)。但是,与其他接口相比,这些编程接口通常通常使用起来不太方便,因为在给定的上下文中它们可能不容易使用。因此,例如,尽管几乎每台计算机都具有USB端口,但ISP所需的SPI接口要少得多,而其他接口(如ATXMega上使用的PID接口)仅受专用编程硬件支持。

因此,例如,如果您想从没有任何外部硬件的常规计算机上更新软件,则可以使用从不同类型的接口(例如,像Arduino上的RS232,USB或USB上的RS232)读取的引导加载程序对设备进行编程通过通用接口。

就是说,如果您不需要此功能,则引导加载程序是完全可选的。无需引导加载程序,微控制器仍可以完全运行其代码。

微处理器

在微处理器上,情况有所不同。尽管大多数微处理器的ROM足够用于引导加载程序,但这些ROM的容量不足以容纳完整的OS。因此,引导加载程序的目的是初始化硬件,寻找可引导的操作系统,加载并运行它。因此,引导加载程序对于每次引导都至关重要。

在x86 / x64系统上,此引导程序是BIOS或UEFI(基本上是BIOS的较新版本)。

有时,您甚至可能有多个引导程序在链中运行。例如,如果您具有使用Windows和Linux的双引导系统,则可能会得到以下结果:

  • BIOS / UEFI启动,并找到已安装的GRUB。然后加载GRUB(= Grand Unified Bootloader)
  • GRUB找到了某种Linux和Windows Bootloader。用户选择Windows Bootloader。
  • Windows引导加载程序将启动,并找到已安装的Windows 7和Windows 10。用户选择Windows 10。
  • Windows 10最终启动。

因此,在这种情况下,可以将三个软件视为引导加载程序。GRUB和Windows Bootloader大多都在这里,为用户提供比BIOS / UEFI提供的更为方便的启动选择选项。它还允许从同一硬盘驱动器甚至同一分区启动多个操作系统。

TLDR

因此,尽管在这两个系统中,引导加载程序都做了类似的事情(帮助用户选择要引导的代码),但是两者在实现方式和确切执行方式上都存在很大差异。


虽然区分具有足够随机访问非易失性存储(ROM或闪存)以容纳整个程序的系统与需要从RAM运行代码的系统是有用的,但存在两种类型的微控制器和两种类型的微处理器。
超级猫

当然,微控制器和微处理器之间的区别不是硬边界,并且某些微控制器的行为更像微处理器,反之亦然。这就是为什么我以AtMega / Arduino和x86 / x64为例,因为它们的行为方式如此。
达卡龙

“微处理器具有足够大的ROM用于引导加载程序...在x86 / x64系统上,该引导加载程序是BIOS或UEFI”。BIOS或UEFI存储在片外闪存中。片上ROM用于更低级别的功能,例如微码的初始化。
Ben Voigt

@Dakkaron:我会根据芯片是否被设计用于非平凡目的而无需地址总线上的其他东西来在微处理器和微控制器之间划清界限。8031 除了具备功能性的8051(绝对是微控制器)之外,没有其他条件,后者在内部ROM中没有指定有用的东西,否则将被设计为完全可从内部存储使用。像RCA东西/ CDP 1802甚至没有资格虽然它可以用于驱动LED的名称标签...
supercat

...没有外部RAM和ROM,因为无RAM /无ROM设计仅限于琐碎的任务。TMS 32050之类的东西,如果我还记得有一个引导程序,并且内部有数千个字的16位字RAM,就可以称为微控制器。尽管许多应用程序需要更多的内存,但如果通过UART连接到另一个系统,则可以在没有任何内存总线的情况下满足多种用途。
supercat
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.