Bootloader作用解析:Boot与Loader目的及实现步骤一

2025-04-11
来源:网络整理

功能和实施步骤

1。功能(目的)

=引导 +

引导的目的:

最终目标:跳到C;要以C语言运行该程序,将进行一系列初始化。如何使用一系列设置允许软件程序员在系统启动后输入C语言/更高级语言环境的开发。此过程是引导的主要目的。

目的:

主要目的是开始执行应用程序逻辑,例如照明:需要灯的接口开发;串行输入和输出:串行端口编程;加载内核:编程,网卡编程和内核启动之前的初始化部分。根据应用程序,会有不同的更改。

如果开发委员会想要执行,则必须首先查看引导的作用。

2。完成启动的最终目的的先决条件

最终目的解释了靴子的最终目的的先决条件:

先决条件:

(1)让SP指向可读且可写的设备空间

(2)符合减少堆栈的规则 - SP找到了一种放置高分子地址的方法

(3)配置的控制器。首选空间不应在系统上电动后立即进行,因此您需要在(1)和(2)之前配置控制器以使其正常工作。

(4)配置系统工作时钟并通过代码配置相应的寄存器。

(5)关闭看门狗,中断,MMU,并通过汇编语言设置相应的寄存器。

开发过程中先决条件的执行顺序:(5),(4),(3),(1),(2)

3。先决条件的详细说明3.1。先决条件的解释(1):

让我们首先看一下代码:

int main() { abc();//main函数中调用abc函数 } int abc() { int a = 10;//假设用r0寄存器保存了立即数10,接下来跳到fun函数中 fun();//abc函数中调用fun函数 if(a xx)//函数fun返回后再判断a的情况,发现a不再是10 } int fun() { int b = 20;/*假设同样用寄存器r0保存20,不用内存保存是因为寄存器的访问速度比内存访问速度快, 函数abc中的变量a在整个代码执行区中不需要再往回传给main函数了,a是一个临时的值, 寄存器r0只有一个,也只能保存一个,所以a只是出现一次,然后就不用了。当abc函数调用fun函数后, 寄存器r0中的值10会被20替换*/ }

bootloader开发流程_bios程序开发_boot开发的小程序

在上述代码操作期间,一旦函数ABC调用函数再次娱乐,寄存器R0中的值将被替换为10到20,并且功能趣味在返回后会出现问题:此时,使用IF语句来判断情况,您会发现A不再等于10。

如果您根据上述逻辑设计组件,将会有很多问题。在这个问题中,C语言为我们提供了堆栈的概念 -

堆栈的逻辑:首先进出,然后首先进出。将堆栈按下堆栈是为了通过代码更新和分配指针的值,然后读取指针指向的内存空间。这具有堆栈指针的概念 - 指针必须指向可以读写和编写的硬件空间。在ARM架构中,堆栈指针由寄存器SP描述。可读性和可写的是与应用程序想法不同的,可读且可写的硬件就像代码:

int a = 10;//这句话执行完后让以a为首地址的那段空间/设备把10赋进去 *(&a)==10;//进行解引用后将值取出来和10是相等的相当于将10写进去了

例如,如果A的地址有问题,则指向不存在的空间。不存在的空间-0000是内存地址,但硬件公司只购买了1600万内存。现在,软件工程师希望在地址0000中放置一个。发送此地址后,显然不在16m的范围内,因此无法进行A的分配。目前,C语言无法帮助我们按下堆栈。

摘要:堆栈指针必须指向合法的设备 - 可读且可写的地址空间。

3.2。先决条件的解释(2):

当系统打开电源时,SP指向地址为0,即ROM,显然无法写入。因此,在跳入C语言之前,您必须让SP指向可读且可写的设备间隔。 SP的首选地址是中等地址。如果在集会上写:

代码是:

MOV SP, #0x2000 0000//跳之前将sp赋值 BL MAIN//跳到MAIN中

这将引起问题。当我们学习ARM的基础知识时,我们就会知道,C语言中有一个用于堆栈指针的规范,该指针称为默认情况下C语言使用SP用作堆栈指针,并且SP指出了将堆栈推下堆栈的过程,因此将堆栈指针指向低位置的堆栈指针是不合适的。 SP指针必须向上指向,因此必须满足减少堆栈的规则。

代码应该是:

MOV SP, #0x2100 0000//跳之前将sp赋值 BL MAIN//跳到MAIN中

问题还没有结束。既然它指向地址0000,并且此地址是内存,那么内存可以在电源上启用吗?不,内存涉及动态充电过程。内存访问:发送地址 - 直接将数据发送到它 - 将数据写在上面。

假设内存大小为16m,则计算地址总线的数量:

总存储量=存储单元×存储单词长度,

然后:

内存单位的数量= 2个地址总线位,内存单位的数量= 2^{地址总线位}内存单位数= 2个地址总线位点

其他:

1MB == ∗ 1024 ============ 2^{20} b1mb == ∗ 1024 ==== 220b

什么是存储单词长度:

存储单词长度:存储单元中的二进制代码(存储单词)的位数。存储单词长度可以是8位,16位,32位,等等。

早期计算机的存储单词长度通常与机器的指令单词长度和数据单词长度相同,因此可以通过访问主内存来撤回一个指令或一个数据。随着计算机的应用范围继续扩展,解决问题的准确性继续提高,指令词长度通常是可变的,并且数据单词长度也需要可变。为了适应指令和数据单词长度的可变性,其长度不是由存储单词长度决定的,而是由字节数表示。 1个字节(字节)定义为由8位(位)二进制代码组成。

存储单词是指存储在存储单元中的二进制代码的组合。存储词可以代表二进制号或字符串。如果存储词是,则可以表示为(代码)由十六进制字符组成,或16位二进制编号。该值对应于13 949的十进制数,也可以表示两个代码:“ 6”和“}”。存储词也可以代表指令。单词长度是同时处理二进制数字的位数,称为单词长度。通常,处理具有单词长度的8位数据的CPU称为8位CPU。 32位CPU将同时处理具有32位单词长度的二进制数据。

存储的单词的长度是存储单词在内存中的长度,可以是或8位。

所以:

16m = 2个地址总线位×存储单词长度16m = 2^{地址总线位}×存储单词长度16m = 2地址总线位×存储单词长度

现在:

(24 ∗ 220)b = 2地址总线位×内存单词长度(2^4*2^{20})B = 2^{地址总线位}×内存Word (24 ∗ 220)b = 2地址总线×内存位置

存储单词长度为1,因此地址总线号为24。

bios程序开发_boot开发的小程序_bootloader开发流程

因此,此内存具有24辆地址总线,可以用这24辆地址总线一一地将16个兆字节介绍。现在,只要CPU发出相应的地址,它将读取和写入数据。

如果芯片具有较大的内存,以减少芯片的大小,则需要减少地址总线的数量。如何使用更少的地址行访问所有较大的内存?使用C语言的一维数组和二维阵列的概念。

作为代码:

int a[16];//在这里定义了16个字节(2^4),用4根线就能找到它(用4bit可以表示)

也就是说,这4行可以代表这16个状态。

现在,我想找到一种减少这4行数量的方法。如何访问同一空间?作为代码:

int b[4][4];//将16个字节分为4行4列

以这种方式访问​​时,您需要知道行的数量和列的数量,范围为0〜3,大小为4个字节。现在可以用2bit(2行访问)表示。首先发行旅行坐标,然后发出列坐标。

通过将其更改为二维数组,外部接口上的位数变小。阵列尺寸越大,在表示相同大小的内存时所需的位数越小。

芯片内存的内部结构可以理解为一个多维阵列,由多个面组成。要访问一个空间,您必须首先知道它的面孔,然后在此面上知道其行坐标(地址)。内部结构大致显示了下图:

引发问题:现在发出地址0000,您需要将此地址转换为此芯片中的面,行和列的地址。此转换过程可以由软件程序员分解或用硬件完成。制作软件的成本很高,而且不是很有意义,因此让硬件帮助我们确定它。让硬件做到另一个概念:此过程是在芯片中的DRAM中指定的:请参阅先决条件描述的内容(3)。

其他详细信息:SP指针应向上指向,但不要随意地指向。在手臂系统中,手臂工作分为7个工作空间。第一个:SVC模式,默认情况下将在系统重置后默认使用的模式,其工作空间;第二个:IRQ模式,中断后的操作模式;第三个:FIQ模式;第四个:USR模式,实际上对应于应用程序空间。

…七个工作空间。

其中,USR模式和SVC模式下的空格具有自己的SP指针,因此用户空间操作的代码不会影响内核。这将引起问题。如果只有一段记忆,则在遵循指向高地址的原理时,两个SP指针可能会反复指向地址。因此,在分配SP值时,您应该考虑要使用哪种模式,以及如何将SP分开:为每个工作模式分开相应的可用内存空间,如下图所示,但此时可能会出现另一个问题。如果USR的内存空间设计不好,一旦发生了死环递归,则堆栈将慢慢向下扩展,堆栈将溢出。溢出后,将修改SVC空间内容。然后,在执行SVC时,结果将是错误的,并且程序将混乱。

因此,当执行先决条件(1)和(2)时,应考虑几个问题。首先,考虑使用了哪些空间/模式,哪些模式用于初始化SP的模式以及如何初始化:有一组专门用于模式切换的指令。其次,将值分配给SP:每个模式的值都无法重复或其他模式不能被覆盖时,存在原则。

3.3。先决条件的解释(3):

CPU直接发送地址后,它现在需要访问它,以便CPU可以告诉控制器它想做什么。控制器将使用我的配置(行地址数量,列地址数量,多少个块,定期充电问题,使其收取多长时间一次)

关于一次充电的频率:CPU是脉冲波形,需要在此处引入正时概念。

时机是芯片的核心。每个上升的边缘都会触发CPU做某事。收取多久一次?

您为什么知道为控制器充电需要多长时间?因此,您必须先配置控制器。配置中还有另一个问题。 CPU和控制器具有自己的工作频率。他们有相同的频率吗?他们共享同一时钟吗?由于外围控制器的成本/芯片过程确定控制器处理数据的能力较弱,从而导致无法同步接收发送给它的数据,因此控制器不会直接使用总时钟总线上的频率,但是在使用它之前将通过频率分隔线降低。因此,您必须首先配置系统工作时钟。只有在配置工作时钟时,您才能计算一次充电的频率。

3.4。先决条件的解释(4):

此步骤是嵌入式开发过程中最耗时的,因为内核最终在后期的RAM上运行,其中包括许多在RAM上运行的程序。在RAM中,如果我们给出的频率不符合芯片本身的物理特性,则该程序很容易逃跑。在PC中,该程序在运行时可能会突然出现蓝屏。蓝色屏幕有很多原因,但大多数是由于内存问题所致。有时,在内存中购买的芯片的物理结构/质量会非常慢。例如:现在CPU希望发送序列1101,现在芯片需要找到一种将这4位以一定速度或此芯片发送到数据总线的方法。假设CPU在1GHz工作(此频率非常快),基本上是1GHz,而4乘以4乘4,则可以在此时发送4位。价格便宜,无法同步1GHz CPU给出的信息,因此内存工作会出现问题,并且出现蓝屏。

配置的困难不仅在于了解芯片手册,还在于了解某些硬件原理,包括一些调试经验,然后动态计算某个开发板的特定工作参数。

3.5。先决条件的解释(5):

在配置系统时钟之前,还有另一个问题。匹配后它无法立即正常工作。在此期间,将需要一段时间才能引入看门狗。看门狗是计时器。如果一段时间内未再次馈送计时器,则一旦将其降低到0,就会触发中断/重置,并且CPU将重新启动。因此,有必要确保有足够的时间实现先决条件(1),(2),(3)和(4),因此必须在配置时钟之前出于安全原因关闭看门狗。同时,必须关闭中断,因为我们尚未输入C或尚未输入系统处理。即使中断出现,我们也不知道该如何处理,因为我们的功能尚未注册。在调用主函数时,最好关闭中断并打开中断。此外,您还可以关闭MMU。 MMU通常是指在有操作系统时使用的。在裸金属程序中,您通常可以为简单的目的而忽略它。为了说明,它们是否可以打开还是关闭都没关系。但是,总的来说,数据目前最好关闭。尽管速度可以提高,但由于数据完整性问题,数据的完整性在打开后可能会产生影响,这给以后的调试带来了很大的麻烦,因此首先将其关闭。

3.6。简要摘要启动阶段的基本过程:

Boot的最终目标是跳到C。在跳到C之前,您必须考虑堆栈指针的初始化,因为C语言编译器必须自动将SP指针用作我们的堆栈空间。这样,我们必须将SP指向可读且可写的设备。必须根据规则确定分配的特定值,然后将其戴上。然后,您需要在擦除之前进行工作和配置。此工作负载相对较大,包括:行地址的数量,列地址的数量,多少个块,周期性充电问题以及在配置之前,有必要计算频率为其充电的频率,因此还必须配置系统时钟,并且系统时钟还需要一些,即关闭看管台,中断,中断,中断,MMU和MMU。

因此,具体来说,无论哪种系统,如果要设计引导阶段,都必须完成上述先决条件的工作。最后,根据每个系统的不同条件,还涉及一个概念,即代码迁移。

为什么需要移动代码?启动芯片时,它将指定只能处理多少代码。如果代码量超过指定的处理量,则将不处理多余的代码。目前,程序员需要将代码移至更大的空间以运行,并且程序员需要自己控制控制器。因此,在执行主函数之前,必须初始化相应内存的控制器,并且必须在移动代码之前初始化相应的控制器。这将使软件工程师更多地起作用,因为首先,这取决于硬件公司用来启动的内存。例如,SD卡需要编写SD卡的驱动程序。如果是NAND启动,则需要编写NAND的驱动程序,然后考虑如何快速读取代码到内存并跳到内存以执行。一般而言,该代码已移至RAM,因此必须基于正常工作。第二个是执行速度问题。如果代码本身之前正在使用,则执行速度比RAM慢得多,因此需要将程序从内存(NOR-)移动以在快速内存上运行。这就是我们谈论的代码迁移。

分享