某单板,更新厂商的sdk到最新后(linux内核从3.10.9升级到3.10.20),运行busybox的reboot命令,串口打 印"The system is going down NOW !!" "Requesting system reboot."后,挂死。
首先从busybox开始,查看reboot命令的流程。流程很简单,busybox最后调用reboot()函数,让系统重启。
用户态的reboot()函数是一个系统调用,因此我在linux内核kernel/printk.c中reboot的系统调用函数的入口添加 printk的调试信息。发现没有任何打印。
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)
难道reboot()函数没有调进内核???
在一次不经意的调试中,我在内核reboot的系统调用中添加了一条低级的打印程序(直接对UART寄存器写,让串口输出),发现 reboot()的调用有打印。
难道printk()函数有问题???
正常的printk是打印到一块环形buffer,这块buffer归属于tty设备。由于reboot运行后,tty设备关闭。环形 buffer内存被释放,指针被清零。MIPS访问到零地址出现exception。而exception又会调用printk,printk递归调用导致死机。
我再将这块代码和标准的linux内核代码比较,发现是不同的。标准的内核直接调用底层的8250的串口输出,而不是通过tty设备。看来是厂商的代码有bug。
问题解决方法:只要打印前判断一下环形buffer的指针是否为NULL,如果NULL直接返回即可。
这个问题花了接近一周的时间才解决,对printk函数太过于信任导致花了很多时间才进入到正确的定位方向。
阅读(6084) | 评论(1) | 转发(0) |