本文基于以下软硬件假定:
架构:AARCH64
内核版本:5.14.0-rc5
在日常工作中经常会有以下情形,当我们正在使用电脑编写代码时,需要临时去开个会或处理一些紧急问题,此时就需要暂停编码工作。电脑在一段时间无操作后,将会关闭大部分硬件的电源,并进入睡眠模式,以降低功耗。当我们回来以后,通过操作键盘或鼠标,则又可以唤醒电脑,并继续先前未完成的工作。
同样当不需要使用手机时,它将会关闭屏幕进入待机状态,此时系统会保存进程上下文,并关闭外设和cpu电源。当需要再次使用手机时,又可通过按键等方式唤醒系统,然后恢复先前保存的上下文。
以上都是系统休眠的一些典型案例,由于休眠需要保存当前执行上下文,且在唤醒时恢复这些上下文,因此与关机相比,休眠唤醒需要处理更多的流程。如休眠时需要先关闭哪些设备,后关闭哪些设备,休眠过程中如何处理中断,以及如何唤醒已休眠的系统等。
与cpuilde类似,系统休眠也有深有浅,其中睡的越深功耗越低,相应的唤醒延迟越大,睡的越浅功耗越高,而其唤醒延迟也越小。根据睡眠状态由浅到深,Linux当前一共支持freeze、standby、mem和disk四种休眠方式,其特点如下:(1)freeze(suspend to idle):这种方式会冻结系统中的进程,挂起所有需要挂起的设备,然后将cpu切换为idle进程,使其进入idle状态。它不会将cpu从内核中移除,因此一旦被唤醒只需从idle状态退出,恢复挂起的设备和被冻结的进程即可
(2)standby(suspend to standby):这种方式除了执行所有freeze相关的流程外,还会将secondary cpu从内核中移除,然后primary cpu进入standby睡眠模式。standby模式睡眠较浅,不会对cpu断电,因此在睡眠时不需要保存cpu上下文。当其一旦被唤醒,cpu就能马上投入工作,并依次恢复系统运行
(3)mem(suspend to mem):相对于standby方式,这种方式下primary cpu需要先将cpu上下文保存到内存中,然后将自身断电。因此它不能直接被唤醒,而是需要先通过其它模块为其上电,然后再执行恢复cpu上下文以及其它模块的工作。由于这种方式,内核整个都已经睡着了,因此也不会有访问ddr的需求,因此也可以将ddr设置为自刷新模式,以进一步降低功耗
(4)disk(suspend to disk或hibernate):这是最深的一种睡眠模式,与suspend to mem将系统相关上下文保存到ddr中不同,它将系统上下文保存到磁盘中。由于所有上下文都已经保存到磁盘中,因此不仅外设、cpu可以下电,而且此时ddr也可以被断电
更进一步,为了更好地节能,SOC一般会将芯片上的电源分为多个power domain,其中aon domain在一般的休眠流程中不会被断电(如唤醒时需要该domain的支持)。而在hibernate时,由于可以从磁盘中的信息恢复整个系统,因此包含aon domain在内的整个系统都会被断电。当需要恢复系统时,则只需为其重新上电,然后从disk中恢复执行系统状态即可
当然系统并不需要支持以上所有休眠方式,如一般的架构都会支持freeze和mem方式,而standby和disk方式则可根据需求确定是否要支持。
我们可通过命令cat /sys/power/state查看系统支持的休眠方式,如在我的ubuntu系统中,支持所有四种休眠模式,其查询结果如下:
而在qemu模拟的arm64系统中,只支持freeze和mem两种休眠方式,其相应的查询结果如下:
由于hibernate休眠方式相对比较特殊,因此除了特别提及以外,后面的介绍将主要围绕suspend to ram进行。
休眠的本质是保存系统当前的运行状态,然后将其设置为一个低功耗模式。当休眠完成被唤醒时,则又通过先前保存的状态恢复系统执行。因此那些能独立执行特定任务的硬件都需要保存其运行状态,如cpu可执行程序代码,设备也可根据配置信息执行特定的功能。故系统休眠不仅需要考虑保存cpu相关的上下文,还需要保存设备相关的上下文。
对于cpu,其执行上下文主要包括进程上下文和中断上下文,因此在休眠时首先需要冻结系统中正在执行的进程,其次需要关闭相关的中断。同时,cpu本身还有一些全局的控制器寄存器(如armv8中的sctlr_elx等),并不与特定的进程上下文或中断上下文相关,因此在休眠时还需要保存cpu本身的上下文。
对于设备而言,由于不同设备的实现千差万别,因此包括上下文保存相关的休眠操作需要由每个设备自身实现。内核只为它们提供一个统一的框架,如在休眠的哪个阶段会调用哪个回调函数,设备驱动就可根据自身的需求实现其中相关的回调函数即可。
由以上介绍可知系统休眠主要包含冻结进程,挂起设备,关闭中断,挂起secondary cpu以及最终挂起primary cpu使整个系统进入休眠状态。其主要执行流程如下:
在该流程中,platform_xxx相关的函数由不同的平台通过回调函数的方式注册到pm core中,回调函数的格式根据休眠方式是否为freeze(suspend to idle)而有所不同,其定义分别如下:
struct platform_s2idle_ops {
int (*begin)(void);
int (*prepare)(void);
int (*prepare_late)(void);
bool (*wake)(void);
void (*restore_early)(void);
void (*restore)(void);
void (*end)(void);
}
struct platform_suspend_ops {
int (*valid)(suspend_state_t state);
int (*begin)(suspend_state_t state);
int (*prepare)(void);
int (*prepare_late)(void);
int (*enter)(suspend_state_t state);
void (*wake)(void);
void (*finish)(void);
bool (*suspend_again)(void);
void (*end)(void);
void (*recover)(void);
}
<< · Back Index ·>>
如果你不註意防范,患上類風濕性關節炎的風險就會增加。傢裡衣物總是晾不幹,被子濕漉漉的,地板和墻面滿是水跡,空氣中還有...