-----------------------------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处: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中
-
-
-
-
-
-
-
-
- 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;
-
- 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);
-
-
-
-
-
-
-
-
- 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);
-
-
- *((unsigned short *)__va(0x472)) = reboot_mode;
-
- for (;;) {
-
- switch (reboot_type) {
- case BOOT_KBD:
- mach_reboot_fixups();
-
- for (i = 0; i < 10; i++) {
- printk("%d\n", i);
- kb_wait();
- udelay(50);
- outb(0xfe, 0x64);
- 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;
-
-
- case BOOT_CF9_COND:
-
- if (port_cf9_safe) {
- u8 cf9 = inb(0xcf9) & ~6;
-
- outb(cf9|2, 0xcf9);
- udelay(50);
- outb(cf9|6, 0xcf9);
- 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的流程。
同样,附一张流程图:
需要清晰大图的请留邮箱