您的位置:首页 > 其它

kernel power off流程分析

2013-07-04 16:57 931 查看
凡是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();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: