Contribute
Register

[Guide] Using Clover to "hotpatch" ACPI

Primarily this is for laptops (hence battery patching, disabling dual/switched-GPU, etc).
But you can apply the same techniques to a desktop. Desktops are usually much simpler as there are typically only a few patches needed.
Typically, if you're going to start asking questions regarding a desktop in the laptop forum, it is something you make a special note of.
Noted and thank you.
 
@RehabMan, asking it here coz it didn't seem right to create a thread for this simple query.

I am creating a single dynamic hot patching SSDT (for ASUS machines) that can be configured according to a user's like. It's still in WIP.

Suppose, I have a Name (CPDV, 8) field.

How can I change it's value dynamically? Like,
Code:
Method (SOME, 0)
{
Local0 = Package()
{
"String1", 2
}
CreateDWordField(DerefOf(Local0[1]), 0, Local1) // I want to change it's value to that of Name (CPDV) in Device (MYDV). Is this the right way do to it? Sorry, I'm still learning ACPI.
Local1 = \MYDV.CPDV
Return (Local0)
}

Secondly, Can I return a package alongside a name, like, quoting an example for setting ACPI Battery manager's RMCF.
Code:
Device (SMB0)
{
Name (RMCF, Package()
{
"FirstPollDelay", 4000
})

Suppose I have a package store in Local1, How do it return it in a name field?

Code:
Name (RMCF, Local1) // I know it is wrong, what is the right way to do it?

Thirdly (sorry),
Can we return your RMCF values from a method? I mean, will your kext read it or it has to be in scope's root?

Like, can we use,

Code:
Scope (SMB0)
{
Method (_INI, 0)
{
Name (RMCF, Package(){...})
}

Instead of,

Code:
Scope (SMB0)
{
Name (RMCF, Package(){...})
}

Also, for my debug script, in your version of the clover, is it possible to have some file in CLOVER dir and have clover detect it.
Like, we could create a file named .extract_origin in CLOVER's root dir. When booting up, if clover detects this file it would dump the origin files automatically and then delete that .dump_origin file? It is not a good idea to include a setting for this in config.plist as it makes no sense.

The example above was just to make you understand what I am trying to say. There may be better ways to do it (barring the config.plist).

If there turns out to be a way, then, we can implement the same for Dumping preboot log.

Please tell me your views on this.

Regards.
 
Last edited:
@RehabMan, asking it here coz it didn't seem right to create a thread for this simple query.

I am creating a single dynamic hot patching SSDT (for ASUS machines) that can be configured according to a user's like. It's still in WIP.

I moved your post to the hotpatch thread.

Suppose, I have a Name (CPDV, 8) field.

How can I change it's value dynamically? Like,
Code:
Method (SOME, 0)
{
Local0 = Package()
{
"String1", 2
}
CreateDWordField(DerefOf(Local0[1]), 0, Local1) // I want to change it's value to that of Name (CPDV) in Device (MYDV). Is this the right way do to it? Sorry, I'm still learning ACPI.
Local1 = \MYDV.CPDV
Return (Local0)
}

Look at SSDT-HDEF.dsl for ideas.

Secondly, Can I return a package alongside a name, like, quoting an example for setting ACPI Battery manager's RMCF.
Code:
Device (SMB0)
{
Name (RMCF, Package()
{
"FirstPollDelay", 4000
})

Suppose I have a package store in Local1, How do it return it in a name field?

Code:
Name (RMCF, Local1) // I know it is wrong, what is the right way to do it?

A Name can be assigned to a package, as a Name is just a variable.
Not sure what you're really trying to do.
Look at the Probook repo as there are a fair number of customizations done within Device(RMCF) for the different models.

Thirdly (sorry),
Can we return your RMCF values from a method? I mean, will your kext read it or it has to be in scope's root?

RMCF can be either a name or method.
ACPI does not care as an object is an object and it will evaluate by name whether it is a name or method.

Like, can we use,

Code:
Scope (SMB0)
{
Method (_INI, 0)
{
Name (RMCF, Package(){...})
}

Instead of,

Code:
Scope (SMB0)
{
Name (RMCF, Package(){...})
}

If you want the package returned from RMCF to be dynamic, make it a Method instead of a Name.

Also, for my debug script, in your version of the clover, is it possible to have some file in CLOVER dir and have clover detect it.
Like, we could create a file named .extract_origin in CLOVER's root dir. When booting up, if clover detects this file it would dump the origin files automatically and then delete that .dump_origin file? It is not a good idea to include a setting for this in config.plist as it makes no sense.

It is possible.
But, of course, it could also be a setting in config.plist.
Your script would be split into two parts...
- first part sets the config.plist setting
- user reboots (or script helps)
- the data is collected
- second part of the script collects all the data and removes the special setting in config.plist

If there turns out to be a way, then, we can implement the same for Dumping preboot log.

But most of the time I need a preboot.log, it is in a scenario where the user can't boot.
I can get a Clover bootlog from ioreg (or your script might extract it automatically with bdmesg).
 
A Name can be assigned to a package, as a Name is just a variable.
Gotcha! Like in some parts of my SSDT I have used _STA as a method that is dynamic based on user's config. Using RMCF as a method never came to my mind.
ACPI does not care as an object is an object and it will evaluate by name whether it is a name or method.
Oh! I see. It is great to know this, solved all my queries.
CreateDWordField(DerefOf(Local0[1]), 0, Local1)
Local1 = \MYDV.CPDV
This code was right.
It is possible.
But, of course, it could also be a setting in config.plist.
Your script would be split into two parts...
- first part sets the config.plist setting
- user reboots (or script helps)
- the data is collected
- second part of the script collects all the data and removes the special setting in config.plist
I will prepare a demo and will show it to you. But clover part, I can't do. Where should I add the "DumpOrigin" key? Under DSDT.aml > ACPI > SSDT would seem more appropriate.

Also, a little query regarding your ACPIBatteryManager, First, let's look at this piece of code from my custom SSDT:
Code:
Scope (SMB0)
        {
            If (LEqual (\ANKD.HSOA, One))
            {
                Method (RMCF, 0, NotSerialized)
                {
                    Store (Package (0x02)
                        {
                            "FirstPollDelay",
                            0x1F40
                        }, Local0)
                    If (CondRefOf (\ANKD.CFPD))
                    {
                        CreateDWordField (DerefOf (Index (Local0, One)), Zero, CFPD)
                        Store (\ANKD.CFPD, CFPD)
                    }

                    Store ("Injected custom FPD for ACPI Battery", Debug)
                    Store (\ANKD.CFPD, Debug)
                    Return (Local0)
                }
            }
        }
I can verify that the method RMCF is being executed in ACPI debug log. It also return value "0x0000000000001F40" (8000) as mentioned above (verified by ACPI Debug log).

But, when I run "ioreg -l | grep "FirstPollDelay" i get FirstPollDelay value as 4000. Weird.

A little background info, I have renamed BAT0 to SMB0, but that shouldn't be an issue as ACPIBatteryManager is attaching to SMB0 in IOREG.

I have to use SMB0 in SSDT as the DeviceObj for battery as BAT0 will give me an AE_NAME_NOT_FOUND exception.

Can you tell what is going wrong? The custom "FirstPollDelay" part of code from the SSDT is the one posted above. Barring that External import line "External (\_SB.PCI0.SMB0, DeviceObj)"

Regards
 
Last edited:
Gotcha! Like in some parts of my SSDT I have used _STA as a method that is dynamic based on user's config. Using RMCF as a method never came to my mind.

Oh! I see. It is great to know this, solved all my queries.

This code was right.

I will prepare a demo and will show it to you. But clover part, I can't do. Where should I add the "DumpOrigin" key? Under DSDT.aml > ACPI > SSDT would seem more appropriate.

Also, a little query regarding your ACPIBatteryManager, First, let's look at this piece of code from my custom SSDT:
Code:
Scope (SMB0)
        {
            If (LEqual (\ANKD.HSOA, One))
            {
                Method (RMCF, 0, NotSerialized)
                {
                    Store (Package (0x02)
                        {
                            "FirstPollDelay",
                            0x1F40
                        }, Local0)
                    If (CondRefOf (\ANKD.CFPD))
                    {
                        CreateDWordField (DerefOf (Index (Local0, One)), Zero, CFPD)
                        Store (\ANKD.CFPD, CFPD)
                    }

                    Store ("Injected custom FPD for ACPI Battery", Debug)
                    Store (\ANKD.CFPD, Debug)
                    Return (Local0)
                }
            }
        }

The RMCF method should not be in a conditional like that.

But, when I run "ioreg -l | grep "FirstPollDelay" i get FirstPollDelay value as 4000. Weird.

The ACPIBatteryManager.kext code does not write the modified value for FirstPollDelay back to the ioreg.
So you will always see the value that came from the Info.plist, even if a different value was used.


A little background info, I have renamed BAT0 to SMB0,

I don't know why you would do that.
 
So you will always see the value that came from the Info.plist, even if a different value was used.
And still ACPIBatteryManager loads up, If I remove FirstPollDelay value, ACPIBatteryManager doesn't load up. So, technically, it is working. I was confused due to that IOREG value.
The RMCF method should not be in a conditional like that.
As it is your method, can RMCF return Zero? ( I know it is just another method so it can return zero, but will it interfere with ACPIBatteryManager's operations?)
I don't know why you would do that.
Technically, no reason. Just coz I like to see names in IOREG/ACPI to be similar to that of my MacBook Air.

How can I add a string and a IntObj together, If I use default method like in C++ I get a kernel panic.

For example, If I have a Name (EXP1, 1000). I want to append it with a string like it says,
Code:
Local0 = "Value of EXP1 is: " + EXP1 // This is wrong. Gives me a panic.

Regards
 
Last edited:
For example, If I have a Name (EXP1, 1000). I want to append it with a string like it says,
Code:
Local0 = "Value of EXP1 is: " + EXP1 // This is wrong. Gives me a panic.

You would need to convert the number to text, then concatenate the two strings.
Would require creating a integer -> string converter method and a string concatenation method.

But if you're just trying to output them in debug, use ACPIDebug.kext.
Code:
\RMDT.P2("Value of EXP1 is:", EXP1)
 
@RehabMan like ioio is for IOREG is there any utility to call ACPI methods on macOS?
Similar to acpi_call on Linux?
I searched but couldn’t find one :(
 
Back
Top