分享

x86平台下Android系统的Linux部分的重启分析

 lifei_szdz 2013-06-18

-----------------------------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/android_huber
交流邮箱:dp.shao@gmail.com
-----------------------------------------------------------------------

        在Android下,我们在命令行中敲入reboot后系统的重启首先是执行的reboot这个应用程序。这是一个比较简单的小程序,其源码在   system/core/toolbox/reboot.c,主要的代码如下:

  1. if(poweroff)  
  2.     ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);  
  3. else if(argc > optind)  
  4.     ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);  
  5. else  
  6.     ret = reboot(RB_AUTOBOOT);  
这边都是通过系统调用进入内核的,LINUX_REBOOT_MAGIC1和LINUX_REBOOT_MAGIC2是两个幻数。进入kernel/sys.c中

  1. /* 
  2.  * Reboot system call: for obvious reasons only root may call it, 
  3.  * and even root needs to set up some magic numbers in the registers 
  4.  * so that some mistake won't make this reboot the whole machine. 
  5.  * You can also set the meaning of the ctrl-alt-del-key here. 
  6.  * 
  7.  * reboot doesn't sync: do that yourself before calling this. 
  8.  */  
  9. 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);

  1. /** 
  2.  *  kernel_restart - reboot the system 
  3.  *  @cmd: pointer to buffer containing command to execute for restart 
  4.  *      or %NULL 
  5.  * 
  6.  *  Shutdown everything and perform a clean reboot. 
  7.  *  This is not safe to call in interrupt context. 
  8.  */  
  9. 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的广播,

  1. void kernel_restart_prepare(char *cmd)  
  2. {  
  3.     blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);  
  4.     system_state = SYSTEM_RESTART;  
  5.     device_shutdown();  
  6.     sysdev_shutdown();  
  7. }  
接着执行machine_restart(cmd);我们会调到arch/x86/kernel/reboot.c中,这里需要知道一个ops

  1. struct machine_ops machine_ops = {  
  2.     .power_off = native_machine_power_off,  
  3.     .shutdown = native_machine_shutdown,  
  4.     .emergency_restart = native_machine_emergency_restart,  
  5.     .restart = native_machine_restart,  
  6.     .halt = native_machine_halt,  
  7. #ifdef CONFIG_KEXEC  
  8.     .crash_shutdown = native_machine_crash_shutdown,  
  9. #endif  
  10. };  
machine_restart就是执行这行这里的native_machine_restart

  1. static void native_machine_restart(char *__unused)  
  2. {  
  3.     printk("machine restart\n");  
  4.   
  5.     if (!reboot_force) {  
  6.         printk("native_machine_restart reboot_force:%d\n", reboot_force);  
  7.         machine_shutdown();  
  8.     }  
  9.     __machine_emergency_restart(0);  
  10. }  
machine_shutdown();中执行一些shutdown工作,重启的工作在__machine_emergency_restart(0);
  1. static void __machine_emergency_restart(int emergency)  
  2. {  
  3.     reboot_emergency = emergency;  
  4.     machine_ops.emergency_restart();  
  5. }  
调用ops中的emergency_restart

  1. static void native_machine_emergency_restart(void)  
  2. {  
  3.     int i;  
  4.   
  5.     if (reboot_emergency)  
  6.         emergency_vmx_disable_all();  
  7.   
  8.     tboot_shutdown(TB_SHUTDOWN_REBOOT);  
  9.       
  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的流程。

同样,附一张流程图:




需要清晰大图的请留邮箱

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多