今天要整理的筆記是WMI ACPI
在BIOS工程師中,對於WMI ACPI應該大家都有玩過,因為許多的OEM都是開發一些OS端的應用程式,然後再透過WMI 這種方式去跟BIOS的ACPI ASL CODE做溝通,以達到可以讀取Thermal 資訊/EC 資訊/ BIOS Setup Utility 資訊....etc.
在網路上或是微軟的相關文件中,你可以看到主要的架構在於wmiacpi.sys 跟acpi.sys 之間的溝通,對於BIOS工程師來說,如果要去提供這種介面就不得不參考微軟的wmi acpi白皮書上面介紹的內容了,底下是微軟文件的說明:
http://msdn.microsoft.com/en-us/library/windows/hardware/dn614028(v=vs.85).aspx
這份文件中主要的概念有幾個:
1. 他跟你說有一個MOF(Managed Object Format) 是用來給 WMI Core使用的,所以他有個資料庫管理這些MOF檔案;當上層的APP跟WMI Core溝通時,他要去這個資料庫撈對應的MOF資訊,從MOF資訊中取得一些資訊後,才知道怎麼跟你的ACPI溝通!
2.溝通的那個ACPI Device有一個特別的PNPID,也就是PNP0C14 ! 所以BIOS工程師要宣告一個ACPI Device然後底下定義_HID , "PNP0C14" 這樣子才能夠溝通~
3.Wmi Core 溝通的方式就請自行看這篇文章,像是如何透過GUID找到ACPI _WDG內比對GUID然後找到兩個字元後,再去看Flag屬性是否是Method,然後去執行相關的ACPI Method...之類的資訊,因為這些資訊已經在網路上很多,大家也應該熟悉了,這邊就不多描述。 底下是對_WDG對應時的C語言格式:
typedef struct
{
GUID guid; // GUID that names data block
union
{
CHAR ObjectId[2]; // 2-character ACPI ID (Data Blocks and Methods)
struct
{
UCHAR NotificationValue; // Byte value passed by event handler control method
UCHAR Reserved[1];
} NotifyId;
}
USHORT InstanceCount; // Number of separate instances of data block
USHORT Flags; // Flags
};
上面的C結構會對應倒ASL的_WDG 內的定義:
Name(_WDG, Buffer() {
0x6a, 0x0f, 0xBC,....//GUID
66, 65, // Object ID (BA) (兩個字元"BA",可能會組成WQBA或是WMBA,看Flag)
3, // Instance Count (有幾筆Data items)
0x01, // Flags (決定他是不是Method...之類的屬性來決定WQXX/WMXX...etc)
})
那大家可能會問說,你不說運作原理那你要說甚麼?
一般BIOS工程師在Debug時一般就是利用這些運作原理去追ACPI 來找出問題點,一般大家會比較忽略說,那上層的MOF是怎麼加進去資料庫的? 所以這邊會對這部分做一個簡單的說明。在說明之前,我們先看看下面這張圖:
Vbscript : 代表的就是上層APP可以透過像是VBScript/C#....etc之類的去開發你的APP。
Wmi Core : 會去撈MOF 資訊跟Acpi.sys溝通(透過WmiAcpi.sys) 。
ACPI ASL : 你要宣告PNP0C14 ,然後有個Name Object 叫做 _WDG (上面圖畫錯了,懶得改了)。
BIOS Function: 然後透過ACPI ASL的相關Method來實做一些BIOS CODE,像是發個SMI去取得一些資訊,再透過WMI_ACPI ASL往回傳給上層APP...etc.。
Installation wmi acpi方式有兩種:
方式1: MOF包在DLL,並註冊到Registry
1. 增加上述說的那些ASL CODE到你的BIOS
2. 建立一個MOF.DLL (類似OS動態連結檔,不過裡面沒有任何OBJ只有MOF資料)
a. 建立wmiacpi.rc 跟wmiacpi.def 檔案
b. 透過VS2010/2012/2013 的link.exe 將他變成wmiacpi.dll 裡面沒有obj,只有 MOF資料
wmiacpi.rc 內容:
#include <windows.h>
#include <ntverp.h>
#define VER_FILETYPE VFT_DLL
#define VER_FILESUBTYPE VFT_UNKNOWN
#define VER_FILEDESCRIPTION_STR "Resource only DLL containing MOF for ASL code"
#define VER_INTERNALNAME_STR "wmimof"
#define VER_ORIGINALFILENAME_STR "wmimof.DLL"
#include "common.ver"
//
// WMIACPI.SYS requires that the mof resource be named MofResource
MofResource MOFDATA wmiacpi.bmf
wmiacpi.def 的內容就只有一行:
LIBRARY wmiacpi.dll
c. link command :
rc /fo"%OUTDIR%\wmiacpi.res" wmiacpi.rc
link /OUT:"%OUTDIR%\wmiacpi.dll" /NOLOGO /DLL "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib"
"ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEF:"wmiacpi.def" %OUTDIR%\wmiacpi.res /MANIFEST /ManifestFile:"%OUTDIR%
\wmiacpi.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /PDB:"%OUTDIR%\wmiacpi.pdb" /TLBID:1 /NOENTRY /DYNAMICBASE
/NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
3. 複製MOF.DLL檔案到%windir%\system32 (也就是C:\Windows\System32)
4. 在Registry 的HKEY_LOCAL_MACHINE\CurrentControlSet\Services\WmiAcpi底下新增MofImagePath,然後裡面的值指向 "C:\Windows\System32\MOF.DLL"
5. 重新開機,然後OS偵測到PNP0C14之後就會自動安裝WmiAcpi.sys 然後會去Registry 找到你包在MOF.DLL內的資料,之後用你的APP來透過WMI Core去存取你的ACPI ASL.
※ 這邊說的MOF.DLL就是你透過link.exe 建立出來的檔案,請自行變更你的名稱
方式2: MOF包在ACPI ASL,等發送特定IRP時回給Wmi Core.
1. 增加上述說的那些ASL CODE到你的BIOS
2. 建立一個MOF.BMF (MOF的Binary格式,副檔名隨便給因為你可以在Compiler時指定副檔名)
3. 透過 wmimofck.exe 產生.x 檔案,在把他的內容包到ACPI ASL之中.
a. 首先先在_WDG內定義一個專屬MOF的GUID(切記不能改變GUID值)
Name(_WDG, Buffer() {
.
// This GUID for returning the MOF data
0x21, 0x12, 0x90, 0x05, 0x66, 0xd5, 0xd1, 0x11, 0xb2, 0xf0, 0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10, //
66, 65, // Object ID (BA) 這兩個字元可以自己改,但是要對應到WQXX.
1, // Instance Count
0x00, // Flags
})
b.將Wmiacpi.x 內容複製貼上到Name Object "WQBA"
Name(WQBA), Buffer(){"MOF Binary data from Wmiacpi.x"}
4. 重新開機,然後OS偵測到PNP0C14之後就會自動安裝WmiAcpi.sys 然後會發送特定的IRP,然後ACPI那邊會回給WMI CORE MOF的資訊~
在這兩中方式中,都需要把wmiacpi.mof 檔案先經過一個工具叫做mofcomp.exe compiler
而這個wmiacpi.mof 檔案的內容就是你在微軟文件那邊看到的,例如:
class WMIEvent : __ExtrinsicEvent
{
};
[WMI,
Locale("MS\\0x409"),
Description("This class contains the definition of the package used in other classes"),
guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")
]
class Package
{
[WmiDataId(1),
read, write,
Description("16 bytes of data")
] uint8 Bytes[16];
};
...
然後經過mofcomp.exe compiler之後,會產生一個MOF binary 檔案,我把他叫做wmiacpi.bmf。
而這個wmiacpi.bmf 可以經過另一個工具wmimofck.exe 來產生c file / c header file ,如果你想自己寫一個Wmi driver時,可以透過這種方式把來幫助你產生一些需要的程式碼,也可以透過wmimofck.exe來產生VBScript 的Sample code(自動產生),所以當然也可以透過wmimofck.exe來產生一堆HEX 文字檔來方便你把MOF binary資料包進去ACPI ASL之中。
底下是我的批次檔,用來測試用的,分享給大家參考~
※ 這邊使用到的資訊都是來自於微軟的相關文件,有興趣請自行查詢!
需要用到的工具:
Windows WDK內的wmimofchk.exe (我是安裝WDK for win7 ,目前最新版是WDK 8.1)
Reference
http://msdn.microsoft.com/en-us/library/windows/hardware/dn614028(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff542012(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/hardware/ff554794(v=vs.85).aspx