***************************************************************************************************************************
作者: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