級別: 初級
范曉炬 (
xiaoju_f@263.net), 聯(lián)想(北京)有限公司軟件設計中心嵌入式研發(fā)處開(kāi)發(fā)工程師, 聯(lián)想(北京)有限公司軟件設計中心
2003 年 8 月 11 日
linux下的關(guān)機和重啟流程對于一般的桌面應用和網(wǎng)絡(luò )服務(wù)器來(lái)說(shuō)并不重要,但是在用戶(hù)自己定義的嵌入式系統內核中就有一定的研究意義,通過(guò)了解Linux 關(guān)機重啟的流程,我們對它可以修改和自定義,甚至以此為基礎開(kāi)發(fā)出全新的功能來(lái)。
在linux下的關(guān)機和重啟可能由兩種行為引發(fā),一是通過(guò)用戶(hù)編程,一是系統自己產(chǎn)生的消息。用戶(hù)和系統進(jìn)行交互的方式也有兩個(gè),一個(gè)是系統調用:sys_reboot,另一個(gè)就是apm或則acpi的設備文件,通過(guò)對其操作也可以使系統關(guān)機或者重啟。
這個(gè)系統調用定義了一系列的MAGIC_NUMBER,在調用的開(kāi)始部分首先檢查MAGIC_NUMBER是否正確,只有正確才繼續向下運行。在重啟的時(shí)候轉向分支
case LINUX_REBOOT_CMD_RESTART:
首先使用notifier_call_chain向其它部分發(fā)出重啟的消息,然后調用machine_restart函數完成重啟。
machine_restart函數的開(kāi)始部分有一段SMP相關(guān)的代碼,主要完成多CPU時(shí)由一個(gè)CPU完成重啟操作,其它CPU處于等待狀態(tài)。之后系統根據一個(gè)變量reboot_thru_bios的內容判斷重啟方式,通過(guò)閱讀reboot_setup我們可以得知,這個(gè)參數的內容是在系統啟動(dòng)時(shí)指定的,決定了是否利用bios,事實(shí)上是系統復位后的入口(FFFF:0000)地址的程序進(jìn)行重啟。在不通過(guò)bios進(jìn)行重啟的情況下,系統首先設定了重啟標志,然后向端口0xfe寫(xiě)入數字0x64,這種重啟的具體原理我還不大清楚,似乎是模擬了一次reset鍵的按下,希望大家和我討論。在通過(guò)bios重啟的情況下,系統同樣先設定了重啟模式,然后切換到了實(shí)模式,通過(guò)一條ljmp $0xffff,$0x0完成了重啟。
回頁(yè)首在系統調用的處理分支上,我們可以看到,首先同樣是檢查MAGIC_NUMBER,然后在
case LINUX_REBOOT_CMD_POWER_OFF:
的執行流程里面,又是使用notifier_call_chain發(fā)出了關(guān)閉計算機電源的消息,緊接著(zhù)執行了machine_power_off函數。我們在machine_power_off函數中可以看到,如果pm_power_off這個(gè)函數指針不為空,那么系統就會(huì )通過(guò)調用這個(gè)函數進(jìn)行關(guān)機。在apm已經(jīng)加載的情況下(SMP除外),實(shí)際上pm_power_off函數實(shí)際上指向了apm.c中的apm_power_off,在這個(gè)函數里系統通過(guò)apm_info結構里的值,使用切換到實(shí)模式關(guān)機,或者使用apm_bios_call_simple函數調用保護模式下的apm接口關(guān)機兩種方法。
回頁(yè)首apm使用其注冊的設備的ioctl接口完成apm的操作,在apm.c的do_ioctl函數中可以看見(jiàn)處理的分支。這里只有suspend和standby的代碼,所以我們不能通過(guò)ioctl這種方法使用apm關(guān)機。
當用戶(hù)按下POWER開(kāi)關(guān)的時(shí)候,如果有apm模塊,那么關(guān)機流程是由apm來(lái)處理的。apm驅動(dòng)在初始化的時(shí)候啟動(dòng)了一個(gè)apm內核線(xiàn)程:apm_mainloop,系統會(huì )在這里檢測到POWEROFF按鍵消息并且將其命名為APM_SYS_SUSPEND,以區別apm -s設置的APM_USER_SUSPEND模式。緊接著(zhù)進(jìn)入了apm_event_handler函數,又從apm_event_handler函數進(jìn)入了check_events函數,處理函數對應的case分支上。系統同樣使用了suspend函數進(jìn)行關(guān)機,不過(guò)由于其它參數的原因,suspend最后調用的是關(guān)機的流程。
回頁(yè)首1)按POWER鍵時(shí)某些主板死機
經(jīng)查只有某些特定的驅動(dòng)裝載之后才會(huì )出現這樣的情況,并且當使用關(guān)機系統調用sys_reboot的時(shí)候沒(méi)有這樣的問(wèn)題。分析apm的處理流程,懷疑是在關(guān)機前驅動(dòng)程序沒(méi)有正確處理apm發(fā)出的詢(xún)問(wèn)消息造成的。由于部分驅動(dòng)程序沒(méi)有源代碼,決定hack掉apm.c的關(guān)機部分,讓兩種方式的關(guān)機走同樣的流程。于是把apm.c的check_events函數中對APM_SYS_SUSPEND部分改寫(xiě)為如下代碼:
ret = exec_usermodehelper(poweroff_helper_path, argv, envp); if (ret) { printk(KERN_ERR "apm.c: failed to exec %s , errno = %d\\n", poweroff_helper_path, errno); } break;
定義了一個(gè)用戶(hù)態(tài)應用程序poweroff_helper_path,當POWEROFF鍵按下的時(shí)候系統運行這個(gè)kernel_helper程序。我們再寫(xiě)一個(gè)通過(guò)sys_reboot系統調用關(guān)機的程序,放在指定的位置下。死機的問(wèn)題就解決了。
2)快速返回實(shí)模式重啟
主要可以參考了process.c中的返回實(shí)模式的代碼,比如我把real_mode_switch換成如下代碼:
// For fast reboot support static unsigned char fast_reboot_switch [] = { 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ 0x66, 0x25, 0x10, 0x11, 0x11, 0x11, /* andl $0x11111110,%eax */ 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ 0xea, 0x00, 0x00, 0x00, 0x70 /* ljmp $0x7000,$0x0000 */ };
系統就可以切換到實(shí)模式中,然后跳轉到7000H:0位置開(kāi)始執行。
回頁(yè)首在2.4.20內核中ACPI模塊被注明為試驗和未完成,里面有一部分功能也許沒(méi)有實(shí)現。如果APM和APCI兩個(gè)模塊同時(shí)編譯進(jìn)內核,APM在A(yíng)CPI前被加載,APM起作用使ACPI退出。對于系統電量、電源實(shí)踐一類(lèi)的支持(主要是在筆記本上有用),靠的是acpid這個(gè)daemon程序。
沒(méi)有一個(gè)功能類(lèi)似apm的應用程序切換狀態(tài),acpi的程序僅僅完成了對acpi狀態(tài)的查詢(xún)。用戶(hù)實(shí)現S0-S4的功能可以直接向/proc/acpi/sleep文件中寫(xiě)入數字來(lái)實(shí)現。通過(guò)讀出(cat)其中的內容可以知道系統到底支持那些模式。
acpi模塊的源代碼主程序在linux/drivers/acpi/driver.c中,如果向sleep文件寫(xiě)東西,就轉到了linux/drivers/acpi/ospm/system/sm_osl.c文件的sm_osl_proc_write_sleep函數中,這個(gè)函數后來(lái)調用了sm_osl_suspend函數。在這個(gè)函數里完成了各種功能,包括保護各種狀態(tài)。最后真正的sleep是通過(guò)對acpi_enter_sleep_state的調用完成的,這個(gè)函數在linux/drivers/acpi/hardware/hwsleep.c文件中,這里寫(xiě)了acpi的寄存器使系統進(jìn)入sleep狀態(tài)。寫(xiě)寄存器的指令在這個(gè)目錄下面的hwregs.c中。
回頁(yè)首本文對acpi的介紹非常簡(jiǎn)略,實(shí)際上ACPI必定會(huì )成為將來(lái)linux內核中首選的電源管理方式。由于目前官方代碼中ACPI版本較低,所以沒(méi)有太詳細的論述,希望將來(lái)的內核能有所改變。
linux-2.4.20源代碼
范曉炬,聯(lián)想(北京)有限公司軟件設計中心嵌入式研發(fā)處開(kāi)發(fā)工程師,研究興趣為 Linux 內核,網(wǎng)絡(luò )安全,XWindow 系統,Linux 桌面應用,人工智能系統。你可以通過(guò)
xiaoju_f@263.net聯(lián)系他。