Linux Hibernate配置以及流程简单分析(@STM32MP157D)
关键词:Hibernate、suspend、swap、swsusp等。
1. Hibernate介绍
Linux支持的System Sleep States包括:freeze、standby、mem、disk。
/sys/power/state | suspend_state_t | 进入方法 |
freeze Suspend-to-Idle |
PM_SUSPEND_TO_IDLE |
1. echo freeze > /sys/power/state 2. echo s2idle > /sys/power/mem_sleep echo mem > /sys/power/state |
standby Power-on Suspend |
PM_SUSPEND_STANDBY |
1. echo standby > /sys/power/state 2. echo shallow> /sys/power/mem_sleep echo mem > /sys/power/state |
mem Suspend-to-RAM |
PM_SUSPEND_MEM |
1. echo deep > /sys/power/mem_sleep echo mem > /sys/power/state |
disk Hibernation/Suspend-to-Disk |
PM_SUSPEND_MAX |
1. echo disk > /sys/power/state |
从freeze->standby->mem->disk,省电程度越来越深,但是睡眠所需处理的工作和恢复复杂度都增加。
用户空间对System Sleep States的操作通过/sys/power目录下sysfs进行。
/sys/power/
├── disk--对state写disk时,保存hibernation镜像后的不同操作进行定义。包括platform/shutdown/reboot/suspend/test_resume。
├── image_size--Hibernation镜像大小限制。
├── mem_sleep--对state写mem时,是进入s2idle/shallow/deep进行配置。
├── pm_async
├── pm_freeze_timeout
├── reserved_size
├── resume
├── resume_offset
├── state--读返回系统支持的状态;写则进行状态设置。
├── suspend_stats
│ ├── fail
│ ├── failed_freeze
│ ├── failed_prepare
│ ├── failed_resume
│ ├── failed_resume_early
│ ├── failed_resume_noirq
│ ├── failed_suspend
│ ├── failed_suspend_late
│ ├── failed_suspend_noirq
│ ├── last_failed_dev
│ ├── last_failed_errno
│ ├── last_failed_step
│ └── success
└── wakeup_count
关于不同System Sleep States的详细说明和sysfs介绍参考:sleep-states.rst - Documentation/admin-guide/pm/sleep-states.rst - Linux source code (v5.4.31) - Bootlin。
2. Linux下Hibernate配置及操作
在内核中使能Hibernation功能:
由于Hibernate镜像需要保存在swap文件中,所以在内核中使能swap功能:
由于在hibernate过程中backlight pwm和panel rgb阻碍suspend流程,在dts和defconfig中关闭:
CONFIG_PWM_STM32=n
CONFIG_PWM_STM32_LP=n
修改cmdline,增加hiernate相关内容:
resume=/dev/mmcblk2p3 hibernate=nocompress
创建并挂载swap分区:
mkswap /dev/mmcblk2p3
swapon /dev/mmcblk2p3
触发系统进入hibernate:
echo disk > /sys/power/state
对设备重启或者重新上电后,会进入hibernate的resume流程。
3. Linux Hibernate简单分析
3.1 Hibernate和Resume日志
对/sys/power/state写入disk会触发Hibernate流程,首先执行Linux Kernel的Suspend to Disk流程,然后通过smc进入到BL32(ARMv7A中BL32代替ARMv8A中BL31和BL32功能)中,执行PSCI的SYSTEM_OFF。
hibernate suspend流程log:
Kernel suspend流程:
[ 52.887333] PM: hibernation entry
[ 52.929313] Filesystems sync: 0.035 seconds
[ 52.932150] Freezing user space processes ... (elapsed 0.001 seconds) done.
[ 52.939024] OOM killer disabled.
[ 52.942457] PM: Preallocating image memory... done (allocated 16233 pages)
[ 53.248077] PM: Allocated 64932 kbytes in 0.30 seconds (216.44 MB/s)
[ 53.254523] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
[ 53.384540] PM: Creating hibernation image:
[ 53.384540] PM: Need to copy 16078 pages
[ 53.384540] PM: Hibernation image created (16078 pages copied)
[ 53.554738] mmc2: switch to bus width 8 failed
[ 53.560104] PM: Saving image data pages (16094 pages)...
[ 53.564545] PM: Image saving progress: 0%
[ 53.601408] PM: Image saving progress: 10%
[ 53.629244] PM: Image saving progress: 20%
[ 53.656327] PM: Image saving progress: 30%
[ 53.685321] PM: Image saving progress: 40%
[ 53.712630] PM: Image saving progress: 50%
[ 53.740625] PM: Image saving progress: 60%
[ 53.768257] PM: Image saving progress: 70%
[ 53.797453] PM: Image saving progress: 80%
[ 53.825003] PM: Image saving progress: 90%
[ 53.859307] PM: Image saving progress: 100%
[ 56.790787] PM: Image saving done
[ 56.792765] PM: Wrote 64376 kbytes in 3.22 seconds (19.99 MB/s)
[ 56.799714] PM: S|
[ 56.858127] reboot: Power downTFA SYSTEM_OFF流程:
INFO: arnoldlu psci_smc_handler smc_fid=0x84000008 [r1:r3]=0x00000000 0x00000000 0x00000000
INFO: arnoldlu psci_system_off
INFO: PSCI Power Domain Map:
INFO: Domain Node : Level 1, parent_node -1, State ON (0x0)
INFO: Domain Node : Level 0, parent_node 0, State ON (0x0)
INFO: CPU Node : MPID 0x0, parent_node 0, State ON (0x0)
INFO: CPU Node : MPID 0xffffffff, parent_node 0, State OFF (0x2)
INFO: arnoldlu stm32_system_off
INFO: arnoldlu stm32_enter_low_power, mode=0x00000005, nsec_addr=0x00000000
INFO: arnoldlu enter_cstop-133
INFO: arnoldlu stm32_pwr_down_wfi-338
INFO: arnoldlu stm32_pwr_down_wfi-343
Hibernate resume在Kernel启动过程中检查swap空间是否存在Hibernate行为,如果是则加载镜像恢复现场。流程log如下:
[ 3.500455] PM: resume from hibernation
[ 3.504076] Freezing user space processes ... (elapsed 0.000 seconds) done.
[ 3.509839] OOM killer disabled.
[ 3.536106] PM: Loading image data pages (16094 pages)...
[ 3.540530] PM: Image loading progress: 0%
[ 3.637384] PM: Image loading progress: 10%
[ 3.652342] PM: Image loading progress: 20%
[ 3.666588] PM: Image loading progress: 30%
[ 3.681412] PM: Image loading progress: 40%
[ 3.695582] PM: Image loading progress: 50%
[ 3.709767] PM: Image loading progress: 60%
[ 3.726351] PM: Image loading progress: 70%
[ 3.740577] PM: Image loading progress: 80%
[ 6.184681] PM: Image loading progress: 90%
[ 6.992923] PM: Image loading progress: 100%
[ 6.997255] PM: Image loading done
[ 6.999253] PM: Read 64376 kbytes in 3.45 seconds (18.65 MB/s)
[ 53.546686] OOM killer enabled.
[ 53.548373] Restarting tasks ... done.
[ 53.554439] PM: hibernation exit
# [ 53.608205] mmc1: Problem switching card into high-speed mode!
3.2 Linux下Hibernate/Resume代码分析
Linux下hibernate suspend流程:
sate_store hibernate hibernation_available lock_system_sleep pm_prepare_console __pm_notifier_call_chain ksys_sync_helper freeze_processes lock_device_hotplug create_basic_memory_bitmaps--针对页表创建memory_bitmap,然后将不需要保存的页表标记。 hibernation_snapshot
platform_begin
hibernate_preallocate_memory
freeze_kernel_threads
hibernate_test
dpm_prepare
suspend_console
create_image--创建Hibernate镜像。
dpm_resume
resume_console
dpm_complete
platform_end
thaw_kernel_threads
swsusp_free swsusp_write swsusp_free power_down--根据hibernate模式不同执行不同流程,通过/sys/power/state设置。 suspend_devices_and_enter--suspend模式,既保存了Hibernate镜像,也进行Suspend流程。当从suspend唤醒时,则丢弃Hibernate镜像;如果走开机流程,检测到Hibernate镜像,则恢复镜像内容。 kernel_restart--reboot模式,最终调用PSCI的SYSTEM_RESET。 hiberrnation_platform_enter--platform模式,由平台自定义睡眠和唤醒流程。 kernel_power_off--默认为shutdown模式,最终调用PSCI的SYSTEM_OFF。
在Linux启动时,调用software_resume检查是否上次为hibernate关闭。此时所有的设备已经被初始化,首先判断Hibernate镜像是否可读。
late_initcall_sync(software_resume)
swsusp_check--从swsusp_resume_device设备中检查Hibernate镜像是否可用。如果不可用,则不会执行如下流程。退出进行正常启动流程。
pm_prepare_console
__pm_notifier_call_chain
freeze_processes--将当前用户空间的进程冻结。
load_image_and_restore
lock_device_hotplug
create_basic_memory_bitmaps
swsusp_read
swsusp_close
hibernation_restore--从Hibernate镜像中恢复。
resume_target_kernel
swsusp_free
free_basic_memory_bitmaps
unlock_device_hotplug
thaw_processes--解冻用户空间进程,此时解冻恢复的进程是Hibernate中的进程。
__pm_notifier_call_chain
pm_restore_console
swsusp_close
以上仅是代码流程简单记录,遗留问题:
1. 如何根据页表属性创建bitmap,然后在进行页表保存的?
2. swsusp保存和恢复镜像的过程?
3. Software Resume流程判断Hibernate镜像的规则?
4. Hibernate镜像采取压缩和非压缩性能和空间对比?