我正在使用 ARM cortex-A8 上的 ELinux 内核。
我知道引导加载程序是如何工作的以及它在做什么。但我有一个问题——为什么我们需要引导加载程序,为什么引导加载程序诞生了?
为什么我们不能在没有引导加载程序的情况下直接将内核从闪存加载到 RAM 中?如果我们加载它会发生什么?事实上,处理器不会支持它,但我们为什么要遵循程序呢?
我正在使用 ARM cortex-A8 上的 ELinux 内核。
我知道引导加载程序是如何工作的以及它在做什么。但我有一个问题——为什么我们需要引导加载程序,为什么引导加载程序诞生了?
为什么我们不能在没有引导加载程序的情况下直接将内核从闪存加载到 RAM 中?如果我们加载它会发生什么?事实上,处理器不会支持它,但我们为什么要遵循程序呢?
在 Linux 的上下文中,引导加载程序负责一些预定义的任务。由于这个问题是arm标记的,我认为ARM 引导可能是一个有用的资源。具体来说,引导加载程序负责建立一个ATAG
描述 RAM 数量、内核命令行和其他参数的列表。最重要的参数之一是机器类型。使用设备树,可以传递电路板的完整描述。如果没有一些代码来设置所描述的参数,这使得库存的 ARM Linux 无法启动。
这些参数允许一个通用Linux 支持多个设备。例如,一个 ARM Debian 内核可以支持数百种不同的板卡类型。 Uboot或其他引导加载程序可以动态确定此信息,也可以对板进行硬编码。
您可能还想在堆栈溢出处查看引导加载程序信息页面。
基本系统可能能够设置ATAGS
NOR 闪存并将其复制到 SRAM。但是,它通常比这更复杂一些。Linux 需要 RAM 设置,因此您可能需要初始化 SDRAM 控制器。如果使用 NAND 闪存,则必须处理坏块,并且副本可能比memcpy()
.
Linux 经常有一些潜在的驱动程序错误,驱动程序会假设时钟已初始化。例如,如果Uboot总是为特定机器初始化一个以太网时钟,Linux 以太网驱动程序可能忽略了设置这个时钟。时钟树尤其如此。
某些系统需要 Linux 不支持的引导映像格式;例如一个可以立即初始化硬件的特殊头文件;就像配置从devices
读取初始代码一样。此外,通常有应该立即配置的硬件;引导加载程序可以快速完成此操作,而 Linux 的正常结构可能会显着延迟此操作,从而导致 I/O 冲突等。
从实用的角度来看,使用引导加载程序更简单。但是,没有什么可以阻止您更改 Linux 的源代码以直接从它引导;尽管它可能就像将引导加载程序代码直接粘贴到 Linux 的开头一样。
另请参阅:Coreboot、Uboot和Wikipedia 的比较。Barebox是一个鲜为人知但结构良好且现代的 ARM 引导加载程序。 RedBoot也用于一些 ARM 系统;内核树支持 RedBoot 分区。
引导加载程序是在完成自检后为计算机加载主操作系统或运行时环境的计算机程序。
^来自维基百科文章
所以基本上引导加载程序正在做你想要的 - 将数据从闪存复制到操作内存中。真的就是这么简单。
如果您想了解更多有关提升操作系统的信息,我强烈建议您阅读链接的文章。引导阶段除了测试之外,还包括检查外围设备和其他一些事情。跳过它们仅在非常简单的嵌入式设备上才有意义,这就是它们的引导加载程序更简单的原因:
一些嵌入式系统不需要明显的引导序列即可开始运行,并且在打开时可以简单地运行存储在 ROM 中的操作程序。
同一来源
主引导加载程序通常内置于芯片中,并执行将在系统中运行的第一个用户代码的加载。
引导加载程序的存在是因为没有用于加载第一个代码的标准化协议,因为它依赖于芯片。有时代码可以通过串口、闪存甚至硬盘加载。定位它是引导加载程序功能。
加载并运行用户代码后,将不再使用引导加载程序,系统执行的正确性由用户负责。
在嵌入式 linux 链中,主引导加载程序将设置并运行 Uboot。然后Uboot会找到linux内核并加载它。
为什么我们不能在没有引导加载程序的情况下直接将内核从闪存加载到 RAM 中?如果我们加载它会发生什么?事实上,处理器不会支持它,但我们为什么要遵循程序呢?
Bartek、Artless 和 Felipe 都给出了部分图片。
每种嵌入式处理器类型(EG 386EX、Coretex-A53、EM5200)在重置或开机时都会自动执行某些操作。有时,根据电源是否循环或设备是否重置,情况会有所不同。一些嵌入式处理器允许您根据设备通电或复位时施加到不同引脚的电压来更改某些内容。
无论如何,处理器可以做的事情是有限的,因为定义某些东西需要处理器上的物理空间,无论是片上闪存、指令微代码还是其他一些机制。
这个限制意味着某物是
所以处理器响应复位或电源循环所做的事情不能改变,也不能做很多事情,我们不希望它自动将数百兆字节或千兆字节复制到可能不存在或可能未初始化的内存中,这可能需要很长时间。
所以....
我们设置了一个小程序,它小于我们将要使用的所有设备所允许的最小尺寸。该程序存储在任何需要它的地方。
有时候小程序就是U-Boot。有时甚至 U-Boot 对于初始加载来说都太大了,所以小程序会依次加载 U-Boot。
关键是某物加载的任何内容都可以根据特定系统的需要进行修改。如果是 U-Boot,很好,如果不是,它知道在哪里加载主操作系统或在哪里加载 U-Boot(或其他一些引导加载程序)。
U-Boot(一般来说是引导加载程序)然后配置一组最小的设备、内存、芯片设置等,以使主操作系统能够被加载和启动。主操作系统 init 负责任何额外的配置或初始化。
所以顺序是:
内核要求您正在使用的硬件处于特定状态。您使用的所有硬件都需要检查其状态并对其进行初始化以供进一步操作。这是在嵌入式(或任何其他环境)中使用引导加载程序的主要原因之一,除了它用于将内核映像加载到 RAM 中。
当您打开系统时,RAM 也不处于有用状态(完全初始化以供使用),我们无法将内核加载到其中。因此,我们不能直接加载内核(回答您的问题),因此需要构造来初始化它。
除了所有其他答案中所述的内容(这是正确的)外,在某些情况下,系统必须经历不同的执行模式,例如用于安全 ARM 芯片的 TrustZone。仍然可以将其视为一种硬件初始化,但它的特殊之处在于存在额外的限制(例如:可用内存),这使得在单个二进制文件中完成所有事情即使不是不可能,也是不切实际的,因此可以使用多个阶段的引导加载程序。
此外,出于安全原因,它们中的每一个都经过签名,并且只有在满足安全要求时才能执行其工作。