针对对象

这篇文章我尽量写的细一些,主要针对于不太懂得嵌入式命令行到系统层过程的新手看,如果觉得有用可以关注一下,不定期写一些新手需要看的文章。

正文

引言

我们在做嵌入式设备的时候,经常会输入一些命令,例如:cat test.txt来查看test.txt文本;又比如输入reboot, 来重启系统。从我们输入reboot到系统重启的整个过程都是如何操作的呢?如果你还不懂,那么可以继续往下面看。

由于笔者的项目环境为Android, 因此借用android工程进行说明,linux开发者不用担心,我会把区别的地方特地标出来

从命令行输入开始分析

大家都知道,在嵌入式设备字符终端中我们输入的每一个命令其实都是 一个二进制可执行的文件,将其编译然后将其所在的目录加入环境变量中,我们就可以在命令行的任何目录去直接输入文件名来运行这个程序(即命令)。
reboot命令也一样,它也是一个由C/C++语言编译的的可执行文件。那么要分析reboot的重启执行过程就需要得到reboot这个命令的源码。linux用户可以从busybox中得到reboot的源码。这里我是android工程,在安卓工程的 \system\core\reboot\reboot.c中,接下来对这个文件进行简单分析。

将reboot代码贴出如下

int main(int argc, char *argv[])
{int ret;size_t prop_len;char property_val[PROPERTY_VALUE_MAX];const char *cmd = "reboot";char *optarg = "";opterr = 0;do {int c;c = getopt(argc, argv, "p");if (c == -1) {break;}switch (c) {case 'p':cmd = "shutdown";break;case '?':fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]);exit(EXIT_FAILURE);}} while (1);if(argc > optind + 1) {fprintf(stderr, "%s: too many arguments\n", argv[0]);exit(EXIT_FAILURE);}if (argc > optind)optarg = argv[optind];prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);if (prop_len >= sizeof(property_val)) {fprintf(stderr, "reboot command too long: %s\n", optarg);exit(EXIT_FAILURE);}ret = property_set(ANDROID_RB_PROPERTY, property_val);if(ret < 0) {perror("reboot");exit(EXIT_FAILURE);}// Don't return early. Give the reboot command time to take effect// to avoid messing up scripts which do "adb shell reboot && adb wait-for-device"while(1) { pause(); }fprintf(stderr, "Done\n");return 0;
}

这里代码不复杂,主要看property_set(ANDROID_RB_PROPERTY, property_val)
这里有个宏,这个宏定义在include\cutils\android_reboot.h, 定义如下
/* Properties */
#define ANDROID_RB_PROPERTY “sys.powerctl”
函数property_set函数如下:

uint32_t property_set(const std::string& name, const std::string& value) {size_t valuelen = value.size();if (!is_legal_property_name(name)) {LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";return PROP_ERROR_INVALID_NAME;}if (valuelen >= PROP_VALUE_MAX) {LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "<< "value too long";return PROP_ERROR_INVALID_VALUE;}//省略中间代码//主要看这个函数property_changed(name, value);return PROP_SUCCESS;
}

别的函数有兴趣可以深入看看具体实现,但这里我们需要知道的就是最后会执行property_changed(name, value); 这个函数

void property_changed(const std::string& name, const std::string& value) {// If the property is sys.powerctl, we bypass the event queue and immediately handle it.// This is to ensure that init will always and immediately shutdown/reboot, regardless of// if there are other pending events to process or if init is waiting on an exec service or// waiting on a property.// In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific// commands to be executed.if (name == "sys.powerctl") {//其他都不重要,看这个就好了if (HandlePowerctlMessage(value)) {shutting_down = true;}}if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);if (waiting_for_prop) {if (wait_prop_name == name && wait_prop_value == value) {LOG(INFO) << "Wait for property took " << *waiting_for_prop;ResetWaitForProp();}}
}

HandlePowerctlMessage函数代码如下

bool HandlePowerctlMessage(const std::string& command) {、、、省略\\都不重要,只要看DoReboot函数auto shutdown_handler = [cmd, command, reboot_target,run_fsck](const std::vector<std::string>&) {DoReboot(cmd, command, reboot_target, run_fsck);return 0;};、、、省略return true;
}

最后这个DoReboot函数中调用了RebootSystem
代码如下

static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {LOG(INFO) << "Reboot ending, jumping to kernel";switch (cmd) {case ANDROID_RB_POWEROFF:reboot(RB_POWER_OFF);break;case ANDROID_RB_RESTART2:syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());break;case ANDROID_RB_THERMOFF:reboot(RB_POWER_OFF);break;}// In normal case, reboot should not return.PLOG(FATAL) << "reboot call returned";abort();
}

这么大堆代码终于到了关键性调用了
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
这里调用了系统函数syscall,这里有个知识点

几乎所有的应用层都是通过这个接口来进行系统调用,具体怎么调用,系统已经封装为库函数,我们不需要去管,只需要知道可以通过这个函数进行系统调用,使用了这个函数也就可以理解为从用户态跳入了内核层(我更喜欢称syscall调用为系统层)。

内核系统调用分析

当调用syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str()); 后进入内核的第一个函数就是
可以查看这个宏SYSCALL_DEFINE4,这个宏定义在include\linux\syscall.h中,可以仔细看一下。我这里简单说下结论,用SYSCALL_DEFINEX定义的函数,
第一个参数为函数名后缀,如上图,则这个定义的函数名字为SyS_reboot。
第二个,第三个一起看,为类型加变量名。
可以发现一共有4组类型加变量名的 变量。所以DEFINE4 中的数字4就代表SyS_reboot有4个参数。同理SYSCALL_DEFINE2就是有2个参数,具体可以去看这个宏的定义。

到这里其实也不需要怎么分析,各位读者看看就应该知道是怎么回事了。下面我简单讲一下。

首先对应用层中syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());传递进来的参数进行分析,判断校验

这里提一下,很多命令行输入reboot不生效,系统没有出现重启,有一部分原因是因为这里判断出错。各位如果有碰到需要多注意下,应用层的传递参数是否是别的值。

然后就调用kernel_restart(buffer);函数,这里需要注意,这里已经是内核重启函数的实现方式了,对于不同厂商,每个人都有定义自己的重启函数,也就是说有些为了特殊需要,可能并没有使用kernel_restart函数进行重启。

kernel_restart_prepare函数进行设备重启前的关闭。这边顺带提一下,如果我们的外设需要在复位的时候做一些工作,可以将shutdown函数注册到设备函数中,然后系统在接收到reboot命令后,最终遍历设备列表并执行shutdown函数,这个步骤就是在kernel_restart_prepare中实现的。
这里主要看一下machine_restart函数。

restart函数调用do_kernel_restart进行复位系统。多数厂商都在这个函数中进行自定义的重启方式。
这里给大家说个野路子
有时候因为一些qiqigaygay的原因,reboot经常出错。这时候我们可以考虑使用硬复位,也就是reset,例如使用开关电路控制电源芯片,然后将控制pin接入cpu的gpio管脚。然后我们在do_kernel_restart这个函数中将gpio管脚拉高拉低来断开电源。。。走投无路的办法,慎用慎用。

我们接着分析,

这里我们do_kernel_restart里面做的是发送一个通知,通知各个通过register_restart_handler注册的钩子函数,执行这个关机函数。我们可以使用sourceinsight搜索这个函数,最后我发现在我系统中是使用看门狗复位来实现重启的。



这里的打印都是我的跟踪打印,大家可以忽略。

最后我们发现是调用的看门狗的restart。然后进入看门狗驱动发现注册的函数

最后在imx2_wdt_restart中对看门狗进行溢出写入,然后看门狗引发系统复位。

到此解析结束。

写在最后

给新手们一个小建议,我们作为新手,或者说我们更多的是为了解决问题,因此我建议,佛系一点,活用打印,不求甚解。我们目的是知道整个的流程,然后针对专一的东西进行深入剖析即可。例如上述文章,reboot的过程又怎是简简单单一篇文章就可以分析透彻与干净,但只需要抓住最终的关键函数,盘他!盘的圆润光滑就好了,盘的最后自己都觉得是这么一回事就行了。

以上有哪些没有写明白,或者有写错的位置,各位可以指出。谢谢。

linux reboot流程,从命令行到内核全解析相关推荐

  1. linux shell中的命令自动补全(compgen complete)与 命令行参数解析

    linux shell中的命令自动补全(compgen complete)与 命令行参数解析 标签: shell脚本 2013-12-31 21:56 6661人阅读 评论(6) 收藏 举报 分类: ...

  2. linux 高效的文件系统事件监控 内核级解析方案 inotify

    转载 http://www.lvtao.net/config/inotify.html linux 高效的文件系统事件监控 内核级解析方案 inotify 安装inotify-tools (http: ...

  3. linux的compgen命令,linux shell中的命令自动补全(compgen complete)与 命令行参数解析...

    很多时候,当我们写一个脚本时,我们总会提供一些可选的命令选项.当可选项比较多的时候,比如git, 如果能够提供命令自动补全,无疑是锦上添花的事.而且个人认为,这种方式,比采用将命令做成选择菜单要更好一 ...

  4. Linux远程管理常用命令(超全超详细)【持续更新】

    目录 1. shutdown命令 2.ifconfig命令 3.uname命令 4.uptime命令 5.free命令 6.who命令 7.last命令 8.history命令 9.ping命令 10 ...

  5. linux睡眠流程,sleep命令_Linux sleep命令:让程序暂停或休眠一段时间

    搜索热词 sleep 命令,让睡眠变得有学问.本文将对 sleep 命令进行详细地介绍,一起来看看 sleep 命令如何让睡眠变得有学问. 先让程序睡上 30 秒 从字面意思看,想必你已经猜出来 sl ...

  6. arm 饱和指令_ARM内核全解析,从ARM7,ARM9到CortexA7,A8,A9,A12,A15到CortexA53,A57

    小伙伴们,你们的干货又来啦~快来拿好你的小板凳学习吧~ 首先我们介绍下 ARM cortex三个A,R ,M系列产品图谱及对应应用领域 1,A系列:顶级主控,手机平板AP应用处理器,GPS... 2, ...

  7. linux查看wifi信号命令_无线信号强度解析及linux如何查看wifi信号强弱等

    dBdB是一个表征相对值的值,纯粹的比值,只表示两个量的相对大小关系,没有单位,当考虑甲的功率相比于乙功率大或小多少个dB时,按下面的计算公式:10log(甲功率/乙功率),如果采用两者的电压比计算, ...

  8. 云运维 linux centos7.2 LAMP环境搭建 一键全解析

    LAMP架构 LAMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写: LAMP=Linux+Apache(httpd)+MySQL+PHP 工作模式: MySQl安装 MySQ ...

  9. ARM内核全解析,从ARM7 ARM9到Cortex-A7 A8 Cortex-A53 A57 A72

    以下总结一下近几年来手机端较为主流的ARM处理器. 以由高到低的方式来看,ARM处理器大体上可以排序为: Cortex-A72处理器.Cortex-A57处理器.Cortex-A53处理器.Cort ...

最新文章

  1. 暑期集训2:ACM基础算法 练习题B:CF-1008B
  2. 一文览尽基于激光雷达点云(lidar)的目标检测方法
  3. shell中的IFS
  4. dnf跨一服务器修复,DNF跨区服务器炸裂:一阶段史诗回档,官方补偿何在
  5. C++高级程序员基本技能你都具备吗?
  6. ASP.NET MVC 4使用PagedList.Mvc分页
  7. Notepad++ 快捷键 大全
  8. 升级鸿蒙系统无法选择应用,申请鸿蒙系统有一个应用选择怎么选择呢
  9. 解决Python中PyCharm导入模块时,模块名下出现红色波浪线的问题
  10. 关于码云的一些基本知识_一些关于 CPU 的基本知识
  11. latex入门到精通----IEEE模块为例
  12. 无法检测的新型 Linux 恶意软件利用 Dogecoin API 攻击 Docker 服务器
  13. docker学习笔记-6.容器关联,容器网络
  14. mysql where range_MYSQL explain详解之range
  15. 最速下滑法c语言程序,最速下降法 C语言.doc
  16. html象棋游戏源码分享
  17. 统计学中p值计算公式_统计学中的p值怎么算,具体步骤
  18. 这个被上帝抛弃的国家,创立了全球一半的科技公司
  19. 通信专业实务(三)——接入网
  20. Linuux-alsa-左右声道处理

热门文章

  1. 01【托业口语】- PART1 Read a text aloud
  2. c盘清理软件:清理垃圾、扩大c盘和系统迁移
  3. 家庭理财管理系统的设计与实现【功能展示+功能描述】
  4. 叶子的离开,是因为风的追求,还是树的不挽留?
  5. 2022-2028全球子宫支架行业调研及趋势分析报告
  6. 克隆系统怎么保护服务器,克隆系统引起MSDTC服务工作不正常
  7. python selenium自动化(二)自动化注册流程
  8. 企业发展理论(八):知识理论
  9. 【数据结构】Java实现双向链表
  10. 喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以多少汽水(编程实现)