天天看點

Windbg跟蹤ACPI亮度設定

有陣子沒更新部落格了,趁着有空更新一下前陣子在工作遇到的内容:

公司要出貨一批筆記本,對螢幕亮度上限有限定。我無意中發現可以通過控制ACPI命名空間中Method(_BCL)的行為來實作該需求,雖然事後證明這種方式是錯誤的,但并不影響我記下windbg跟蹤ACPI的方法。

先簡單介紹一下Method(_BCL)的作用,翻開ACPI Spec會看到下列定義:

Windbg跟蹤ACPI亮度設定

這是一個Bios提供給OS用于設定集顯亮度百分比的接口(強調一下,僅設定集顯,不包含外顯)。對于Win10,Method(_BCL)在切換顯示比列時會生效(當然點亮螢幕前也會生效),即切換下圖紅框處的設定:

Windbg跟蹤ACPI亮度設定

一般Method(_BCL)會傳回一個從0到100的數組,分别代表100種亮度比例;如果傳回的是從0到50的數組,那麼當你把上圖綠框中的滑塊拖到最右邊,你會發現螢幕隻有正常亮度的一半(真節能燈)!

Method(_BCL,0)
  {
    //
    // List of supported brightness levels in the following sequence.
    // Level when machine has full power.
    // Level when machine is on batteries.
    // Other supported levels.
    //
      Return(Package(){80, 50, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ..., 95, 96, 97, 98, 99, 100})
  }      

好,背景交代完畢,切入正題,用windbg調試這個ACPI method。以往,AML解釋器----!amli擴充指令隻內建在Checked build的Acpi.sys檔案中,多數調試者止步于此。現在,win10 Free build的Acpi.sys也支援該功能(但需要acpi.pdb,解決無法連接配接M$調試符号伺服器的解決方法參考附錄1)

Step1.

開啟中斷到amli解釋器的功能,如此可以下在ASL code上下斷點:

5: kd> !amli set dbgbrkon      

Step2.

雖然_BCL是已知對象,但是根據ACPI spec,每個對象位于ACPI命名空間的樹狀結構中,是以必須要從ACPI命名空間的根節點"\"開始,為特定對象下斷點。搜尋對象在樹狀結構中的路徑需要用到!amli find指令,找到對象後用!amli bp下斷點:

6: kd> !amli find _BCL
\_SB.PCI0.GFX0.DD1F._BCL

6: kd> !amli bp \_SB.PCI0.GFX0.DD1F._BCL      

Step3.

觸發中斷條件,就是在Settings->System->Display->"Scale and layout"中切換顯示比列,此時windbg會中斷到!amli解釋器中,并且,windbg "Command Line"的提示符從kd>變為Input>,這時可以直接在解釋器中輸入!amli的參數:

AMLI(? for help)-> lc
 Ctxt=ffff8e0c81c23050, ThID=ffff8e0c74c0e080, Flgs=----R----, pbOp=ffff8e0c71b292ea, Obj=\_SB.PCI0.GFX0.DD1F._BCL      

上面的lc用于顯示ACP中斷時,目前的上下文。很明顯,我們已經執行了_BCL函數。

Step4.

單步調試ACPI運作是不可能了,但是有折中的辦法:用!amli u反彙編ACPI函數,并在指定分支處下斷點。雖然這個辦法效率很低,但好在ACPI method代碼量不大,還算可行

AMLI(? for help)-> u \_SB.PCI0.GFX0.DD1F._BCL
ffff8e0c71b292ea:[\_SB.PCI0.GFX0.DD1F._BCL]
ffff8e0c71b292ea : If(CondRefOf(\PBCL, ))
ffff8e0c71b292f4 : {
ffff8e0c71b292f4 : | Return(PBCL())
ffff8e0c71b292f9 : }
ffff8e0c71b292f9 : Else
ffff8e0c71b292fc : {
...

AMLI(? for help)-> bp ffff8e0c71b292ea


AMLI(? for help)-> g