Linux關機重啟流程分析

來源:互聯網
上載者:User

linux下的關機和重啟流程對於一般的案頭應用和網路伺服器來說並不重要,但是在使用者自己定義的嵌入式系統核心中就有一定的研究意義,通過瞭解Linux 關機重啟的流程,我們對它可以修改和自訂,甚至以此為基礎開發出全新的功能來。
  1.概述
  在linux下的關機和重啟可能由兩種行為引發,一是通過使用者編程,一是系統自己產生的訊息。使用者和系統進行互動的方式也有兩個,一個是系統調用:sys_reboot,另一個就是apm或則acpi的裝置檔案,通過對其操作也可以使系統關機或者重啟。
  2.通過系統調用sys_reboot的重啟
  這個系統調用定義了一系列的MAGIC_NUMBER,在調用的開始部分首先檢查MAGIC_NUMBER是否正確,只有正確才繼續向下運行。在重啟的時候轉向分支
  case LINUX_REBOOT_CMD_RESTART:
  首先使用notifier_call_chain向其它部分發出重啟的訊息,然後調用machine_restart函數完成重啟。
  machine_restart函數的開始部分有一段SMP相關的代碼,主要完成多CPU時由一個CPU完成重啟操作,其它CPU處於等待狀態。之後系統根據一個變數reboot_thru_bios的內容判斷重啟方式,通過閱讀reboot_setup我們可以得知,這個參數的內容是在系統啟動時指定的,決定了是否利用bios,事實上是系統複位後的入口(FFFF:0000)地址的程式進行重啟。在不通過bios進行重啟的情況下,系統首先設定了重啟標誌,然後向連接埠0xfe寫入數字0x64,這種重啟的具體原理我還不大清楚,似乎是類比了一次reset鍵的按下,希望大家和我討論。在通過bios重啟的情況下,系統同樣先設定了重啟模式,然後切換到了實模式,通過一條ljmp $0xffff,$0x0完成了重啟。
  3.通過系統調用sys_reboot進行關機
  在系統調用的處理分支上,我們可以看到,首先同樣是檢查MAGIC_NUMBER,然後在
  case LINUX_REBOOT_CMD_POWER_OFF:
  的執行流程裡面,又是使用notifier_call_chain發出了關閉電腦電源的訊息,緊接著執行了machine_power_off函數。我們在machine_power_off函數中可以看到,如果pm_power_off這個函數指標不為空白,那麼系統就會通過調用這個函數進行關機。在apm已經載入的情況下(SMP除外),實際上pm_power_off函數實際上指向了apm.c中的apm_power_off,在這個函數裡系統通過apm_info結構裡的值,使用切換到實模式關機,或者使用apm_bios_call_simple函數調用保護模式下的apm介面關機兩種方法。
  4.apm驅動本身的關機過程
  apm使用其註冊的裝置的ioctl介面完成apm的操作,在apm.c的do_ioctl函數中可以看見處理的分支。這裡只有suspend和standby的代碼,所以我們不能通過ioctl這種方法使用apm關機。
  當使用者按下POWER開關的時候,如果有apm模組,那麼關機流程是由apm來處理的。apm驅動在初始化的時候啟動了一個apm核心線程:apm_mainloop,系統會在這裡檢測到POWEROFF按鍵訊息並且將其命名為APM_SYS_SUSPEND,以區別apm -s設定的APM_USER_SUSPEND模式。緊接著進入了apm_event_handler函數,又從apm_event_handler函數進入了check_events函數,處理函數對應的case分支上。系統同樣使用了suspend函數進行關機,不過由於其它參數的原因,suspend最後調用的是關機的流程。
  5.解決問題執行個體
  1)按POWER鍵時某些主板死機
  經查只有某些特定的驅動裝載之後才會出現這樣的情況,並且當使用關機系統調用sys_reboot的時候沒有這樣的問題。分析apm的處理流程,懷疑是在關機前驅動程式沒有正確處理apm發出的詢問訊息造成的。由於部分驅動程式沒有原始碼,決定hack掉apm.c的關機部分,讓兩種方式的關機走同樣的流程。於是把apm.c的check_events函數中對APM_SYS_SUSPEND部分改寫為如下代碼:
  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;
  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 */
  };
  系統就可以切換到實模式中,然後跳轉到7000H:0位置開始執行。
  6.ACPI概述
  在2.4.20核心中ACPI模組被註明為實驗和未完成,裡面有一部分功能也許沒有實現。如果APM和APCI兩個模組同時編譯進核心,APM在ACPI前被載入,APM起作用使ACPI退出。對於系統電量、電源實踐一類的支援(主要是在筆記本上有用),靠的是acpid這個daemon程式。
  沒有一個功能類似apm的應用程式切換狀態,acpi的程式僅僅完成了對acpi狀態的查詢。使用者實現S0-S4的功能可以直接向/proc/acpi/sleep檔案中寫入數字來實現。通過讀出(cat)其中的內容可以知道系統到底支援那些模式。
  acpi模組的原始碼主程式在linux/drivers/acpi/driver.c中,如果向sleep檔案寫東西,就轉到了linux/drivers/acpi/ospm/system/sm_osl.c檔案的sm_osl_proc_write_sleep函數中,這個函數後來調用了sm_osl_suspend函數。在這個函數裡完成了各種功能,包括保護各種狀態。最後真正的sleep是通過對acpi_enter_sleep_state的調用完成的,這個函數在linux/drivers/acpi/hardware/hwsleep.c檔案中,這裡寫了acpi的寄存器使系統進入sleep狀態。寫寄存器的指令在這個目錄下面的hwregs.c中。
  7.總結
  本文對acpi的介紹非常簡略,實際上ACPI必定會成為將來linux核心中首選的電源管理方式。由於目前官方代碼中ACPI版本較低,所以沒有太詳細的論述,希望將來的核心能有所改變。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.