码迷,mamicode.com
首页 > 系统相关 > 详细

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

时间:2016-08-16 00:08:20      阅读:250      评论:0      收藏:0      [点我收藏+]

标签:

http://www.xuebuyuan.com/736763.html

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

***************************************************************************************************************************
作者:EasyWave                                                                                 时间:2013.01.26

类别:Linux 内核系统源码分析                                                             声明:转载,请保留链接

注意:如有错误,欢迎指正。这些是我学习的日志文章......

***************************************************************************************************************************

一:Busyobx层的分析

        这段时间,在忙到一个项目时,需要在busybox中用到reboot命令,开始在busybox中的shell中输入reboot命令,始终如下的信息,然后就停止在那里了,无法重启...为了彻底的弄明白这个问题,我在网络上找了很久,终于有个人写的一个reboot流程分析,我就借花献佛.在这里重新分析下busybox是如何运行这个命令,同时又是如何调用到Linux内核中的mach_reset中的arch_reset,当针对不同的ARM芯片时,作为Linux内核开发和驱动开发的朋友,对于这个流程还是一定要了解的。要不,出现问题,又如何找出问题呢。忘记了reboot的打印信息了,如下:

The system is going down NOW !!

Sending SIGTERM to all processes.

Sending SIGKILL to all processes.

Please stand by while rebooting the system.

Restarting system.

.


通过分析busybox1.20.0的代码可以看出在init.c中有这样一行的代码,如下:

int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;

int init_main(int argc UNUSED_PARAM, char **argv)

{

          static const int magic[] = {

                    RB_HALT_SYSTEM,

                    RB_POWER_OFF,

                    RB_AUTOBOOT

          };

          static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };

          ......

          /* struct sysinfo is linux-specific */

#ifdef __linux__

          /* Make sure there is enough memory to do something useful. */

          if (ENABLE_SWAPONOFF) { //是否配置了swapoff命令

                    struct sysinfo info;

 

                    if (sysinfo(&info) == 0

                     && (info.mem_unit ? info.mem_unit : 1) * (long long)info.totalram < 1024*1024

                    ) {

                               message(L_CONSOLE, "Low memory, forcing swapon");

                               /* swapon -a requires /proc typically */

                               new_init_action(SYSINIT, "mount -t proc proc /proc", "");

                               /* Try to turn on swap */

                               new_init_action(SYSINIT, "swapon -a", "");

                               run_actions(SYSINIT);   /* wait and removing */

                    }

          }

#endif

          ......

/* Make the command line just say "init"  - thats all, nothing else */

          strncpy(argv[0], "init", strlen(argv[0]));

          /* Wipe argv[1]-argv[N] so they don‘t clutter the ps listing */

          while (*++argv)

                    memset(*argv, 0, strlen(*argv));

 

          /* Set up signal handlers */

          /* Set up signal handlers */

          if (!DEBUG_INIT) {

                    struct sigaction sa;

 

                    bb_signals(0

                               + (1 << SIGUSR1) /* halt */

                               + (1 << SIGTERM) /* reboot */

                               + (1 << SIGUSR2) /* poweroff */

                               , halt_reboot_pwoff);//看到这个halt_reboot_pwoff

                    signal(SIGQUIT, restart_handler); /* re-exec another init */ //看到这个restart_handler函数,这是我们需要分析的

 

                    /* Stop handler must allow only SIGCONT inside itself */

                    memset(&sa, 0, sizeof(sa));

                    sigfillset(&sa.sa_mask);

                    sigdelset(&sa.sa_mask, SIGCONT);

                    sa.sa_handler = stop_handler;

                    /* NB: sa_flags doesn‘t have SA_RESTART.

                     * It must be able to interrupt wait().

                     */

                    sigaction_set(SIGTSTP, &sa); /* pause */

                    /* Does not work as intended, at least in 2.6.20.

                     * SIGSTOP is simply ignored by init:

                     */

                    sigaction_set(SIGSTOP, &sa); /* pause */

 

                    /* SIGINT (Ctrl-Alt-Del) must interrupt wait(),

                     * setting handler without SA_RESTART flag.

                     */

                    bb_signals_recursive_norestart((1 << SIGINT), record_signo);

          }

          ......

}

单独拿出halt_reboot_pwoff和restart_handler这个函数来看看

/* The SIGUSR[12]/SIGTERM handler */

static void halt_reboot_pwoff(int sig) NORETURN;

static void halt_reboot_pwoff(int sig)

{

          const char *m;

          unsigned rb;

 

          /* We may call run() and it unmasks signals,

           * including the one masked inside this signal handler.

           * Testcase which would start multiple reboot scripts:

           *  while true; do reboot; done

           * Preventing it:

           */

          reset_sighandlers_and_unblock_sigs();

 

          run_shutdown_and_kill_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, "Requesting system %s", m);

          pause_and_low_level_reboot(rb);

          /* not reached */

}


restart_handler函数如下:

/* Handler for QUIT - exec "restart" action,

 * else (no such action defined) do nothing */

static void restart_handler(int sig UNUSED_PARAM)

{

          struct init_action *a;

 

          for (a = init_action_list; a; a = a->next) {

                    if (!(a->action_type & RESTART))

                               continue;

 

                    /* Starting from here, we won‘t return.

                     * Thus don‘t need to worry about preserving errno

                     * and such.

                     */

 

                    reset_sighandlers_and_unblock_sigs();

 

                    run_shutdown_and_kill_processes();

 

#ifdef RB_ENABLE_CAD

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

                     * This is how kernel sets it up for init, we follow suit.

                     */

                    reboot(RB_ENABLE_CAD); /* misnomer */

#endif

 

                    if (open_stdio_to_tty(a->terminal)) {

                               dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);

                               /* Theoretically should be safe.

                                * But in practice, kernel bugs may leave

                                * unkillable processes, and wait() may block forever.

                                * Oh well. Hoping "new" init won‘t be too surprised

                                * by having children it didn‘t create.

                                */

                               //while (wait(NULL) > 0)

                               //        continue;

                               init_exec(a->command);

                    }

                    /* Open or exec failed */

                    pause_and_low_level_reboot(RB_HALT_SYSTEM);

                    /* not reached */

          }

}


通过分析,我们看到他们都会有调用这两个函数:reset_sighandlers_and_unblock_sigs();以及 run_shutdown_and_kill_processes();,我们重点关注如下这个函数:

static void run_shutdown_and_kill_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);

 

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

 

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

          kill(-1, SIGTERM);

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

          sync();

          sleep(1);

 

          kill(-1, SIGKILL);

          message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");

          sync();

          /*sleep(1); - callers take care about making a pause */

}


嘿嘿,终于看到了上面的打印信息:The system is going down NOW !! 以及Sending SIGTERM to all processes. 同时在上面的halt_reboot_pwoff和restart_handler中都会调用这样一个函数,如下:

static void pause_and_low_level_reboot(unsigned magic) NORETURN;

static void pause_and_low_level_reboot(unsigned magic)

{

          pid_t pid;

 

          /* Allow time for last message to reach serial console, etc */

          sleep(1);

 

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

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

           * the init process exits... */

          pid = vfork();

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

                    reboot(magic);

                    _exit(EXIT_SUCCESS);

          }

          while (1)

                    sleep(1);

}


看到了吗?有一个reboot(magic)函数,对于vfork函数,请参考fork函数。这里不多说了.... 我们现在来看看reboot.h文件,如下:

/*

 * Definitions related to the reboot() system call,

 * shared between init.c and halt.c.

 */

 

#include <sys/reboot.h>

 

#ifndef RB_HALT_SYSTEM

# if defined(__linux__)

#  define RB_HALT_SYSTEM  0xcdef0123

#  define RB_ENABLE_CAD   0x89abcdef

#  define RB_DISABLE_CAD  0

#  define RB_POWER_OFF    0x4321fedc

#  define RB_AUTOBOOT     0x01234567

# elif defined(RB_HALT)

#  define RB_HALT_SYSTEM  RB_HALT

# endif

#endif

 

/* Stop system and switch power off if possible.  */

#ifndef RB_POWER_OFF

# if defined(RB_POWERDOWN)

#  define RB_POWER_OFF  RB_POWERDOWN

# elif defined(__linux__)

#  define RB_POWER_OFF  0x4321fedc

# else

#  warning "poweroff unsupported, using halt as fallback"

#  define RB_POWER_OFF  RB_HALT_SYSTEM

# endif

#endif

而在linux的内核中的定义如下:


busybox和linux内核中的REBOOT的定义值是一样的。看到了没有了。这个很重要的哦,否则busybox是无法调用linux内核的reboot函数。

 

二:Linux内核层的分析


Linux内核是如何衔接busybox的reboot函数的呢,如下代码:

/*

 * Reboot system call: for obvious reasons only root may call it,

 * and even root needs to set up some magic numbers in the registers

 * so that some mistake won‘t make this reboot the whole machine.

 * You can also set the meaning of the ctrl-alt-del-key here.

 *

 * reboot doesn‘t sync: do that yourself before calling this.

 */

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,

                    void __user *, arg)

{

          char buffer[256];

          int ret = 0;

 

          /* We only trust the superuser with rebooting the system. */

          if (!capable(CAP_SYS_BOOT))

                    return -EPERM;

 

          /* For safety, we require "magic" arguments. */

          if (magic1 != LINUX_REBOOT_MAGIC1 ||

              (magic2 != LINUX_REBOOT_MAGIC2 &&

                          magic2 != LINUX_REBOOT_MAGIC2A &&

                               magic2 != LINUX_REBOOT_MAGIC2B &&

                          magic2 != LINUX_REBOOT_MAGIC2C))

                    return -EINVAL;

 

          /* Instead of trying to make the power_off code look like

           * halt when pm_power_off is not set do it the easy way.

           */

          if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)

                    cmd = LINUX_REBOOT_CMD_HALT;

 

          lock_kernel();

          switch (cmd) {

          case LINUX_REBOOT_CMD_RESTART:

                    kernel_restart(NULL); //这个就是重新启动Linx的命令

                    break;

 

          case LINUX_REBOOT_CMD_CAD_ON:

                    C_A_D = 1;

                    break;

 

          case LINUX_REBOOT_CMD_CAD_OFF:

                    C_A_D = 0;

                    break;

 

          case LINUX_REBOOT_CMD_HALT:

                    kernel_halt();

                    unlock_kernel();

                    do_exit(0);

                    panic("cannot halt");

 

          case LINUX_REBOOT_CMD_POWER_OFF:

                    kernel_power_off();

                    unlock_kernel();

                    do_exit(0);

                    break;

 

          case LINUX_REBOOT_CMD_RESTART2:

                    if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {

                               unlock_kernel();

                               return -EFAULT;

                    }

                    buffer[sizeof(buffer) - 1] = ‘\0‘;

 

                    kernel_restart(buffer);

                    break;

 

#ifdef CONFIG_KEXEC

          case LINUX_REBOOT_CMD_KEXEC:

                    ret = kernel_kexec();

                    break;

#endif

 

#ifdef CONFIG_HIBERNATION

          case LINUX_REBOOT_CMD_SW_SUSPEND:

                    ret = hibernate();

                    break;

#endif

 

          default:

                    ret = -EINVAL;

                    break;

          }

          unlock_kernel();

          return ret;

}


继续跟踪kernel_restart()函数,如下:

 

最终会调用一个machine_restart(cmd)函数,这个是跟具体的芯片有很大的关系的,我们进一步的分析如下:

 

 

 

看到了吗,最终是调用arch_reset来复位整个系统的。同时我们也看到了S3C2440的reset的函数如下:

 

在arm_pm_restart = s3c24xx_pm_restart()函数,最终也是调用arm_machine_restart(mod, cmd)来实现的。而在arm_machine_restart()函数中,最终也是调用arch_reset()函数来实现,而这个函数是在哪里呢。在S3C2440没有看到arch_reset函数的实现,因此从S3C2410中找到了如下的代码,请继续看下面的代码:

 

       终于看到了arch_reset函数,最终是采用S3C2410或者S3C2440的WatchDog来实现reboot的命令的。大家可以想想,busybox的poweroff命令,是如何实现通过Linux系统关闭整个系统的电源呢,其实很简单,只需要实现下面的函数中的pm_power_off的回调函数即可。

 

       我们可以通过一个GPIO来控制整个系统的电源,而通过上面的pm_power_off的回调函数来实现,只需要在pm_power_off函数对GPIO进行操作就可以了。你看不是很简单吗?

 

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

标签:

原文地址:http://www.cnblogs.com/embedded-linux/p/5774516.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!