如何优化U-boot到内核切换代码?

时间:2014-06-26 13:01:15

标签: c linux linux-kernel

平台:Xilinx Zynq SoC上的ARM Cortex A9上的Linux。

我问了一个问题:Why is kernel boot starting too late

基本上我试图了解并最小化这两个事件之间的延迟:

[Sat Apr 12 19:33:50.692 2014] Starting kernel ...
[Sat Apr 12 19:33:50.692 2014] 
[Sat Apr 12 19:33:51.298 2014] Booting Linux on physical CPU 0x0

第一行告诉控件现在正在给内核,而第二行告诉控件现在是内核并且正在由CPU执行。

从u-boot到内核的这种切换对我们的应用程序来说花费了太多时间。

为了理解这两个事件之间发生了什么,我在下面插入了printf语句:

1- bootm.c

我将以下行放在函数static void boot_jump_linux(bootm_headers_t *images, int flag)

的末尾
         }
        if (!fake)
               {printf("above kernel_entry in boot_jump_linux in bootm.c\n");
                kernel_entry(0, machid, r2);
                printf("below kernel_entry boot_jump_linux in bootm.c\n");

               }
}

2- main.c

我在start_kernel函数中添加了这样的声明:

asmlinkage void __init start_kernel(void)
{
  printk("I am the first statement in start_kernel in main.c" );
        char * command_line;
        extern const struct kernel_param __start___param[], __stop___param[];

然后我编译了u-boot和内核,新的日志消息包含以下行:

[Sat Apr 12 19:33:50.692 2014] Starting kernel ...
[Sat Apr 12 19:33:50.692 2014] above kernel_entry in boot_jump_linux in bootm.c

[Sat Apr 12 19:33:51.298 2014] I am the first statement in start_kernel in main.c 
[Sat Apr 12 19:33:51.298 2014] Booting Linux on physical CPU 0x0

(实际上我把printf语句放在很多地方但是所有的thsoe都在上面"启动内核......"或者在#34;在物理CPU 0x0和#34上启动Linux,所以我在这个讨论中忽略它。我也使用ftrace来查看热点,但它没有报告u-boot功能)。

我在bootm.c"中的boot_jump_linux中观察到"在kernel_entry下面。永远不会打印在日志消息中的任何位置。这表明在函数kernel_entry(0,machid,r2)之后控件不会返回;之所以被调用,是因为linux现在已经控制并正在执行。

所以我的目标是知道在这两个事件中正在执行哪个功能。

现在要了解发生了什么(即使在插入我的printf / printk消息后仍未清楚)我问了以下问题:

1- In u-boot, kernel_entry points to which function?

2- Trying to understand the usage of function pointer

基于那里的答案,我怀疑我的热点,即花费很多时间的代码位于以下文件之一:

1- https://github.com/Xilinx/linux-xlnx/blob/master/arch/arm/kernel/head.S

2- https://github.com/Xilinx/linux-xlnx/blob/master/arch/arm/kernel/head-common.S

3- https://github.com/Xilinx/linux-xlnx/blob/master/arch/arm/boot/compressed/head.S

我的问题:

1-我的理解是否正确,我应该专注于上述文件?

2-调用kernel_entry(0, machid, r2);后,控件转到上面的代码和哪一行?

我怀疑文件https://github.com/Xilinx/linux-xlnx/blob/master/arch/arm/boot/compressed/head.S  对我来说是没用的,因为这是解压缩所必需的,但是我的内核已经解压缩,因为在u-boot日志中很早就可以看到以下行:

[Sat Apr 12 19:33:50.596 2014]    Uncompressing Kernel Image ... OK

完整日志为here

有人可以在这方面让我高兴吗?

非常感谢提前!!

2 个答案:

答案 0 :(得分:3)

  

我的目标是尽可能快地进行切换   您是否认为使用早期的printk我可以更快地启动,因为切换会很早?

你的问题和你的计算方法"快速"或者"延迟"基于有缺陷的数据。

您认为0.5秒"延迟"实际上是U-Boot在 实时 中输出"启动内核..." ,而内核 缓冲 推迟 输出"引导Linux" 直到系统和控制台已初始化。这是将苹果与橙子进行比较 至少你必须通过启用早期printk 让内核以 实时 (就像U-Boot)输出。然后您的时间戳将更好地指示实际经过的时间。

摘自chapter 18 of the Linux Kernel Map(我强调):

  

确实存在printk()的坚固性。 它在内核启动过程中的某个点之前无法使用,在控制台初始化之前实际上,如果控制台未初始化,输出应该在哪里?< / p>      

这通常不是问题,除非您在引导过程中很早就调试问题(例如,在setup_arch()中执行特定于体系结构的初始化)。这样的调试是一个挑战,并且缺少任何类型的打印方法只会使问题复杂化。

     

有一些希望,但不是很多。硬核架构黑客使用可以工作的硬件(比如串口)与外界进行通信。相信我这对大多数人来说并不好玩。一些受支持的架构确实实现了一个理智的解决方案,然而其他(包括i386)有可用的补丁,也可以节省一天。

     

解决方案是一个printk()变种,可以在启动过程的早期输出到控制台:early_printk()。行为与printk()相同,只有名称及其名称早期工作的能力发生了变化。然而,这不是可移植的解决方案,因为并非所有支持的体系结构都实现了这样的方法。但是,如果确实如此,它可能会成为你最好的朋友。

有关启用早期printk 的详细信息,请参阅this answer相同的问题(由您的双胞胎?)。

所以不,使用早期printk 不会改善&#34;切换&#34;或整体开机时间 但它应该有助于防止您查找幻像阻塞。

答案 1 :(得分:0)

我想知道可以发生什么

您通过指向其他功能的函数指针显示直接函数调用。

我不知道除了中断代码之外的任何事情都会干扰它。

所花费的时间是600毫秒,这不是很多,但当然在很多情况下都很明显(特别是在Zynq相关的地方)。

要调查的事项:

  • 你可以单步执行函数指针跳转吗?这将让你看到PC最终的位置。
  • 你能否关闭中断,只是为了确保没有任何虚假的事情发生?
  • 你可以记录伐木所需的时间吗?如果它通过串口,它会阻塞吗?打印&#34; [Sat Apr 12 19:33:51.298 2014] I am the first statement in start_kernel in main.c&#34; (82字节)到9600 bps的阻塞串行端口大约需要83 ms。