BusyBox reboot 流程分析

基于Linux与Busybox的Reboot命令流程分析 这段时间,在忙到一个项目时,需要在busybox中用到reboot命令,开始在busybox中的shell中输入reboot命令,始终如下的信息,然后就停止在那里了,无法重启...为了彻底的弄明白这个问题,我在网络上找了很久,终于有个人写的一个reboot流程分析,我就借花献佛.在这里重新分析下busybox是如何运行这个命令 阅读详情

用户在console下输入reboot命令,

busybox会调用到halt_main

 

int halt_main(int argc ATTRIBUTE_UNUSED, char **argv)

{

.....

/* Perform action. */
 if (ENABLE_INIT && !(flags & 4)) {
  if (ENABLE_FEATURE_INITRD) {
   pid_t *pidlist = find_pid_by_name("linuxrc");
   if (pidlist[0] > 0)
    rc = kill(pidlist[0], signals[which]);
   if (ENABLE_FEATURE_CLEAN_UP)
    free(pidlist);
  }
  if (rc)
   rc = kill(1, signals[which]);    //如果INIT 进程有,就发信号给它
 } else
  rc = reboot(magic[which]);   //否则直接调用kernel的reboot

 if (rc)
  bb_error_msg("no");
 return rc; 

}

 

在init.c/init_main中(这是INIT被config 以后才会使用的函数,也就是busybox默认的init)

int init_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
 struct init_action *a;
 pid_t wpid;

......

 bb_signals(0
   + (1 << SIGUSR1)  /* halt */
   + (1 << SIGUSR2)  /* poweroff */
   + (1 << SIGTERM)  /* reboot */
   , halt_reboot_pwoff);   //挂载reboot,halt,poweroff 信号处理的handler

.....

}

 

所以此时当halt_main中发信号要reboot以后,系统进入halt_reboot_pwoff

static void halt_reboot_pwoff(int sig)

{

       const char *m;

       int rb;

 

       kill_all_processes();   //杀死所有进程,也就是发消息

 

       m = "halt";

       rb = RB_HALT_SYSTEM;

       if (sig == SIGTERM) {

              m = "reboot";

              rb = RB_AUTOBOOT;

       } else if (sig == SIGUSR2) {

              m = "poweroff";

              rb = RB_POWER_OFF;

       }

       message(L_CONSOLE | L_LOG, "Requesting system %s", m);

       /* allow time for last message to reach serial console */

       sleep(2);

       init_reboot(rb);   //真正调用kernel的重启动

       loop_forever();

}

 

static void kill_all_processes(void)

{

       /* run everything to be run at "shutdown".  This is done _prior_

        * to killing everything, in case people wish to use scripts to

        * shut things down gracefully... */

       run_actions(SHUTDOWN);  //调用run_action ,它会parse inittab中的action去做一些事情

 

       /* first disable all our signals */

       sigprocmask_allsigs(SIG_BLOCK);

 

       message(L_CONSOLE | L_LOG, "The system is going down NOW!");

 

       /* Allow Ctrl-Alt-Del to reboot system. */

       init_reboot(RB_ENABLE_CAD);   //告诉系统可以用CAD来重启

 

       /* Send signals to every process _except_ pid 1 */

       message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");

       kill(-1, SIGTERM);  //发送终止信号

       sync(); //刷cache回设备

       sleep(1);

 

       message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL");

       kill(-1, SIGKILL);  //杀死进程

       sync();

       sleep(1);

}

 

/* Run all commands of a particular type */

static void run_actions(int action_type)

{

       struct init_action *a, *tmp;

 

       for (a = init_action_list; a; a = tmp) {

              tmp = a->next;

              if (a->action_type & action_type) {

                     // Pointless: run() will error out if open of device fails.

                     ///* a->terminal of "" means "init's console" */

                     //if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {

                     //     //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);

                     //     delete_init_action(a);

                     //} else

                     if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {

                            waitfor(run(a));   //做事的是run函数

                            delete_init_action(a);

                     } else if (a->action_type & ONCE) {

                            run(a);

                            delete_init_action(a);

                     } else if (a->action_type & (RESPAWN | ASKFIRST)) {

                            /* Only run stuff with pid==0.  If they have

                             * a pid, that means it is still running */

                            if (a->pid == 0) {

                                   a->pid = run(a);

                            }

                     }

              }

       }

}

 

static pid_t run(const struct init_action *a)

{

  …

       init_exec(a->command); //真正执行命令, 这个函数应该会使用之前parse inittab 中产生的shutddown action

  …

}

 

回头来看 init_reboot

先看下magic 定义

       RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */

       RB_ENABLE_CAD = 0x89abcdef,

       RB_DISABLE_CAD = 0,

       RB_POWER_OFF = 0x4321fedc,

       RB_AUTOBOOT = 0x01234567,

 

对比linux kernel的看看,一致

#define  LINUX_REBOOT_CMD_RESTART 0x01234567

#define  LINUX_REBOOT_CMD_HALT              0xCDEF0123

#define  LINUX_REBOOT_CMD_CAD_ON         0x89ABCDEF

#define  LINUX_REBOOT_CMD_CAD_OFF 0x00000000

#define  LINUX_REBOOT_CMD_POWER_OFF   0x4321FEDC

#define  LINUX_REBOOT_CMD_RESTART2      0xA1B2C3D4

#define  LINUX_REBOOT_CMD_SW_SUSPEND       0xD000FCE2

#define  LINUX_REBOOT_CMD_KEXEC            0x45584543

 

static void init_reboot(unsigned long magic)

{

       pid_t pid;

       /* We have to fork here, since the kernel calls do_exit(0) in

        * linux/kernel/sys.c, which can cause the machine to panic when

        * the init process is killed.... */

       pid = vfork();

       if (pid == 0) { /* child */

              reboot(magic);  //最重要的事情,调用reboot

              _exit(0);

       }

       waitfor(pid);

}

 

Busybox的调用顺序看完了,我们来看看linux reboot做了哪些事情

Linux2.6.28 kernel(是不是有点老,手边就这个最方便) sys.c/sys_reboot

Sys_reboot 是reboot的系统调用,自然我们看这个

asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg)

{

 …

case LINUX_REBOOT_CMD_RESTART:

              kernel_restart(NULL);         //系统重启

              break;

 

       case LINUX_REBOOT_CMD_CAD_ON:

              C_A_D = 1;                //允许用户ctrl_alt_del重启

              break;

 

       case LINUX_REBOOT_CMD_CAD_OFF:

              C_A_D = 0;

              break;

 

       case LINUX_REBOOT_CMD_HALT:

              kernel_halt();

              unlock_kernel();

              do_exit(0);

              break;

 

       case LINUX_REBOOT_CMD_POWER_OFF:

              kernel_power_off();

              unlock_kernel();

              do_exit(0);

              break;

….

}

系统重启:

void kernel_restart(char *cmd)

{

kernel_restart_prepare(cmd);  //这个函数中kernel/和设备驱动等需要做重启前的准备工作

if (!cmd) {

  printk(KERN_EMERG "Restarting system./n");

} else {

  printk(KERN_EMERG "Restarting system with command '%s'./n", cmd);

}

printk("./n");

machine_restart(cmd);

}

kernel 的重启准备

void kernel_restart_prepare(char *cmd)
{
 blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); //调用reboot 的notifier 链表,很多必要的设备,驱动都会注册一个reboot_notifier,这样在内核准备重启时还有机会把设备最后需要做的事情完成
 system_state = SYSTEM_RESTART;
 device_shutdown();
 sysdev_shutdown();
}

 

设备驱动会调用这个函数来注册reboot notifier:

/**
 * register_reboot_notifier - Register function to be called at reboot time
 * @nb: Info about notifier function to be called
 *
 * Registers a function with the list of functions
 * to be called at reboot time.
 *
 * Currently always returns zero, as blocking_notifier_chain_register()
 * always returns zero.
 */
int register_reboot_notifier(struct notifier_block *nb)
{
 return blocking_notifier_chain_register(&reboot_notifier_list, nb);
}

看看MTD 设备挂的接口:

struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
 .....

 mtd->priv = map;
 mtd->type = MTD_NORFLASH;

 /* Fill in the default mtd operations */
 mtd->erase   = cfi_intelext_erase_varsize;
 mtd->read    = cfi_intelext_read;
 mtd->write   = cfi_intelext_write_words;
 mtd->sync    = cfi_intelext_sync;
 mtd->lock    = cfi_intelext_lock;
 mtd->unlock  = cfi_intelext_unlock;
 mtd->suspend = cfi_intelext_suspend;
 mtd->resume  = cfi_intelext_resume;
 mtd->flags   = MTD_CAP_NORFLASH;
 mtd->name    = map->name;
 mtd->writesize = 1;

 mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;

....

}

 

static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
{
...
 register_reboot_notifier(&mtd->reboot_notifier);

....
 return NULL;
}

 

再看看这个函数,如果是bus就调用bus的shutdown,如果设备就调用设备的。

/**
 * device_shutdown - call ->shutdown() on each device to shutdown.
 */
void device_shutdown(void)
{
 struct device *dev, *devn;

 list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
    kobj.entry) {
  if (dev->bus && dev->bus->shutdown) {
   dev_dbg(dev, "shutdown/n");
   dev->bus->shutdown(dev);
  } else if (dev->driver && dev->driver->shutdown) {
   dev_dbg(dev, "shutdown/n");
   dev->driver->shutdown(dev);
  }
 }
 kobject_put(sysfs_dev_char_kobj);
 kobject_put(sysfs_dev_block_kobj);
 kobject_put(dev_kobj);
}

 

其他看看吧

void machine_restart(char *cmd)

{

       machine_ops.restart(cmd);

}

struct machine_ops machine_ops = {

       .power_off = native_machine_power_off,

       .shutdown = native_machine_shutdown,

       .emergency_restart = native_machine_emergency_restart,

       .restart = native_machine_restart,

       .halt = native_machine_halt,

#ifdef CONFIG_KEXEC

       .crash_shutdown = native_machine_crash_shutdown,

#endif

};

 

static void native_machine_restart(char *__unused)

{

       printk("machine restart/n");

 

       if (!reboot_force)

              machine_shutdown();  //à最后指向native_machine_shutdown

       machine_emergency_restart(); //->最后指向native_machine_emergency_restart

}

 

native_machine_emergency_restart 中定义了集中reboot的的方式

方式如下,它们由reboot_setup设置,用户也可以传入,default by KBD。

/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]

   warm   Don't set the cold reboot flag

   cold   Set the cold reboot flag

   bios   Reboot by jumping through the BIOS (only for X86_32)

   smp    Reboot by executing reset on BSP or other CPU (only for X86_32)

   triple Force a triple fault (init)

   kbd    Use the keyboard controller. cold reset (default)

   acpi   Use the RESET_REG in the FADT

   efi    Use efi reset_system runtime service

   force  Avoid anything that could hang.

 */

 

Reboot_setup由Setup.c/setup_arch调用,

 

顺便分析下native_machine_emergency_restart

native_machine_emergency_restart

{

 …

For (;;){

 ..

       switch (reboot_type) {

              case BOOT_KBD:

...  //使用keyboard 8042去reboot硬件

case BOOT_TRIPLE:

case BOOT_BIOS://bios boot

case BOOT_ACPI://使用ACPI table提供的方法来boot

case BOOT_EFI://使用EFI 的runtime service reset 来reset 系统

}

}

1、电源管理入门之关机重启详解 也就是说,这个接口被执行后,只有一个CPU在运行,用于完成后续的reboot动作。mhu-->transport-->scmi-->scmi_system_power-->power_domain-->ppu/system_power-->i2c/cru,最后SCP固件通过控制PMIC/CRU的硬件寄存器实现对系统的关机重启设置。调用blocking_notifier_call_chain接口,向关心reboot事件的进程,发送SYS_RESTART、 SYS_HALT或者SYS_POWER_OFF事件。 阅读详情

相关推荐

【openwrt】Openwrt系统的reboot流程

当我们在openwrt系统的终端中敲下reboot指令后,系统需要进行一系列动作后,才会真正的进行硬件重启。而这一系列的动作可以分为——应用程序的停止和内核的停止。在Openwrt系统中,应用程序的停止是1号进程(也就是。)完成的,应用程序全部停止后才会进入内核的重启流程。

分享嵌入式Linux技术知识 3110

busybox之reboot命令流程分析

busybox启动的时候,会注册reboot的处理信号。

szembed的博客 1517

高通linux-reboot 分析

reboot 分析 1       版本 平台:高通8009 busybox:1.24 linux kernel:3.18.48   2       流程 可以通过reboot、halt、poweroff等命令,对linux操作系统进行控制,具体的操作流程如下:   3       分析 在arm 板上,可知: # ls /sbin/reboot -la lrwxrwx...

智能硬件研发,欢迎交流 2447

简单理解Busybox下halt/poweroff/reboot实现及区别

关键词:halt/poweroff/reboot、reboot()、SIGUSR1/SIGTERM/SIGUSR2等。 1. busybox下的halt/poweroff/reboot实现 通过applets.h下的halt/poweroff/reboot可知,实现都在halt_main()中。 IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DRO...

weixin_30549657的博客 749

科研笔记:怎样写好博士论文?

博士论文外审避坑指南与写作要点 博士论文外审的核心关注点呈现5级优先级:科研成果(硬指标)>创新性>逻辑结构与场景合理性>文献综述与规范性>工作量验证。外审专家会重点核查:1)成果清单是否达标;2)创新点是否真实明确;3)章节逻辑是否自洽、应用场景是否细化;4)文献综述是否构建"研究坐标系";5)实验/理论支撑是否充分。需特别注意三大雷区:科学错误(直接挂稿)、伪创新、场景不合理。写作时应强化选题依据的场景细化,通过"发展阶段+跨领域对比"提升文献综述质量。

Grow into a more wonderful you 1064

【技能---ubuntu20.04更换国内镜像源】

安装好ubuntu20.04后,在下载软件等安装包的时候,速度特别的慢,为此就想着更换一下镜像源,以此来增加下载的速度!!!下面是换源的具体流程!!!提示:以下是本篇文章正文内容,下面案例可供参考以上到这里就更换完软件源了,如有不足之处,请大家斧正!!!

fyc300的博客 1万+

BusyBox 版本1.10-2

BusyBox 版本1.10-2 用户在console下输入reboot命令, busybox会调用到halt_main int halt_main(int argc ATTRIBUTE_UNUSED, char **argv) { ..... /* Perform action. */ if (ENABLE_INIT && !(flags & 4)) { if (ENABLE

sunxianchuan123的专栏 796

CKAD-CN 考试知识点分享(12) Secret - 1

步骤操作完成1提取 Deployment 中的硬编码 Secret 值✅2创建名为postgres的 Secret✅3修改 Deployment 使用引用 Secret✅4验证新 Pod 正常运行✅❌未删除原 Deployment✅(遵守要求)✅任务完成。敏感信息已从环境变量移出,安全地存储在 Kubernetes Secret 中。

轻的博客 632

linux reboot 流程,基于Linux与Busybox的Reboot命令流程分析

一:Busyobx层的分析这段时间,在忙到一个项目时,需要在busybox中用到reboot命令,开始在busybox中的shell中输入reboot命令,始终如下的信息,然后就停止在那里了,无法重启...为了彻底的弄明白这个问题,我在网络上找了很久,终于有个人写的一个reboot流程分析,我就借花献佛.在这里重新分析下busybox是如何运行这个命令,同时又是如何调用到Linux内核中的mach...

weixin_29002209的博客 909

德国冯哈勃 Faulhaber2342L012空心杯减速电机带编码器

为了制作平衡车,我在淘宝上面买了一个 Faulhaber2342L012空心杯减速电机电机,具体参数如下: 一:电机参数 型    号:德国冯哈勃Faulhaber带编码器空心杯减速电机2342L012  12V每分 钟 120转 工作电压: 12V 空载转速:8100RPM(转每分钟) 减速后速:120RPM(转每分钟) 直     径:30mm

u011511430的专栏 1万+

【python】import pandas as pd用法

是 Python 里最常用的数据分析库之一。 的意思是:导入 pandas 库,并给它起个别名 。这样用起来更简洁: 下面总结 pandas 的常见用法(配例子)。目录🔹 1. 数据结构(1) Series(一维数据,类似于数组 + 标签)(2) DataFrame(二维数据表,类似于 Excel 表格)🔹 2. 数据读写🔹 3. 数据查看🔹 4. 数据选择与索引🔹 5. 数据清洗🔹 6. 数据运算🔹 7. 数据筛选(布尔索引)🔹 8. 分组与聚合🔹 9. 排序 Pandas 常用方

2401_86285609的博客 1531

基于linux与busybox的reboot命令流程分析

http://www.xuebuyuan.com/736763.html 基于Linux与Busybox的Reboot命令流程分析 *************************************************************************************************************************** 作者:Easy...

weixin_34038293的博客 194

【HAL库】STM32CubeMX开发----STM32F407----ETH+LWIP----TCPclient客户端

STM32F407开发板 为TCPclient客户端,PC端 为TCPserver服务端,相互之间的发送和接收实验。

MQ0522的博客 3048

busybox:reboot 命令流程

busybox,reboot

JiMoKuangXiangQu的专栏 207

Dify智能体开发:大语言模型(LLM)问题分类

通过定义分类描述,问题分类器能够根据用户输入,使用 LLM 推理与之相匹配的分类并输出分类结果,向下游节点提供更加精确的信息。

王国平的博客 2249

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

上一篇: RTP负载类型及时间戳介绍
下一篇: 嵌入式Linux下开源路由器OpenWRT简介
wang-bob
博客等级 码龄20年 356粉丝 112原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值