BusyBox reboot 流程分析

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_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]);   //
否则直接调用kernelreboot

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

}

 

init.c/init_main中(这是INITconfig 以后才会使用的函数,也就是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_setupSetup.c/setup_arch调用,

 

顺便分析下native_machine_emergency_restart

native_machine_emergency_restart

{

 

For (;;){

 ..

       switch (reboot_type) {

              case BOOT_KBD:

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

case BOOT_TRIPLE:

case BOOT_BIOS://bios boot

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

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

}

}

 

你可能感兴趣的:(busybox,linux,kernel)