SlideShare a Scribd company logo
The Power 
On 
Linux-Kernel 
課程:Linux-Kernel At Summer Training In 2014. 
學生:陳冠宇、郭儲嘉 
老師:張大緯老師
• Agenda 
• Introduction 
Why we choice 
Data structure in “Kconfig” 
• Explain Code 
autosleep.c 
poweroff.c 
suspend.c 
• Summary 
2014/8/26 
2
• Introduction 
 Why we choice. 
 Data structure in “Kconfig” 
2014/8/26 
3
• Why we choice 
「電」的問題無論在任何電器用品上都是重 
要的一環。任何控制設備都與電息息相關,舉 
凡開關機、待機、休眠、外接設備的驅動程式 
等皆與「電」脫離不了關係。 
鑑於此,選擇此主題將是我們對於核心與外 
部設施連接的最佳切入點。 
2014/8/26 
4
• Kconfig 
• SUSPEND 
• SUSPEND_FREEZER 
• HIBERNATION 
• PM_STD_PARTITION 
• PM_AUTOSLEEP 
• PM_WAKELOCK 
• PM_RUNTIME 
• PM_DEBUG 
• PM_ADVANCED_DEBUG 
• PM_SUSPEND_TEST 
2014/8/26 
5
• SUSPEND 
• 允許系統進入睡眠狀態。在對記憶體供電的 
狀況下將內容保存起來。 
例如:SUSPEND– TO–RAM. 
• 相依於ARCH_SUSPEND_POSSIBLE. 
• SUSPEND_FREEZER 
• 如果關閉此功能,在暫停的狀況下就不會讓 
任務凍結。(強烈不推薦關閉) 
• 相依於SUSPEND. 
2014/8/26 
6
• HIBERNATION 
• 啟動「Suspend to disk(STD)」的功能,在許多 
作業系統的User Interface之中,大家都稱呼他 
為「休眠」。STD會將確認點放置於系統當中 
以確認系統的資料從記憶體儲存到硬碟當中, 
並將之斷電。當重新啟動的時候,此確認點 
將會置放於reboot上。 
• 相依於 
• SWAP 
• ARCH_HIBERNATION_POSSIBLE 
2014/8/26 
7
• HIBERNATION(contd.) 
• 在Kconfig中有推薦使用者可以將resume的路 
徑放置在核心的bootloader的配置檔案 
(configuration file)當中。 
2014/8/26 
8
• PM_STD_PARTITION 
• 預設的重新啟動區域在做STD時將會尋找映像 
檔案以完成動作。幾乎全部的使用者在此區 
域上都會有所不同。 
• 該配置(PM_STD_PARTITION)必須在暫停 
之前設置成SWAP磁區,否則休眠後將無法甦 
醒。另外,該磁區是可以被指定覆寫的。 
格式:resume=/dev/<other device> 
範例:resume=/dev/sda2 
• 相依於HIBERNATION 
2014/8/26 
9
• PM_AUTOSLEEP 
• 允許核心觸發系統功能「進入全域性的睡眠 
模式」,只要沒有任何喚醒源有活動將之影 
響到,就不會導致喚醒的動作發生。 
• 相依於PM_SLEEP(尋根究底和SUSPEND有關) 
• PM_WAKELOCK 
• 允許使用者空間可以搭配sysfs-based的 
Interface去創造、啟動和關閉喚醒源的事件。 
• 相依於PM_SLEEP. 
2014/8/26 
10
• PM_WAKELOCK(contd.) 
• Sysfs:為Linux2.6所提供的虛擬檔案系統,這 
個檔案系統不僅可以把裝置、驅動程式的資 
訊從核心輸到用戶空間,也可以用來對裝置 
和驅動程式做設定。 
每個被加入Driver model tree的物件包括驅動 
程式、裝置等都會在sysfs檔案系統中以目錄 
的方式呈現。 
2014/8/26 
11
• PM_RUNTIME 
• 允許I/O裝置可以在特別指定的閒置週期過後 
的run-time狀況下進入低功耗狀態,如果有硬 
體生成的喚醒事件或是由裝置需求導致而產 
生,將會為了回應這些事件而導致其甦醒。 
• 相依於!IA64_HP_SIM(init/Kconfig) 
2014/8/26 
12
• 各種硬體配置、工業標準等。 
2014/8/26 
13
• PM_DEBUG 
• 該選項允許在Power management code中做各 
種調整的支援,這對於PM在Debug和回報錯 
誤上是相當有幫助,例如suspend support。 
• 相依於PM. 
• PM_ADVANCED_DEBUG 
• 加入一個額外的sysfs的屬性,從使用者的空 
間去訪問裝置物件中PM的檔案。 
• 在此該註解特別提醒:「如果您不是一個對 
除錯和測試PM相當有興趣的核心系統開發人 
員,請別任意使用。」 
• 相依於PM_DEBUG. 
2014/8/26 
14
• PM_SUSPEND_TEST 
• 此選項可以讓您在啟動狀態下暫停您的機器, 
並且在數秒後再次甦醒。其甦醒源使用了RTC 
的計時使之產生喚醒源的警告。 
當然,使用者必須先擁有系統的RTC裝置的鏈 
結,並請確保它是可以用的,否則使用者將 
無法測試。 
• 相依於 
• SUSPEND 
• PM_DEBUG 
• RTC_CLASS 
2014/8/26 
15
• Explan Code 
• autosleep.c 
• poweroff.c 
• suspend.c 
2014/8/26 
16
• autosleep.c 
• 在閒暇之時,讓系統「睡眠」。 
1. 宣告、定義工作的內容和屬性。 
2. 得知現行的「目標」及「狀況」。 
3. 「確保」手邊的工具齊全。 
4. 「開始」工作。 
2014/8/26 
17
• 注意事項 
• 若是喚醒源被呼叫,可以利用mutex以確保資 
源的安全,否則將有可能會進入死結的狀態 
當中。 
• 另外mutex_lock_interruptible是可以被使用的, 
但是如果auto_sleep的循環不斷嘗試著去Freeze 
processes,則將會發生錯誤。 
2014/8/26 
18
• Autosleep_state: 
經被宣告為int型態的suspend_state_ttypedef所宣 
告。 
• 參考:include/linux/suspend.h 
• autosleep_wq: 經Workqueue_struct宣告,內 
部宣告了工作隊列表、保護用的mutex、顏色、 
隊列甚至如果想要的話,則還有sysfs、 
lockdep可用。 
• 參考:kernel/workqueue.h 
2014/8/26 
19
2014/8/26 
20
• try_to_suspend(struct work_struct *work) 
1. 判斷喚醒源數量 
2. 系統是否有在跑動 
3. 自動睡眠的模式為何 
4. 確認是否有其他的任務也嘗試著讓系統睡眠 
5. 再次判斷喚醒源的數量,若還是有,則代表 
有錯誤發生,處理錯誤。 
2014/8/26 
21
• pm_get_wakeup_count(): 
• 功用:讀取暫存器的wakeup-events的數量。如 
果並沒有任何處理中的喚醒事件則回傳ture。 
• 來源:drivers/base/power/wakeup.c 
2014/8/26 
22
• pm_save_wakeup_count(): 
• 功用:若當前的Counter和喚醒源的事件數量相 
同且並無任何喚醒源事件,則將目前的Counter 
記錄下來並且回傳True確認正在處理事件。 
• 來源:drivers/base/power/wakeup.c 
2014/8/26 
23
• PM_SUSPEND_ON: 
• 功用:ACPI的S0。 
• 來源:driver/acpi/sleep.c 
2014/8/26 
24
• ACPI 
• ACPI( Advanced configuration and power 
interface):工業標準。提供作業系統應用程式 
管理所有電源管理介面。其中工作狀態分之 
為: 
• G0(S0):正常工作狀態。 
• G1:睡眠,細分為S1~S4四種狀態,喚醒時間 
從S1~S4愈來愈慢。 
• STANDBY、MEM、MAX,分別等於S1(最耗 
電的睡眠模式)、S3(掛置到記憶體中,稱之為 
暫停,仍然對記憶體供電)及S5(G2) 
2014/8/26 
25
• ACPI(contd.) 
G2(S5):Soft off,電腦仍然可以被鍵盤、clk、 
網路、電話或是USB裝置所喚醒。 
G3:Mechanical off。幾乎和G2相同,將電腦的 
電源全部移開,但此時的RTC依然在跳動。 
2014/8/26 
26
• pm_suspend() : 
• 功用:確認系統暫停的狀態。確認是否有其他 
的任務也試著讓系統進入暫停狀態。而後藉由 
Freeze來凍結外部的程序。 
• 來源:kernel/power/suspend.c 
2014/8/26 
27
• schedule_timeout_uninterruptible(HZ/2) 
• 功用:若系統喚醒的發生原因未知,則會等待, 
並防止系統暫停及喚醒的循環。如果之後程式 
正常,則會繼續排程(schedule)。但如果有問題, 
則會由核心告知系統錯誤並且傾印問題進入 
stack中。 
• 來源: kernel/timer.c 
2014/8/26 
28
2014/8/26 
29
• static DECLARE_WORK() 
• 功用:在此是將try_to_suspend初始化。利用到 
__WORK_INITIALIZER(n, f)),將內部的料、 
入口、使用Function、工作的lockdep等初始化。 
• 來源:include/linux/workqueue.h 
2014/8/26 
30
• queue_up_suspend_work() 
• 功用:讓設備在指定的CPU中工作。內部判斷目 
前autosleep的狀態,如果到達一定標準則開始 
做排隊,此時才會去關閉一些外部設備,否則 
若無此判斷進來無意義。__queue_work(cpu, 
*wq, *work)來指定相對的CPU和隊列、工作等 
將之傳入。 
• 來源:kernel/workqueue.c 
2014/8/26 
31
• pm_autosleep_state(void) 
• 功用:整數型態。將回傳目前autosleep的狀態 
autosleep_state。(呼應到suspend_state_t) 
• 來源:kernel/power 
2014/8/26 
32
• pm_autosleep_lock(void) 
• 功用:整數型態。內部將判斷該藉由快速通道 
或是慢速來進行mutex的luck。若為快速則是內 
部count從1->0時上lock,若為慢速則有可能會 
使用到interrupt. 
• 來源: 
• asm-generic/mutex-xchg.h 
• kernel/locking/mutex.c 
2014/8/26 
33
• 快速:藉使用mutex_set_owner直接對該 
lock.owner做當前狀態的儲存。 
• 慢速:必須將目前的LOCK、任務中斷、回傳點 
等一一傳入__mutex_lock_common中,禁止搶占 
(preempt_disable)後才可以取得mutex的使用。 
2014/8/26 
34
• pm_autosleep_unlock(void) 
• 功用:相對於pm_autosleep_lock,此function則 
是利用mutex_unlock()直接解除autosleep_lock的 
鎖。 
• 來源:kernel/locking/mutex.c 
2014/8/26 
35
• pm_autosleep_set_state(int state) 
• 功用:確認目前的狀態,如果狀態確定是非正 
常工作狀態才進入suspend,否則就關閉自動睡 
眠並且回到正常工作。 
• 步驟: 
1. 通知PM Core有喚醒事件。(防止其他喚醒源) 
2. Mutex上鎖、讀取當前工作的狀態。 
3. 通知PM Core喚醒事件已經結束了。 
4. 確認目前工作狀態。 
5. 解除mutex。 
2014/8/26 
36
• EINVAL(invalid argument無效參數)=22。 
• 來源:include/uapi/asm-generic/errno-base.h 
2014/8/26 
37
• __pm_stay_awake(autosleep_ws) 
• 功用:通知PM Core喚醒事件,傳入參數為 
Wakeup-source。告知目前狀態的喚醒源。 
• 來源:drivers/base/power/wakeup.c 
2014/8/26 
38
• __pm_relax(autosleep_ws) 
• 功用:通知PM Core喚醒事件結束。允許其他 
喚醒源通知。 
• 來源:drivers/base/power/wakeup.c 
2014/8/26 
39
• pm_wakep_autosleep_enabled(bool) 
• 功用:修改全部喚醒源的autosleep的啟動狀態。 
• 來源: drivers/base/power/wakeup.c 
2014/8/26 
40
• pm_autosleep_init(void) 
• 功用:初始化autosleep,結果正常則會回傳0, 
否則將回傳ENOMEM。 
• 步驟: 
1. 判斷喚醒源是否製造成功 
2. 判斷分配工作隊列是否成功 
3. 移除喚醒源,回傳錯誤。 
2014/8/26 
41
• wakeup_source_register(char *name) 
• 功用:製造一個喚醒源並且將之加入到列表中。 
內部會先使用wakeup_source_create(name),並 
且利用wakeup_source_add將之加入。 
• ENOMEM=Out of memory 
• 來源:drivers/base/power/wakeup.c 
2014/8/26 
42
• alloc_ordered_workqueue(name, arg) 
• 功用:分配已有序的工作隊列。與 
alloc_workqueue相關,分配一個特定的區段給 
它。 
• 來源: 
• include/linux/workqueue.h 
• Documentation/workqueue.txt. 
2014/8/26 
43
• wakeup_source_unregister(void) 
• 功用:從表列中移除喚醒源。利用到 
wakeup_source_remove(ws) , wakeup_source_des 
troy(ws)。 
• 來源: deivers/base/power/wakeup.c 
2014/8/26 
44
• Poweroff.c 
• 系統要求正常地將機器關機(斷電)。 
• 步驟: 
1. 設定關機的執行步驟 
2. 將「關機」這項工作宣告好 
3. 將此「工作」放進排程中 
4. 宣告成結構,方便呼叫引用 
5. 初始化此結構,並將此初始化放置於列表中。 
2014/8/26 
45
• do_poweroff(struct) 
• 功用:將系統正常關機,內部使用到 
kernel_power_off。 
• 步驟: 
1. 關機前的準備。(shutdown_prepare) 
2. 判斷是否準備完成(指定完成),完成後 
做該Function的動作。(Poweroff-prepare) 
3. 設定指定的CPU去工作。(migrate) 
4. 讓系統核心逐一關閉。(syscore-shutdown) 
5. 系統回傳信息後將核心信息存好。 
(kmsg_dump) 
6. 機器關機。(machine_power_off) 
2014/8/26 
46
2014/8/26 
47
• kernel_shutdown_perpare(enum) 
• 功用:關機前的準備。使用鏈上的功能,並將 
當前系統狀態處存下來,而後關閉 
Usermodehelper並將每一個裝置關機。 
• 來源:kernel/reboot.c 
2014/8/26 
48
• 通知鏈結(notifier_call_chain): 
• 功用:Linux系統中有提供「通知鏈結」的功能, 
鏈表上的每一個節點都有一個Function,當事件 
發生時表上的節點所對應的Function將會被執行。 
所以對表來說有一個接收、一個通知。 
• 總和來說,事件的接收者將事件發生時所對應 
的操作存起來,當事件發生時通知者依次執行 
每一個元素的Function。 
• 程式中使用的是可阻塞的通知鏈。 
• 程式來源:kernel/reboot.c 
2014/8/26 
49
• 通知時的注意事項 
• 功用:關閉RCU機制才去做通知。 
• 來源:kernel/reboot.c 
2014/8/26 
50
• RCU(Read Copy Update) 
• 功能:允許多個讀取與更新同時發生的事件, 
不使用Lock的概念,適合讀者多寫者少的狀況。 
利用read-lock(時間到輪流)來避免強佔事件。 
• 來源:kernel/locking/rwsem.c 
2014/8/26 
51
• usermodehelper_disable() : 
• 功用:一般而言,系統調用函式是相當常見的, 
一般而言都是由使用者調用kernel的function。 
• 當方向相反的使用則需要使用usermodehelper。 
例如當kernel找到一個device,而需要load某個 
module。而此function就是防止有新的helper出 
現。 
• 來源: Kernel/kmod.c 
2014/8/26 
52
2014/8/26 
53
• device_shutdown() 
• 功用:對每一個裝置呼叫shutdown()指令。利用 
尋訪Device list去一一的將裝置關機,又稱 
offline 
• 來源:drivers/base/core.c 
2014/8/26 
54
2014/8/26 
55
• pm_power_off_prepare() 
• 功用:利用Function point的方式,可以從外部 
將需要的功能存入此函式中並且將之執行。用 
判斷式判斷是否已指向需要的Function。 
• 來源:kernel/reboot.c 
2014/8/26 
56
• migrate_to_reboot_cpu() 
• 功用:關閉熱插拔裝置、運行任務在指定的 
CPU上並防止有其他的任務遷移至本區、確認 
只運行在適當的處理器上。可參考同檔案下的 
kernel_restart。 
• 來源:kernel/reboot.c 
2014/8/26 
57
• CPU_hotplug_disable() 
• 功用:將熱插拔系統關閉。熱插拔指的是在電 
腦熱機的狀態增減硬體。過去大家是使用套件, 
當新裝置進入時該套件會自行配置。在linux2.6 
版過後,採用udev自動產生,而它不只是一個 
設備檔案產生器,更是一個核心信息的監聽器。 
• 來源: kernel/cpu.c 
2014/8/26 
58
• set_cpus_allowed_ptr(current, cpumask_of(cpu)) 
• 功用:確保只運行在指定的CPU上。內部使用 
到task_lock來確認不會有其他的任務參雜且可 
確認任務的正確性及CPU使用的正確性。 
• 來源: kernel/sched/core.c 
2014/8/26 
59
• syscore_shutdown() 
• 功用:執行Function使得被暫存的系統核心逐一 
關閉,例如中斷裝置等。本部分也是利用list的 
方式逐一關閉。 
• 來源: deivers/base/syscore.c 
2014/8/26 
60
• pr_emerg("Power downn") 
• 功用:在定義中使用printk的方式由核心告知使 
用者,優先權為KERN_EMERG(最高優先權, 
告知系統不可用) 
• 來源: include/linux/printk.h, kern_levels.h 
2014/8/26 
61
• kmsg_dump() 
• 功用:將kernel的log傾印至kernel message 
dumpers中,方便以後檢索時可以使用。傾印可 
以儲存程式資訊,以便在偵錯的時候使用。 
• 來源: kernel/printk/printk.c 
2014/8/26 
62
• machine_power_off(void) 
• 功用:因include reboot.c,故以該檔內的意思為 
主。 
直接執行struct machine_ops的power_off將系統 
關閉,此處若用int做受值可以接受回傳的系統 
值即可知道錯誤與否。 
• 來源: arch/sh/kernel/reboot.c 
2014/8/26 
63
• DECLARE_WORK(poweroff_work, do_poweroff) 
• 功用:工作的宣告。此Function是使用 
__WORK_INITIALIZER()去初始化結構內部的值, 
第一個是之後使用的入口地址、後方放的是「工 
作」,初始化包含data, entry address, function and 
lockdep。 
• 來源: include/linux/lockdep.h 
2014/8/26 
64
• Lockdep:假設每一個Process都是鑰匙,而資 
源稱之為鎖。在linux系統中,如果發生了AB-BA 
死結狀態,可能可以用「順序」的方式去 
解開,但是面對成千上萬的「鎖」卻無法如 
此。 
• 而lockdep在2006年引入Linux-kernel中,它的 
操作並非以單一一個資源為例,而是以同個 
類別去觀察。 
• 它循跡每一個鎖的狀態和關係,並且通過一 
系列的驗證規則以確保各個狀態之間的依賴 
關係是可行且正確的。 
• 參考:include/linux/lockdep.h 
2014/8/26 
65
• handle_poweroff(int key) 
• 功用:在啟動的CPU上運行系統所要求的關機 
指令。使用到schedule_work_on,將從目前在 
線的CPU列表中挑選出第一個,並將它及關機 
的動作送入工作排程之中。 
2014/8/26 
66
• queue_work() 
• 功用:讓工作排在工作隊列上。如果回傳False 
則代表already。在此要特別注意,此工作雖然 
一樣是讓工作在特定的CPU上排隊準備,但這 
邊要請使用者確認該工作不會突然離去導致隊 
列出問題。 
• 來源:include/linux/workqueue.h 
2014/8/26 
67
• 將設置好的動作送入結構中以備使用需要 
• 將初始化的動作包裝起,送入列表當中。 
2014/8/26 
68
• pm_sysrq_init(void) 
• 功用:呼叫了__sysrq_swap_key_ops,將結構送 
入sysrq_key_table[i]列表中。最後將RCU做同步, 
使得更新與讀取是為同步。 
• 來源:drivers/tty/sysrq.c 
2014/8/26 
69
• subsys_initcall() 
• 功用:子程序的初始化,此Function定義於 
__define_initcall中,通常USB及外部裝置都會 
將相關的函式放入其內。 
它們使用並非隨便任意,而是有相關的順序, 
而順序取決於當時給予其之參數。 
• 來源:include/linux/init.h 
2014/8/26 
70
•Suspend.c 
• 流程 
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish 
2014/8/26 
71
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
int pm_suspend(suspend_state_t state) 
(line 427) 
• 判斷狀態參數是否正確 
• include/linux/suspend.h, line 36 
• #define PM_SUSPEND_ON ((__force suspend_state_t) 0) 
• #define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1) 
• #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2) 
• #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) 
• #define PM_SUSPEND_MIN PM_SUSPEND_FREEZE 
• #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) 
• 進入enter_state 
• 將結果記錄下來
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static int enter_state(suspend_state_t state) 
(line 370) 
• 追蹤suspend_enter的狀態 
• include/trace/events/power.h, line 12 
• #define TPS(x) tracepoint_string(x) 
• include/linux/ftrace_event.h, line 604 
• 可將該參數的狀態、內容等等資訊映射出來
static int enter_state(suspend_state_t state) 
(line 370) 
• 判斷是否為凍結狀態 
• kernel/power/main.c, line 75 
• [TEST_NONE] = "none" 
• [TEST_CORE] = "core" 
• [TEST_CPUS] = "processors" 
• [TEST_PLATFORM] = "platform" 
• [TEST_DEVICES] = "devices" 
• [TEST_FREEZER] = "freezer"
static int enter_state(suspend_state_t state) 
(line 370) 
• 判斷是否支持該電源狀態 
• 需要較低層級的支持和實作 
• 互斥鎖 
• 只允許處理一個suspend 
• 如果state是freeze,調用freeze_begin, 將凍結喚醒 
關閉(suspend_freeze_wake = false)
static int enter_state(suspend_state_t state) 
(line 370) 
• 追蹤sync_filesystems的狀態 
• 同步filesystems 
• 進行suspend前的準備
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static int suspend_prepare(suspend_state_t state) 
(line 167) 
• 需要處理什麼狀態,同時是否支援此狀態 
• 將當前console切換到一個虛擬console並重定向 
kernel的kmsg
static int suspend_prepare(suspend_state_t state) 
(line 167) 
• 發送suspend開始的消息 
• include/linux/suspend.h, line 350 
• #define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ 
• #define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ 
• #define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ 
• #define PM_POST_SUSPEND 0x0004 /* Suspend finished */ 
• #define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ 
• #define PM_POST_RESTORE 0x0006 /* Restore failed */ 
• 追蹤freeze_processes的狀態 
• freeze user processes和一些kernel threads
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static int enter_state(suspend_state_t state) 
(line 370) 
• 判斷是否為suspend to freeze 
• 避免在suspend過程中使用I/O設備
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
int suspend_devices_and_enter(suspend_state_t state) 
(line 297) 
• 再次檢查是否提供此狀態處理 
• Suspend console 
• 由"kernel/printk/printk.c"實現,主要是hold住一個lock, 
該lock會阻止其它訪問console 
• 開始測試系統suspend/resume過程是否有異常 
• 將其測試時間設為jiffies 
• 每秒1000次
int suspend_devices_and_enter(suspend_state_t state) 
(line 297) 
• 準備設備的狀態轉換,並暫停他們 
• drivers/base/power/main.c, line 1647 
• 調用所有設備的->prepare和->suspend
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static int suspend_enter(suspend_state_t state, bool 
*wakeup) 
(line 213) 
• 設備的狀態轉換 
• drivers/base/power/main.c, line 1280 
• 調用所有設備的->suspend_late和->suspend_noirq 
• suspend_noirq:防止設備接收中斷和呼叫noirq的處理 
• 追蹤machine_suspend的狀態 
• 進入freeze_enter 
• idle processors
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static void freeze_enter(void) 
(line 63) 
• enable the “deepest idle” mode 
• drivers/cpuidle/cpuidle.c, line 78 
• cpuidle會忽略調節器 
• 此功能只能在調用cpuidle_pause之後被呼叫 
• cpuidle_resume 
• drivers/cpuidle/cpuidle.c, line 259 
• cpuidle_install_idle_handler 
• drivers/cpuidle/cpuidle.c, line 208 
• 確保我們切換到new idle之前,完成所有變更 
• 等待suspend_freeze_wake變為true
static void freeze_enter(void) 
(line 63) 
• cpuidle_pause 
• drivers/cpuidle/cpuidle.c, line 251 
• cpuidle_uninstall_idle_handler 
• drivers/cpuidle/cpuidle.c, line 220 
• 強制所有CPU空閒出來 
• disable the “deepest idle” mode
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static int suspend_enter(suspend_state_t state, bool *wakeup) 
(line 213) 
• 停止function tracer 
• 禁止所有的non-boot cpu 
• 關閉local中斷 
• 如果無法關閉,則為bug 
• suspend所有system core
static int suspend_enter(suspend_state_t state, bool *wakeup) 
(line 213) 
• 是否有喚醒事件發生,如果有就要終止suspend 
• 恢復所有system core 
• 開啟local中斷 
• 恢復所有的non-boot cpu 
• 恢復function tracer 
• dpm_resume_start 
• 調用所有設備的->noirq和->early
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static int enter_state(suspend_state_t state) 
(line 370) 
• 恢復使用I/O設備
• pm_suspend-> 
• enter_state-> 
• suspend_prepare 
• suspend_devices_and_enter->suspend_enter 
->freeze_enter 
• suspend_finish
static void suspend_finish(void) 
(line 355) 
• 恢復所有的user processes和kernel threads 
• 發送suspend結束的通知 
• 將console切換回原來的console
• Summary 
• Data Flow. 
• Program structure. 
2014/8/26 
100
• Reference 
• Hackpad of Emp-Chen-Learn. 
https://emp-learn.hackpad.com/2014Linux-Kernel-ajEOESxnPs5 
2014/8/26 
101
Thanks you for attention. 
2014/8/26 
102

More Related Content

PDF
基于MHA的MySQL高可用方案
PDF
主库自动切换 V2.0
PDF
淘宝主备数据库自动切换
PPTX
Mininet Learning Guide(Mininet 学习指南)
PPTX
UseNUMA做了什么?(2012-03-14)
PPTX
SDN ryu 專題安裝
PPTX
Java Crash分析(2012-05-10)
PDF
OpenWRT, A value-add base solution for your product. (1st part, chihchun)
基于MHA的MySQL高可用方案
主库自动切换 V2.0
淘宝主备数据库自动切换
Mininet Learning Guide(Mininet 学习指南)
UseNUMA做了什么?(2012-03-14)
SDN ryu 專題安裝
Java Crash分析(2012-05-10)
OpenWRT, A value-add base solution for your product. (1st part, chihchun)

Viewers also liked (8)

PPTX
2014 1029 adaptive dissmination of safety data among vehicles
PPTX
車用通信報告
PPTX
Stm32 develop tool introduction
PPT
第三章Ti msp430平台介紹 v3
PPTX
Densebox
PPTX
The design of electronic license plate recognition terminal system based on n...
PDF
Based on raspberry pi with the application of Stepper
PPT
Verilog 語法教學
2014 1029 adaptive dissmination of safety data among vehicles
車用通信報告
Stm32 develop tool introduction
第三章Ti msp430平台介紹 v3
Densebox
The design of electronic license plate recognition terminal system based on n...
Based on raspberry pi with the application of Stepper
Verilog 語法教學
Ad

Similar to 2014暑期訓練之Linux kernel power (20)

PPTX
Notes of jcip
PDF
MySQL自动切换设计与实现
PPTX
Track2 -刘继伟--openstack in gamewave
PDF
基于Fuel的超融合一体机
PPS
并发编程实践与思考
PDF
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
PDF
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
PDF
Rootkit 101
PDF
Chapter2
PPTX
IOS入门分享
PDF
Clipper@datacon.2019.tw
PPTX
LabView with Lego NXT
PPTX
Oh K8s Is Swag - Kubernetes Basics
PDF
Foundation of software development 2
PPTX
Kafka & mafka client开发与实践
PDF
20241025 - CNTUG meetup - Kubernetes v1.31 簡單雜談
PPT
Java并发编程培训
PPT
Java并发编程培训
PDF
Nova与虚拟机管理
KEY
ZeroMQ简介
Notes of jcip
MySQL自动切换设计与实现
Track2 -刘继伟--openstack in gamewave
基于Fuel的超融合一体机
并发编程实践与思考
Java SE 7 技術手冊投影片第 11 章 - 執行緒與並行API
探索 ISTIO 新型 DATA PLANE 架構 AMBIENT MESH - GOLANG TAIWAN GATHERING #77 X CNTUG
Rootkit 101
Chapter2
IOS入门分享
Clipper@datacon.2019.tw
LabView with Lego NXT
Oh K8s Is Swag - Kubernetes Basics
Foundation of software development 2
Kafka & mafka client开发与实践
20241025 - CNTUG meetup - Kubernetes v1.31 簡單雜談
Java并发编程培训
Java并发编程培训
Nova与虚拟机管理
ZeroMQ简介
Ad

2014暑期訓練之Linux kernel power

  • 1. The Power On Linux-Kernel 課程:Linux-Kernel At Summer Training In 2014. 學生:陳冠宇、郭儲嘉 老師:張大緯老師
  • 2. • Agenda • Introduction Why we choice Data structure in “Kconfig” • Explain Code autosleep.c poweroff.c suspend.c • Summary 2014/8/26 2
  • 3. • Introduction  Why we choice.  Data structure in “Kconfig” 2014/8/26 3
  • 4. • Why we choice 「電」的問題無論在任何電器用品上都是重 要的一環。任何控制設備都與電息息相關,舉 凡開關機、待機、休眠、外接設備的驅動程式 等皆與「電」脫離不了關係。 鑑於此,選擇此主題將是我們對於核心與外 部設施連接的最佳切入點。 2014/8/26 4
  • 5. • Kconfig • SUSPEND • SUSPEND_FREEZER • HIBERNATION • PM_STD_PARTITION • PM_AUTOSLEEP • PM_WAKELOCK • PM_RUNTIME • PM_DEBUG • PM_ADVANCED_DEBUG • PM_SUSPEND_TEST 2014/8/26 5
  • 6. • SUSPEND • 允許系統進入睡眠狀態。在對記憶體供電的 狀況下將內容保存起來。 例如:SUSPEND– TO–RAM. • 相依於ARCH_SUSPEND_POSSIBLE. • SUSPEND_FREEZER • 如果關閉此功能,在暫停的狀況下就不會讓 任務凍結。(強烈不推薦關閉) • 相依於SUSPEND. 2014/8/26 6
  • 7. • HIBERNATION • 啟動「Suspend to disk(STD)」的功能,在許多 作業系統的User Interface之中,大家都稱呼他 為「休眠」。STD會將確認點放置於系統當中 以確認系統的資料從記憶體儲存到硬碟當中, 並將之斷電。當重新啟動的時候,此確認點 將會置放於reboot上。 • 相依於 • SWAP • ARCH_HIBERNATION_POSSIBLE 2014/8/26 7
  • 8. • HIBERNATION(contd.) • 在Kconfig中有推薦使用者可以將resume的路 徑放置在核心的bootloader的配置檔案 (configuration file)當中。 2014/8/26 8
  • 9. • PM_STD_PARTITION • 預設的重新啟動區域在做STD時將會尋找映像 檔案以完成動作。幾乎全部的使用者在此區 域上都會有所不同。 • 該配置(PM_STD_PARTITION)必須在暫停 之前設置成SWAP磁區,否則休眠後將無法甦 醒。另外,該磁區是可以被指定覆寫的。 格式:resume=/dev/<other device> 範例:resume=/dev/sda2 • 相依於HIBERNATION 2014/8/26 9
  • 10. • PM_AUTOSLEEP • 允許核心觸發系統功能「進入全域性的睡眠 模式」,只要沒有任何喚醒源有活動將之影 響到,就不會導致喚醒的動作發生。 • 相依於PM_SLEEP(尋根究底和SUSPEND有關) • PM_WAKELOCK • 允許使用者空間可以搭配sysfs-based的 Interface去創造、啟動和關閉喚醒源的事件。 • 相依於PM_SLEEP. 2014/8/26 10
  • 11. • PM_WAKELOCK(contd.) • Sysfs:為Linux2.6所提供的虛擬檔案系統,這 個檔案系統不僅可以把裝置、驅動程式的資 訊從核心輸到用戶空間,也可以用來對裝置 和驅動程式做設定。 每個被加入Driver model tree的物件包括驅動 程式、裝置等都會在sysfs檔案系統中以目錄 的方式呈現。 2014/8/26 11
  • 12. • PM_RUNTIME • 允許I/O裝置可以在特別指定的閒置週期過後 的run-time狀況下進入低功耗狀態,如果有硬 體生成的喚醒事件或是由裝置需求導致而產 生,將會為了回應這些事件而導致其甦醒。 • 相依於!IA64_HP_SIM(init/Kconfig) 2014/8/26 12
  • 14. • PM_DEBUG • 該選項允許在Power management code中做各 種調整的支援,這對於PM在Debug和回報錯 誤上是相當有幫助,例如suspend support。 • 相依於PM. • PM_ADVANCED_DEBUG • 加入一個額外的sysfs的屬性,從使用者的空 間去訪問裝置物件中PM的檔案。 • 在此該註解特別提醒:「如果您不是一個對 除錯和測試PM相當有興趣的核心系統開發人 員,請別任意使用。」 • 相依於PM_DEBUG. 2014/8/26 14
  • 15. • PM_SUSPEND_TEST • 此選項可以讓您在啟動狀態下暫停您的機器, 並且在數秒後再次甦醒。其甦醒源使用了RTC 的計時使之產生喚醒源的警告。 當然,使用者必須先擁有系統的RTC裝置的鏈 結,並請確保它是可以用的,否則使用者將 無法測試。 • 相依於 • SUSPEND • PM_DEBUG • RTC_CLASS 2014/8/26 15
  • 16. • Explan Code • autosleep.c • poweroff.c • suspend.c 2014/8/26 16
  • 17. • autosleep.c • 在閒暇之時,讓系統「睡眠」。 1. 宣告、定義工作的內容和屬性。 2. 得知現行的「目標」及「狀況」。 3. 「確保」手邊的工具齊全。 4. 「開始」工作。 2014/8/26 17
  • 18. • 注意事項 • 若是喚醒源被呼叫,可以利用mutex以確保資 源的安全,否則將有可能會進入死結的狀態 當中。 • 另外mutex_lock_interruptible是可以被使用的, 但是如果auto_sleep的循環不斷嘗試著去Freeze processes,則將會發生錯誤。 2014/8/26 18
  • 19. • Autosleep_state: 經被宣告為int型態的suspend_state_ttypedef所宣 告。 • 參考:include/linux/suspend.h • autosleep_wq: 經Workqueue_struct宣告,內 部宣告了工作隊列表、保護用的mutex、顏色、 隊列甚至如果想要的話,則還有sysfs、 lockdep可用。 • 參考:kernel/workqueue.h 2014/8/26 19
  • 21. • try_to_suspend(struct work_struct *work) 1. 判斷喚醒源數量 2. 系統是否有在跑動 3. 自動睡眠的模式為何 4. 確認是否有其他的任務也嘗試著讓系統睡眠 5. 再次判斷喚醒源的數量,若還是有,則代表 有錯誤發生,處理錯誤。 2014/8/26 21
  • 22. • pm_get_wakeup_count(): • 功用:讀取暫存器的wakeup-events的數量。如 果並沒有任何處理中的喚醒事件則回傳ture。 • 來源:drivers/base/power/wakeup.c 2014/8/26 22
  • 23. • pm_save_wakeup_count(): • 功用:若當前的Counter和喚醒源的事件數量相 同且並無任何喚醒源事件,則將目前的Counter 記錄下來並且回傳True確認正在處理事件。 • 來源:drivers/base/power/wakeup.c 2014/8/26 23
  • 24. • PM_SUSPEND_ON: • 功用:ACPI的S0。 • 來源:driver/acpi/sleep.c 2014/8/26 24
  • 25. • ACPI • ACPI( Advanced configuration and power interface):工業標準。提供作業系統應用程式 管理所有電源管理介面。其中工作狀態分之 為: • G0(S0):正常工作狀態。 • G1:睡眠,細分為S1~S4四種狀態,喚醒時間 從S1~S4愈來愈慢。 • STANDBY、MEM、MAX,分別等於S1(最耗 電的睡眠模式)、S3(掛置到記憶體中,稱之為 暫停,仍然對記憶體供電)及S5(G2) 2014/8/26 25
  • 26. • ACPI(contd.) G2(S5):Soft off,電腦仍然可以被鍵盤、clk、 網路、電話或是USB裝置所喚醒。 G3:Mechanical off。幾乎和G2相同,將電腦的 電源全部移開,但此時的RTC依然在跳動。 2014/8/26 26
  • 27. • pm_suspend() : • 功用:確認系統暫停的狀態。確認是否有其他 的任務也試著讓系統進入暫停狀態。而後藉由 Freeze來凍結外部的程序。 • 來源:kernel/power/suspend.c 2014/8/26 27
  • 28. • schedule_timeout_uninterruptible(HZ/2) • 功用:若系統喚醒的發生原因未知,則會等待, 並防止系統暫停及喚醒的循環。如果之後程式 正常,則會繼續排程(schedule)。但如果有問題, 則會由核心告知系統錯誤並且傾印問題進入 stack中。 • 來源: kernel/timer.c 2014/8/26 28
  • 30. • static DECLARE_WORK() • 功用:在此是將try_to_suspend初始化。利用到 __WORK_INITIALIZER(n, f)),將內部的料、 入口、使用Function、工作的lockdep等初始化。 • 來源:include/linux/workqueue.h 2014/8/26 30
  • 31. • queue_up_suspend_work() • 功用:讓設備在指定的CPU中工作。內部判斷目 前autosleep的狀態,如果到達一定標準則開始 做排隊,此時才會去關閉一些外部設備,否則 若無此判斷進來無意義。__queue_work(cpu, *wq, *work)來指定相對的CPU和隊列、工作等 將之傳入。 • 來源:kernel/workqueue.c 2014/8/26 31
  • 32. • pm_autosleep_state(void) • 功用:整數型態。將回傳目前autosleep的狀態 autosleep_state。(呼應到suspend_state_t) • 來源:kernel/power 2014/8/26 32
  • 33. • pm_autosleep_lock(void) • 功用:整數型態。內部將判斷該藉由快速通道 或是慢速來進行mutex的luck。若為快速則是內 部count從1->0時上lock,若為慢速則有可能會 使用到interrupt. • 來源: • asm-generic/mutex-xchg.h • kernel/locking/mutex.c 2014/8/26 33
  • 34. • 快速:藉使用mutex_set_owner直接對該 lock.owner做當前狀態的儲存。 • 慢速:必須將目前的LOCK、任務中斷、回傳點 等一一傳入__mutex_lock_common中,禁止搶占 (preempt_disable)後才可以取得mutex的使用。 2014/8/26 34
  • 35. • pm_autosleep_unlock(void) • 功用:相對於pm_autosleep_lock,此function則 是利用mutex_unlock()直接解除autosleep_lock的 鎖。 • 來源:kernel/locking/mutex.c 2014/8/26 35
  • 36. • pm_autosleep_set_state(int state) • 功用:確認目前的狀態,如果狀態確定是非正 常工作狀態才進入suspend,否則就關閉自動睡 眠並且回到正常工作。 • 步驟: 1. 通知PM Core有喚醒事件。(防止其他喚醒源) 2. Mutex上鎖、讀取當前工作的狀態。 3. 通知PM Core喚醒事件已經結束了。 4. 確認目前工作狀態。 5. 解除mutex。 2014/8/26 36
  • 37. • EINVAL(invalid argument無效參數)=22。 • 來源:include/uapi/asm-generic/errno-base.h 2014/8/26 37
  • 38. • __pm_stay_awake(autosleep_ws) • 功用:通知PM Core喚醒事件,傳入參數為 Wakeup-source。告知目前狀態的喚醒源。 • 來源:drivers/base/power/wakeup.c 2014/8/26 38
  • 39. • __pm_relax(autosleep_ws) • 功用:通知PM Core喚醒事件結束。允許其他 喚醒源通知。 • 來源:drivers/base/power/wakeup.c 2014/8/26 39
  • 40. • pm_wakep_autosleep_enabled(bool) • 功用:修改全部喚醒源的autosleep的啟動狀態。 • 來源: drivers/base/power/wakeup.c 2014/8/26 40
  • 41. • pm_autosleep_init(void) • 功用:初始化autosleep,結果正常則會回傳0, 否則將回傳ENOMEM。 • 步驟: 1. 判斷喚醒源是否製造成功 2. 判斷分配工作隊列是否成功 3. 移除喚醒源,回傳錯誤。 2014/8/26 41
  • 42. • wakeup_source_register(char *name) • 功用:製造一個喚醒源並且將之加入到列表中。 內部會先使用wakeup_source_create(name),並 且利用wakeup_source_add將之加入。 • ENOMEM=Out of memory • 來源:drivers/base/power/wakeup.c 2014/8/26 42
  • 43. • alloc_ordered_workqueue(name, arg) • 功用:分配已有序的工作隊列。與 alloc_workqueue相關,分配一個特定的區段給 它。 • 來源: • include/linux/workqueue.h • Documentation/workqueue.txt. 2014/8/26 43
  • 44. • wakeup_source_unregister(void) • 功用:從表列中移除喚醒源。利用到 wakeup_source_remove(ws) , wakeup_source_des troy(ws)。 • 來源: deivers/base/power/wakeup.c 2014/8/26 44
  • 45. • Poweroff.c • 系統要求正常地將機器關機(斷電)。 • 步驟: 1. 設定關機的執行步驟 2. 將「關機」這項工作宣告好 3. 將此「工作」放進排程中 4. 宣告成結構,方便呼叫引用 5. 初始化此結構,並將此初始化放置於列表中。 2014/8/26 45
  • 46. • do_poweroff(struct) • 功用:將系統正常關機,內部使用到 kernel_power_off。 • 步驟: 1. 關機前的準備。(shutdown_prepare) 2. 判斷是否準備完成(指定完成),完成後 做該Function的動作。(Poweroff-prepare) 3. 設定指定的CPU去工作。(migrate) 4. 讓系統核心逐一關閉。(syscore-shutdown) 5. 系統回傳信息後將核心信息存好。 (kmsg_dump) 6. 機器關機。(machine_power_off) 2014/8/26 46
  • 48. • kernel_shutdown_perpare(enum) • 功用:關機前的準備。使用鏈上的功能,並將 當前系統狀態處存下來,而後關閉 Usermodehelper並將每一個裝置關機。 • 來源:kernel/reboot.c 2014/8/26 48
  • 49. • 通知鏈結(notifier_call_chain): • 功用:Linux系統中有提供「通知鏈結」的功能, 鏈表上的每一個節點都有一個Function,當事件 發生時表上的節點所對應的Function將會被執行。 所以對表來說有一個接收、一個通知。 • 總和來說,事件的接收者將事件發生時所對應 的操作存起來,當事件發生時通知者依次執行 每一個元素的Function。 • 程式中使用的是可阻塞的通知鏈。 • 程式來源:kernel/reboot.c 2014/8/26 49
  • 50. • 通知時的注意事項 • 功用:關閉RCU機制才去做通知。 • 來源:kernel/reboot.c 2014/8/26 50
  • 51. • RCU(Read Copy Update) • 功能:允許多個讀取與更新同時發生的事件, 不使用Lock的概念,適合讀者多寫者少的狀況。 利用read-lock(時間到輪流)來避免強佔事件。 • 來源:kernel/locking/rwsem.c 2014/8/26 51
  • 52. • usermodehelper_disable() : • 功用:一般而言,系統調用函式是相當常見的, 一般而言都是由使用者調用kernel的function。 • 當方向相反的使用則需要使用usermodehelper。 例如當kernel找到一個device,而需要load某個 module。而此function就是防止有新的helper出 現。 • 來源: Kernel/kmod.c 2014/8/26 52
  • 54. • device_shutdown() • 功用:對每一個裝置呼叫shutdown()指令。利用 尋訪Device list去一一的將裝置關機,又稱 offline • 來源:drivers/base/core.c 2014/8/26 54
  • 56. • pm_power_off_prepare() • 功用:利用Function point的方式,可以從外部 將需要的功能存入此函式中並且將之執行。用 判斷式判斷是否已指向需要的Function。 • 來源:kernel/reboot.c 2014/8/26 56
  • 57. • migrate_to_reboot_cpu() • 功用:關閉熱插拔裝置、運行任務在指定的 CPU上並防止有其他的任務遷移至本區、確認 只運行在適當的處理器上。可參考同檔案下的 kernel_restart。 • 來源:kernel/reboot.c 2014/8/26 57
  • 58. • CPU_hotplug_disable() • 功用:將熱插拔系統關閉。熱插拔指的是在電 腦熱機的狀態增減硬體。過去大家是使用套件, 當新裝置進入時該套件會自行配置。在linux2.6 版過後,採用udev自動產生,而它不只是一個 設備檔案產生器,更是一個核心信息的監聽器。 • 來源: kernel/cpu.c 2014/8/26 58
  • 59. • set_cpus_allowed_ptr(current, cpumask_of(cpu)) • 功用:確保只運行在指定的CPU上。內部使用 到task_lock來確認不會有其他的任務參雜且可 確認任務的正確性及CPU使用的正確性。 • 來源: kernel/sched/core.c 2014/8/26 59
  • 60. • syscore_shutdown() • 功用:執行Function使得被暫存的系統核心逐一 關閉,例如中斷裝置等。本部分也是利用list的 方式逐一關閉。 • 來源: deivers/base/syscore.c 2014/8/26 60
  • 61. • pr_emerg("Power downn") • 功用:在定義中使用printk的方式由核心告知使 用者,優先權為KERN_EMERG(最高優先權, 告知系統不可用) • 來源: include/linux/printk.h, kern_levels.h 2014/8/26 61
  • 62. • kmsg_dump() • 功用:將kernel的log傾印至kernel message dumpers中,方便以後檢索時可以使用。傾印可 以儲存程式資訊,以便在偵錯的時候使用。 • 來源: kernel/printk/printk.c 2014/8/26 62
  • 63. • machine_power_off(void) • 功用:因include reboot.c,故以該檔內的意思為 主。 直接執行struct machine_ops的power_off將系統 關閉,此處若用int做受值可以接受回傳的系統 值即可知道錯誤與否。 • 來源: arch/sh/kernel/reboot.c 2014/8/26 63
  • 64. • DECLARE_WORK(poweroff_work, do_poweroff) • 功用:工作的宣告。此Function是使用 __WORK_INITIALIZER()去初始化結構內部的值, 第一個是之後使用的入口地址、後方放的是「工 作」,初始化包含data, entry address, function and lockdep。 • 來源: include/linux/lockdep.h 2014/8/26 64
  • 65. • Lockdep:假設每一個Process都是鑰匙,而資 源稱之為鎖。在linux系統中,如果發生了AB-BA 死結狀態,可能可以用「順序」的方式去 解開,但是面對成千上萬的「鎖」卻無法如 此。 • 而lockdep在2006年引入Linux-kernel中,它的 操作並非以單一一個資源為例,而是以同個 類別去觀察。 • 它循跡每一個鎖的狀態和關係,並且通過一 系列的驗證規則以確保各個狀態之間的依賴 關係是可行且正確的。 • 參考:include/linux/lockdep.h 2014/8/26 65
  • 66. • handle_poweroff(int key) • 功用:在啟動的CPU上運行系統所要求的關機 指令。使用到schedule_work_on,將從目前在 線的CPU列表中挑選出第一個,並將它及關機 的動作送入工作排程之中。 2014/8/26 66
  • 67. • queue_work() • 功用:讓工作排在工作隊列上。如果回傳False 則代表already。在此要特別注意,此工作雖然 一樣是讓工作在特定的CPU上排隊準備,但這 邊要請使用者確認該工作不會突然離去導致隊 列出問題。 • 來源:include/linux/workqueue.h 2014/8/26 67
  • 68. • 將設置好的動作送入結構中以備使用需要 • 將初始化的動作包裝起,送入列表當中。 2014/8/26 68
  • 69. • pm_sysrq_init(void) • 功用:呼叫了__sysrq_swap_key_ops,將結構送 入sysrq_key_table[i]列表中。最後將RCU做同步, 使得更新與讀取是為同步。 • 來源:drivers/tty/sysrq.c 2014/8/26 69
  • 70. • subsys_initcall() • 功用:子程序的初始化,此Function定義於 __define_initcall中,通常USB及外部裝置都會 將相關的函式放入其內。 它們使用並非隨便任意,而是有相關的順序, 而順序取決於當時給予其之參數。 • 來源:include/linux/init.h 2014/8/26 70
  • 71. •Suspend.c • 流程 • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish 2014/8/26 71
  • 72. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 73. int pm_suspend(suspend_state_t state) (line 427) • 判斷狀態參數是否正確 • include/linux/suspend.h, line 36 • #define PM_SUSPEND_ON ((__force suspend_state_t) 0) • #define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1) • #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2) • #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) • #define PM_SUSPEND_MIN PM_SUSPEND_FREEZE • #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) • 進入enter_state • 將結果記錄下來
  • 74. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 75. static int enter_state(suspend_state_t state) (line 370) • 追蹤suspend_enter的狀態 • include/trace/events/power.h, line 12 • #define TPS(x) tracepoint_string(x) • include/linux/ftrace_event.h, line 604 • 可將該參數的狀態、內容等等資訊映射出來
  • 76. static int enter_state(suspend_state_t state) (line 370) • 判斷是否為凍結狀態 • kernel/power/main.c, line 75 • [TEST_NONE] = "none" • [TEST_CORE] = "core" • [TEST_CPUS] = "processors" • [TEST_PLATFORM] = "platform" • [TEST_DEVICES] = "devices" • [TEST_FREEZER] = "freezer"
  • 77. static int enter_state(suspend_state_t state) (line 370) • 判斷是否支持該電源狀態 • 需要較低層級的支持和實作 • 互斥鎖 • 只允許處理一個suspend • 如果state是freeze,調用freeze_begin, 將凍結喚醒 關閉(suspend_freeze_wake = false)
  • 78. static int enter_state(suspend_state_t state) (line 370) • 追蹤sync_filesystems的狀態 • 同步filesystems • 進行suspend前的準備
  • 79. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 80. static int suspend_prepare(suspend_state_t state) (line 167) • 需要處理什麼狀態,同時是否支援此狀態 • 將當前console切換到一個虛擬console並重定向 kernel的kmsg
  • 81. static int suspend_prepare(suspend_state_t state) (line 167) • 發送suspend開始的消息 • include/linux/suspend.h, line 350 • #define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ • #define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ • #define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ • #define PM_POST_SUSPEND 0x0004 /* Suspend finished */ • #define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ • #define PM_POST_RESTORE 0x0006 /* Restore failed */ • 追蹤freeze_processes的狀態 • freeze user processes和一些kernel threads
  • 82. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 83. static int enter_state(suspend_state_t state) (line 370) • 判斷是否為suspend to freeze • 避免在suspend過程中使用I/O設備
  • 84. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 85. int suspend_devices_and_enter(suspend_state_t state) (line 297) • 再次檢查是否提供此狀態處理 • Suspend console • 由"kernel/printk/printk.c"實現,主要是hold住一個lock, 該lock會阻止其它訪問console • 開始測試系統suspend/resume過程是否有異常 • 將其測試時間設為jiffies • 每秒1000次
  • 86. int suspend_devices_and_enter(suspend_state_t state) (line 297) • 準備設備的狀態轉換,並暫停他們 • drivers/base/power/main.c, line 1647 • 調用所有設備的->prepare和->suspend
  • 87. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 88. static int suspend_enter(suspend_state_t state, bool *wakeup) (line 213) • 設備的狀態轉換 • drivers/base/power/main.c, line 1280 • 調用所有設備的->suspend_late和->suspend_noirq • suspend_noirq:防止設備接收中斷和呼叫noirq的處理 • 追蹤machine_suspend的狀態 • 進入freeze_enter • idle processors
  • 89. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 90. static void freeze_enter(void) (line 63) • enable the “deepest idle” mode • drivers/cpuidle/cpuidle.c, line 78 • cpuidle會忽略調節器 • 此功能只能在調用cpuidle_pause之後被呼叫 • cpuidle_resume • drivers/cpuidle/cpuidle.c, line 259 • cpuidle_install_idle_handler • drivers/cpuidle/cpuidle.c, line 208 • 確保我們切換到new idle之前,完成所有變更 • 等待suspend_freeze_wake變為true
  • 91. static void freeze_enter(void) (line 63) • cpuidle_pause • drivers/cpuidle/cpuidle.c, line 251 • cpuidle_uninstall_idle_handler • drivers/cpuidle/cpuidle.c, line 220 • 強制所有CPU空閒出來 • disable the “deepest idle” mode
  • 92. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 93. static int suspend_enter(suspend_state_t state, bool *wakeup) (line 213) • 停止function tracer • 禁止所有的non-boot cpu • 關閉local中斷 • 如果無法關閉,則為bug • suspend所有system core
  • 94. static int suspend_enter(suspend_state_t state, bool *wakeup) (line 213) • 是否有喚醒事件發生,如果有就要終止suspend • 恢復所有system core • 開啟local中斷 • 恢復所有的non-boot cpu • 恢復function tracer • dpm_resume_start • 調用所有設備的->noirq和->early
  • 95. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 96. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 97. static int enter_state(suspend_state_t state) (line 370) • 恢復使用I/O設備
  • 98. • pm_suspend-> • enter_state-> • suspend_prepare • suspend_devices_and_enter->suspend_enter ->freeze_enter • suspend_finish
  • 99. static void suspend_finish(void) (line 355) • 恢復所有的user processes和kernel threads • 發送suspend結束的通知 • 將console切換回原來的console
  • 100. • Summary • Data Flow. • Program structure. 2014/8/26 100
  • 101. • Reference • Hackpad of Emp-Chen-Learn. https://emp-learn.hackpad.com/2014Linux-Kernel-ajEOESxnPs5 2014/8/26 101
  • 102. Thanks you for attention. 2014/8/26 102