一般拿到一个 Linux SDK 的时候,方案商已经内置了很实用的 busybox,用来执行 poweroff / reboot 命令。但嵌入式开发时,往往需要自定义板子在执行 reboot / poweroff 之后的一些行为。本文就是负责简单易懂地解释如何修改。
本文地址: https://segmentfault.com/a/1190000006216529
基于Linux与Busybox的Reboot命令流程分析 这篇文章讲得还是挺浅显易懂的。这里就不转载了,给出全文链接。下面我提纲一下。
在 busybox 中,很容易让人错误地以为 reboot
/ poweroff
就像其他命令一样,是一个独立的功能。实际上这并不准确。
在 busybox 中,实现了 Linux 中基础的 init
进程。因此你可以从参考文章中看到,poweroff / reboot 功能的代码实际上是在 busybox 的 init.c
里的(嗯,并没有“poweroff.c” 或者 “reboot.c”)。
原理上,reboot 和 poweroff 命令执行时,busybox 就向 init 发了一个 signal。可以看到,reboot 命令对应的 signal 是 SIGTERM
(所以你直接在 shell 里执行“ pkill init
”的效果和执行 reboot 是一样的),而 poweroff 对应的是 SIGUSR2
。
在相应的信号处理函数中, init.c
的处理逻辑首先是关闭所有的网络连接,然后就是向所有的进程发出 SIGTERM
和 SIGKILL
信号。最后执行 reboot()
系统调用
reboot()
系统调用到达 kernel 之后,kernel 首先判断这是一个什么指令,然后执行相应的回调函数。reboot / poweroff 回调函数是 kernel 启动后,芯片初始化代码中分配的。
这篇文章着重操作性,我就不讲整个系统调用的流程了,直接讲 “怎么改” 的问题:
如果你清楚你的芯片初始化代码在哪,那就最好。Kernel 里面回调的声明在 reset.h
文件中,而定义在 reset.c
中。我的情况,用的是 MIPS 芯片,那么就是 linux-a.b.c.d/arch/mips/kernel/reset.c
中。
然而这 并不重要
。重要的是找到你的具体芯片的回调注册函数。我的 SDK 则将回调定义在 linux-a.b.c.d/arch/mips/厂商名/reset.c
中。虽然都叫 reset.c,但是两个文件的内容是完全不一样的。找到相应的 poweroff / reboot 回调,修改成你想要的软件行为即可。
如果你不知道你手头这套 Linux 调用的是哪个回调?哎,那就学我,翻芯片手册!芯片手册里八成有一个寄存器,管所有模块的 reset 操作,而这个寄存器有一个 “reset all” 的位。动用 Source Insight 的 Search in Project,根据寄存器的偏移值,找到这个寄存器的宏,然后根据这个宏,找到它被调用的地方!十有八九,你就看到一个 blahblah_reset
或者是 blahblah_reboot
的函数了。Bingo!