kernel power off流程分析

来源:互联网 发布:htc数据连接不可用 编辑:程序博客网 时间:2024/05/16 14:45

凡是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_offpm_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();

}

原创粉丝点击