Linux电源管理(二)系统reboot/shutdown过程

来源:互联网 发布:oecd数据公布 编辑:程序博客网 时间:2024/06/06 05:10

概述

计算机包括嵌入式设备,关机和重启是常见的两个操作。本文主要主要描述这两个动作背后和流程和实现。

下机我们先看一下,linux支持的类似关机重启这样的命令的其它相关命令。

/* * Commands accepted by the _reboot() system call. * * RESTART     Restart system using default command and mode. * HALT        Stop OS and give system control to ROM monitor, if any. * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command. * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task. * POWER_OFF   Stop OS and remove all power from system, if possible. * RESTART2    Restart system using given command string. * SW_SUSPEND  Suspend system using software suspend if compiled in. * KEXEC       Restart system using a previously loaded Linux kernel */#define LINUX_REBOOT_CMD_RESTART    0x01234567 //重启命令#define LINUX_REBOOT_CMD_HALT       0xCDEF0123 #define LINUX_REBOOT_CMD_CAD_ON     0x89ABCDEF#define LINUX_REBOOT_CMD_CAD_OFF    0x00000000#define LINUX_REBOOT_CMD_POWER_OFF  0x4321FEDC//关机命令#define LINUX_REBOOT_CMD_RESTART2   0xA1B2C3D4#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2#define LINUX_REBOOT_CMD_KEXEC      0x45584543

reboot/shutdown流程

在Linux操作系统中,可以通过reboot、halt、poweroff等命令,发起reboot,具体的操作流程如下:
这里写图片描述

  • 一般的Linux操作系统,在用户空间都提供了一些工具集合(如常在嵌入式系统使用的Busybox),这些工具集合包含了reboot、halt和poweroff三个和Reboot相关的命令。读者可以参考man帮助文档,了解这些命令的解释和使用说明
  • 用户空间程序通过reboot系统调用,进入内核空间
  • 内核空间根据执行路径的不同,提供了kernel_restart、kernel_halt和kernel_power_off三个处理函数,响应用空间的reboot请求
  • 这三个处理函数的处理流程大致相同,主要包括:向关心reboot过程的进程发送Notify事件;调用drivers核心模块提供的接口,关闭所有的外部设备;调用drivers syscore模块提供的接口,关闭system core;调用Architecture相关的处理函数,进行后续的处理;最后,调用machine相关的接口,实现真正意义 Reboot 
  • 另外,借助TTY模块提供的Sysreq机制,内核提供了其它途径的关机方法,如某些按键组合、向/proc文件写入命令等。

实现流程分析

系统调用入口

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:        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_restart(char *cmd){    kernel_restart_prepare(cmd);  //通知链通知,关闭所有设备(bus,driver的shutdown接口)    migrate_to_reboot_cpu();//    syscore_shutdown(); //系统核心器件关闭(例如中断等)    if (!cmd)        printk(KERN_EMERG "Restarting system.\n");    else        printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);    kmsg_dump(KMSG_DUMP_RESTART); //向世界发出最后的声音    machine_restart(cmd); //由machine-core的代码,接管后续的处理}

关机接口

void kernel_power_off(void){    kernel_shutdown_prepare(SYSTEM_POWER_OFF);    if (pm_power_off_prepare)        pm_power_off_prepare();    migrate_to_reboot_cpu();    syscore_shutdown();    printk(KERN_EMERG "Power down.\n");    kmsg_dump(KMSG_DUMP_POWEROFF);    machine_power_off();}

驱动需要实现什么?

实现各自的shutdown接口,以正确关闭对应的设备

参考资料

<1>.http://www.wowotech.net/pm_subsystem/reboot.html

阅读全文
0 0
原创粉丝点击