corpnewt / SSDTTime

SSDT/DSDT hotpatch attempts.
MIT License
1.09k stars 180 forks source link

ASUS Z790-E Gaming Wifi latest bios booting error #73

Closed rokmc820 closed 2 days ago

rokmc820 commented 3 days ago

I am using an ASUS Z790-E Gaming WiFi motherboard and recently updated to the latest bios v2703.

After applying ACPI patches using SSDTTime,

I encountered the error shown in the screenshot.

My bootloader is opencore v1.0.2. Everything worked fine with bios v1801,

but the issue has persisted with every version after that.

I’ve posted questions on reddit and tonymacx86, but no one seems to know the root cause.

My guess is that it’s an issue between opencore and the bios.

Does anyone here know what might be causing this problem?

IMG_48720

corpnewt commented 3 days ago

Would you mind uploading a video of the boot process as well? My best guess is that Asus has orphaned some element which is causing a table to be rejected (due to all the AE_NOT_FOUND prints), but I'd like to be sure of that.

-CorpNewt

corpnewt commented 3 days ago

So - while waiting for a video, I took some time to analyze the DSDT - and it seems one potential culprit is the \_SB.PC00.RP25 device. It is referenced in the DSDT and SSDT10, but is only ever defined in the DSDT. The device definition is locked behind an If () statement, so the macOS ACPI parser does not see it happen:

If ((LPEN == Zero))
{
    // The ACPI parser will not check here when
    // initially building the namespace, so this
    // device definition is not seen:
    Device (RP25)
    {

If we dig more - later in the DSDT, there's a top-level Scope () set to that same RP25 device, but it is not contained within an If () statement:

Scope (_SB.PC00.RP25)
{
    Method (AWAK, 1, NotSerialized)
    {
        If ((UHCS == One))
        {
            If (((Arg0 == 0x03) || (Arg0 == 0x04)))
            {
                WK34 = One
            }
        }
    }
}

The issue here is that that ACPI parser never sees RP25 being created, but it does see it being referenced. If you are familiar with coding, referencing a variable before defining is invalid in many coding languages - so the macOS ACPI parser is likely rejecting the DSDT entirely. When that happens, every other table that references elements within the DSDT (which is the vast majority of them) also gets rejected, and you just have cascading ACPI failures.

So - what can be done abou this? Well, the most complete approach would be to fix that top-level Scope () set to it first checks whether or not that device exists, but that would require reworking the firmware itself. A more manageable approach may be to patch out the If () statement itself - replacing it with Noop instructions (No Operation) so that the macOS ACPI parser can actually see the RP25 device being defined.

That begs the question though: How does one do that?

There are a handful of steps involved - but if you are familiar with writing or patching ACPI they're not too bad. If () statements in ACPI are considered "packages" - and when compiled, they keep their length information in the first handful of bytes in the package - which means we don't have to worry about patching out a lone closing curly brace or similar; instead we just need to find the bytes that represent that If ((PCHS == 0x04)) line and replace them with Noop bytes.

The first step is to disassemble the DSDT as a mixed listing file - which lists the source code followed by hex data representing the compiled equivalent of that code. We can disassemble the DSDT.aml in this way by passing it to iasl with the -l switch.

The next step is to find the code that corresponds to that If () statement where Device (RP25) is defined. I found it starting at line 14447 though your exact line may differ:

            If ((LPEN == Zero))
            {

    D8B5: A0 2F 93 4C 50 45 4E 00                          // ./.LPEN.

                Device (RP25)
                {

    D8BD: 5B 82 26 52 50 32 35                             // [.&RP25

Now that we have that - we can gather up some of that hex data and see what we're working with. The following line is the hex data representing the If ((LPEN == Zero)) statement:

D8B5: A0 2F 93 4C 50 45 4E 00

A0 tells us it's an If () statement, then the next byte gives us some info about the length of the If () package (i.e. how many bytes it encompasses) - then we get the data for the actual condition checked. If you're curious how package length is parsed - you can see the iasl source for it here.

Since we only want to Noop that If () statement, we can use A0 2F 93 4C 50 45 4E 00 as the foundation for our Find value in our would-be ACPI -> Patch entry, but we want to make sure that we're not accidentally affecting anything else in this table (since If ((LPEN == Zero)) does show up more than once). It turns out that we'll need to grab a neighboring byte to ensure our Find value is actually unique in this table. If we look at the lines above If ((LPEN == Zero)), we can see the following:

                    Return (PD1C) /* \_SB_.PD1C */
                }
            }

    D8B0: A4 50 44 31 43                                   // .PD1C

            If ((LPEN == Zero))

We can use that last byte (43) above to "pad" our Find value and make it unique in this case (NOTE: for other tables, you may need more than just one byte to pad - I've already verified this is enough to make this patch unique though). So, our resulting Find value contains the following hex bytes: 43 A0 2F 93 4C 50 45 4E 00 with the first just being used as a pad byte to ensure it's only matched once.

Now we need to create our Replace value. Since we padded with 43, we'll leave that as the first byte since we don't want to change anything but the If () statement itself. We can then replace the rest of the hex bytes with Noops, which get compiled to A3 in hex. Our Replace value would then look like: 43 A3 A3 A3 A3 A3 A3 A3 A3. If we manually apply that patch to the DSDT.aml file directly (via a hex editor or otherwise), and then disassemble it again as a mixed listing file as we'd done before, we can see that our changes did indeed take effect as expected:

                    Return (PD1C) /* \_SB_.PD1C */
                }
            }

    D8B0: A4 50 44 31 43                                   // .PD1C

            Noop

    D8B5: A3                                               // .

            Noop

    D8B6: A3                                               // .

            Noop

    D8B7: A3                                               // .

            Noop

    D8B8: A3                                               // .

            Noop

    D8B9: A3                                               // .

            Noop

    D8BA: A3                                               // .

            Noop

    D8BB: A3                                               // .

            Noop

    D8BC: A3                                               // .

            Device (RP25)
            {

    D8BD: 5B 82 26 52 50 32 35                             // [.&RP25

Instead of an If () statement blocking the definition of RP25, we have a bunch of no operation calls (which functionally do nothing). This means that the definition of that device has been pushed top-level, so the macOS ACPI parser can spot it during its first pass while building the namespace.

So - we now need to create a config.plist -> ACPI -> Patch entry to reflect that info. You can use any standard plist editor to add the Find and Replace values as most will accept hexadecimal for Data values. The rest of the fields can be filled out either to match the target table (for the least possible chance of false positive matches), or to be permissive on table ids/length (which lowers patching strictness, but may survive BIOS updates better). Given that this is a more complicated process, the latter is probably fine in this case - so the resulting patch would look like the following:

<dict>
    <key>Base</key>
    <string></string>
    <key>BaseSkip</key>
    <integer>0</integer>
    <key>Comment</key>
    <string>\_SB.PC00.RP25 NoOp to force-enable</string>
    <key>Count</key>
    <integer>0</integer>
    <key>Enabled</key>
    <true/>
    <key>Find</key>
    <data>
    Q6Avk0xQRU4A
    </data>
    <key>Limit</key>
    <integer>0</integer>
    <key>Mask</key>
    <data>
    </data>
    <key>OemTableId</key>
    <data>
    AAAAAAAAAAA=
    </data>
    <key>Replace</key>
    <data>
    Q6Ojo6Ojo6Oj
    </data>
    <key>ReplaceMask</key>
    <data>
    </data>
    <key>Skip</key>
    <integer>0</integer>
    <key>TableLength</key>
    <integer>0</integer>
    <key>TableSignature</key>
    <data>
    AAAAAA==
    </data>
</dict>

If my hunch is right - adding that patch to your config.plist -> ACPI -> Add section should prevent the DSDT from being rejected by the ACPI parser. This has been a growing trend of late, and I'm hoping it gets nipped soon - as it is rather poor coding practice even if Windows/Linux do not complain - and it would be nice to see firmware get treated with a bit more care.

Hopefully that helps.

-CorpNewt

rokmc820 commented 2 days ago

Hi CorpNewt

Sorry for the delayed response.

I just saw your comment.

Thanks to your guidance, I was able to successfully boot my system.

I've attached videos showing the results before and after applying the patch.

I truly appreciate your help. I had posted questions on reddit and tonymacx86 but couldn’t get the right answer.

As a last hope, I decided to ask here, and thankfully, your solution worked perfectly.

Thank you so much again.

I hope your days are always filled with happiness.

Once again, thank you!

corpnewt commented 2 days ago

Glad to hear that worked out. Enjoy your Hackintosh!

-CorpNewt

rokmc820 commented 2 days ago

Glad to hear that worked out. Enjoy your Hackintosh!

-CorpNewt

Thank you so much :)