Bootloader作用及实现步骤
一、Bootloader作用(目的)
二、完成Boot最终目的的前提条件
三、对前提条件的详细说明
3.1、对前提条件(1)的说明:
3.2、对前提条件(2)的说明:
3.3、对前提条件(3)的说明:
3.4、对前提条件(4)的说明:
3.5、对前提条件(5)的说明:
3.6、Boot阶段基本流程简单总结:
四、loader是干啥的
一、Bootloader作用(目的)
Bootloader=Boot + loader
Boot的目的: 最终目的:跳到C语言中;为了C语言运行程序会进行一系列的初始化,系统一上电后如何通过一系列的设置让软件程序员进入C语言/更高级语言环境的开发,这个过程就是boot的主要目的。
Loader的目的: 主要目的是开始执行应用逻辑,比如点灯:需要灯的接口开发;串口输入输出:需要串口编程;加载linux的内核:flash的编程、网卡的编程、内核启动前的初始化部分。根据不同的应用会有不同的变化。
一个开发板要想执行loader,要先看boot做了什么事。
二、完成Boot最终目的的前提条件
围绕boot的最终目的,对执行最终目的的前提条件进行说明: 前提条件: (1)让SP指向可读可写的设备空间中
(2)满足递减栈的规则—SP想办法放在内存的高段地址
(3)配置SDRAM的控制器。首选空间为SDRAM,SDRAM不是系统一上电就好,所以在做(1)、(2)之前要配置SDRAM的控制器,使SDRAM可以正常工作。
(4)配置系统工作时钟,通过代码对相应寄存器进行相关配置即可实现。
(5)关闭看门狗、中断、MMU、CACHE,通过汇编语言对相应的寄存器进行置位即可实现。
开发时前提条件的执行顺序:(5)、(4)、(3)、(1)、(2)
三、对前提条件的详细说明
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替换*/
}
在上述代码运行过程中,一旦函数abc又调用了函数fun,寄存器r0中的值会被替换,从10变成了20,函数fun在返回后就会出现问题:这时用if语句判断a的情况,会发现a已经不再等于10了。
如果按照上述逻辑去设计汇编的话问题会有很多。于此问题,C语言给我们提供了栈的概念—stack
栈的逻辑:先进后出、后进先出,压栈出栈是通过代码对指向栈区指针的值进行更新、赋值,进而对指针指向的内存空间进行读和写。由此有了栈指针概念—该指针必须指向一个具备可以进行读写的硬件空间。在Arm体系架构中,栈指针用寄存器SP来描述。何为可读可写——与应用程序思路不同,硬件上的可读可写如代码:
int a = 10;//这句话执行完后让以a为首地址的那段空间/设备把10赋进去
*(&a)==10;//进行解引用后将值取出来和10是相等的相当于将10写进去了
如果a的地址有问题,比如它指向的是一个不存在的空间。何为不存在的空间——0x2000 0000是内存机地址,但硬件公司只买了一个16M的内存,现在软件工程师想把a放在地址0x2100 0000,这个地址发出去后显然没有落到16M的范围内,那么对a的赋值就无法进行了。这时C语言无法帮我们进行压栈入栈的操作。
小结:栈指针一定要指向一个合法的设备——可读可写的地址空间。
3.2、对前提条件(2)的说明:
系统刚上电时SP指向的是0地址,即ROM,显然写不进去。所以在跳到C语言之前一定要让SP指向一个可读可写的设备区