今天早上看了一上午的bootloader简单源码,终于捋顺了bootloader的执行过程,之前只是知道bootloader代码会先被irom中的代码拷贝到iram中一部分,然后执行这部分代码,会把整个bootloader代码拷贝到sdram中,最终在sdram执行剩下的代码,而这段代码会把kernel拷贝到sdram的某个地址,最终引导起来整个内核。但是我今天早上看代码的时候看到一个问题,我所有的代码都是自己动手实现的,只要一步一步按照顺序来,不就可以实现么?为什么还要拷贝来拷贝去的。感觉直接按照跳转的方式,跳转值进行指令的跳转就行,但是想过之后,我意识到自己真是无知了。比如说在irom中执行的时候,会有一次跳转到iram中某一个地址,当然pc是肯定可以直接跳转到指定的任何一个地址,但是在这个地址中没有存放指令码,这时候,肯定是一个有去无回的过程,不仅这样,这个pc跳到这里后,就会很迷茫,前不着村,后不着店的,不知道自己的所去所从,就会死到这里。只有先把代码拷贝到将要跳转的地址中,pc指针才会顺着跳转后的指令继续执行,也就是说每一个指令都要负责人,确保执行完这个指令后,一定要有另一个指令去接纳pc。这样pc才会一直活在我的代码中。
下边我就再把我更进一步了解到的bootloader执行过程再重新叙述一下:
我使用的是s5pv210芯片、K9K8G08U0A型号的nand flash
第一步:cpu启动起来后,先来到0x00000000这个地址处(也就是irom的地址),此时会看到有一段代码(这是irom中固定的代码)在这里,这段代码会找到bootloader的第一段代码(以下就称为BL1)存放的地址,由于BL1存放在nand flash中,不支持片上执行,所以irom会把这段代码拷贝到iram中,
但是在拷贝之前,irom会先把iram的起始4个地址分别写上一定的内容(不过通常只写0x00地址为BL1所占空间的大小(一般是8k),而其他三个地址全写为0),把BL1这段代码拷贝到iram后,irom的使命就快要完成了,irom的最后一个任务就是把pc指针指向放BL1的那块地址的起始位置,然后就按照这个地址的指令开始执行。
第二步:这个时候开始执行BL1的代码。这段代码的功能是初始化硬件,比如串口,内存,显示器,按键等等。
在初始化所有需要初始化的硬件后,BL1还会有一个拷贝指令,就是要把bootloader拷贝到sdram中一般会把bootloader的代码放到BLADD(表示为bootloader在sdram中存放的地址。
这时候BL1的使命也将要完成,于是,BL1会把pc指针跳转到BL2的地址,此时所有要运行的代码都在sdram中,这次的跳转不会直接从这次拷贝的开始地址执行,而是跳过BL1代码所占的地址,从BL2开始执行。
第三步:执行BL2中的代码。此时BL2代码的功能主要是实现MTD设备驱动初始化,电源、时钟初始化,堆栈空间,以及各种必要的初始化,并且会提供一个命令行,可以进行交互。在这之后会有一个设置内核参数的过程,这些参数在内存中的存在方式也是以结构体存储,以链表进行关联的,而这个 链表有一个固定的起始地址-0x3000_0100;每一个结构体代表一个信息,并首尾相连,内核在需要这些参数时,就可以再对应的地址上取数据。这一步执行完毕后,就要把kernel的代码拷贝到sdram中的一个指定地址,并且会把这个地址强制转换成一个函数指针,并且向这个函数中传递一些参数,最终会到内核中执行内核代码。这个时候,内核就会被引导到执行状态。
这就是我今天大半天的心得,写出来,看到这篇文章的你,肯定也是对这方面感兴趣的,希望可以互相交流,尽情来吐槽我的这篇文章吧,把你所认为不对或者我没有想到的内容告诉我,大家共同进步!