← Documents Documentation/wmi/devices/msi-wmi-platform.rst GitHub 원문 ↗

Linux 6.18.37 · WMI / Device Drivers

MSI WMI Platform Features driver

MSI notebook EC 위의 32바이트 WMI protocol, fan RPM과 interface version 조회를 설명합니다.

Source pathDocumentation/wmi/devices/msi-wmi-platform.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

msi-wmi-platform.rst:1-198

MSI notebook EC 위의 32바이트 WMI protocol, fan RPM과 interface version 조회를 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0-or-later
2
3 ===================================================
4 MSI WMI Platform Features driver (msi-wmi-platform)
5 ===================================================
6
7 Introduction
8 ============
9
10 Many MSI notebooks support various features like reading fan sensors. This features are controlled
11 by the embedded controller, with the ACPI firmware exposing a standard ACPI WMI interface on top
12 of the embedded controller interface.
13
14 WMI interface description
15 =========================
16
17 The WMI interface description can be decoded from the embedded binary MOF (bmof)
18 data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
19
20 ::
21
22 [WMI, Locale("MS\0x409"),
23 Description("This class contains the definition of the package used in other classes"),
24 guid("{ABBC0F60-8EA1-11d1-00A0-C90629100000}")]
25 class Package {
26 [WmiDataId(1), read, write, Description("16 bytes of data")] uint8 Bytes[16];
27 };
28
29 [WMI, Locale("MS\0x409"),
30 Description("This class contains the definition of the package used in other classes"),
31 guid("{ABBC0F63-8EA1-11d1-00A0-C90629100000}")]
32 class Package_32 {
33 [WmiDataId(1), read, write, Description("32 bytes of data")] uint8 Bytes[32];
34 };
35
36 [WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"),
37 Description("Class used to operate methods on a package"),
38 guid("{ABBC0F6E-8EA1-11d1-00A0-C90629100000}")]
39 class MSI_ACPI {
40 [key, read] string InstanceName;
41 [read] boolean Active;
42
43 [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a package")]
44 void GetPackage([out, id(0)] Package Data);
45
46 [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a package")]
47 void SetPackage([in, id(0)] Package Data);
48
49 [WmiMethodId(3), Implemented, read, write, Description("Return the contents of a package")]
50 void Get_EC([out, id(0)] Package_32 Data);
51
52 [WmiMethodId(4), Implemented, read, write, Description("Set the contents of a package")]
53 void Set_EC([in, id(0)] Package_32 Data);
54
55 [WmiMethodId(5), Implemented, read, write, Description("Return the contents of a package")]
56 void Get_BIOS([in, out, id(0)] Package_32 Data);
57
58 [WmiMethodId(6), Implemented, read, write, Description("Set the contents of a package")]
59 void Set_BIOS([in, out, id(0)] Package_32 Data);
60
61 [WmiMethodId(7), Implemented, read, write, Description("Return the contents of a package")]
62 void Get_SMBUS([in, out, id(0)] Package_32 Data);
63
64 [WmiMethodId(8), Implemented, read, write, Description("Set the contents of a package")]
65 void Set_SMBUS([in, out, id(0)] Package_32 Data);
66
67 [WmiMethodId(9), Implemented, read, write, Description("Return the contents of a package")]
68 void Get_MasterBattery([in, out, id(0)] Package_32 Data);
69
70 [WmiMethodId(10), Implemented, read, write, Description("Set the contents of a package")]
71 void Set_MasterBattery([in, out, id(0)] Package_32 Data);
72
73 [WmiMethodId(11), Implemented, read, write, Description("Return the contents of a package")]
74 void Get_SlaveBattery([in, out, id(0)] Package_32 Data);
75
76 [WmiMethodId(12), Implemented, read, write, Description("Set the contents of a package")]
77 void Set_SlaveBattery([in, out, id(0)] Package_32 Data);
78
79 [WmiMethodId(13), Implemented, read, write, Description("Return the contents of a package")]
80 void Get_Temperature([in, out, id(0)] Package_32 Data);
81
82 [WmiMethodId(14), Implemented, read, write, Description("Set the contents of a package")]
83 void Set_Temperature([in, out, id(0)] Package_32 Data);
84
85 [WmiMethodId(15), Implemented, read, write, Description("Return the contents of a package")]
86 void Get_Thermal([in, out, id(0)] Package_32 Data);
87
88 [WmiMethodId(16), Implemented, read, write, Description("Set the contents of a package")]
89 void Set_Thermal([in, out, id(0)] Package_32 Data);
90
91 [WmiMethodId(17), Implemented, read, write, Description("Return the contents of a package")]
92 void Get_Fan([in, out, id(0)] Package_32 Data);
93
94 [WmiMethodId(18), Implemented, read, write, Description("Set the contents of a package")]
95 void Set_Fan([in, out, id(0)] Package_32 Data);
96
97 [WmiMethodId(19), Implemented, read, write, Description("Return the contents of a package")]
98 void Get_Device([in, out, id(0)] Package_32 Data);
99
100 [WmiMethodId(20), Implemented, read, write, Description("Set the contents of a package")]
101 void Set_Device([in, out, id(0)] Package_32 Data);
102
103 [WmiMethodId(21), Implemented, read, write, Description("Return the contents of a package")]
104 void Get_Power([in, out, id(0)] Package_32 Data);
105
106 [WmiMethodId(22), Implemented, read, write, Description("Set the contents of a package")]
107 void Set_Power([in, out, id(0)] Package_32 Data);
108
109 [WmiMethodId(23), Implemented, read, write, Description("Return the contents of a package")]
110 void Get_Debug([in, out, id(0)] Package_32 Data);
111
112 [WmiMethodId(24), Implemented, read, write, Description("Set the contents of a package")]
113 void Set_Debug([in, out, id(0)] Package_32 Data);
114
115 [WmiMethodId(25), Implemented, read, write, Description("Return the contents of a package")]
116 void Get_AP([in, out, id(0)] Package_32 Data);
117
118 [WmiMethodId(26), Implemented, read, write, Description("Set the contents of a package")]
119 void Set_AP([in, out, id(0)] Package_32 Data);
120
121 [WmiMethodId(27), Implemented, read, write, Description("Return the contents of a package")]
122 void Get_Data([in, out, id(0)] Package_32 Data);
123
124 [WmiMethodId(28), Implemented, read, write, Description("Set the contents of a package")]
125 void Set_Data([in, out, id(0)] Package_32 Data);
126
127 [WmiMethodId(29), Implemented, read, write, Description("Return the contents of a package")]
128 void Get_WMI([out, id(0)] Package_32 Data);
129 };
130
131 Due to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only
132 happen when a invalid byte field is ultimately accessed), all methods require a 32 byte input
133 buffer, even if the Binary MOF says otherwise.
134
135 The input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of
136 input data, the meaning of which depends on the subfeature being accessed.
137
138 The output buffer contains a single byte which signals success or failure (``0x00`` on failure)
139 and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.
140
141 .. note::
142 The ACPI control method responsible for handling the WMI method calls is not thread-safe.
143 This is a firmware bug that needs to be handled inside the driver itself.
144
145 WMI method Get_EC()
146 -------------------
147
148 Returns embedded controller information, the selected subfeature does not matter. The output
149 data contains a flag byte and a 28 byte controller firmware version string.
150
151 The first 4 bits of the flag byte contain the minor version of the embedded controller interface,
152 with the next 2 bits containing the major version of the embedded controller interface.
153
154 The 7th bit signals if the embedded controller page changed (exact meaning is unknown), and the
155 last bit signals if the platform is a Tigerlake platform.
156
157 The MSI software seems to only use this interface when the last bit is set.
158
159 WMI method Get_Fan()
160 --------------------
161
162 Fan speed sensors can be accessed by selecting subfeature ``0x00``. The output data contains
163 up to four 16-bit fan speed readings in big-endian format. Most machines do not support all
164 four fan speed sensors, so the remaining reading are hardcoded to ``0x0000``.
165
166 The fan RPM readings can be calculated with the following formula:
167
168 RPM = 480000 / <fan speed reading>
169
170 If the fan speed reading is zero, then the fan RPM is zero too.
171
172 WMI method Get_WMI()
173 --------------------
174
175 Returns the version of the ACPI WMI interface, the selected subfeature does not matter.
176 The output data contains two bytes, the first one contains the major version and the last one
177 contains the minor revision of the ACPI WMI interface.
178
179 The MSI software seems to only use this interface when the major version is greater than two.
180
181 Reverse-Engineering the MSI WMI Platform interface
182 ==================================================
183
184 .. warning:: Randomly poking the embedded controller interface can potentially cause damage
185 to the machine and other unwanted side effects, please be careful.
186
187 The underlying embedded controller interface is used by the ``msi-ec`` driver, and it seems
188 that many methods just copy a part of the embedded controller memory into the output buffer.
189
190 This means that the remaining WMI methods can be reverse-engineered by looking which part of
191 the embedded controller memory is accessed by the ACPI AML code. The driver also supports a
192 debugfs interface for directly executing WMI methods. Additionally, any safety checks regarding
193 unsupported hardware can be disabled by loading the module with ``force=true``.
194
195 More information about the MSI embedded controller interface can be found at the
196 `msi-ec project <https://github.com/BeardOverflow/msi-ec>`_.
197
198 Special thanks go to github user `glpnk` for showing how to decode the fan speed readings.
199

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

EC 위의 ACPI WMI layer

1-13

많은 MSI notebook은 fan sensor 읽기 같은 기능을 지원합니다. embedded controller가 기능을 제어하고 ACPI firmware가 EC interface 위에 표준 ACPI WMI interface를 노출합니다.

.. SPDX-License-Identifier: GPL-2.0-or-later

===================================================
MSI WMI Platform Features driver (msi-wmi-platform)
===================================================

Introduction
============

Many MSI notebooks support various features like reading fan sensors. This features are controlled
by the embedded controller, with the ACPI firmware exposing a standard ACPI WMI interface on top
of the embedded controller interface.

16·32바이트 package class

14-35

embedded binary MOF는 `bmfdec`로 decode할 수 있습니다. `Package` class는 16바이트, `Package_32`는 32바이트 byte array를 담고 다른 class의 method I/O에 사용됩니다.

MSI package class
Class크기Field
Package16 bytesBytes[16]
Package_3232 bytesBytes[32]

WMI method가 전달하는 고정 크기 buffer입니다.

WMI interface description
=========================

The WMI interface description can be decoded from the embedded binary MOF (bmof)
data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:

::

  [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];
  };

  [WMI, Locale("MS\0x409"),
   Description("This class contains the definition of the package used in other classes"),
   guid("{ABBC0F63-8EA1-11d1-00A0-C90629100000}")]
  class Package_32 {
    [WmiDataId(1), read, write, Description("32 bytes of data")] uint8 Bytes[32];
  };

MSI_ACPI method

36-130

GUID `ABBC0F6E-8EA1-11d1-00A0-C90629100000`의 `MSI_ACPI` class는 package, EC, BIOS, SMBus, battery, temperature, thermal, fan, device, power, debug, AP, generic data와 WMI version을 다루는 29개 method를 선언합니다.

MSI_ACPI WMI method
IDMethod설명
1GetPackage16-byte Package 조회
2SetPackage16-byte Package 설정
3Get_ECembedded controller package 조회
4Set_ECembedded controller package 설정
5Get_BIOSBIOS package 조회
6Set_BIOSBIOS package 설정
7Get_SMBUSSMBus package 조회
8Set_SMBUSSMBus package 설정
9Get_MasterBatterymaster battery package 조회
10Set_MasterBatterymaster battery package 설정
11Get_SlaveBatteryslave battery package 조회
12Set_SlaveBatteryslave battery package 설정
13Get_Temperaturetemperature package 조회
14Set_Temperaturetemperature package 설정
15Get_Thermalthermal package 조회
16Set_Thermalthermal package 설정
17Get_Fanfan package 조회
18Set_Fanfan package 설정
19Get_Devicedevice package 조회
20Set_Devicedevice package 설정
21Get_Powerpower package 조회
22Set_Powerpower package 설정
23Get_Debugdebug package 조회
24Set_Debugdebug package 설정
25Get_APAP package 조회
26Set_APAP package 설정
27Get_Datadata package 조회
28Set_Datadata package 설정
29Get_WMIWMI interface version package 조회

각 WmiMethodId가 조회하거나 설정하는 package입니다.

  [WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"),
   Description("Class used to operate methods on a package"),
   guid("{ABBC0F6E-8EA1-11d1-00A0-C90629100000}")]
  class MSI_ACPI {
    [key, read] string InstanceName;
    [read] boolean Active;

    [WmiMethodId(1), Implemented, read, write, Description("Return the contents of a package")]
    void GetPackage([out, id(0)] Package Data);

    [WmiMethodId(2), Implemented, read, write, Description("Set the contents of a package")]
    void SetPackage([in, id(0)] Package Data);

    [WmiMethodId(3), Implemented, read, write, Description("Return the contents of a package")]
    void Get_EC([out, id(0)] Package_32 Data);

    [WmiMethodId(4), Implemented, read, write, Description("Set the contents of a package")]
    void Set_EC([in, id(0)] Package_32 Data);

    [WmiMethodId(5), Implemented, read, write, Description("Return the contents of a package")]
    void Get_BIOS([in, out, id(0)] Package_32 Data);

    [WmiMethodId(6), Implemented, read, write, Description("Set the contents of a package")]
    void Set_BIOS([in, out, id(0)] Package_32 Data);

    [WmiMethodId(7), Implemented, read, write, Description("Return the contents of a package")]
    void Get_SMBUS([in, out, id(0)] Package_32 Data);

    [WmiMethodId(8), Implemented, read, write, Description("Set the contents of a package")]
    void Set_SMBUS([in, out, id(0)] Package_32 Data);

    [WmiMethodId(9), Implemented, read, write, Description("Return the contents of a package")]
    void Get_MasterBattery([in, out, id(0)] Package_32 Data);

    [WmiMethodId(10), Implemented, read, write, Description("Set the contents of a package")]
    void Set_MasterBattery([in, out, id(0)] Package_32 Data);

    [WmiMethodId(11), Implemented, read, write, Description("Return the contents of a package")]
    void Get_SlaveBattery([in, out, id(0)] Package_32 Data);

    [WmiMethodId(12), Implemented, read, write, Description("Set the contents of a package")]
    void Set_SlaveBattery([in, out, id(0)] Package_32 Data);

    [WmiMethodId(13), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Temperature([in, out, id(0)] Package_32 Data);

    [WmiMethodId(14), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Temperature([in, out, id(0)] Package_32 Data);

    [WmiMethodId(15), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Thermal([in, out, id(0)] Package_32 Data);

    [WmiMethodId(16), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Thermal([in, out, id(0)] Package_32 Data);

    [WmiMethodId(17), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Fan([in, out, id(0)] Package_32 Data);

    [WmiMethodId(18), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Fan([in, out, id(0)] Package_32 Data);

    [WmiMethodId(19), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Device([in, out, id(0)] Package_32 Data);

    [WmiMethodId(20), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Device([in, out, id(0)] Package_32 Data);

    [WmiMethodId(21), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Power([in, out, id(0)] Package_32 Data);

    [WmiMethodId(22), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Power([in, out, id(0)] Package_32 Data);

    [WmiMethodId(23), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Debug([in, out, id(0)] Package_32 Data);

    [WmiMethodId(24), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Debug([in, out, id(0)] Package_32 Data);

    [WmiMethodId(25), Implemented, read, write, Description("Return the contents of a package")]
    void Get_AP([in, out, id(0)] Package_32 Data);

    [WmiMethodId(26), Implemented, read, write, Description("Set the contents of a package")]
    void Set_AP([in, out, id(0)] Package_32 Data);

    [WmiMethodId(27), Implemented, read, write, Description("Return the contents of a package")]
    void Get_Data([in, out, id(0)] Package_32 Data);

    [WmiMethodId(28), Implemented, read, write, Description("Set the contents of a package")]
    void Set_Data([in, out, id(0)] Package_32 Data);

    [WmiMethodId(29), Implemented, read, write, Description("Return the contents of a package")]
    void Get_WMI([out, id(0)] Package_32 Data);
  };

32바이트 I/O protocol과 직렬화

131-144

Windows가 ACPI `CreateByteField()` 오류를 실제 잘못된 byte field에 접근할 때만 발생시키는 특성 때문에 binary MOF의 선언과 관계없이 모든 method에는 32바이트 입력 buffer가 필요합니다.

입력은 subfeature를 고르는 1바이트와 subfeature별 의미를 갖는 data 31바이트입니다. 출력은 성공·실패를 나타내는 1바이트와 output data 31바이트이며, status `0x00`은 실패를 뜻합니다.

WMI method call을 처리하는 ACPI control method는 thread-safe하지 않습니다. 이는 driver 내부에서 직렬화해 처리해야 하는 firmware bug입니다.

MSI WMI buffer
방향Byte 0Byte 1~31
입력subfeature selectorsubfeature별 input data
출력status; 0x00은 실패subfeature별 output data

고정 32바이트 입력·출력 layout입니다.

Due to a peculiarity in how Windows handles the ``CreateByteField()`` ACPI operator (errors only
happen when a invalid byte field is ultimately accessed), all methods require a 32 byte input
buffer, even if the Binary MOF says otherwise.

The input buffer contains a single byte to select the subfeature to be accessed and 31 bytes of
input data, the meaning of which depends on the subfeature being accessed.

The output buffer contains a single byte which signals success or failure (``0x00`` on failure)
and 31 bytes of output data, the meaning if which depends on the subfeature being accessed.

.. note::
   The ACPI control method responsible for handling the WMI method calls is not thread-safe.
   This is a firmware bug that needs to be handled inside the driver itself.

Get_EC controller 정보

145-158

`Get_EC`는 선택한 subfeature와 관계없이 EC 정보를 반환합니다. output에는 flag 1바이트와 28바이트 controller firmware version 문자열이 들어 있습니다.

flag의 처음 4bit는 EC interface minor version, 다음 2bit는 major version입니다. 7번째 bit는 EC page 변경을 나타내지만 정확한 의미는 알려지지 않았고, 마지막 bit는 Tigerlake platform 여부를 나타냅니다. MSI software는 마지막 bit가 설정된 경우에만 이 interface를 사용하는 것으로 보입니다.

Get_EC flag
Bit의미
0~3EC interface minor version
4~5EC interface major version
6 (7th)EC page changed; 정확한 의미는 미상
7 (last)Tigerlake platform

flag byte의 알려진 bit 의미입니다.

WMI method Get_EC()
-------------------

Returns embedded controller information, the selected subfeature does not matter. The output
data contains a flag byte and a 28 byte controller firmware version string.

The first 4 bits of the flag byte contain the minor version of the embedded controller interface,
with the next 2 bits containing the major version of the embedded controller interface.

The 7th bit signals if the embedded controller page changed (exact meaning is unknown), and the
last bit signals if the platform is a Tigerlake platform.

The MSI software seems to only use this interface when the last bit is set.

Get_Fan RPM 계산

159-171

`Get_Fan`은 subfeature `0x00`으로 fan speed sensor를 읽습니다. output은 최대 네 개의 big-endian 16비트 fan speed reading을 담습니다. 지원하지 않는 sensor 자리는 `0x0000`으로 고정됩니다.

RPM은 `RPM = 480000 / <fan speed reading>`으로 계산합니다. reading이 0이면 RPM도 0으로 처리해 0으로 나누지 않습니다.

fan RPM 변환
Get_Fan subfeature 0x00 호출big-endian u16 reading 최대 4개 해석reading이 0이면 RPM 0그 밖에는 480000을 reading으로 나눔

raw reading을 RPM으로 바꾸는 조건입니다.

WMI method Get_Fan()
--------------------

Fan speed sensors can be accessed by selecting subfeature ``0x00``. The output data contains
up to four 16-bit fan speed readings in big-endian format. Most machines do not support all
four fan speed sensors, so the remaining reading are hardcoded to ``0x0000``.

The fan RPM readings can be calculated with the following formula:

        RPM = 480000 / <fan speed reading>

If the fan speed reading is zero, then the fan RPM is zero too.

Get_WMI interface version

172-180

`Get_WMI`는 subfeature와 관계없이 ACPI WMI interface version을 반환합니다. output 첫 byte는 major version, 두 번째이자 마지막 byte는 minor revision입니다.

MSI software는 major version이 2보다 큰 경우에만 이 interface를 사용하는 것으로 보입니다.

WMI method Get_WMI()
--------------------

Returns the version of the ACPI WMI interface, the selected subfeature does not matter.
The output data contains two bytes, the first one contains the major version and the last one
contains the minor revision of the ACPI WMI interface.

The MSI software seems to only use this interface when the major version is greater than two.

MSI WMI reverse engineering

181-198

embedded controller interface를 무작위로 건드리면 장치 손상과 원치 않는 부작용이 생길 수 있으므로 매우 주의해야 합니다.

기반 EC interface는 `msi-ec` 드라이버도 사용하며 많은 method가 EC memory 일부를 output buffer로 복사하는 것으로 보입니다. 따라서 ACPI AML이 어느 EC memory 영역에 접근하는지 조사해 나머지 method를 분석할 수 있습니다.

driver의 debugfs interface로 WMI method를 직접 실행할 수 있으며 `force=true`로 load하면 미지원 hardware 안전 검사를 끌 수 있습니다. 이는 분석용 기능으로 위험성을 이해하고 사용해야 합니다.

MSI EC interface의 추가 정보는 `msi-ec` project에 있으며 fan speed reading 해석 방법을 알려 준 GitHub 사용자 `glpnk`에게 감사를 표합니다.

Reverse-Engineering the MSI WMI Platform interface
==================================================

.. warning:: Randomly poking the embedded controller interface can potentially cause damage
             to the machine and other unwanted side effects, please be careful.

The underlying embedded controller interface is used by the ``msi-ec`` driver, and it seems
that many methods just copy a part of the embedded controller memory into the output buffer.

This means that the remaining WMI methods can be reverse-engineered by looking which part of
the embedded controller memory is accessed by the ACPI AML code. The driver also supports a
debugfs interface for directly executing WMI methods. Additionally, any safety checks regarding
unsupported hardware can be disabled by loading the module with ``force=true``.

More information about the MSI embedded controller interface can be found at the
`msi-ec project <https://github.com/BeardOverflow/msi-ec>`_.

Special thanks go to github user `glpnk` for showing how to decode the fan speed readings.