WMI简介
WMI历史
Windows Management Instrumentation(WMI)是Microsoft基于Web的企业管理(WBEM)的实现,WBEM是一项行业倡议,旨在开发用于在企业环境中访问管理信息的标准技术。WMI使用通用信息模型(CIM)行业标准来表示系统,应用程序,网络,设备和其他托管组件。CIM由分布式管理任务组(DMTF)开发和维护。WMI最初于1998年作为Windows NT 4.0 Service Pack 4的附加组件发布,是Windows 2000,Windows XP和Windows Server 2003家族操作系统中内置的支持核心管理的技术。(详情见微软官网WMI Document)。
作用
在WMI之前,可以通过编程方式访问Windows资源的唯一方法是通过Win32 API。 这种情况使Windows系统管理员无法轻松地使用流行的脚本语言来自动化常见的系统管理任务,因为大多数脚本语言无法直接调用Win32 API。 WMI通过提供一个一致的模型和框架来描述所有Windows资源并将其公开给外界,从而改变了这种状况。 WMI是一种工具和管道,通过它可以访问,配置,管理和监视所有(几乎所有)Windows资源,系统管理员可以使用WMI脚本库创建系统管理脚本,以管理通过WMI公开的任何Windows资源!
BIOS与WMI的关系
通常,BIOS不需要为WMI做任何事情,Windows提供了Windows管理所需的所有WMI。 但是有时候,客户想要实现特殊的OEM功能,则需要BIOS通过WMI与AP / Driver配合,例如在CML 7C43&P340 Project中Lenovo Module通过LenovoGameZone.mof和Lenovo.mof作为Provider,声明BIOS提供给OS的WMI接口。
WMI架构图
wmi可以使用多种方式进行调用,具体可以参考上图:
首先是wm使用者,比如脚本或者其他用到wm接口的应用程序。由wm使用者访问CIM对象管理器WinMgmt(即WMI服务),后者再访问CIM(公共信息模型Common Information Model)存储库。静态或动态的信息(对象的属性)就保存在CM库中,同时保存对象的方法。比如启动一个服务,通过执行对象的方法实现,实际上是通过COM技术调用各种dll,最后由dll中封装的API完成请求。WMI是事件驱动的,操作系统、服务、应用程序、设备驱动程序等都可以作为事件源,通过COM接口生成事件通知,WinMgmt捕捉到事件,然后刷新CM库中的动态信息。这也是为什么WM服务依赖于EventLog的原因。就像注册表有Key和Value一样,CIM库也有分类,用面向对象的术语描述来说,叫做命名空间(Name Space)。
OemWmi ModulePart
ModulePart说明
建立OemWmi ModulePart,简单的封装一个接口注册到OS下,实现向80 Port写值的动作,应用层可以通过通过VB Script或C++调用。
示例代码
- OemWmi.mof
//****************************************************
//filename:MyWmi.mof
// MOF(Managed Object File) Sample
// 2020.08.05
// MOF comment as C++
#pragma AUTORECOVER
//WMI checks the integrity of the WMI repository when the operating system
//starts WMI. If the repository is damaged, WMI automatically rebuilds the
//repository and recompiles it.
#pragma namespace("\\root\\wmi")
//specify the namespace when autorecover or register.
[WMI,
Dynamic,
Provider("WmiProv"),
Locale("MS\\0x409"),
Description("My WMI Sample Class"),
guid("{E2E0B817-EA48-4bad-81A6-FBEB8776A7AF}")]
//WMI Class Qualifiers
class MyClass
{
[key, read] string InstanceName;
[read] Boolean Active;
[WmiMethodId(1),
Implemented,
read, write,
Description("Send to Port 0x80")
]void SendTo80([in] uint8 Data);
};
//Required Items in WMI Class
//*****************************************************
- OemWmi.sdl
PCIDEVICE
Title = "OemWmi"
Parent = "PciHost (Virtual)"
Attribute = "0x0"
Dev_type = "Container"
Dev = 00h
Fun = 00h
SleepNum = 01h
ASLfile = "'OemPkg\OemWmi\OemWmi.asl;After Pci Tree'"
DeviceType = OnBoard
PCIBusSize = 32bit
ROMMain = No
Virtual = Yes
End
TOKEN
Name = "OemWmi_INF_SUPPORT"
Value = "1"
Help = "Main switch to enable OemWmi support in Project"
TokenType = Boolean
TargetMAK = Yes
Master = Yes
End
INFComponent
Name = "OemWmi"
File = "OemWmi.inf"
Package = "OemWmi"
Token = "OemWmi_INF_SUPPORT" "=" "1"
End
- OemWmi.cif
PCIDEVICE
Title = "OemWmi"
Parent = "PciHost (Virtual)"
Attribute = "0x0"
Dev_type = "Container"
Dev = 00h
Fun = 00h
SleepNum = 01h
ASLfile = "'OemPkg\OemWmi\OemWmi.asl;After Pci Tree'"
DeviceType = OnBoard
PCIBusSize = 32bit
ROMMain = No
Virtual = Yes
End
TOKEN
Name = "OemWmi_INF_SUPPORT"
Value = "1"
Help = "Main switch to enable OemWmi support in Project"
TokenType = Boolean
TargetMAK = Yes
Master = Yes
End
INFComponent
Name = "OemWmi"
File = "OemWmi.inf"
Package = "OemWmi"
Token = "OemWmi_INF_SUPPORT" "=" "1"
End
- OemWmi.asl
Scope( \_SB ){
Device(WMI2)
{
// PNP0C14 is Plug and Play ID assigned to WMI mapper
Name(_HID, EISAID("PNP0C14"))
Name(_UID, 2)
//
// _WDG evaluates to a data structure that specifies the data
// blocks supported by the ACPI device.
//
Name(_WDG, Buffer() {
//guid{E2E0B817-EA48-4bad-81A6-FBEB8776A7AF}
// -------- Method execution for SendTo80
0x17, 0xb8, 0xe0, 0xe2, 0x48, 0xea, 0xad, 0x4b, 0x81, 0xa6,
0xfb, 0xeb, 0x87, 0x76, 0xa7, 0xaf,
69, 49, // Object ID (E1)
1, // Instance Count
0x02, // Flags WMIACPI_REGFLAG_METHOD
// -------- MOF data
0x21, 0x12, 0x90, 0x05, 0x66, 0xd5, 0xd1, 0x11, 0xb2, 0xf0,
0x00, 0xa0, 0xc9, 0x06, 0x29, 0x10,
66, 65, // Object ID (BA)
1, // Instance Count
0x00, // Flags
})
OperationRegion (DBG, SystemIO, 0x80, 0x2)
Field (DBG, WordAcc, NoLock, Preserve)
{
P80H, 16
}
Method(WME1, 3) {
If(LEqual(Arg1,1))
{
Store(Arg2,P80H)
}
Return(0)
}
Name(WQBA, Buffer()
{
0x46, 0x4f, 0x4d, 0x42, 0x01, 0x00, 0x00, 0x00, 0x74, 0x02, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00,
0x44, 0x53, 0x00, 0x01, 0x1a, 0x7d, 0xda, 0x54, 0x28, 0xd3, 0x82, 0x00, 0x01, 0x06, 0x18, 0x42,
0x20, 0xc4, 0x01, 0x89, 0xc0, 0xb2, 0x69, 0x24, 0xc2, 0x01, 0x0c, 0x46, 0x03, 0x88, 0xe4, 0x40,
0xc8, 0x05, 0x13, 0x83, 0x0b, 0x21, 0xaf, 0x02, 0x6c, 0x0a, 0x30, 0x09, 0xa2, 0xfe, 0xfd, 0x21,
0x4a, 0x82, 0x43, 0x09, 0x81, 0x90, 0x44, 0x01, 0xe6, 0x05, 0xe8, 0x16, 0x60, 0x58, 0x80, 0x6d,
0x01, 0xa6, 0x05, 0x38, 0x86, 0xa4, 0xd2, 0xc0, 0x29, 0x81, 0xa5, 0x40, 0x48, 0xa8, 0x00, 0xe5,
0x02, 0x7c, 0x0b, 0xd0, 0x8e, 0x28, 0xc9, 0x02, 0x2c, 0xc3, 0x88, 0xc0, 0xa3, 0x88, 0x6c, 0x34,
0x0e, 0x8d, 0x1d, 0x86, 0x65, 0x82, 0x69, 0x10, 0x87, 0x51, 0x36, 0xb2, 0x08, 0x3c, 0xa1, 0x4e,
0x05, 0xc8, 0x15, 0x20, 0x4c, 0x80, 0x78, 0x54, 0x61, 0x34, 0x07, 0x45, 0xf0, 0x43, 0x63, 0xc4,
0x8c, 0x89, 0xc0, 0x76, 0x8e, 0xad, 0x51, 0x9c, 0x46, 0xe1, 0x02, 0xa4, 0x63, 0x68, 0x04, 0xc7,
0x15, 0xde, 0x23, 0x2b, 0x68, 0x86, 0x14, 0xe4, 0x10, 0xce, 0xcd, 0x80, 0xa7, 0x61, 0x9c, 0x0e,
0x41, 0x04, 0x14, 0x3b, 0xc2, 0x01, 0x6b, 0x10, 0x28, 0x19, 0x10, 0xf2, 0x2c, 0xc0, 0xfa, 0xe8,
0x08, 0x81, 0xdd, 0x0b, 0xb0, 0x28, 0x40, 0x19, 0x84, 0xc6, 0x53, 0xe1, 0xf8, 0x0b, 0x30, 0x26,
0xc0, 0x9b, 0x00, 0x5b, 0x38, 0x32, 0x38, 0x27, 0xe1, 0x44, 0x89, 0x51, 0xf1, 0x0c, 0x84, 0x1a,
0x25, 0x9c, 0xb1, 0x6a, 0x43, 0x91, 0x46, 0x54, 0x21, 0xc6, 0x35, 0x6c, 0x84, 0x48, 0xb1, 0x62,
0x84, 0x88, 0xd5, 0xfe, 0x20, 0x48, 0x9c, 0xb3, 0x80, 0x24, 0x80, 0x28, 0xd2, 0x68, 0x50, 0xe3,
0x4f, 0xf0, 0x3c, 0xe0, 0x99, 0x9d, 0xdd, 0x41, 0x1d, 0xe0, 0x49, 0x04, 0x39, 0xc7, 0x33, 0xab,
0x73, 0x72, 0x64, 0xc8, 0x0c, 0x2b, 0xc1, 0xbf, 0x81, 0x4f, 0x06, 0x78, 0xd7, 0x80, 0x9a, 0xe9,
0x03, 0x01, 0x9b, 0x65, 0x38, 0xcc, 0x10, 0xfd, 0xff, 0x1f, 0x74, 0xb8, 0xf3, 0xf2, 0x48, 0x18,
0xc4, 0x11, 0x3e, 0x0b, 0x60, 0x47, 0x7c, 0x32, 0xc7, 0x5d, 0xaa, 0x00, 0xb3, 0x97, 0x00, 0x4d,
0x2e, 0xc1, 0xf1, 0xf8, 0x04, 0xe0, 0xf9, 0x9c, 0x70, 0x02, 0xcb, 0x1f, 0x04, 0x6a, 0x64, 0x86,
0xf6, 0x14, 0x4f, 0xeb, 0x45, 0xc0, 0xe7, 0x83, 0xc3, 0x62, 0x62, 0x21, 0xa4, 0x00, 0x42, 0xe3,
0x01, 0xff, 0xe0, 0x9f, 0x0e, 0x22, 0x3c, 0x17, 0x78, 0xbe, 0x3e, 0x36, 0xc0, 0x18, 0x90, 0xfd,
0x0a, 0x40, 0x08, 0xfe, 0xe2, 0x70, 0x44, 0xcf, 0x08, 0x11, 0x1e, 0x14, 0xd8, 0x11, 0x01, 0x27,
0xf0, 0xd8, 0x80, 0x86, 0xe6, 0x47, 0x80, 0xc8, 0x61, 0xcf, 0x24, 0xf4, 0xb1, 0x44, 0x89, 0x7c,
0x30, 0x3e, 0x50, 0x18, 0xe1, 0x14, 0x9f, 0x23, 0x7a, 0xbf, 0x54, 0x10, 0x02, 0xcb, 0x59, 0xa2,
0x4e, 0x1e, 0x96, 0x02, 0x22, 0x1b, 0x8b, 0xf4, 0x11, 0x83, 0x4a, 0xa1, 0x12, 0xfc, 0x69, 0x1d,
0xd6, 0x41, 0x9e, 0x5c, 0xec, 0xd7, 0x84, 0x73, 0xf4, 0x23, 0x84, 0x1d, 0x43, 0x78, 0x74, 0x08,
0x05, 0x1f, 0x0d, 0x65, 0x73, 0x54, 0x30, 0x0a, 0xe2, 0x81, 0x3b, 0x06, 0x84, 0x8c, 0x9c, 0x01,
0x50, 0x23, 0xf7, 0xf1, 0xe2, 0xf4, 0xde, 0x15, 0x7c, 0x22, 0x21, 0x07, 0x05, 0x68, 0x77, 0x02,
0x9f, 0x00, 0x38, 0x9c, 0x3f, 0x27, 0x14, 0x8e, 0x5c, 0x00, 0x4e, 0x20, 0x01, 0x97, 0x75, 0x10,
0x80, 0xf2, 0xff, 0x3f, 0x08, 0xe0, 0x2e, 0x19, 0x9e, 0xc2, 0xb9, 0x1c, 0xdf, 0xa1, 0x63, 0xcf,
0x01, 0xf0, 0x80, 0x3c, 0x77, 0x2b, 0x1d, 0x3f, 0x9d, 0x42, 0x88, 0x30, 0xd1, 0x0c, 0x8f, 0x89,
0x0d, 0xa1, 0x3f, 0x8c, 0xc7, 0xe3, 0x61, 0xf1, 0xe3, 0x80, 0x4f, 0x2a, 0x0c, 0xfb, 0xe4, 0x0f,
0xa6, 0xe8, 0xc1, 0x6b, 0xf6, 0xc7, 0xf4, 0xca, 0xe0, 0x41, 0x1b, 0xd6, 0x03, 0xe5, 0xb0, 0x46,
0x7b, 0x2a, 0xe1, 0x57, 0x0d, 0x4f, 0xcc, 0x18, 0x61, 0x7d, 0xc8, 0x00, 0x07, 0x20, 0xfe, 0x8a,
0xf0, 0x7e, 0xe1, 0x09, 0x18, 0x90, 0xcd, 0xf1, 0xd1, 0x05, 0x2c, 0xe7, 0x04, 0x3e, 0x88, 0x50,
0x91, 0x62, 0x1c, 0x6e, 0x8c, 0x90, 0x61, 0xa2, 0x3c, 0xce, 0xf8, 0xae, 0xc0, 0x14, 0xda, 0xf4,
0xa9, 0xd1, 0xa8, 0x55, 0x83, 0x32, 0x35, 0xca, 0x34, 0xa8, 0xd5, 0xa7, 0x52, 0x63, 0xc6, 0x4e,
0x28, 0x16, 0xf2, 0x4c, 0xd0, 0x70, 0x1d, 0x03, 0x84, 0x06, 0xa5, 0xd0, 0x49, 0xc1, 0xb1, 0x41,
0x04, 0xe4, 0xff, 0x3f
})
}//End of Device(WMI2)
}//End of Scope(\_SB)
MOF编译为BMF
Bios\Windows通过WMI相互通信需要借助MOF(经过编译后为BMF)文件,MOF描述了BIOS导出的WMI接口名字。按Windows Instrumentation: WMI and ACPI的描述,MOF可能存在于2处:
- HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WmiAcpi的MofImagePath指定;不过我在CML 7C43 Project MB中没有找到这样的设定,应该是应用层编写WMI Provider,生成dll会采取这种方式Register,所以不做讨论。
- 作为Buffer资源,将编译的MOF文件二进制BMF资源包进ASL Source Code,嵌入到ACPI命名空间下。
一个MOF描述文件,它经过mofcomp编译后,会生成二进制MOF资源文件。OEM厂商提取MOF资源文件中的字节流,嵌入到ACPI命名对象中。另外,WDK工具集中还提供wmimofck工具,该工具以MOF资源文件为输入,生成MOF所描述的WMI接口的测试脚本。下面两行命令将依次生成bmf文件(即MOF资源文件)和vbs接口测试脚本:
ASL Code部分逻辑
BIOS在ASL Source Code中需要向WMI mapper声明设备:PNP0C14和_WDG对象。另外,OEM厂商或者IBV会在声明_WDG对象时,顺带声明嵌入式MOF对象。ACPI spec没有规定嵌入式MOF对象的名字,所以各家OEM会有不同的对象名。但是这并不是问题,它是有迹可循的:
- 嵌入式MOF对象位于_WDG对象附近,并且具有形如”Name (WQxy, Buffer()){…”的ACPI对象定义,(其含义为:定义一个包含MOF资源的Buffer,并将该Buffer命名为WQxy。前缀WQ代表这是WMI查询接口,xy是2个16进制数值,用于标识WMI查询接口);
- 最重要的,该ACPI对象定义中包含了大量的16进制Byte,即BMF文件的字节流,并且开头4Byte是一个魔术字:”FOMB”,如下:
OS下调用
Related Tool
为了验证WMI功能,我们可以使用WMICodeCreator,它是Microsoft的免费工具。 下载:WMI Code Creator v1.0,使用WMI Code Creator工具可以生成VBScript,C#和VB .NET代码,这些代码使用WMI完成管理任务,例如查询管理数据,从WMI类执行方法或使用WMI接收事件通知。
或者也可用第三方开源软件WMI Explorer来对WMI进行管理查询。指定method调用
以管理员身份运行WMICodeCreator.exe,来验证和执行BIOS提供的WMI接口,先执行Query for data from a WMI class,再执行Excute a method,Namespace选择root\WMI,Classes选择MyClass。VB Script调用