kernel power off流程分析
凡是linux内核上层关机时,底层均会调到kernel_power_off(),电脑可以使用按键ctr+alt+del键进入关机,下面我们看看代码流程:
SYSCALL_DEFINE4() -> kernel_power_off()-> pm_power_off_prepare() -> machine_power_off()-> pm_power_off()
在这里我想说的是pm_power_off_prepare()和pm_power_off()都是与平台相关,有些平台只有填充pm_power_off而pm_power_off_prepare并没有填充。而在pm_power_off()函数中一般函数不能被调用因为整个syscore已经关闭,系统不能调用idle thread。所以关机前我们通常在pm_power_off_prepare()函数来实现,关机前通常很有可能需要完成的其他事,我们在这里就可以填充。
/*
* Function pointers to optional machine specific functions
*/
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
/*
* If set, this is used for preparing the system to power off.
*/
void (*pm_power_off_prepare)(void);
例如我们在高通平台所加的:
在arch/arm/mach-msm/restart.c
static int __init msm_restart_init(void)
{
pm_power_off = msm_power_off;
pm_power_off_prepare = msm_power_off_prepare;
}
源代码:
Kernel/sys.c
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;
}
void kernel_power_off(void)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
if (pm_power_off_prepare)
pm_power_off_prepare();
disable_nonboot_cpus();
syscore_shutdown();
printk(KERN_EMERG "Power down.\n");
kmsg_dump(KMSG_DUMP_POWEROFF);
machine_power_off();
}
void machine_power_off(void)
{
machine_shutdown();
if (pm_power_off)
pm_power_off();
}
更多推荐
所有评论(0)