android reboot重启分析

android代码system/core/libcutils/android_reboot.c

int android_reboot(int cmd, int flags, char *arg)
{
    int ret;
    sync();
    remount_ro();

    switch (cmd) {
        case ANDROID_RB_RESTART:
            /** SPRD: modify for reboot sliently when system exception crash @{ */
            //ret = reboot(RB_AUTOBOOT);
            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                           LINUX_REBOOT_CMD_RESTART2, "");
            /** @} */
            break;

        case ANDROID_RB_POWEROFF:
            ret = reboot(RB_POWER_OFF);
            break;

        case ANDROID_RB_RESTART2:
            ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                           LINUX_REBOOT_CMD_RESTART2, arg);
            break;

        default:
            ret = -1;
    }

    return ret;
}

 

reboot命令执行后调用系统内核函数kernel\kernel\reboot.c

kernel reboot代码

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
		void __user *, arg)
{
	struct pid_namespace *pid_ns = task_active_pid_ns(current);
	char buffer[256];
	int ret = 0;

	/* We only trust the superuser with rebooting the system. */
	if (!ns_capable(pid_ns->user_ns, 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;

	/*
	 * If pid namespaces are enabled and the current task is in a child
	 * pid_namespace, the command is handled by reboot_pid_ns() which will
	 * call do_exit().
	 */
	ret = reboot_pid_ns(pid_ns, cmd);
	if (ret)
		return ret;

	/* 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:
		ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
		if (ret < 0) {
			ret = -EFAULT;
			break;
		}
		buffer[sizeof(buffer) - 1] = '\0';

		kernel_restart(buffer);
		break;

#ifdef CONFIG_KEXEC_CORE
	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;
}

 

查看kernel_restart函数

void kernel_restart(char *cmd)
{
	kernel_restart_prepare(cmd);
	migrate_to_reboot_cpu();
	syscore_shutdown();
	if (!cmd)
		pr_emerg("Restarting system\n");
	else
		pr_emerg("Restarting system with command '%s'\n", cmd);
	kmsg_dump(KMSG_DUMP_RESTART);
	machine_restart(cmd);
}

 

machine_restart(cmd); 函数

void machine_restart(char *cmd)
{
	if(arm_pm_restart_prepare)
		arm_pm_restart_prepare(cmd);
	local_irq_disable();
	smp_send_stop();

	/* Flush the console to make sure all the relevant messages make it
	 * out to the console drivers */
	arm_machine_flush_console();

	if (arm_pm_restart)
		arm_pm_restart(reboot_mode, cmd);
	else
		do_kernel_restart(cmd);

	/* Give a grace period for failure to restart of 1s */
	mdelay(1000);

	/* Whoops - the platform was unable to reboot. Tell the user! */
	printk("Reboot failed -- System halted\n");
	local_irq_disable();
	while (1);
}

 

if(arm_pm_restart_prepare)

arm_pm_restart_prepare(cmd);

arm_pm_restart_prepare在wdt中定义: 展讯平台定义在sprd_pmic_wdt.c函数中

static int sprd_reboot_probe(struct platform_device *pdev)
{
	int ret = 0;
	u32 value = 0;
	struct device_node *node = pdev->dev.of_node;
	struct regmap *sprd_reboot;

	sprd_reboot = dev_get_regmap(pdev->dev.parent, NULL);
	if (!sprd_reboot) {
		dev_err(&pdev->dev, "sprd reboot probe failed!\n");
		return -EINVAL;
	}

	reboot_device = to_spi_device(sprd_reboot->dev);
	if (!reboot_device) {
		dev_err(&pdev->dev, "sprd reboot device probe failed!\n");
		return -EINVAL;
	}

	ret = of_property_read_u32(node, "reg", &value);
	if (ret) {
		dev_err(&pdev->dev, "sprd reboot probe failed!\n");
		return -EINVAL;
	}

	sprd_wdt_base = (unsigned long)value;
#ifdef CONFIG_X86
	x86_pm_restart_prepare = sprd_restart_prepare;
	x86_pm_restart = sprd_restart_handle;
#else
	arm_pm_restart_prepare = sprd_restart_prepare;
	arm_pm_restart = sprd_restart_handle;
#endif
	dev_info(&pdev->dev, "PMIC Watchdog probe OK!\n");
	spin_lock_init(&reboot_flag_lock);
	reboot_mode_flag = 0;

#if defined(CONFIG_SPRD_DEBUG) && defined(CONFIG_SPRD_SYSDUMP)
	pr_emerg("userdebug enable sysdump in default !!!\n");
	sprd_set_reboot_mode("dumpenable");
	set_sysdump_enable(1);
	sysdump_status = 1;
#endif
	return ret;
}

 

arm_pm_restart_prepare 设置重启的参数,

arm_pm_restart 看门狗重启

arm_pm_restart_prepare = sprd_restart_prepare;

arm_pm_restart = sprd_restart_handle;

 

static void sprd_restart_prepare(const char *cmd)
{
	sprd_set_reboot_mode(cmd);
}
void sprd_set_reboot_mode(const char *cmd)
{
	if (!cmd)
		return;

	pr_info("sprd_set_reboot_mode:cmd=%s\n", cmd);

	spin_lock(&reboot_flag_lock);
	if (cmd && !(strncmp(cmd, "recovery", 8)))
		reboot_mode_flag |= HWRST_STATUS_RECOVERY;
	else if (cmd && !strncmp(cmd, "alarm", 5))
		reboot_mode_flag |= HWRST_STATUS_ALARM;
	else if (cmd && !strncmp(cmd, "fastsleep", 9))
		reboot_mode_flag |= HWRST_STATUS_SLEEP;
	else if (cmd && !strncmp(cmd, "bootloader", 10))
		reboot_mode_flag |= HWRST_STATUS_FASTBOOT;
	else if (cmd && !strncmp(cmd, "panic", 5))
		reboot_mode_flag |= HWRST_STATUS_PANIC;
	else if (cmd && !strncmp(cmd, "special", 7))
		reboot_mode_flag |= HWRST_STATUS_SPECIAL;
	else if (cmd && !strncmp(cmd, "cftreboot", 9))
		reboot_mode_flag |= HWRST_STATUS_CFTREBOOT;
	else if (cmd && !strncmp(cmd, "autodloader", 11))
		reboot_mode_flag |= HWRST_STATUS_AUTODLOADER;
	else if (cmd && !strncmp(cmd, "iqmode", 6))
		reboot_mode_flag |= HWRST_STATUS_IQMODE;
	else if (cmd && !strncmp(cmd, "sprdisk", 7))
		reboot_mode_flag |= HWRST_STATUS_SPRDISK;
	else if (cmd && !strncmp(cmd, "dumpenable", 10)) {
		pr_emerg("sprd_set_reboot_mode: enable sysdump!\n");
		reboot_mode_flag |= HWRST_STATUS_SYSDUMP;
	} else if (cmd && !strncmp(cmd, "dumpdisable", 11)) {
		pr_emerg("sprd_set_reboot_mode: disable sysdump!\n");
		reboot_mode_flag &= ~(HWRST_STATUS_SYSDUMP);
	} else
		reboot_mode_flag = HWRST_STATUS_NORMAL;

	spin_unlock(&reboot_flag_lock);
}

 

重启参数设置完毕后保存在全局变量reboot_mode_flag中,然后执行arm_pm_restart进行重启操作

static void sprd_restart_handle(enum reboot_mode reboot_mode, const char *cmd)
{
	arch_reset(reboot_mode, cmd);

	mdelay(1000);

	pr_info("reboot failed!\n");

	while (1)
		;
}

 

static void arch_reset(char mode, const char *cmd)
{
	sprd_adi_raw_write(reboot_device, ANA_RST_STATUS, reboot_mode_flag);
	if (mode == REBOOT_WDT)
		sprd_turnon_watchdog(400);
	else
		sprd_turnon_watchdog(50);
#ifdef CONFIG_SPRD_DMC_DRV
	sprd_ddr_force_light_sleep();
#endif
}

 

所以只要在终端执行 reboot recovery就可以进入recovery模式。

 

这些模式通过写入PMIC的寄存器中做保存,

uboot启动过程中会读取PMIC的寄存器然后启动处理。

 

点赞