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的寄存器然后启动处理。