***************************************************************************************************************************
作者: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 };
- ......
-
- #ifdef __linux__
-
- if (ENABLE_SWAPONOFF) {
- 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");
-
- new_init_action(SYSINIT, "mount -t proc proc /proc", "");
-
- new_init_action(SYSINIT, "swapon -a", "");
- run_actions(SYSINIT);
- }
- }
- #endif
- ......
-
- strncpy(argv[0], "init", strlen(argv[0]));
-
- while (*++argv)
- memset(*argv, 0, strlen(*argv));
-
-
-
- if (!DEBUG_INIT) {
- struct sigaction sa;
-
- bb_signals(0
- + (1 << SIGUSR1)
- + (1 << SIGTERM)
- + (1 << SIGUSR2)
- , halt_reboot_pwoff);
- signal(SIGQUIT, restart_handler);
-
-
- memset(&sa, 0, sizeof(sa));
- sigfillset(&sa.sa_mask);
- sigdelset(&sa.sa_mask, SIGCONT);
- sa.sa_handler = stop_handler;
-
-
-
- sigaction_set(SIGTSTP, &sa);
-
-
-
- sigaction_set(SIGSTOP, &sa);
-
-
-
-
- bb_signals_recursive_norestart((1 << SIGINT), record_signo);
- }
- ......
- }
单独拿出halt_reboot_pwoff和restart_handler这个函数来看看
-
- static void halt_reboot_pwoff(int sig) NORETURN;
- static void halt_reboot_pwoff(int sig)
- {
- const char *m;
- unsigned rb;
-
-
-
-
-
-
-
- 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);
-
- }
restart_handler函数如下:
-
-
- 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;
-
-
-
-
-
-
- reset_sighandlers_and_unblock_sigs();
-
- run_shutdown_and_kill_processes();
-
- #ifdef RB_ENABLE_CAD
-
-
-
- reboot(RB_ENABLE_CAD);
- #endif
-
- if (open_stdio_to_tty(a->terminal)) {
- dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
-
-
-
-
-
-
-
-
- init_exec(a->command);
- }
-
- pause_and_low_level_reboot(RB_HALT_SYSTEM);
-
- }
- }
通过分析,我们看到他们都会有调用这两个函数:reset_sighandlers_and_unblock_sigs();以及 run_shutdown_and_kill_processes();,我们重点关注如下这个函数:
- static void run_shutdown_and_kill_processes(void)
- {
-
-
-
- run_actions(SHUTDOWN);
-
- message(L_CONSOLE | L_LOG, "The system is going down NOW!");
-
-
- 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();
-
- }
嘿嘿,终于看到了上面的打印信息: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;
-
-
- sleep(1);
-
-
-
-
- pid = vfork();
- if (pid == 0) {
- reboot(magic);
- _exit(EXIT_SUCCESS);
- }
- while (1)
- sleep(1);
- }
看到了吗?有一个reboot(magic)函数,对于vfork函数,请参考fork函数。这里不多说了.... 我们现在来看看reboot.h文件,如下:
-
-
-
-
-
- #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
-
-
- #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函数的呢,如下代码:
-
-
-
-
-
-
-
-
- SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
- void __user *, arg)
- {
- char buffer[256];
- int ret = 0;
-
-
- if (!capable(CAP_SYS_BOOT))
- return -EPERM;
-
-
- if (magic1 != LINUX_REBOOT_MAGIC1 ||
- (magic2 != LINUX_REBOOT_MAGIC2 &&
- magic2 != LINUX_REBOOT_MAGIC2A &&
- magic2 != LINUX_REBOOT_MAGIC2B &&
- magic2 != LINUX_REBOOT_MAGIC2C))
- return -EINVAL;
-
-
-
-
- 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);
- 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进行操作就可以了。你看不是很简单吗?
转自:http://blog.csdn.net/wavemcu/article/details/8544333