Android reboot分析

  1. /system/core/android_reboot.c

    int android_reboot(int cmd, int flags, char *arg)

    该函数作为通用API, 可以分别用在如下地方:
    1. adb shell mode reboot
    2. fastboot downloading mode reboot
    3. recovery mode reboot
    4. Charging mode reboot

  2. /kernel/include/linux/reboot.h
    • 定义了 __reboot() 系统调用的 magic value
    • 定义了 __reboot  系统调用的 command
    • 需要关注一下某些函数是体系结构无关的,某些是有体系结构依赖的

      /*
       * Architecture-specific implementations of sys_reboot commands.
       */
      
      extern void machine_restart(char *cmd);
      extern void machine_halt(void);
      extern void machine_power_off(void);
      
      extern void machine_shutdown(void);
      struct pt_regs;
      extern void machine_crash_shutdown(struct pt_regs *);
      
      /* 
       * Architecture independent implemenations of sys_reboot commands.
       */
      
      extern void kernel_restart_prepare(char *cmd);
      extern void kernel_restart(char *cmd);
      extern void kernel_halt(void);
      extern void kernel_power_off(void);
      
      extern int C_A_D; /* for sysctl */
      void ctrl_alt_del(void);
      
      #define POWEROFF_CMD_PATH_LEN	256
      extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
      
      extern int orderly_poweroff(bool force);
      
      /*
       * Emergency restart, callable from an interrupt handler.
       */
      
      extern void emergency_restart(void);
      #include <asm/emergency-restart.h>
      

    • 展开 <asm/emergency-restart.h> 后如下

      static inline void machine_emergency_restart(void)
      {
      	machine_restart(NULL);
      }


  3. /kernel/kernel/sys.c  reboot() system call

    reboot() 系统调用需要:
    • Only root may call it with obvious reasons
    • root needs to setup some magic numbers in registers 以避免错误
    • 这里可以添加 ctrl-alt-del-key 响应
    • reboot() 不做sync() 动作, 需要自己显式调用 sync()


    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;
    }


  4. 体系结构无关的 API 将会调用平台体系结构相关的 API


    /**
     *	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);
    }


  5. 对于 arm platform, 下一步是 /kernel/arch/arm/kernel/process.c

    void machine_restart(char *cmd)
    {
    	machine_shutdown();
    	arm_pm_restart(reboot_mode, cmd);
    }
    

  6. 同文件里面进行了函数指针转换

    void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
    EXPORT_SYMBOL_GPL(arm_pm_restart);

  7. arm_machine_restart() 如下

    void arm_machine_restart(char mode, const char *cmd)
    {
    	/* Flush the console to make sure all the relevant messages make it
    	 * out to the console drivers */
    	arm_machine_flush_console();
    
    	/* Disable interrupts first */
    	local_irq_disable();
    	local_fiq_disable();
    
    	/*
    	 * Tell the mm system that we are going to reboot -
    	 * we may need it to insert some 1:1 mappings so that
    	 * soft boot works.
    	 */
    	setup_mm_for_reboot(mode, NULL);
    
    	/* Clean and invalidate caches */
    	flush_cache_all();
    
    	/* Turn off caching */
    	cpu_proc_fin();
    
    	/* Push out any further dirty data, and ensure cache is empty */
    	flush_cache_all();
    
    	/*
    	 * Now call the architecture specific reboot code.
    	 */
    	arch_reset(mode, cmd);
    
    	/*
    	 * Whoops - the architecture was unable to reboot.
    	 * Tell the user!
    	 */
    	mdelay(1000);
    	printk("Reboot failed -- System halted\n");
    	while (1);
    }


  8. 然后是 /kernel/arch/arm/plat-xxxx/include/mach/system.h
    对于Qualcomm是
    #include <mach/hardware.h>
    
    void arch_idle(void);
    
    static inline void arch_reset(char mode, const char *cmd)
    {
    	for (;;) ;  /* depends on IPC w/ other core */
    }
    
    /* low level hardware reset hook -- for example, hitting the
     * PSHOLD line on the PMIC to hard reset the system
     */
    extern void (*msm_hw_reset_hook)(void);
    

    对于Samsung S3C2410是
    extern void (*s3c24xx_reset_hook)(void);
    
    static void
    arch_reset(char mode, const char *cmd)
    {
    	if (mode == 's') {
    		cpu_reset(0);
    	}
    
    	if (s3c24xx_reset_hook)
    		s3c24xx_reset_hook();
    
    	arch_wdt_reset();
    
    	/* we'll take a jump through zero as a poor second */
    	cpu_reset(0);
    }
    

    典型的示例如下:
    static inline void arch_idle(void)
    {
        cpu_do_idle();
    }
    
    static inline void arch_reset(char mode, const char *cmd)
    {
        cpu_reset(0);
    }
    
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值