Linux电源管理(3)_关机和重启的过程

原文:Linux电源管理(3)_Generic PM之重新启动过程

1.前言

在使用计算机的过程中,关机和重启是最先学会的两个操作。同样,这两个操作在Linux中也存在,可以关机和重启。这就是这里要描述的对象。在Linux Kernel中,主流的关机和重新启动都是通过“ reboot”系统调用(具体可参考kernel / sys.c)来实现的。另外,除了我们常用的shutdown和restart两类操作之外,该系统调用也提供了其他的reboot方式,也会在这里一一说明。

2.内核支持的reboot方式

也许你会奇怪,reboot是重启的意思,所以用它实现Restart是合理的,但怎么用它实现关机操作呢?答案是这样的:关机之后,早晚也会开机啊!所以关机是一种特殊的重新启动过程,只不过持续的时间有点长而已。所以,内核根据不同的表现方式,将重新启动分成如下的几种方式:

​​​​​​​

   1: / *   2: * _reboot()系统调用接受的命令。   3: *   4: *重新启动使用默认命令和模式重新启动系统。   5: * HALT停止OS,并将系统控制权交给ROM监视器(如果有)。   6: * CAD_ON Ctrl-Alt-Del序列导致RESTART命令。   7: * CAD_OFF Ctrl-Alt-Del序列将SIGINT发送到初始化任务。   8: * POWER_OFF如果可能,请停止OS并从系统中断开所有电源。   9: * RESTART2使用给定的命令字符串重新启动系统。  10: * SW_SUSPEND使用软件挂起的挂起系统(如果已编译)。  11: * KEXEC使用先前加载的Linux内核重新启动系统  12: * /  13:           14: #define LINUX_REBOOT_CMD_RESTART 0x01234567  15: #define LINUX_REBOOT_CMD_HALT 0xCDEF0123  16: #define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF  17: #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000  18: #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC  19: #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4  20: #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2  21: #define LINUX_REBOOT_CMD_KEXEC 0x4558454

操作类型

英文全称/别名

功能描述

备注

RESTART

Restart

正常重启系统,重新加载内核和用户空间。

用户最常用的重启方式,等同于

reboot

命令。

HALT

Halt

停止操作系统,将控制权交给其他代码(如 BIOS/UEFI 或监控程序)。

表现形式依赖具体硬件实现,可能完全断电或进入低功耗状态。

CAD_ON/CAD_OFF

Ctrl+Alt+Del On/Off

允许/禁止通过

Ctrl+Alt+Del

组合键触发重启(RESTART)。

需键盘驱动支持,默认行为由内核配置决定。

POWER_OFF

Power Off

正常关机,停止操作系统并切断电源(ACPI 状态

S5

)。

等同于

poweroff

命令,需硬件支持完全断电。

RESTART2

Restart with Command

重启时携带自定义字符串(

cmd

),传递给关注重启事件的进程或机器相关代码。

用途由设备厂商自定义(如安卓的恢复模式)。

SW_SUSPEND

Software Suspend

挂起到内存(Suspend-to-RAM)或磁盘(Hibernate),进入低功耗状态。

依赖

CONFIG_SUSPEND

内核选项,详见后续休眠专题。

KEXEC

Kernel Execute

跳过 BIOS/UEFI,直接重启到预加载的其他内核镜像(需

CONFIG_KEXEC

支持)。

用于快速内核热替换或崩溃恢复(如

kexec -l

加载新内核)。

3.重新启动相关的操作流程

在Linux操作系统中,可以通过重新启动,停止,关闭电源等命令,启动重新启动,具体的操作流程如下:

一般的Linux操作系统,在用户空间都提供了一些工具集合(如常在嵌入式系统使用的Busybox),这些工具集合包含了重新引导,停止和关机三个和重新引导相关的命令。

用户空间程序通过reboot系统调用,进入内核空间,内核空间根据执行路径的不同,提供了kernel_restart,kernel_halt和kernel_power_off三个处理函数,响应用空间的reboot请求这三个处理函数的处理流程大致相同,主要包括:向有关重新引导过程的进程发送通知事件;调用驱动程序核心模块提供的接口,关闭所有的外部设备;调用驱动程序syscore模块提供的接口,关闭系统核心;调用架构相关的处理函数,进行后续的处理;最后,调用计算机相关的接口,实现真正意义上的重新启动另外,采用TTY模块提供的Sysreq机制,内核提供了其他途径的关机方法,如某些按键组合,向/ proc文件写入命令等

4.重新启动过程的内部动作和代码分析

4.1重启系统调用

重新启动系统调用的实现位于“ kernel / sys.c”,其函数原型如下:​​​​​​​

   1: SYSCALL_DEFINE4(reboot,int,magic1,int,magic2,unsigned  int,cmd,   2:                 void __user *,arg)reboot,该系统调用的名称。magic1,magic2,两个int类型的“魔力数”,用于防止误操作。具体在“ include / uapi / linux / reboot.h”中定义,感兴趣的同学可以去看看(话说这些数字还是蛮有意思的,例如Linus同学及其家人的生日就在里面,猜出来的可以在文章下面留言)。cmd,第2章所描绘的reboot方式。arg,其他的额外参数。

reboot系统调用的内部动作比较简单:

1)确定调用者的用户权限,如果不是超级用户(superuser),则直接返回错误(这也是我们再用户空间执行reboot,halt,poweroff等命令时,必须是root用户的原因);

2)判断预测的魔术数是否匹配,如果不匹配,直接返回错误。这样就可以进行的防止误动作发生;

3)调用reboot_pid_ns接口,检查是否需要由该接口处理reboot请求。

4)如果是POWER_OFF命令,且没有注册电源关闭的机器处理函数(pm_power_off),把该命令转换为HALT命令;

5)根据特定的cmd命令,执行具体的处理,包括,

      如果是RESTART或RESTART2命令,调用kernel_restart。

      如果是CAD_ON或CAD_OFF命令,更新C_A_D的值,则表示允许通过Ctrl + Alt + Del组合键重新启动系统。

      如果是HALT命令,调用kernel_halt。

      如果是POWER_OFF命令,调用kernel_power_off。

      如果是KEXEC命令,调用kernel_kexec接口

      如果是SW_SUSPEND,则调用hibernate接口

6)返回上述的处理结果,系统调用结束。

4.2 kernel_restart,kernel_halt和kernel_power_off

1)调用kernel_xxx_prepare函数,进行重新启动/停止/ power_off前的准备工作,包括,

      调用blocking_notifier_call_chain接口,向关心reboot事件的进程,发送SYS_RESTART,SYS_HALT或SYS_POWER_OFF事件。并发送出去。

      将系统状态设置为相应的状态(SYS_RESTART,SYS_HALT或SYS_POWER_OFF)。

      调用usermodehelper_disable接口,禁止用户模式辅助

      调用device_shutdown,关闭所有的设备

2)如果是power_off,并且存在PM相关的power off prepare函数(pm_power_off_prepare),则调用该调用函数;

3)调用migrate_to_reboot_cpu接口,将当前的进程(任务)移到一个CPU上;

注2:对于多CPU的机器,无论由哪个CPU触发了当前的系统调用,代码都可以运行在任意的CPU上。这个接口将代码分派到一个特定的CPU上,并禁止调度器分派代码到其他CPU上。首先,这个接口被执行后,只有一个CPU在运行,用于完成后续的重新启动动作。

4)调用syscore_shutdown接口,将系统核心器件关闭(例如中断等);

5)调用printk以及kmsg_dump,向这个世界发出最后的声音(打印日志);

6)最后,由machine-core的代码,接管后续的处理。

4.3 device_shutdown

设备模型中和device_shutdown有关的逻辑包括:

1.每个设备(结构设备)都会保存该设备的驱动(结构设备驱动程序)指针,以及该设备所在的总线(结构总线类型)的指针

2.设备驱动中有一个名称为“ shutdown”的某种函数,用于在device_shutdown时,关闭该设备

3.总线中也有一个名称为“ shutdown”的某种函数,用于在device_shutdown时,关闭该设备

4.系统的所有设备,都存在于“ / sys / devices /”目录下,而该目录由名称为“ devices_kset”的kset表示。kset中会使用一个链表保存其下所有的kobject(也即“ / sys / devices /”目录下的所有设备)。”的最终结果就是,以“ devices_kset”为根目录,将内核中所有的设备(以相应的kobject为代表),组织成一个树状结构

device_shutdown的实现,该接口位于“ drivers / base / core.c”中,执行逻辑如下。​​​​​​​

   1: / **   2: * device_shutdown-在每个设备上调用-> shutdown()以关闭。   3: * /   4: 无效device_shutdown(void)   5: {   6:         结构设备* dev,* parent;   7:            8:          spin_lock(&devices_kset-> list_lock);   9:         / *  10:          *向后移动设备列表,依次关闭每个设备。  11:          *请注意,设备拔出事件也可能会开始拉  12:          *设备离线,即使系统正在关闭。  13:          * /  14:         while (!list_empty(&devices_kset->list)) {  15:                 dev = list_entry(devices_kset->list.prev, struct device,  16:                                 kobj.entry);  17:   18:                 /*  19:                  * hold reference count of device's parent to  20:                  * prevent it from being freed because parent's  21:                  * lock is to be held  22:                  */  23:                 parent = get_device(dev->parent);  24:                 get_device(dev);  25:                 /*  26:                  * Make sure the device is off the kset list, in the  27:                  * event that dev->*->shutdown() doesn't remove it.  28:                  */  29:                 list_del_init(&dev->kobj.entry);  30:                 spin_unlock(&devices_kset->list_lock);  31:   32:                 /* hold lock to avoid race with probe/release */  33:                 if (parent)  34:                         device_lock(parent);  35:                 device_lock(dev);  36:   37:                 /* Don't allow any more runtime suspends */  38:                 pm_runtime_get_noresume(dev);  39:                 pm_runtime_barrier(dev);  40:   41:                 if (dev->bus && dev->bus->shutdown) {  42:                         if (initcall_debug)  43:                                 dev_info(dev, "shutdown\n");  44:                         dev->bus->shutdown(dev);  45:                 } else if (dev->driver && dev->driver->shutdown) {  46:                         if (initcall_debug)  47:                                 dev_info(dev, "shutdown\n");  48:                         dev->driver->shutdown(dev);  49:                  }  50:   51:                  device_unlock(dev);  52:                 如果(父母)  53:                          device_unlock(parent);  54:   55:                  put_device(dev);  56:                  put_device(父);  57:   58:                  spin_lock(&devices_kset-> list_lock);  59:          }  60:          spin_unlock(&devices_kset-> list_lock);  61:          async_synchronize_full();  62: }

4.4 system_core_shutdown

系统核心的关机和设备的关机类似,也是从一个链表中,遍历所有的系统核心,并调用它的关机接口。

4.5 machine_restart,machine_halt和machine_power_off

虽然以machine_为预先命名,这三个接口却是属于架构相关的处理函数,如ARM。以ARM为例,它们在“ arch / arm / kernel / process.c”中实现,具体如下。

4.5.1机器重启​​​​​​​

   1: / *   2: *重新启动要求辅助CPU停止执行任何活动   3: *,同时主CPU重置系统。具有单个CPU的系统可以   4: *使用soft_restart()作为其机器描述符的.restart钩子,因为   5: *将导致唯一可用的CPU复位。具有多个CPU的系统必须   6: *提供硬件重新启动实施,以确保所有CPU立即复位。   7: *这是必需的,以便在主CPU上复位后运行的任何代码   8: *不必与其他CPU协调以确保它们仍然不处于运行状态   9: *执行预重置代码,并使用主CPU的代码希望的RAM  10: *使用。实施这种协调基本上是不可能的。  11: * /  12: void machine_restart(char * cmd)  13: {  14:          smp_send_stop();  15:   16:          arm_pm_restart(reboot_mode,cmd);  17:   18:         / *给失败的宽限期1s * /  19:          mdelay(1000);  20:   21:         / *糟糕-平台无法重新启动。告诉用户!* /  22:          printk(“重新启动失败-系统停止\ n”);  23:          local_irq_disable();  24:         而(1);  25: }

0)先转述一下该接口的注释;

对于多CPU的机器而言,重新启动之前必须保证其他的CPU位于非活动状态,由其中一个主CPU负责重新启动动作。并且,必须实现一个基于硬件的重新启动操作,以保证所有CPU同步重启,这是设计的重点!

对于单CPU机器而言,就相对简单了,可以直接用软件reset的方式实现重启。

1)调用smp_send_stop接口,确保其他CPU位于非活动状态;

2)调用机器相关的重启接口,实现真正的重启。该接口是一个变量函数,由“ arch / arm / kernel / process.c”声明,由具体的机器代码实现。格式如下:

      void(* arm_pm_restart )(char str,const char * cmd)= null_restart;

      EXPORT_SYMBOL_GPL(arm_pm_restart);

3)等待1s;

4)如果没有返回,则重启成功,否则失败,打印错误信息。

4.5.2 machine_halt

ARM的halt很简单,就是将其他CPU停下来,并禁止当前CPU的中断后,死循环!确实,中断被禁止了,又死循环了,不halt才怪。代码如下:​​​​​​​

   1: / *   2: *停止仅要求辅助CPU停止执行任何操作   3: *活动(执行任务,处理中断)。smp_send_stop()   4: *实现此目标。   5: * /   6: void machine_halt(void)   7: {   8:          smp_send_stop();   9:   10:          local_irq_disable();  11:         而(1)  12: }

4.5.3 machine_power_off

power off动作和restart类似,即停止其他CPU,调用其他函数。power off的某些函数和restart类似,就不再说明了。

5.总结与思考

5.1建筑和机器的概念

本文是我们在分析Linux内核时第一次遇到架构和机器的概念,顺便解释一下。内核代码中最常见的目录结构就是:arch / xxx / mach-xxx /(例如arch / arm / mach-bcm /)。由该目录结构可知,架构(简称arch)是指具体的体系结构,如ARM,X86等。机器呢,是指具体体系结构下的一个或多个的SOC,如bcm等。

5.2电源管理驱动(和reboot有关的部分)需要实现的内容

由上面的分析可知,在Reboot的过程中,大部分的逻辑是否内核处理的,具体的驱动程序需要关注2点即可:

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

2)实现机器相关的接口,以确保足够的机器可以正确重启或关闭电源

看来还是很简单的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903467.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 继承详解

继承是面向对象程序设计(OOP)中的核心概念之一,它极大地增强了代码的重用性、扩展性和维护性。本篇文章将详细讲解C#中的继承机制,包括基础概念、语法特法、多重继承(通过接口实现)、继承的规则和实际应用示…

SQLAlchemy 2.x 异步查询方法比较

SQLAlchemy 2.x 异步查询中常用的 结果处理方法速查表,包含方法说明、使用场景、返回类型及典型用途。 SQLAlchemy 查询结果处理方法速查表(适用于 AsyncSession) 方法 说明 返回类型 示例 SQL 示例输出 scalars().all() 获取单列所有…

极客天成参与”AI助力智慧城市构建”主题演讲暨招商引智专题推介活动

4月7日下午,北京极客天成科技有限公司参加了天津市河东区数据局举办的“AI赋能智慧城市构建”主题演讲暨招商引智专题推介活动。 活动中,华为(天津)有限公司数字政府解决方案总监姜华庚围绕“政务大模型赋能智慧城市建设”&#x…

理解 EKS CloudWatch Pod CPU Utilization 指标:与 `kubectl top` 及节点 CPU 的关系

在使用 AWS EKS 时,CloudWatch Container Insights 提供了丰富的容器级别监控指标,帮助我们深入了解应用的运行状态。如下截图中的 ContainerInsights pod_cpu_utilization 指标就是一个非常重要的维度。本文将详细解释这个指标的含义,并将其…

使用pip3安装软件包报错`externally-managed-environment`的几种解决方式

1、pip3安装软件包报错 报错externally-managed-environment的原因: 从 Python 3.11 开始引入了 PEP 668 规范,该规范限制了在系统级 Python 环境中使用 pip 安装第三方包,以避免与系统包管理器(如 apt)产生冲突。 如…

spring security用户退出

Spring security默认实现了用户退出的功能,用户退出主要考虑退出后会话如何管理以及跳转到哪个页面。HttpSecurity类提供了logout()方法开启退出登录的支持,默认触发用户退出操作的URL为“/logout”,用户退出时同时也会清除Session等默认用户…

爱普生SG2520HHN晶振数据中心服务器的理想解决方案

在当今数字化时代,数据中心作为海量数据存储、处理与传输的核心枢纽,其服务器的高效稳定运行至关重要。服务器作为其核心设备,对时钟信号的精度和稳定性提出了严苛要求——微小的时序误差可能导致数据传输失败或系统宕机。爱普生 SG2520HHN 差…

LeetCode 155题解 | 最小栈

最小栈 一、题目链接二、题目三、算法原理思路1:用一个变量存储最小元素思路2:双栈普通栈和最小栈 四、编写代码五、时间复杂度 一、题目链接 最小栈 二、题目 三、算法原理 栈用数组、链表实现都行,最主要的就是在能在常数时间内检索到最…

es+kibana---集群部署

其实一般es要跑3个节点的,这样才能做高可用,处理并发大,但是我这里只是一个pod mkdir -p /stroe/data/es es搭建: #【拉取镜像】 #docker pull elasticsearch:6.8.7 #docker pull busybox:1.28 【导入镜像】 docker load -i es.…

WPF常用技巧汇总 - Part 2

WPF常用技巧汇总-CSDN博客 主要用于记录工作中发现的一些问题和常见的解决方法。 目录 WPF常用技巧汇总-CSDN博客 1. DataGrid Tooltip - Multiple 2. DataGrid Tooltip - Cell值和ToolTip值一样 3. DataGrid Tooltip - Cell值和ToolTip值不一样 4. DataGrid - Ctrl A /…

uniapp打包apk如何实现版本更新

我们做的比较简单,在后端设置版本号,并在uniapp的config.js中定义版本号,每次跟后端的进行对比,不一致的话就更新。 一、下载apk 主要代码(下载安装包,并进行安装,一般得手动同意安装&#xf…

局部和整体的关系

Prompt:为什么要研究局部和整体的关系呢?是因为很多情况下,局部就能表达出整体? 这是一个非常本质的问题,其实你已经接近数学和物理中“几何本质”的核心了。我们研究局部和整体的关系,是因为:…

企业办公协同平台安全一体化生态入住技术架构与接口标准分析报告

全球组织数字化与智能化背景下 企业办公协同平台安全一体化生态入住技术架构与接口标准分析报告 一、背景与市场需求 市场规模与增量 根据Statista数据,全球协同办公平台市场规模预计从2023年的$480亿增长至2027年的$900亿,年复合增长率(CAG…

【2025最新面试八股常问知识点】HTTP1.0,HTTP1.1,HTTP2.0,HTTP3.0,HTTP的进化之路。

HTTP 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的…

【算法练习】归并排序和归并分治

文章目录 1.归并排序1.1 递归版本1.2 非递归版本 2.归并分治2.1 计算数组的小和2.2 计算翻转对 1.归并排序 归并排序的核心步骤是: 拆分:将无序数组不断对半拆分成小块,直到每个小块只剩一个元素(自然有序)。 合并&a…

域对齐是什么

域对齐(Domain Alignment)是在机器学习和计算机视觉等领域中常用的技术 定义 域对齐旨在将不同域(Domain)的数据映射到一个共同的特征空间中,使得来自不同域的数据在该空间中具有相似的分布。这里的“域”可以指代不…

【linux】git安装、升级

git安装、升级 一、快捷安装版本2.18.0二、自定义版本安装(安装、升级)1、移除旧文件2、安装所需依赖3、选择指定版本4、解压文件、编译5、增加环境变量,验证是否版本 三、升级 一、快捷安装版本2.18.0 yum install git git --version二、自…

编程日志4.24

栈的链表基础表示结构 #include<iostream> #include<stdexcept> using namespace std; //模板声明&#xff0c;表明Stack类是一个通用的模板&#xff0c;可以用于存储任何类型的元素T template<typename T> //栈的声明 //Stack类的声明&#xff0c;表示一…

《冰雪传奇点卡版》:探索冰雪世界的传奇旅程!

《冰雪传奇点卡版》以“纯净打金”为核心&#xff0c;摒弃复杂付费坑&#xff0c;回归经典传奇玩法。以下从核心玩法、资源获取、职业搭配、交易变现四维度展开&#xff0c;助你高效开启冰雪传奇之旅。 一、核玩法解析&#xff1a;如何高效获取资源&#xff1f; 1. 职业定位与…

DeepClaude开源程序可以实现代码生成、创作诗句以及内容创作等功能

一、软件介绍 文末提供程序和源码下载 DeepClaude开源程序是增强的 AI&#xff0c;可以实现代码生成&#xff1a;DeepSeek r1 Claude 3.7 十四行诗 - 无与伦比的性能&#xff01;内容创作&#xff1a;DeepSeek r1 Gemini 2.5 Pro - 卓越的质量&#xff01;OpenAI 兼容。流媒…