技术开发 频道

自己动手编写嵌入式Bootloader---基本功能流程

  5. boot kernel zImage

  zImage 二进制文件包含两部分内容,起始部分是解压缩程序,后面是压缩的内核。解压缩程序是最先运行的,内核中文件是:arch/arm/boot /compressed/head.S,它负责把压缩的内核解压到0x30008000处。因此zImage可以下载到RAM任意位置处,由解压缩程序负责搬移到正确的运行地址。

  所以 Bootloader启动Linux内核的方法就是直接跳转到内核的第一条指令处,也就是跳转到内存中存放内核映像的开始地址,内核映像具有自解压功能,会把自己释放到正确的运行地址。Tag列表怎样传给内核呢?使用的方法是把Tag列表的起始地址传给内核。首先,定义一个指向函数的指针:

  typedef void (*LINUX_KERNEL_ENTRY)(int, int, UINT32);

  LINUX_KERNEL_ENTRY pfExecKernel;

  这样pfExecKernel就是一个函数指针,函数具有三个整型变量。然后,让pfExecKernel指向内核映像的起始地址处,这里使用强制类型转换把地址转换成函数指针类型:

  pfExecKernel = (LINUX_KERNEL_ENTRY)pKernelStartAddr;

  最后,以三个参数调用pfExecKernel函数:

  pfExecKernel(0, MACH_ID, ATAG_BASE);

  其中第一个参数默认为零,可以不必理会。第二个参数是机器ID号,不同的CPU有不同的号码与之对应,可以在内核源代码的linux/arch/arm/tools/mach-types 文件中查到,S3C2440 对应的MACH_ID 为362。第三个参数ATAG_BASE就是上文讲到的Tag列表的首地址。

  这个函数调用的作用其实就是设置 r0=0,r1=机器ID,r2=TAG首地址,然后跳到arch/arm/boot/compressed/head.S文件中的第一条指令处。

  既然可以把TAG首地址传递给内核,那么TAG LIST就可以放在RAM中的任何位置了,只要不与其它有用内容冲突即可。但是事实却并不是想象的这样。实验发现,第三个参数传递进去的TAG首地址似乎没有起到作用,因为启动时总是找不到正确的启动参数。后来发现内核有个默认的TAG首地址0x30000100,它总是到0x30000100去寻找启动参数,而不理会我们传进来的第三个参数。所以,S-Boot中把TAG首地址就设置为0x30000100。

0
相关文章