1. 实验平台
cpu: omap4460 blaze tablet
memory: 1-GB DRAM
OS: android 4.0.3, kernel 3.0.31
2.流程分析
2.1 create and save image procedure
1).
echo "disk" > /sys/power/state
2). state_store() kernel/power/main.c
3). hibernate() kernel/power/hibernate.c
pm_prepare_console()
pm_notifier_call_chain(PM_HIBERNATION_PREPARE)
usermodehelper_disable()
//usermode enables multiple virtual linux systems (known as guests) to run as an application within a normal Linux system (known as the host)
//from wiki usermode
create_basic_memory_bitmaps()
//create bitmaps needed for marking page frames that should not be saved and free page frames.
//forbidden_pages_map, free_pages_map
sys_sync()
prepare_processes()
freeze_processes() kernel/power/process.c
//freeze user space process and kernel task
hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM)
//hibernation_mode=HIBERNATION_SHUTDOWN
//Quiesce devices and create a hibernation image
4). hibernation_snapshot()
dpm_prepare(PMSG_FREEZE) drivers/base/power/main.c
//execute ->prepare() callback for all non-sysdev devices, device list movement dpm_list-->dpm_prepared_list
hibernate_preallocate_memory() kernel/power/snapshot.c
//Preallocate memory for hibernation image
suspend_console()
pm_restrict_gfp_mask()
//avoid i/o and fs to allocate memory during suspend procedure
//clear bit GFP_IOFS of gfp_allowed_mask
dpm_suspend(PMSG_FREEZE)
//execute ->suspend() callback for all non-sysdev devices, device list movement dpm_prepared_list-->dpm_suspended_list
5). create_image()
dpm_suspend_noirq(PMSG_FREEZE)
//execute "late suspend"
suspend_device_irqs() kernel/irq/pm.c
//disable all currently enabled interrupt lines
//after this function, device will can't receive interrupt
device_suspend_noirq()
//execute -->suspend_noirq callback for all non-sysdev devices, device list movement dpm_suspended_list-->dpm_noirq_list
disable_nonboot_cpus()
local_irq_disable()
syscore_suspend() driver/base/syscore.c
//execute all the registered system core suspend callbacks
//all system core devices linked with syscore_ops_list
pm_wakeup_pending()
//Check if power transition in progress should be aborted.
//set in_suspend to 1 ,it is saved in nosave section of ELF format
save_processor_state() include/linux/suspend.h
preempt_disable() include/linux/preempt.h
swsusp_arch_suspend() arch/arm/kernel/swsusp.S <patch from swsusp>
//Save the current CPU state to memory
//store cpu's registers to memory address ctx in turn
//system mode register:cpsr,r0--14
//supervisor mode register: spsr,sp,lr
adr r0, ctx
mrs r1, cpsr
stm r0!, {r1} /* current CPSR */
msr cpsr_c, #SYSTEM_MODE
stm r0!, {r0-r14} /* user regs */
msr cpsr_c, #SVC_MODE
mrs r2, spsr
stm r0!, {r2, sp, lr} /* SVC SPSR, SVC regs */
msr cpsr, r1 /* restore original mode */
__save_processor_state arch/arm/mach-omap2/sleep44xx.S
//store r0--12,lr to stack
//store CPU CP15 registers to memory address ctx in turn
// sp,spsr,lr
//c1,c2,c3,c10,c12,c13,cpsr,c1_controler_register
blv7_flush_dcache_all
//Flush all data from the L1 data cache before disabling SCTLR.C bit
//Clear the SCTLR.C bit to prevent further data cache allocation. Clearing SCTLR.C would make all the data accesses strongly ordered and would not hit the cache.
//pop stack to r0--12,pc; so this is sub function(__save_processor_state) return
b swsusp_save
//swsusp_save is a C-function, it exit will cause
swsusp_arch_suspend return
swsusp_save() kernel/power/snapshot.c
//Creating hibernation image
swsusp_alloc()
//allocate memory for the suspend image
drain_local_pages(NULL) mm/page_alloc.c
//Spill all of this CPU's per-cpu pages back into the buddy allocator
copy_data_pages(©_bm, &orig_bm)
restore_processor_state()
include/linux/suspend.h
preempt_enable()
syscore_resume()
//Execute all the registered system core resume callbacks.
local_irq_enable()
enable_nonboot_cpus()
dpm_resume_noirq(PMSG_RECOVER)
device_resume_noirq()
//Execute an "early resume" callback for given device,
device list movement dpm_noirq_list-->dpm_suspended_list
resume_device_irqs() kernel/irq/pm.c
//enable interrupt lines disabled by suspend_device_irqs()
dpm_resume(
PMSG_RECOVER)
resume_console()
dpm_complete(
PMSG_RECOVER)
swsusp_write()
swsusp_free()
power_down()
2.2 power on and restore procedure