christoph_peter_s Tux's lil' helper
Joined: 30 Nov 2015 Posts: 108
|
Posted: Tue Jun 18, 2019 12:42 pm Post subject: Fixing the DSDT of an Asus P8Z68V-Pro |
|
|
After having fixed some rotten tubes of the water cooling system, I wanted to reuse an Asus P8Z68V-Pro carrying an i7-3770K and 32GB RAM as a Gentoo based workstation. The box had served as my main Windoze box for quite some time - so I never realized, how badly Asus messed up the bios of that mainboard. The issue is this: whenever I enable Wake-on-Lan (which I badly deserve as the box has been moved to my basement compartment), the unit will no longer be able to be switched-off. Whenever issuing a shutdown command, the box does switch-off - and power-up again after a one or two seconds.
After a lot of searching, I found a thread on exactly that malfunction on an Asus H87I-Plus board in an Arch-Linux forum (see: https://bbs.archlinux.org/viewtopic.php?id=173648). As this was virtually the only piece of information I could find after a lot of searching, and as things are always a bit different for Gentoo (and to give something back to the great Gentoo community), I decided to write this small tutorial, on how to fix the issue.
Background information
The bios of a mainboard contains lists, which describe the individual hardware sitting on the board as well as the information on how to access it. A good chunk of this information is then handed over to the booting operating system, which during boot enables one piece after another. In order to allow different OS to boot, the information is expected to be formatted according to well defined standards. There are however to notable exceptions: one is Apple, which supplies a bundled set of hard- and software, which is difficult to break apart - and in fact, it is not too simple to build an Hackintosh...
The other notable exception is Microsoft, which uses to deliberately incorporate subtle nuances to accepted standards in their products, which nearly achieve interoperability - but in fact they are designed to do not. One of these spoiled implementations is the M$ way of implementing the Intel ACPI Source Language, iASL for short, which is the basic means to describe the mainboards hardware in a set of tables. The most cumbersome one is the Differentiated System Description Table DSDT. Background information can be found here: https://www.coreboot.org/ACPI and here: https://acpica.org/documentation. Also there is a community, which deals with the hacking of tuned bioses to re-enable crippled features of popular non-high end mainboards. It is not too complicated stuff - but it is a bit of reading. Also one whishes to have a flash programmer at hand, when really fixing the bios. But this would be an overkill for the given issue... As You will see later, we can cope with our issue in a less intrusive way.
It is worthwhile to note, that Linux seemed to face issues with crappy bios implementation since its very beginning. So it did conceive an elegant means on how to deal with it: it offers an mechanism, to replace a buggy DSDT on the fly during the boot-up process, either by compiling a DSDT copy into the kernel, or by loading one early in the boot process from a give file location. I have chosen the latter approach, as I did not manage to make the first one working.
On a technical level I should add, that the term ACPI Source Language, commonly referred to as ASL, is the human readable hardware description. Within the bios a compiled version of it is used, the ACPI Machine Language AML. Compilation and decompilation is performed by the a compiler, in our case by the open source Intel ACPI Soure Language compiler. An informative, but outdated wiki article is here: https://forums.gentoo.org/viewtopic-t-122145-start-0.html (but I wasn't aware of this, besides: it is _really_ outdated...).
Preparing the arena
There are a few things necessary for the fix:
[*] the Intel ACPI Source Language compiler from the package https://packages.gentoo.org/packages/sys-power/iasl
[*] the Intel iASL compiler documentation https://acpica.org/sites/acpica/files/aslcompiler_10.pdf
[*] the ACPI specification https://uefi.org/sites/default/files/resources/ACPI_6_2.pdf
[*] the Arch-Wiki entry on the DSDT https://wiki.archlinux.org/index.php/DSDT
Extraction of the DSDT
The first step is to extract the actual DSDT and copy it to a working directory.
Code: | HOME\peter@hydra ~ $ mkdir dsdt
HOME\peter@hydra ~ $ cd dsdt
HOME\peter@hydra ~ $ sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.dat |
Next we decompile the DSDT using the Intel iasl:
Code: | HOME\peter@hydra ~/dsdt $ iasl -d dsdt.dat
Intel ACPI Component Architecture
ASL+ Optimizing Compiler/Disassembler version 20180810
Copyright (c) 2000 - 2018 Intel Corporation
Input file dsdt.dat, Length 0xBAFE (47870) bytes
ACPI: DSDT 0x0000000000000000 00BAFE (v02 ALASKA A M I 00000015 INTL 20051117)
Pass 1 parse of [DSDT]
Pass 2 parse of [DSDT]
Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)
Parsing completed
Found 6 external control methods, reparsing with new information
Pass 1 parse of [DSDT]
Pass 2 parse of [DSDT]
Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)
Parsing completed
Disassembly completed
ASL Output: dsdt.dsl - 435088 bytes
iASL Warning: There were 6 external control methods found during
disassembly, but only 0 were resolved (6 unresolved). Additional
ACPI tables may be required to properly disassemble the code. This
resulting disassembler output file may not compile because the
disassembler did not know how many arguments to assign to the
unresolved methods. Note: SSDTs can be dynamically loaded at
runtime and may or may not be available via the host OS.
To specify the tables needed to resolve external control method
references, the -e option can be used to specify the filenames.
Example iASL invocations:
iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml
iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml
iasl -e ssdt*.aml -d dsdt.aml
In addition, the -fe option can be used to specify a file containing
control method external declarations with the associated method
argument counts. Each line of the file must be of the form:
External (<method pathname>, MethodObj, <argument count>)
Invocation:
iasl -fe refs.txt -d dsdt.aml
|
The decompiler generates the file dsdt.dsl, which is the ASL (ACPI Source Language) source of the DSDT.
Fixing the DSDT
Fixing the DSDT means to achieve two things:
[*] the first and foremost issue is to fix the bugs, which are thrown during the recompilation.
[*] second we must remove the offending entries, that prevent the box from a proper shutdown.
So let's start...
Code: | HOME\peter@hydra ~/dsdt $ iasl -tc dsdt.dsl
Intel ACPI Component Architecture
ASL+ Optimizing Compiler/Disassembler version 20180810
Copyright (c) 2000 - 2018 Intel Corporation
dsdt.dsl 2541: CreateDWordField (BUF0, \_SB.PCI0._Y0F._LEN, MSLN) // _LEN: Length
Warning 3128 - ResourceTag larger than Field ^ (Size mismatch, Tag: 64 bits, Field: 32 bits)
dsdt.dsl 2564: CreateDWordField (BUF0, \_SB.PCI0._Y0F._LEN, M4LN) // _LEN: Length
Warning 3128 - ResourceTag larger than Field ^ (Size mismatch, Tag: 64 bits, Field: 32 bits)
dsdt.dsl 2790: Return (Zero)
Error 6105 - ^ Invalid object type for reserved name (_CRS: found Integer, Buffer required)
.... |
That's a lot... we copy it to a file Code: | HOME\peter@hydra ~/dsdt $ iasl -tc dsdt.dsl &> iasl_errors.txt |
After having deleted all the warnings and notifications, we see, what we need to address:
Code: | dsdt.dsl 2790: Return (Zero)
Error 6105 - ^ Invalid object type for reserved name (_CRS: found Integer, Buffer required)
dsdt.dsl 4727: Name (_HID, "pnp0c14") // _HID: Hardware ID
Error 6136 - Non-hex letters must be upper case ^ (pnp0c14)
dsdt.dsl 6242: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6279: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6318: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6357: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6396: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6435: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6474: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6513: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 6552: PLD_Revision = 0x1,
Error 6105 - Invalid object type for reserved name ^ (_PLD: found Buffer, Package required)
dsdt.dsl 12779: Name (_HID, "ABCDEFGH") // _HID: Hardware ID
Error 6035 - ^ _HID suffix must be all hex digits (GH)
Compilation complete. 12 Errors, 6 Warnings, 52 Remarks, 305 Optimizations |
So we have three different errors, where one error occurs a multiple times. That's not too bad...
So we fire up vim, set numbers move to the first error location and find:
Code: | 2786 Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
2787 {
2788 If (TPMF)
2789 {
2790 Return (Zero)
2791 }
2792
2793 Return (CRS) /* \_SB_.PCI0.TPMX.CRS_ */
2794 } |
Now it is time, to study the ACPI specification, which defines the ASL in chapter 19. After having a short glance on it, we note chapter 19.3.5.2 Explicit Data Type Conversions - there is a conversion function ToBuffer, which seem to deliver, what the error message complained about. So we modify our dsdt.dsl accordingly:
Code: | 2786 Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
2787 {
2788 If (TPMF)
2789 {
2790 Return (ToBuffer(Zero))
// ^^^^^^^^^^ here!
2791 }
2792
2793 Return (CRS) /* \_SB_.PCI0.TPMX.CRS_ */
2794 } |
The fix on line 4727 (Non-hex letters must be upper case) is trivial ("PNP0c14").
The next error on lines 6242 (_PLD: found Buffer, Package required) again requires that the return argument is declared as a package, rather then returning the plain buffer. We have a look on the package declaration in chapter 19.6.101 of the ACPI specification. The syntax is Package (NumElements) {PackageList}. Have a look on the example provided there.
So we change the lines
Code: | 6241 Name (_PLD, ToPLD (
6242 PLD_Revision = 0x1,
6243 PLD_IgnoreColor = 0x1,
...
6266 PLD_Order = 0x0) |
to
Code: | 6241 Name (_PLD, Package() {ToPLD (
6242 PLD_Revision = 0x1,
6243 PLD_IgnoreColor = 0x1,
...
6266 PLD_Order = 0x0)} |
We have to do this for nine occurences of the error. The remaining error in line 12779 ("ABCDEF00") is again a trivial one.
Thus we can go over to the second stage, namely to remove that offending routine, which gives those, who want to build a Hackintosh so much grieve. Study the comment #42 of user fseek in https://bbs.archlinux.org/viewtopic.php?id=173648&p=2. So the lesson is, to replace the variable NEXP by One, so that it could never fail... So we have
Code: | 2594 If (((Arg0 == GUID) && NEXP))
2595 {
2596 SUPP = CDW2 /* \_SB_.PCI0._OSC.CDW2 */
2597 CTRL = CDW3 /* \_SB_.PCI0._OSC.CDW3 */
...
10482 If (NEXP)
10483 { |
which we change to
Code: | 2594 If (((Arg0 == GUID) && One))
2595 {
2596 SUPP = CDW2 /* \_SB_.PCI0._OSC.CDW2 */
2597 CTRL = CDW3 /* \_SB_.PCI0._OSC.CDW3 */
...
10482 If (One)
10483 { |
Finally we don't forget to increase the OEM verision from 0x15 to 0x16 according to https://wiki.archlinux.org/index.php/DSDT...
Code: | DefinitionBlock ("", "DSDT", 2, "ALASKA", "A M I", 0x00000016) |
and recompile dsdt.dsl a last time...
Code: | HOME\peter@hydra ~/dsdt $ iasl -tc dsdt.dsl
...
ASL Input: dsdt.dsl - 12868 lines, 435204 bytes, 5260 keywords
AML Output: dsdt.aml - 48016 bytes, 1420 named objects, 3840 executable opcodes
Hex Dump: dsdt.hex - 450539 bytes
Compilation complete. 0 Errors, 6 Warnings, 52 Remarks, 315 Optimizations, 1 Constants Folded |
Applying the fixed DSDT
I have failed to compile the DSDT directly into the kernel, apparently I had the same issues described here https://forums.gentoo.org/viewtopic-t-1088712-start-0.html - no solution yet given. So I had to follow the cpio approach (where I did not find really good documentation - but maybe I just was a bit overworked, as the whole DSDT hacking was less straightforeward then written down here...).
Code: | hydra /usr/src/dsdt # mkdir -p /usr/src/dsdt/kernel/firmware/acpi
hydra /usr/src/dsdt # cp /home/peter/dsdt/dsdt.aml /usr/src/dsdt/kernel/firmware/acpi
hydra /usr/src/dsdt #find kernel | cpio -H newc --create > /boot/acpi_override
hydra /usr/src/dsdt #grep acpi /etc/default/grub
#GRUB_CMDLINE_LINUX="quiet splash acpi=noirq"
GRUB_EARLY_INITRD_LINUX_CUSTOM="microcode.cpio acpi_override"
hydra /usr/src/dsdt #grub-mkconfig -o /boot/grub/grub.cfg |
Anyway, reboot the box - and now the shutdown should work OK with an enabled Wake-on-LAN...
Best regards
Peter
PS: there is still room for improvement - and I would be glad to extent especially the last chapter. If somebody could give me some pointers to both the cpio mechanism and to the direct kernel integration of a patched DSDT. |
|