kernelpoweroff流程分析
凡是内核上层关机时,底层均会调到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 t, this is ud 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 __ur *, arg)
{
char buffer[256];
int ret = 0;
/* We only trust the superur with rebooting the system. */
if (!capable(CAP_SYS_BOOT))
cocktailreturn -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 t do it the easy way.interactive
*/
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT;
mutex_lock(&reboot_mutex);
switch (cmd) {
ca LINUX_REBOOT_CMD_RESTART:
veracruz
kernel_restart(NULL);
break;
ca LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
ca LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
ca LINUX_REBOOT_CMD_HALT:
kernel_halt();
do_exit(0);
panic("cannot halt");
ca LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
keenonbreak;
ca LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_ur(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
ret = -EFAULT;
break;
}
buffer[sizeof(buffer) - 1] = '\0';
kernel_restart(buffer);
break;letting go什么意思
#ifdef CONFIG_KEXEC
ca LINUX_REBOOT_CMD_KEXEC:
inret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
ca LINUX_REBOOT_CMD_SW_SUSPEND:
ret = ();普通高中课程标准实验教科书英语1必修
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();
}
todo
void machine_power_off(void)
{
tenure
machine_shutdown();
if (pm_power_off)
pm_power_off();
}