Open Wer-Wolf opened 4 months ago
Hi @Wer-Wolf, I've analyzing WMI and WMI2 interface too. Look at #98 and #101 (TLDR about versions). I guess that all WMI2 layout is identical, at least inside specific version. Get_WMI
returns this WMI2 version. You can check DSDT Device (SCM0)
which has Name (MAJR, 0x02); Name (MINR, 0x08)
or similar. WMI1 don't have these parameters.
Do you use ImHex? I wrote hexpat for WMI1 and WMI2 based on DSDT content. WMI2 map include ThePBone pattern. Also, I've planned to add a map from MControlCenter
How you decompiled BMOF? MS mofcomp
or pali's bmfdec
Since you guys have seen a look of MSI EC register layouts, maybe you can help us decode the fan data?
I think that exists 2-3 different layout generation, 2 of them I call WMI1 and WMI2
According to DSDT, and some text files from app folder, looks like MSI laptop cold have up to 4 cooler.
This is Get/Set_Fan, RPM (or derivative) is on 0 argument [C8-CF], CPU is 1 [71-78], GPU is [89-90].
So you need to call [fully qualified ACPI path to SCM (ends on WMAM)] [any] [WMI id for Get_Fan] [[0, ....]]
, where [[]] is Package
with length 0x20, and the first byte is the argument
from sentence above.
Are you implementing thermal curve?
You should look for Get/Set_Temperature
. It is define temperature levels for speed levels from Fan
[0]: 68 - CPUt, 80 GPUt, 9F unused? [1]: 69-70 CPU thermal curve [2]: 81-88 GPU thermal curve
In WMI2 temps in 1,2 lists is mixed for some reason.
The WMI method read the following registers:
Parameter 0x00: 0xC8 - 0xCF Parameter 0x01: 0x71 - 0x78 Parameter 0x02: 0x89 - 0x90
0 - RPMs, 1 - CPU fan curve, 2 - GPU fan curve Fan curves in range 0-150%
Also, exists Get/Set_Thermal
but it's content looks weird
UPD: you can check how implemented RPM conversion in MControlCenter
it uses some averaged value. Result in MSI app is slightly different. Report
Many thanks, i can confirm that this WMI interface is called WMI2 by MSI Center. Is there a way to detect how many fans are available (MSI Center shows a single fan)?
I've analyzed apps a little, but drop it because of questionable legality.
I can share my hexpats if you want
Sure
https://github.com/glpnk/hexpats
You need to use nightly version or Web because of some new features for comfort pattern toggle
@Wer-Wolf Which tool you use to decompile BMOF?
I used bmfdec, but it needs a patch in order to fully decode the MOF file.
The owner cannot currently access the repository, so it will take a while
I also found a possible formula to calculate the fan rpm from the bytes in buffer 0x00:
Fan RPM = (1 / Byte ) * 480000
Seems the fan speed is measured in clock circles of some internal reference clock.
On WMI1 "RPM" registries is called AP
. I also can't imagine the laptop with 4 coolers
On kernel /drivers/platform/x86/msi-wmi.c listed some different from "SCM"(WMI1/2) GUIDs.
BMOFs on latest apps is the same, older devices use app with only WMI1 part
According to dll metadata, some components are pretty old
Yes, msi-wmi
seems to control a different WMI interface.
I also found a possible formula to calculate the fan rpm from the bytes in buffer 0x00:
Fan RPM = (1 / Byte ) * 480000
They use different const, but close in value
Will be great to analyze how events works. @Wer-Wolf do you know some dummy ACPI-WMI events handler? According to DSDT table, there are not many different values are returned, just with different header value/event id(?)
You mean a driver which just logs the received WMI events to console?
I can write such a driver, if you wish.
Yeah, something like you write GUID to sysfs file and read events from it. Or something easier to implement. With just built-in GUID and log to file.
I can create a generic WMI event debugging driver which logs all received events to dmesg
. This driver can then be selected with the standard driver_override
sysfs attribute.
Awesome!
I finished the necessary patches, but they depend on some other patches to the WMI driver core. I will notify you when i finished upstreaming those patches.
Hi, @Wer-Wolf do you know which driver is used for accessing SystemMemory
Region in DSDT? Or it just mapping kernel memory space without any driver?
AFAIK no special driver is used for this, just the general purpose memory mapping subsystem. Why are you asking?
Thanks. My friend have Xiaomi laptop with, probably, software disabled camera and microphone, and it's EC mapped as SystemMemory
Hello,
i am working on reverse engineering the MSI WMI interface, which does provide similar access to the EC:
class WMIEvent : __ExtrinsicEvent { };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set Software"), guid("{24418D6A-0A79-524C-9AB1-18B78CA68CE7}")] class MSI_Software { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Software")] uint8 Software; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set Device"), guid("{4AFBD56B-9F91-8f49-81F5-995BA73822AF}")] class MSI_Device { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Device")] uint8 Device; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set Power"), guid("{2D3CBA6C-1C9C-7f41-B54C-F5D5D580D482}")] class MSI_Power { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Power")] uint8 Power; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set Master_Battery"), guid("{40BA026D-075D-cd4a-9710-F7C57347CAC9}")] class MSI_Master_Battery { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Master_Battery")] sint16 Master_Battery; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set Slave_Battery"), guid("{8DBCCF6E-9DB4-0e46-A3F2-99AFAAA77A7A}")] class MSI_Slave_Battery { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Slave_Battery")] sint16 Slave_Battery; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set CPU"), guid("{BD2A216F-2FB9-a640-B807-DDDBAD656891}")] class MSI_CPU { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("CPU")] uint8 CPU; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set VGA"), guid("{1EC3EC7A-1E9B-e74a-9026-CF122B0BBD21}")] class MSI_VGA { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("VGA")] uint8 VGA; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set System"), guid("{A1753D7B-B621-de4a-B41A-55716A0ECE7A}")] class MSI_System { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("System")] uint8 System; };
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\0x409"), Description("Class to ECRam Query/Set AP"), guid("{A1753D7C-B621-de4a-B41A-55716A0ECE7A}")] class MSI_AP { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("AP")] uint8 AP; };
[WMI, Dynamic, Provider("WmiProv"), Local("MS\0x409"), Description("Event defined by MSI"), guid("{5B3CC38A-40D9-7245-8AE6-1145B751BE3F}")] class MSI_Event : WMIEvent { [key, read] string InstanceName; [read] boolean Active; [WmiDataId(1), read, write, Description("Event defined by MSI")] uint32 MSIEvt; };
[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("{ABBC0F61-8EA1-11d1-00A0-C90629100000}")] class Package_1 { [WmiDataId(1), read, write, Description("1 bytes of data")] uint8 Bytes[1]; };
[WMI, Locale("MS\0x409"), Description("This class contains the definition of the package used in other classes"), guid("{ABBC0F62-8EA1-11d1-00A0-C90629100000}")] class Package_10 { [WmiDataId(1), read, write, Description("10 bytes of data")] uint8 Bytes[10]; };
[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]; };
[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); };
A user asked me for reverse engineering the
Get_Fan
method, see here for additional data.Since you guys have seen a look of MSI EC register layouts, maybe you can help us decode the fan data?
The WMI method read the following registers:
0x00
:0xC8
-0xCF
0x01
:0x71
-0x78
0x02
:0x89
-0x90
Since we suspect that other MSI ECs use a similar register layout, maybe you can help us in finding out what those registers contain.
Thanks, Armin Wolf