一般拿到一个 Linux SDK 的时候,方案商已经内置了很实用的 busybox,用来执行 poweroff / reboot 命令。但嵌入式开发时,有时需要自定义执行 reboot / poweroff 之后的一些行为。本文就是负责简单易懂地解释如何修改。
本文地址:https://segmentfault.com/a/1190000006216529
Reference
基于Linux与Busybox的Reboot命令流程分析
这篇文章讲得还是挺浅显易懂的。这里就不转载了,给出全文链接。下面我提纲一下。
Busybox 的 reboot / poweroff 基本原理
在 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()
系统调用
Linux Kernel 的 reboot / poweroff 基本原理
reboot()
系统调用到达 kernel 之后,kernel 首先判断这是一个什么指令,然后执行相应的回调函数。reboot / poweroff 回调函数是 kernel 启动后,芯片初始化代码中分配的。
如何创建自定义的 reboot / poweroff
这篇文章着重操作性,我就不讲整个系统调用的流程了,直接讲 “怎么改” 的问题:
如果你清楚你的芯片初始化代码在哪,那就最好。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!