LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

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

 关于suspend(mem),《Generic PM之Suspend功能》和《Hibernate和Sleep功能介绍》中做了详细介绍;Hibernate包括对镜像保存和恢复,甚至可以和Suspend流程混合使用,《Hibernate功能》中做了简单介绍。

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 down

TFA 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镜像采取压缩和非压缩性能和空间对比?

posted on 2022-12-10 23:47  ArnoldLu  阅读(1567)  评论(0编辑  收藏  举报

导航