Linux电源管理(12)_Hibernate功能

作者:Physh 发布于:2014-12-22 11:51 分类:电源管理子系统

出于省电和快速开机的需求, Hibernation经常被应用到Laptop和移动终端上,本文就简单讲讲Hibernation的一种实现实现方法,SWSUSP( Swap Suspend),其实swsusp从2.6开始就已经被引入到内核版本树中了,所以如果想分析swsusp的代码实现的话,还是挺方便的,只要有有2.6之后的内核代码即可。


本文不会过分深入分析代码,但文章最后会给出hibernation 和 resume的整体流程图。


swsusp是一种STD(Suspend to Disk)/STF(Suspend to Flash)的实现方法,其目的是系统断电之后再次开启时还可以恢复用户现场,从开发的角度切入,为了实现这一目的,系统至少需要保存的关键信息有三类:CPU 状态,Register状态,Memory状态。Swap Suspend中的Swap的含义即指明了该方法如何保存Memory的状态,将Memory保存到Swap分区上,当系统恢复时从Swap分区中读出对应的页面并恢复到Memory中。

那其他两类信息呢?一方面可以另开一块内存空间保留CPU、Register的状态,之后随着Memory一起保存到Swap分区,这种方法之后会讲到,在通过U-boot实现的STF的方法用到了。内核使用了另外一种方法,借用了Kernel CPU Suspend框架,Suspend时让CPU进入Suspend状态,Resume时再从这个状态返回,这样就不同特地去保存CPU、Register状态,不过,话是这样讲,其实本质上还是和第一种方法差不多,CPU Suspend会将Register保存在一个名为sleep_save_sp的指针变量指向的一块预留的内核栈空间中,恢复时从中获取寄存器信息。


从简单入手,思考一下通过U-boot如何试下STF/STD?

要从正常运行的系统跳转到U-boot,可以想到的唯一的办法只有Reset了。那Reset之前需要做什么呢?从U-boot的角度来考虑这个问题吧,如果要通过U-boot来实现这个功能,U-boot就有三种状态,1. 冷启动, 2. 热启动(Restore), 3. 制作内存镜像。

这三种状态肯定需要类似于Flag的东西来区别,所以系统Reset之前需要设置Flag来告知U-boot这次Reset的目的是制作内存镜像;另外,U-boot对当前内存使用情况以及Register状态一无所知,不过这些都还不是大问题,因为一般U-boot事先会知道PAGE_OFFSET,这样就可以通过PAGE_OFFSET得出swap_page_dir以及page_map[],寄存器的状态也可以在进入U-boot之后立即保存下来即可。不过,必须提及的是,Reset必须在所有已经都停止之后做,并且Resume回来的时候所有硬件都必须重新初始化。


通过U-boot实现无可避免就是需要多保存内存,当拿到page_map[]之后,U-boot可以通过各个Page的属性来判断这个页面是否需要保存,当然也可以把整块RAM都保存下来,不过是浪费一点空间。还有一个问题就是U-boot中不能依靠内核Swap机制的接口,所以这些数据往哪儿保存呢?直接往Swap分区写肯定是不行的,因为里边还有系统正常运行时swap out出来页面,要么就要像内核一样有办法获取Swap分区的free block,不行就另想办法,可以往文件里边写,或者弄一个保留分区啥的。


回到正题,Swsusp如何实现STF。

内核对于这个目的的实现就显得比U-boot优雅得多了,与此同时,也复杂的多了,所以说有时粗暴的方法也不见得就是坏办法。swsusp会尝试把最终snapshot image制作的尽可能小,不过这个尺寸用户是可以调控的。

A. Memory Bitmap 机制

看到bitmap估计很多人都会想起内核启动期间用到的boot_mem,这里的所提及的bitmap和boot_mem本质是一样,只是在swsusp中不同的bitmap所代表的作用不一,但方法都是通过bit来代表offset,最终对应到一个Page。

swsusp会扫描zone_list,把不需要保存的page标记起来,这样在制作snapshot image就可以减少image的尺寸。整个过程中用到的bitmap有四张,forbidden_pages_map, free_pages_map, copy_bm, orig_bm,其中不需要保存的page就在forbidden_pages_maps中标记,free_pages_map的作用用于标识当前系统空闲的PAGE,copy_bm标记的是临时保存要写如swap分区中的页面,orig_bm标志系统中所有需要保存的PAGE。

B. Swap 接口

说这个就直接看下面这个图好了,最终往Swap写入之后Swap的状态大致如下图:


swap_snapshot map.png

C. Kernel Power Manage机制

之前讲过,swsusp中嵌入Kernel PM从而避免了很多电源管理的冗余操作,其实这样做的好处还可以避免花多很功夫去使得各个驱动恢复到Hibernate之前的状态,所以从各个设备的角度去看,可以认为系统进入一个Suspend状态,只是时间有点长,中途还断电了,不过这些设备都不必操心,因为Restore的时候,它们走标准PM Resume流程又回到之前的状态。

D. Swap Header & swap_page_map

在Hibernation的时候,内核会把swap分区的swap_header换掉,换成自己的swap_header,这么做的原因是因为Swap 分区在正常使用过程中是按照内存方式使用的,所以如果是冷启动Swap分区肯定更要重置,因此标准的swap_header没必要记录一些offset什么的,但是restore的时候不一样,拿到Swap分区如何找到snapshot image放在什么地方?这就需要替换的swap_header来提供了,而swap_header在swap分区中的位置是不会变的。

还有一个问题就是,Swap中保存snapshot image的page不一定是连续,因此还得有一个方式来映射,这个工作就由swap_page_map做了,它本质还是一种bitmap,只是保存的不是内存的页面,而是Swap中的Offset。

(全文完)

如上流程图:

Hibernation.pdf

Resume Flowchart.pdf



标签: Kernel hibernation

评论:

大衍真君
2020-04-15 10:16
@wowo
1、对于hibernate功能的实现像是纯软件实现的,不依赖特定的硬件平台,但是为何默认都不支持此功能(移动设备,比如手机)?
2、hibernate中模式:reboot,platform和shutdown,对于platform跟shutdown有什么区别呢
吴兵
2019-11-01 21:08
是否可以分析一下STDisk的性能如何,在移动设备实现STD是否有必要
Rafe
2018-03-27 14:17
Hi Physh, Wowo,

请教个问题:我现在用的高通的平台,想要实现suspend to disk的功能,可是在内核中没有发现save_processor_state(),swsusp_arch_suspend()的实现,感觉是被裁剪了......或者我没找到.....
请问Physh分析Hibernate流程中的实现路径在哪里?另外,如何确定内核本身是否有实现这个功能?
Thanks~~
HelloYBSZ
2016-03-15 15:26
你好,我想问下, 您在 内容B. Swap 接口 里面画的图 里面的1,2,3 bitmap metadata 是指之前提到的copy_bm和orig_bm 吗,还是copy_bm和orig_bm这两个bitmap 会在snapshot image 里面
Physh
2017-10-25 17:15
@HelloYBSZ:如果没记错的话,bitmap metadata存放就是orig_bm, 具体有些不记得了~copy_bm和orig_bm不会放到snapshot image里边去。
HelloYBSZ
2016-02-25 17:47
你好,请问下在TuxOnice中 为什么要设置两个PageSet 。官方说是如不用两个PageSet  就只能保存一半内存的镜像大小。这是为什么呢?
wowo
2016-02-25 19:01
@HelloYBSZ:帮你找了一个链接(d. Write the first part of the image.):
Pageset 2 contains pages on the active and inactive lists; essentially the page cache. Pageset 1 contains all other pages, including the kernel.

http://tuxonice.nigelcunningham.com.au/node/50,按理说TuxOnice就是这样设计的,应该不需要纠结吧。
HelloYBSZ
2015-12-30 21:00
还有一个问题,Linux休眠时候,系统休眠的数据是保存到swap分区的。能否保存到其他地方的,比如对于持久化内存,这些数据能否保存到持久化内存里面?
wowo
2015-12-30 21:27
@HelloYBSZ:是不是可以在保存到swap分区之后,dd到其它分区中?
HelloYBSZ
2015-12-30 21:54
@wowo:恩,我想问下,不能跨过swap分区,直接保存到其他分区?
wowo
2015-12-30 22:14
@HelloYBSZ:应该可以,你可以看看写swap的代码,变成写分区的就可以了。
HelloYBSZ
2015-12-31 11:54
@wowo:请问博主了解做全系统状态保存的开源项目吗,目前一头雾水,我想看下别人怎么做的,学习下。
HelloYBSZ
2015-12-31 11:55
@HelloYBSZ:或者热启动的实现,特别是保存数据和恢复状态这一块
Physh
2017-10-25 17:16
@HelloYBSZ:可以把持久化内存直接挂成swap分区呀
HelloYBSZ
2015-12-30 09:57
你好,我想问下如何实现热启动,特别是内存数据,CPU数据,寄存器数据的保存和恢复这一块
komex
2015-05-14 21:19
LZ写的太好了  受益匪浅,尤其是画的图
zr
2015-01-12 23:04
请问Hibernation.pdf和Resume Flowchart.pdf 是用什么工具画出来的?很好看
Physh
2015-01-16 10:04
@zr:就是流程图软件啊
wowo
2014-12-22 18:22
文章写的非常不错,特别是附件的流程图,把整个Hibernate的过程,讲的很清楚。谢谢分享。
有两个小建议:
1. 编辑文章时,在下面部分可以添加摘要信息,那样首页就不会出现整篇文章。
2. 我之前写过一些电源管理子系统的文章(http://www.wowotech.net/sort/pm_subsystem),其中STR、autosleep、wakelocks等都有介绍,但hibernate功能一直没写,不知您能否把这篇文章补充进去?例如Linux电源管理(12)_Hibernate功能。
非常感谢!!
wowo
2014-12-22 18:28
@wowo:另外后台有有一个“文章链接别名”的功能,可以给文章链接起个别名,例如现在的链接是:http://www.wowotech.net/linux_kenrel/127.html,通过别名(如”hibernate“),可以修改为:http://www.wowotech.net/linux_kenrel/hibernate.html。
这样的会丰富一点。
Physh
2014-12-25 11:06
@wowo:我好像没有启用连接别名的权限哦,是否需要蜗蜗开启权限呢?
wowo
2014-12-25 12:22
@Physh:不用的,你看到的那个提示,只是一个提示。只要是作者都有权限。
Physh
2014-12-25 10:58
@wowo:嗯,谢谢肯定,我加进去

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog