函数指针在bootloader中的妙用

来源:互联网 发布:板式换热器设计软件 编辑:程序博客网 时间:2024/06/06 10:52

       最近在弄一块叫pcduino的板子,为了修改uboot使之成为pcduino的bootloader,便稍微看了一下uboot的一些相关代码。在看到整个bootloader运行到最后的倒数两行代码的时候,我发现了一个很有意思的地方。

       那两行代码形式是这样的:

       theKernel(0,machid,bd->bi_boot_params);

       return 1;

       这两行代码干了什么东西呢?嵌入式系统中,通常并没有像bios那样的固件程序,因此整个系统的加载启动任务就完全由bootloader来完成。而bootloader最终的任务就是加载内核到内存并跳转到内核起始地址开始运行。而上面的第一行代码做了两件事情:1、传递了三个参数给内核;2、跳转到了内存中内核的起始地址并运行内核。

       这一行代码是怎么做到这两件事情的呢?第一个念头是这个函数执行了不少东西。来看一下它的定义便应该清楚了。它的定义如下:

       void (*theKernel)(int zero , int machid , uint params);

       完了。

       我去,居然是个函数指针。

       什么是函数指针呢?我们来看一下百度百科里面的解释:函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。

好了,知道了什么是函数指针,我们来接着看thKernel是怎么赋值的:

theKernel = (void(*)(int , int , uint))addr;

上面这行代码中addr就是内核加载到内存中的起始物理地址,即内核的入口地址。它把入口地址强制类型转换后赋值给theKernel.这时thKernel就是一个指向内核入口地址并带三个参数的函数指针。

当运行:

theKernel(0,machd,bd->bi_boot_params);

就相当于跳到了内核入口地址执行指向的函数,这里所说的执行指向的函数,即是从内核入口开始执行内核代码了。上面这行代码还把三个参数送到了三个寄存器r0、r1、r2,当执行内核代码的时候内核直接从这三个寄存器中提取参数信息,这样便做到了把参数传递给内核。而那最后一行 return 1 是永远都不会返回执行了,除非发生了错误。

怎么样,这个小技巧算有意思吧。

第一次写博客,技术上多有欠缺,请大家多多包含和指教,谢谢!

0 0
原创粉丝点击