在Android下,我们在命令行中敲入reboot后系统的重启首先是执行的reboot这个应用程序。这是一个比较简单的小程序,其源码在 system/core/toolbox/reboot.c,主要的代码如下:
01.if(poweroff)
02. ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
03.else if(argc > optind)
04. ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
05.else
06. ret = reboot(RB_AUTOBOOT);
这边都是通过系统调用进入内核的,LINUX_REBOOT_MAGIC1和LINUX_REBOOT_MAGIC2是两个幻数。进入kernel/sys.c中
01./*
02. * Reboot system call: for obvious reasons only root may call it,
03. * and even root needs to set up some magic numbers in the registers
04. * so that some mistake won't make this reboot the whole machine.
05. * You can also set the meaning of the ctrl-alt-del-key here.
06. *
07. * reboot doesn't sync: do that yourself before calling this.
08. */
09.SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
10. void __user *, arg)
11.{
12. char buffer[256];
13. int ret = 0;
14.
15. /* We only trust the superuser with rebooting the system. */
16. if (!capable(CAP_SYS_BOOT))
17. return -EPERM;
18.
19. /* For safety, we require "magic" arguments. */
20. if (magic1 != LINUX_REBOOT_MAGIC1 ||
21. (magic2 != LINUX_REBOOT_MAGIC2 &&
22. magic2 != LINUX_REBOOT_MAGIC2A &&
23. magic2 != LINUX_REBOOT_MAGIC2B &&
24. magic2 != LINUX_REBOOT_MAGIC2C))
25. return -EINVAL;
26.
27. /* Instead of trying to make the power_off code look like
28. * halt when pm_power_off is not set do it the easy way.
29. */
30. if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
31. cmd = LINUX_REBOOT_CMD_HALT;
32.
33. mutex_lock(&reboot_mutex);
34. switch (cmd) {
35. case LINUX_REBOOT_CMD_RESTART:
36. kernel_restart(NULL);
37. break;
38.
39. case LINUX_REBOOT_CMD_CAD_ON:
40. C_A_D = 1;
41. break;
42.
43. case LINUX_REBOOT_CMD_CAD_OFF:
44. C_A_D = 0;
45. break;
46.
47. case LINUX_REBOOT_CMD_HALT:
48. kernel_halt();
49. do_exit(0);
50. panic("cannot halt");
51.
52. case LINUX_REBOOT_CMD_POWER_OFF:
53. kernel_power_off();
54. do_exit(0);
55. break;
56.
57. case LINUX_REBOOT_CMD_RESTART2:
58. if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
59. ret = -EFAULT;
60. break;
61. }
62. buffer[sizeof(buffer) - 1] = '\0';
63.
64. kernel_restart(buffer);
65. break;
66.
67.#ifdef CONFIG_KEXEC
68. case LINUX_REBOOT_CMD_KEXEC:
69. ret = kernel_kexec();
70. break;
71.#endif
72.
73.#ifdef CONFIG_HIBERNATION
74. case LINUX_REBOOT_CMD_SW_SUSPEND:
75. ret = hibernate();
76. break;
77.#endif
78.
79. default:
80. ret = -EINVAL;
81. break;
82. }
83. mutex_unlock(&reboot_mutex);
84. return ret;
85.}
我们通过命令行敲reboot的话进入的是LINUX_REBOOT_CMD_RESTART这个分支,可以看到接下来会调用kernel_restart(NULL);
01./**
02. * kernel_restart - reboot the system
03. * @cmd: pointer to buffer containing command to execute for restart
04. * or %NULL
05. *
06. * Shutdown everything and perform a clean reboot.
07. * This is not safe to call in interrupt context.
08. */
09.void kernel_restart(char *cmd)
10.{
11. kernel_restart_prepare(cmd);
12. if (!cmd)
13. printk(KERN_EMERG "Restarting system.\n");
14. else
15. printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
16. kmsg_dump(KMSG_DUMP_RESTART);
17. machine_restart(cmd);
18.}
这个函数里面会打印出我们常看到的log,Restarting system.
kernel_restart_prepare(cmd);里会去调用设备的shutdown接口,去power off设备,并且发送SYS_RESTART的广播,
01.void kernel_restart_prepare(char *cmd)
02.{
03. blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
04. system_state = SYSTEM_RESTART;
05. device_shutdown();
06. sysdev_shutdown();
07.}
接着执行machine_restart(cmd);我们会调到arch/x86/kernel/reboot.c中,这里需要知道一个ops
01.struct machine_ops machine_ops = {
02. .power_off = native_machine_power_off,
03. .shutdown = native_machine_shutdown,
04. .emergency_restart = native_machine_emergency_restart,
05. .restart = native_machine_restart,
06. .halt = native_machine_halt,
07.#ifdef CONFIG_KEXEC
08. .crash_shutdown = native_machine_crash_shutdown,
09.#endif
10.};
machine_restart就是执行这行这里的native_machine_restart
01.static void native_machine_restart(char *__unused)
02.{
03. printk("machine restart\n");
04.
05. if (!reboot_force) {
06. printk("native_machine_restart reboot_force:%d\n", reboot_force);
07. machine_shutdown();
08. }
09. __machine_emergency_restart(0);
10.}
machine_shutdown();中执行一些shutdown工作,重启的工作在__machine_emergency_restart(0);
01.static void __machine_emergency_restart(int emergency)
02.{
03. reboot_emergency = emergency;
04. machine_ops.emergency_restart();
05.}
调用ops中的emergency_restart
01.static void native_machine_emergency_restart(void)
02.{
03. int i;
04.
05. if (reboot_emergency)
06. emergency_vmx_disable_all();
07.
08. tboot_shutdown(TB_SHUTDOWN_REBOOT);
09.
10. /* Tell the BIOS if we want cold or warm reboot */
11. *((unsigned short *)__va(0x472)) = reboot_mode;
12.
13. for (;;) {
14. /* Could also try the reset bit in the Hammer NB */
15. switch (reboot_type) {
16. case BOOT_KBD:
17. mach_reboot_fixups(); /* for board specific fixups */
18.
19. for (i = 0; i < 10; i++) {
20. printk("%d\n", i);
21. kb_wait();
22. udelay(50);
23. outb(0xfe, 0x64); /* pulse reset low */
24. udelay(50);
25. }
26.
27. case BOOT_TRIPLE:
28.
29. load_idt(&no_idt);
30.
31. __asm__ __volatile__("int3");
32.
33. reboot_type = BOOT_KBD;
34. break;
35.
36.#ifdef CONFIG_X86_32
37. case BOOT_BIOS:
38. machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
39. reboot_type = BOOT_KBD;
40. break;
41.#endif
42.
43. case BOOT_ACPI:
44.
45. acpi_reboot();
46. reboot_type = BOOT_KBD;
47. break;
48.
49. case BOOT_EFI:
50.
51. if (efi_enabled)
52. efi.reset_system(reboot_mode ?
53. EFI_RESET_WARM :
54. EFI_RESET_COLD,
55. EFI_SUCCESS, 0, NULL);
56. reboot_type = BOOT_KBD;
57. break;
58.
59. case BOOT_CF9:
60.
61. port_cf9_safe = true;
62. /* fall through */
63.
64. case BOOT_CF9_COND:
65.
66. if (port_cf9_safe) {
67. u8 cf9 = inb(0xcf9) & ~6;
68.
69. outb(cf9|2, 0xcf9); /* Request hard reset */
70. udelay(50);
71. outb(cf9|6, 0xcf9); /* Actually do the reset */
72. udelay(50);
73. }
74. reboot_type = BOOT_KBD;
75. break;
76. }
77. }
78.}
这边就是重启的最后部分了,默认的是通过BOOT_KBD方式重启的,这种方式是通过键盘控制器去模拟按下键盘上的reset键来重启的,往0x64端口中写0xfe即可,然后系统会在__asm__ __volatile__("int3");中中断。int3是一个breakpoint,用来使程序停止在这,等待重启。
这里再说下,通过cf9来重启,用注释来解释Use the so-called "PCI reset register", CF9,通过这个寄存器可以使系统hard reset。
对于上面的一些重启方式,我将在下一篇文章里去介绍他们的用法,以及我在调试reboot中遇到的一些问题,这篇文章主要就是分析一下reboot的流程。
原文地址:
http://blog.csdn.net/android_huber/article/details/7428553