嵌入式 Linux 中自定义 reboot / poweroff 行为

494 查看

一般拿到一个 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的处理逻辑首先是关闭所有的网络连接,然后就是向所有的进程发出SIGTERMSIGKILL信号。最后执行reboot()系统调用

Linux Kernel 的 reboot / poweroff 基本原理

reboot()系统调用到达 kernel 之后,kernel 首先判断这是一个什么指令,然后执行相应的回调函数。reboot / poweroff 回调函数是 kernel 启动后,芯片初始化代码中分配的。

如何创建自定义的 reboot / poweroff

这篇文章着重操作性,我就不讲整个系统调用的流程了,直接讲 “怎么改” 的问题:

  1. 如果你清楚你的芯片初始化代码在哪,那就最好。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 回调,修改成你想要的软件行为即可。

  2. 如果你不知道你手头这套 Linux 调用的是哪个回调?哎,那就学我,翻芯片手册!芯片手册里八成有一个寄存器,管所有模块的 reset 操作,而这个寄存器有一个 “reset all” 的位。动用 Source Insight 的 Search in Project,根据寄存器的偏移值,找到这个寄存器的宏,然后根据这个宏,找到它被调用的地方!十有八九,你就看到一个 blahblah_reset 或者是 blahblah_reboot 的函数了。Bingo!