-----------------------------------------------------------------------
本文系本站原創,歡迎轉載!
轉載請註明出處:http://blog.csdn.net/android_huber
交流郵箱:[email protected]
-----------------------------------------------------------------------
在Android下,我們在命令行中敲入reboot後系統的重啓首先是執行的reboot這個應用程序。這是一個比較簡單的小程序,其源碼在 system/core/toolbox/reboot.c,主要的代碼如下:
if(poweroff)
ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
else if(argc > optind)
ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
else
ret = reboot(RB_AUTOBOOT);
這邊都是通過系統調用進入內核的,LINUX_REBOOT_MAGIC1和LINUX_REBOOT_MAGIC2是兩個幻數。進入kernel/sys.c中
/*
* 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;
mutex_lock(&reboot_mutex);
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();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
ret = -EFAULT;
break;
}
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;
}
mutex_unlock(&reboot_mutex);
return ret;
}
我們通過命令行敲reboot的話進入的是LINUX_REBOOT_CMD_RESTART這個分支,可以看到接下來會調用kernel_restart(NULL);
/**
* kernel_restart - reboot the system
* @cmd: pointer to buffer containing command to execute for restart
* or %NULL
*
* Shutdown everything and perform a clean reboot.
* This is not safe to call in interrupt context.
*/
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
if (!cmd)
printk(KERN_EMERG "Restarting system.\n");
else
printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
kmsg_dump(KMSG_DUMP_RESTART);
machine_restart(cmd);
}
這個函數裏面會打印出我們常看到的log,Restarting system.
kernel_restart_prepare(cmd);裏會去調用設備的shutdown接口,去power off設備,並且發送SYS_RESTART的廣播,
void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
device_shutdown();
sysdev_shutdown();
}
接着執行machine_restart(cmd);我們會調到arch/x86/kernel/reboot.c中,這裏需要知道一個ops
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
};
machine_restart就是執行這行這裏的native_machine_restart
static void native_machine_restart(char *__unused)
{
printk("machine restart\n");
if (!reboot_force) {
printk("native_machine_restart reboot_force:%d\n", reboot_force);
machine_shutdown();
}
__machine_emergency_restart(0);
}
machine_shutdown();中執行一些shutdown工作,重啓的工作在__machine_emergency_restart(0);static void __machine_emergency_restart(int emergency)
{
reboot_emergency = emergency;
machine_ops.emergency_restart();
}
調用ops中的emergency_restart
static void native_machine_emergency_restart(void)
{
int i;
if (reboot_emergency)
emergency_vmx_disable_all();
tboot_shutdown(TB_SHUTDOWN_REBOOT);
/* Tell the BIOS if we want cold or warm reboot */
*((unsigned short *)__va(0x472)) = reboot_mode;
for (;;) {
/* Could also try the reset bit in the Hammer NB */
switch (reboot_type) {
case BOOT_KBD:
mach_reboot_fixups(); /* for board specific fixups */
for (i = 0; i < 10; i++) {
printk("%d\n", i);
kb_wait();
udelay(50);
outb(0xfe, 0x64); /* pulse reset low */
udelay(50);
}
case BOOT_TRIPLE:
load_idt(&no_idt);
__asm__ __volatile__("int3");
reboot_type = BOOT_KBD;
break;
#ifdef CONFIG_X86_32
case BOOT_BIOS:
machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
reboot_type = BOOT_KBD;
break;
#endif
case BOOT_ACPI:
acpi_reboot();
reboot_type = BOOT_KBD;
break;
case BOOT_EFI:
if (efi_enabled)
efi.reset_system(reboot_mode ?
EFI_RESET_WARM :
EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL);
reboot_type = BOOT_KBD;
break;
case BOOT_CF9:
port_cf9_safe = true;
/* fall through */
case BOOT_CF9_COND:
if (port_cf9_safe) {
u8 cf9 = inb(0xcf9) & ~6;
outb(cf9|2, 0xcf9); /* Request hard reset */
udelay(50);
outb(cf9|6, 0xcf9); /* Actually do the reset */
udelay(50);
}
reboot_type = BOOT_KBD;
break;
}
}
}
這邊就是重啓的最後部分了,默認的是通過BOOT_KBD方式重啓的,這種方式是通過鍵盤控制器去模擬按下鍵盤上的reset鍵來重啓的,往0x64端口中寫0xfe即可,然後系統會在__asm__ __volatile__("int3");中中斷。int3是一個breakpoint,用來使程序停止在這,等待重啓。
這裏再說下,通過cf9來重啓,用註釋來解釋Use the so-called "PCI reset register", CF9,通過這個寄存器可以使系統hard reset。
對於上面的一些重啓方式,我將在下一篇文章裏去介紹他們的用法,以及我在調試reboot中遇到的一些問題,這篇文章主要就是分析一下reboot的流程。
同樣,附一張流程圖:
需要清晰大圖的請留郵箱