睡眠 4 种模式:

  • S2I (Suspend-to-Idle): 挂起系统,IO进入低功耗模式。需配置CONFIG_SUSPEND。

  • Standby:执行S2I后,把AP (nonboot CPU) 离线。除了CONFIG_SUSPEND的支持外,还需要向suspend子系统注册,如果是基于ACPI的系统,需要映射到S1状态。

  • S2RAM(Suspend-to-RAM):又称为STR,系统状态保存到内存,所有的外围设备,总线都进入低功耗或者断电的状态,内核在最后一步会把控制权给到BIOS,并映射到S3状态(ACPI系统)。除了CONFIG_SUSPEND的支持外,还需要向suspend子系统注册。

  • Hibernation(Suspend-to-Disk or STD) : 创建当前系统的内存镜像(内核和应用进程),保存到硬盘,然后,系统断电或者进入低功耗模式。唤醒时,bios启动一个新的内核(恢复内核)加载内存镜像,新内核自我更新,恢复先前的内核和进程状态。需要CONFIG_HIBERNATION的支持。

sys 接口

/sys/power/state (kernel/power/main.c)

  • state_show: 对应的read函数。

  • state_store:对应的write函数。

stat_show( )显示系统可用到睡眠模式,pm_states_init( ) 会初始化状态,其中S2I和 S2RAM是默认支持的,Standby 和 Hibernation 则需要进行检测硬件平台是否系统支持,不支持的话,就不会显示出来,显示值依次是:freeze,standby,mem,disk.

sys接口是功能的入口,从 stat_store( ) 里可以看到待机和休眠的入口函数分别是:

  • pm_suspend(state)

  • hibernate()

待机(SUSPEND)

入口:int pm_suspend(suspend_state_t state),有效参数是:

  • #define PM_SUSPEND_TO_IDLE ((__force suspend_state_t) 1)

  • #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2)

  • #define PM_SUSPEND_MEM ((__force suspend_state_t) 3)

待机可以分为3个阶段:

1: 准备阶段

主要是冻结应用程序和内核线程,外设进入睡眠状态。这个是公共部分,所有的suspend状态都要执行。

下图时一个基本的流程框架。

(suspend的流程框架图)

冻结程序

修改用户进程状态为 PF_FROZEN,使任务并进入__refrigerator( )里的一个循环,直到被唤醒——称之为 freeze。内核线程也是类似的情况,它进入另外的循环。freeze不是强制的,创建时可以配置为不可冻结。

冻结程序和内核线程的主要原因是:防止休眠时文件系统因为读写而损坏;防止驱动读写一个已经挂起的设备;等等(详见freezing-of-tasks.rst)。打开refrigerator( )里日志可以看到如下消息:

    Freezing user space processes ... systemd entered refrigeratorgdbus entered refrigeratoremacs entered refrigeratorbash entered refrigerator

当前系统所有的应用程序都被冻结了,系统唤醒后,各任务退出循环,继续运行。

设备待机

主要是在DPM(device power manager,base/power/main.c)模块的 dpm_suspend( )中实现,轮询 dpm设备list,依次调用 device_suspend(dev) 来 callback每个设备注册的suspend( ). 以pci设备为例:

    struct bus_type pci_bus_typs = { .pm        = PCI_PM_OPS_PTR,}struct dev_pm_ops pci_dev_pm_ops = {.suspend = pci_pm_suspend, ...}

因此,每个pci设备都是先callback pci_pm_suspend( ),在这个函数里再callback各个设备的 pm->suspend(dev) 。

dpm list是通过 device_add( ) --> device_pm_add( ) 来生成的,也就是添加设备时,进行检测,支持PM管理的设备会被放入 dmp list,当执行suspend时,轮询该列表依次callback各个设备注册的 suspend函数。

2: 进入待机

这个阶段主要时执行底层函数,进入待机状态,具体实现同CPU架构相关。

入口是 suspend_enter( ),先检测pm状态,如果是S2I,则走s2idle_loop( ),不需要待机。否则走 syscore_suspend( ),先轮询syscore_ops_list,执行每个对象的suspend( ), 最后,调用平台相关的suspend_ops->enter(state),执行cpu模块的底层函数,写数据到bios后,系统由bios接管,进入待机状态。

syscore_ops_list 通过register_syscore_ops( )(drivers/base/syscore.c)来注册,一般在同cpu架构相关的代码里面。suspend_ops是通过suspend_set_ops( )来注册的,以龙芯mips为例:

suspend_set_ops(&loongson_pm_ops);
suspend_ops->enter -->loongson_pm_enter
-->mach_suspend: (arch/mips/loongson64/loongson-3/pm.c)-->保存一些寄存器
-->loongson_suspend_enter: (arch/mips/loongson64/loongson-3/sleep.S)写数据到bios后待机,系统在当前位置挂机,bios开始接管系统。

3: 恢复

待机后,系统就挂在当前的执行位置,当用户唤醒(按电源键或者键盘)系统时,bios先恢复CPU,然后CPU从当前位置开始唤醒系统,唤醒刚好是一个相反的过程,先从架构相关的底层开始,逐级唤醒系统,主要的代码流程是在 suspend_enter( )的后半段,也是从suspend_ops->enter( ) 开始,这个函数的退出,表示系统已开始唤醒,接着syscore_resume( ) -->... --> ahci_pci_device_resume ( ) ....;依次调用各模块的 resume( ) callback。

休眠(Hibernation)

入口是 hibernate( ) kernel/power/hibernate.c,主要的工作流程都在这个函数里面。

休眠的3种模式

cat /sys/power/disk 可以看到休眠支持的3种模式:

  • 'platform': 检测是否有平台支持(ACPI等),进入平台的待机模式。

  • 'shutdown':关机。

  • 'reboot': 重启,功能测试用。

工作流程

  • freeze_processes

  • freeze_kernel_threads()

  • dpm_suspend(PMSG_FREEZE)

  • create_image(platform_mode)

  • dpm_resume(msg)

  • swsusp_write(flags)

  • power_down( )

上面的函数流已经可以自解释了,先是冻结用户进程和内核线程,接着设备也进入待机,已防后面创建镜像时出现bug,镜像创建后,恢复设备,为关机做准备。最后的步骤是镜像写入交换分区,然后关机。

恢复的入口函数是:software_resume( ),加载内存镜像后,内核自我更新状态,恢复先前的状态。

ACPI

ACPI在睡眠框架里不是必选项,不是所有的架构都支持ACPI。它的入口是acpi_sleep_init( ) (drivers/acpi/sleep.c),主要是3个初始化函数:

  • acpi_sleep_syscore_init();

  • acpi_sleep_suspend_setup();

  • acpi_sleep_hibernate_setup();

分别注册对应级别的callback,当系统睡眠时,它会callback ACPI中相关的函数,与bios进行通讯,完成对应的睡眠功能。

参考资料

Documentation/admin-guide/pm/sleep-status.rst

Documentation/power/freezing-of-tasks.rst

linux的睡眠框架及实现相关推荐

  1. Linux SPI驱动框架(2)——控制器驱动层

    SPI控制器驱动层   上节中,讲了SPI核心层的东西,这一部分,以全志平台SPI控制器驱动为例,对SPI控制器驱动进行说明. SPI控制器驱动,即SPI硬件控制器对应的驱动,核心部分需要实现硬件SP ...

  2. Linux SPI驱动框架(1)——核心层

    概述   linux SPI驱动框架主要分为核心层,控制器驱动层以及设备驱动层.具体结构可参考下图   图中,最下层是硬件空间,SPI总线控制器,总线控制器负责硬件上的数据交互.内核空间中,需要有对应 ...

  3. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  4. Linux uart驱动框架

    Linux uart驱动框架 串口驱动框架包括两部分 struct uart_driver int uart_register_driver(struct uart_driver *uart); vo ...

  5. Linux PCI驱动框架分析:(Peripheral Component Interconnect,外部设备互联)

    <DPDK 20.05 | rte_pci_bus思维导图 | 第一版> <linux系统下:IO端口,内存,PCI总线 的 读写(I/O)操作> <Linux指令:ls ...

  6. Linux进程睡眠状态disk sleep

    Linux进程睡眠状态disk sleep <Linux-进程管理> 1. Linux进程状态 Running(R):运行或将要运行 Interruptible(S):被阻断而等待一个事件 ...

  7. buildroot:Linux平台构建嵌入式Linux系统的框架

    buildroot是Linux平台上一个构建嵌入式Linux系统的框架.整个Buildroot是由Makefile脚本和Kconfig配置文件构成的.你可以和编译Linux内核一样,通过buildro ...

  8. platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架

    platform框架 input. pinctrl. gpio 子系统都是 Linux 内核针对某一类设备而创建的框架, input子系统是管理输入的子系统 pinctrl 子系统重点是设置 PIN( ...

  9. Linux I2C驱动框架(超详细)

    Linux I2C驱动框架 文章目录 Linux I2C驱动框架 一.几个重要的对象 1.I2C总线 2.I2C驱动 3.I2C设备 4.I2C设配器 小结 二.内核源码分析 1.注册I2C驱动 2. ...

最新文章

  1. 对于电单车同学们提出的改动建议
  2. STL中的栈结构和队列结构
  3. SAP S/4HANA product search implementation debug in backend
  4. python编辑elif显示错误_Python运行的17个时新手常见错误小结
  5. OpenGL进阶演示样例1——动态画线(虚线、实线、颜色、速度等)
  6. Linux日志收集logrotate原理介绍
  7. 生产者消费者问题 操作系统
  8. 27岁到来之际,我在大厂实现了年薪40W+的小目标
  9. https open api_通过bilibili_api获取弹幕+绘制词云的方法
  10. [转载] python(numpy) 实现神经网络训练 (卷积 全连接 池化)
  11. ng的概念层次(官方文档摘录)
  12. 本地通过Eclipse链接Hadoop操作Mysql数据库问题小结
  13. 没有找到dllregisterserver输入点_「Mac实用技巧」将浏览器的点密码转换成文本密码的三种方法分享...
  14. 快速生成电子发票的EXCEL表格
  15. 天天生鲜项目——登录页面
  16. MATLAB希尔伯特Hilbert变换求包络谱
  17. JAVA简单聊天室的实现
  18. node mysql菜鸟教程_Node.js 路由
  19. 更实用 批量解析 Sanger 测序.ab1文件 出图出文本
  20. Microsoft Edge浏览器黑色背景修改

热门文章

  1. 信号完整性之S参数(六)
  2. 温湿度传感器驱动SHT85 单片机STM32 HAL库
  3. 信号与系统(二十一)——无失真传输和理想低通滤波器
  4. 7-8 打死我也不说
  5. 集合——Collections
  6. python 图片正方形化
  7. python 英语翻译_Python 实现中英文翻译
  8. 租赁行业如何将电子合同活用起来?
  9. JDK1.8文档中文版
  10. QT错误1-error: invalid use of incomplete type ‘class xxx‘