ACPI簡介_Linux

來源:互聯網
上載者:User

http://www.columbia.edu/~ariel/acpi/acpi_howto.txt

ACPI – the Advanced Configuration & Power Interface. ACPI是OS,BIOS和硬體之間的抽象層。它允許OS和平台獨立的發展,比如新的OS可以控制老的平台,老的OS也可以控制新的平台而不需要額外的修改。ACPI的基本結構圖如下:

電腦領域的一個基本方法是增加一個抽象層,從而使得抽象層的上下兩層獨立的發展,ACPI事實上也是借鑒類似的思想。ACPI的抽象主要是通過ACPI表中提供的資訊來實現,這些資訊包括ACPI寄存器、AML代碼、配置資訊等。

  • ACPI寄存器,描述了和ACPI相關的寄存器。OS可以直接從ACPI表中取得這些寄存器的資訊,因此不必瞭解具體的硬體設定。
  • AML代碼,一種類C的代碼。由BIOS提供,OS的AML解譯器(在Linux中叫ACPI CA)解釋執行這些代碼。這是ACPI抽象層的關鍵,下面會詳細介紹。
  • 配置資訊,ACPI包含的配置資訊很多,比如多處理器配置資訊(MADT)、NUMA配置資訊(SRAT、SLIT)、高精度定時器(HPET)等。

AML代碼是抽象的關鍵。為了消除平台相關性,BIOS把平台相關的操作用AML代碼來實現。OS不需要知道平台細節,它只是解釋執行這些代碼,在解釋執行的過程中平台相關的操作就被執行了。ACPI規範定義了一些標準的AML函數,OS解釋執行一個這樣的標準函數就可以實現特定的功能。舉個例子:

Scope (_SB.PCI0.LPC) { OperationRegion (LPCS, PCI_Config, 0x00, 0x0100) Field (LPCS, AnyAcc, NoLock, Preserve) { Offset (0x60),                                            PIRA,   8, } } Device (LNKA) {                     Method (_DIS, 0, NotSerialized) {                                           Or (\_SB.PCI0.LPC.PIRA, 0x80, \_SB.PCI0.LPC.PIRA) } }

比如我們想禁止LNKA裝置,ACPI規範定義了OS必須執行此裝置的_DIS函數。從硬體的角度來講,禁止LNKA裝置需要將某個PCI裝置的配置空間的寄存器0×60的最高位置上。OS不需要知道硬體的細節,它解釋執行_DIS函數即可。上面的代碼就是AML代碼,由BIOS提供,語句‘Or (\_SB.PCI0.LPC.PIRA, 0×80, \_SB.PCI0.LPC.PIRA)’實際上就是給寄存器\_SB.PCI0.LPC.PIRA置上最高位, 而PIRA就是PCI裝置LPC的配置空間的寄存器0×60。從此段代碼我們可以明顯的看出BIOS以AML代碼的形式隱藏(抽象)了硬體的細節,從而使得OS看到的是一個平台無關的硬體。

更多的ACPI預定義的函數可以在ACPI規範中找到,可以在http://www.acpi.info下載最新的規範。

Linux/ACPI實現中使用的AML解譯器是ACPICA -the ACPI Component Architecture. 可以從http://www.intel.com/technology/iapc/acpi/downloads.htm得到。它包含一個AML解譯器(Linux kernel包含了這個解譯器,很多其他OS也是如此,比如BSD、opensolaris等),一個編譯器(將ACPI Source Language (ASL)編譯成AML代碼)和一些測試載入器。

最新的Linux/ACPI的代碼可以使用git在http://www.kernel.org/git/?p=linux/kernel/git/lenb/linux-acpi-2.6.git得到。

為什麼學習ACPI

ACPI是Intel(i386,x86_64,IA64)平台的標準韌體規範,絕大部分OS需要從BIOS得到的資訊都可以從ACPI得到,並且現在的趨勢是未來的任何新的特性相關的資訊都只能從ACPI得到。ACPI的內容龐雜,學習ACPI至少可以協助我們理解:

  • 配置資訊。這些資訊從legacy PNP裝置的配置,到多處理器,到NUMA,比如現在的Multiple Core的資訊就只能從ACPI得到。Linux啟動很多代碼就是處理這些配置資訊,比如APIC,IOAPIC設定等。
  • ACPI相關裝置。主要是膝上型電腦相關的裝置,包括電源開關,電池,外接電源,風扇,熱鍵等。
  • 底層硬體。比如PCI中斷路由,chipset(主要是南橋PCI-to-LPC bridge)操作等。
  • 電源管理。ACPI定義的電源管理包括CPU的電源管理(調頻率P-state,idle C-state,throtting T-state),裝置電源管理(D-state),系統電源管理(Suspend-to-Ram, Suspend-to-Disk, power off)等。
  • 裝置熱插拔。ACPI用一種統一的方式來描述裝置的熱插拔,這樣的裝置從單一的PCI裝置,到膝上型電腦的Docking Station,到整個PCI hierarchy,CPU,Memory,甚至整個NUMA節點。

可以說要理解現代PC平台必須瞭解ACPI。

解決ACPI問題的小竅門

首先可以看看是否這是一個regression,如果以前版本的Linux kernel可以工作,但新的不行,則是一個regression,可以測試不同的kernel從而找出哪個版本引入了bug。使用git-bisect是一個好的選擇,它可以幫你定位到哪個patch導致了regression。一些git-bisect相關的資料如下: http://www.stardust.webpages.pl/files/handbook/handbook-en.pdf http://www.kernel.org/pub/software/scm/git/docs/tutorial.html http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html

系統不能啟動

試試kernel參數”acpi=off”,如果此參數沒有帶來任何改變,那麼這不是一個ACPI bug。反之,則這很可能是一個ACPI bug。 確定了是一個ACPI bug後,我們還有其他一些參數來更進一步的區分到底是ACPI哪個部分的bug。

acpi=ht

這個參數和"acpi=off"幾乎一樣,它禁止了除多處理器配置相關的內容以外的所有ACPI功能。如果acpi=off正常,但acpi=ht 不正常, 則解析ACPI 表或者Linux SMP的代碼有bug.

pci=noacpi

禁止使用ACPI來處理任何PCI相關的內容,包括PCI root bus的枚舉和PCI裝置中斷路由。

acpi=noirq

禁止使用ACPI來處理PCI裝置中斷路由,和pci=noacpi的區別是它允許使用ACPI來枚舉PCI root bus.

pnpacpi=off

禁止使用ACPI來枚舉PNP裝置,比如串口、PS2鍵盤滑鼠等。

noapic

禁止使用io-apic來做裝置中斷路由,這樣做的效果之一是ACPI返回的中斷路由表將是針對PIC(8259)的。

nolapic

禁止使用Local-APIC和IO-APIC。
裝置中斷相關的問題

出現中斷問題的可能性很多,比如驅動程式有bug。由ACPI導致的最常見的中斷問題是kernel打出:”irqXX: nobody cared!”。這意味著kernel收到一個中斷,但是沒有驅動程式來處理此中斷。Kernel會將此中斷禁止,從而導致掛在此中斷上的所有裝置都停止工作。pci=noacpi, acpi=noirq, pnpacpi=off, noapic, nolapic這些參數可以協助隔離一些問題。另外一個有用的參數是”irqpoll”,出現上面的中斷問題時,它可以使kernel自動探測哪個裝置發出了中斷。這個參數對於調試那些中斷路由有問題的系統很有用。

Suspend to RAM問題

STR的一個常見問題是Resume回來後黑屏,但是系統並沒有死掉,比如可以通過網路訪問系統或者鍵盤燈工作正常。可以試試kernel參數acpi_sleep=s3_bios/s3_mode,它會嘗試將顯示器開啟。如果不行可以試試vbetools(http://www.srcf.ucam.org/~mjg59/vbetool),在resume回來後輸入 $ vbetool post 為了方便,你可以在你的STR指令碼中調用此命令。

STR的另一個常見問題是系統沒法resume回來,你可以試試acpi_sleep=s3_beep。如果你聽不到電腦的擴音器產生的聲音,那麼resume的代碼完全沒被執行。這可能是BIOS的原因,也可能是Linux的原因,目前還沒有太好的辦法處理。反之,很有可能是Linux driver的原因,你可以嘗試儘可能少的載入驅動程式,只保留最基本的驅動,比如硬碟驅動。

Suspend to Disk 問題

TBD

ACPI debug參數

參數是acpi.debug_level and acpi.debug_layer。如果開啟debug參數,ACPI可以產生很多詳細的運行輸出。這些輸出可以協助我們定位出錯的原因。

對於debug_layer和debug_level,include/acpi/acoutput.h裡麵包含了很多值,這些值決定了Linux/ACPI輸出資訊的詳細程度和內容約制。acpi.debug_level和 acpi.debug_layer是kernel參數,也可以在系統運行時改變這些值,它們是/sys/module/acpi/parameters/debug_{level,layer}。

注意,這些輸出資訊可能很快就將kernel的ring buffer用完,你可能需要使用log_buf_len=XY來增加ring buffer的大小。使用serial console (Documentation/serial-console.txt)來得到kernel輸出是一個好的方法。如果你的膝上型電腦沒有串口,可以試試netconsole (Documentation/networking/netconsole.txt)。

使用定製的 DSDT

DSDT (Differentiated System Description Table)是一個主要的ACPI表,它包含了很多AML代碼。因為BIOS的bug,這些代碼本身可能有錯。Linux提供的一種方法能讓你使用定製的DSDT表,這對於調試很有協助。讓kernel使用定製的DSDT步驟如下:

    首先要得到原始的DSDT表(後面的章節會介紹acpidump等工具):     $ acpidump > acpidump.out     $ acpixtract DSDT acpidump > DSDT.dat     這樣我們就得到了DSDT表的二進位檔案,將它反組譯碼     $ iasl -d DSDT.dat     我們會得到一個AML代碼檔案,你可以修改它     $ vi DSDT.dsl     然後重新編譯     $ iasl -tc DSDT.dsl     把它拷貝到kernel source中     $ cp DSDT.hex $SRC/include/

加入下面幾行到你的kernel設定檔(.config):

CONFIG_STANDALONE=n CONFIG_ACPI_CUSTOM_DSDT=y CONFIG_ACPI_CUSTOM_DSDT_FILE=”DSDT.hex”

編譯kernel,運行,你的dmesg中應該有如下輸出: Table [DSDT] replaced by host OS

使用這種方法,你可以修正DSDT的bug。這種方法帶來的一個有用的debug方法是:將ACPI的debug選項開啟,然後在你的DSDT中加入類似如下的語句: Store(”hello world!”, Debug) Store(Local0, Debug) 即將某個變數儲存到特殊的目標Debug中。加入了這樣語句後的函數被kernel解釋執行時你可以看到如下輸出: [ACPI Debug] String: [0x0C] “hello world!” [ACPI Debug] Integer: 0×00000042 由此我們可以在AML代碼層級進行調試。

報告ACPI bug

Linux/ACPI社區使用kernel bugzilla來跟蹤bug 。http://bugzilla.kernel.org/enter_bug.cgi?product=ACPI。這個網站主要是跟蹤base kernel的bug,如果你有特定發行版的bug,不要發到這個網站。Linux/ACPI有自己的郵件清單(linux-acpi@vger.kernel.org),你也可以在那裡討論問題。另外,Intel的Linux/ACPI組也有一個郵件地址(acpi@linux.intel.com),如果你的問題不方便公開,可以發到這兒。

如果你報告一個bug,請提交如下資訊:

  1. 產生bug的kernel版本
  2. 以前的kernel有沒有這樣的bug。如果這是一個regression,最近可以工作的kernel版本是什麼。如果你能使用git-bisect找到哪個patch帶來regression,那問題基本上就等於解決了。
  3. 出錯的kernel和最近工作kernel的dmesg資訊。你可能需要使用serial console來得到這些資訊。
  4. 如果這是中斷相關的問題,可能的話請提供kernel出錯和工作的時候/proc/interrupts的輸出。/sbin/lspci –vvv和/sbin/lspci -xxx的輸出也很有用。
  5. 請提供acpidump的輸出。Acpidump是一個工具,它可以將系統中的ACPI表打出來。你可以在http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils/找到這個工具。注意acpidump輸出的是BIOS的表,不同的BIOS版本可能會有不同的表。
  6. 如果我們發現BIOS有問題,我們可以將此系統列入黑名單,在這種情況下需要提供dmidecode(通常在/usr/sbin/下)工具的輸出。
  7. 產生bug的kernel設定檔
如何使用ACPI工具

http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils/,按照包裡面的README編譯。使用步驟如下:匯出所有的表,這些表都是二進位的 $ acpidump > acpidump.out

上面的輸出包含了很多個ACPI表,如果你希望將它們分離開,使用 $ acpixtract -a acpidump.out

反組譯碼某個表 $ iasl -d TABLE.dat 這樣就得到類C的AML代碼。

參考文檔

ACPI in Linux – Myths vs. Reality(OLS 2007) paper: https://ols2006.108.redhat.com/2007/Reprints/brown_1-Reprint.pdf presentation: http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/doc/OLS2007-acpi-myths-web/

ACPI in Linux – Architecture, Advances, and Challenges(OLS 2005) paper: http://www.linuxsymposium.org/2005/linuxsymposium_procv1.pdf presentation: http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/doc/ACPI_OLS_2005.pdf

The State of ACPI in the Linux Kernel(OLS 2004) http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/doc/Reprint-Brown-OLS2004.pdf

TODO列表
  1. Suspend/resume的穩定性。Suspend-to-ram在很多膝上型電腦上不能工作。很多驅動程式沒有實現.suspend/.resume方法或者實現有問題。
  2. Hotkey的支援。很多膝上型電腦廠商使用完全不同的方法來支援hotkey,現在Linux支援IBM,Asus,Toshiba等。但是還有很多廠商的不支援,即使支援的廠商也有很多筆記本型號不支援。
  3. 運行時裝置電源管理。Linux還缺乏一個架構在系統運行時對裝置進行電源管理,例如在某個裝置空閑時將它關閉而不影響整個系統的運行。
  4. Device model方面的改進。Linux仍然缺乏一個好的機制將ACPI裝置和它對應的物理裝置統一起來處理。
  5. Bugzilla上有很多ACPI的bug

轉自:http://wiki.zh-kernel.org/project/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.