How to create or modify a simple System SSDT.aml by means of DSDT and IOREG ACPI information

PCI (Peripheral Component Interconnect), is a local computer bus for attaching hardware devices. Attached devices can take either the form of an integrated curcuit fitted onto the motherboard itself (on-board devices like Audio or USB controllers) or an expansion card connected to any of the available PCI expansion slots on the Mainbaord (e.g. GPU, TB-expansion card, 10GB NIC, BT/WIFI adapter, etc.)

In order to properly implement a PCI device, one usually needs adequate ACPI (Advanced Configuration and Power Interface) DSDT (Differentiated System Description Table) Replacements and a sophisticated SSDT (Secondary System Description Table) implementing the correct ACPI tables, i.e ACPI path and PCI device properties.

Some ACPI DSDT Replacements can be part of the config.plist others might be direct part of a System SSDT. Note that the ACPI DSDT Replacements in the config.plist or any System SSDT are mainboard and PCIe slot population dependent and have to be verified, adopted or modified for all mainboards different from a certain mainboard model or at least mainboard brand and for all builds with a PCIe slot population different from the one that constitutes the baseline for the respective ACPI replacements. The same also states for the ACPI path of a PCIe device in general. Any ACPI path implemented within some system SSDT is mainboard and PCIe slot population dependent and has to be verified, adopted or modified when applying the respective SSDT on a mainboard and within a PCIe slot population different from the baseline.

Important Note: It is strongly recommended to always perform a stepwise PCI Device implementation by means of a minimalistic starter SSDT, which just contains the Definition Block and Device Implementation for a single specific device. Once this PCI device has been successfully implemented, other PCI Devices can be added to the SSDT. In case that subsequently the implementation of a specific PCI Device would be erroneous and fail, also all other already successfully implemented PCI devices would disappear from Section “PCI” of Apple’s System report and the entire “PCI” Device implementation would fail. Thus a stepwise PCI device implementation/adaptation is highly recommended and sometimes even deemed necessary!

Below one finds a simple example of an SSDT PCI device implementation for the OSXWIFI PCIe Adaptor in PCIe Slot-3 of the ASUS Prime X299 Deluxe. Once you understand the logics and methodology, how to implement the OSXWIFI Airport PCIe device, you should be also able to build and implement a more complex and sophisticated system SSDT by adding other PCIe devices.

In general a DSDT consists of a DefinitionBlock and the underlying PCI device implementations.

Within the definition block one must call or initialise existing, predefined and already implemented external devices or methods etc. that will be part of the respective SSDT PCI device implementation. In case of our OSXWIFI PCIe Adaptor in PCIe Slot-3 of the ASUS Prime X299 Deluxe, the required definition block looks the following in concordance with the original ACPI DSDT implementation visualised with IOREG.

DefinitionBlock ("", "SSDT", 1, "KGP", "X299VEGA", 0x00000000)
{
     External (_SB_.PC03.BR3D, DeviceObj)    // (from opcode)
     External (_SB_.PC03.BR3D.PEGP, DeviceObj)    // (from opcode)
     External (_SB_.PC03.BR3D.SL0C, DeviceObj)    // (from opcode)
     External (DTGP, MethodObj)    // 5 Arguments (from opcode)
}

Method DTPG, is usually implemented in form of a separate external aml-file with the following content:

DefinitionBlock ("", "SSDT", 2, "KGP ", "DTPG", 0x00001000)
{
    Method (DTGP, 5, NotSerialized)
    {
        If (LEqual (Arg0, ToUUID ("a0b5b7c6-1318-441c-b0c9-fe695eaf949b")))
        {
            If (LEqual (Arg1, One))
            {
                If (LEqual (Arg2, Zero))
                {
                    Store (Buffer (One)
                        {
                             0x03                         
                        }, Arg4)
                    Return (One)
                }

                If (LEqual (Arg2, One))
                {
                    Return (One)
                }
            }
        }

        Store (Buffer (One)
            {
                 0x00                         
            }, Arg4)
        Return (Zero)
    }
}

“PC03.BR3D.SLOC” is the original ACPI Device Path implemented in the original ACPI table defined within the DSDT.

As the usual OSX ACPI PCI device nomenclature for an “Airport” device is “ARPT”, we want to subsequently replace the original device “SLOC” in form of a new device “ARPT”.

ACPI replacements sometimes can be quite complex and tricky, which basically depends on the original DSDT PCI device implementation. When nulling an existing PCI device to be replaced by a new PCI device definition, one therefore always has to inspect the respective DSDT ACPI device implementation.

The original DSDT.aml of any system can be dumped into /EFI/CLOVER/ACPI/original/ by pressing F4 in the Clover boot menu, before booting the respective MacOS System partition. Like any other aml-file (also the SSDT is an aml-file), also the DSDT.aml can be edited, inspected and modified by means of MaciASL.app (courtesy to Rehabman), an ASL/DSL editor and ASL optimizer/compiler/dissambler.

Instead of inspecting the DSDT.aml, many times it is easier to change within the IOREG from IOService to IOACPIPlane and inspect the original PC03.BR3D ACPI-Table implementation.

As we can see, under PC03.BR3D the original ACPI Table contains two devices, the active device “SL0C” and the yet passive device “PEGP”

In this particular  case, nulling “PC03.BR3D.SLOC” yields “PC03.BR3D.PEGP” (as defined in the DSDT). Thus, to free the way for implementing the desired new device “ARPT”, one also needs to null “PC03.BR3D.PEGP” to finally implement “PC03.BR3D.ARPT” in form of a new device.

Original SLOT ACPI tables  can also just implement one device, thus one ACPI replacement is sufficient to implement the desired new variable. Other original SLOT ACPI tables can have more than two devices, thus one has to perform several replacements before being able to implement the desired new variable.

Any existing, predefined external device used within the SSDT must also be called and initialised within the definition block of the SSDT. Thus, in our case of the OSXWIFI in Slot-3 of the ASUS Prime X299 Deluxe, we have to call and intialise, “PC03.BR3D”, “PC03.BR3D.SLOC” and “PC03.BR3D.PEGP” in the definition block of the SSDT.

Finally, the intrinsic SSDT ACPI replacement subsequent to the definition block of the SSDT is realised as follows:

Note the peculiarity that existing, predefined external devices are addressed within the SSDT with a “Scope” command, while a new device must be implemented by means of a “Device” command followed by the ADR device definition of the former ADR device address. As SL0C was implemented in form of SLOC@0, also ARPT must be implemented in form of ARPT@0.

Any ACPI DSDT variable replacement directly implemented within a system SSDT can also be performed within the config.plist. In fact in this particular case, the config.plist equivalent would implement the direct “SL0C -> ARPT” DSDT ACPI replacement, as the intermediate SL0C -> PEGP replacement is not required in this case. However, such replacement only can be performed in case that “SL0C” is uniquely defined within the system DSDT ACPI table.

Any DSDT ACPI replacement in the config.plist is usually implemented under “DSDT” and “Patches” in Section “ACPI” of Clover Configurator.

It consists of a replacement “Comment” like e.g. “SL0C -> ARPT” and the proper DSDT ACPI replacement, implemented in form of a hexadecimal value for the variable to be replaced Find* [Hex] and a hexadecimal value for the resulting variable Replace* [Hex] .

Both hexadecimal values are simply the text -> hexadecimal conversion of the text variables to be converted, in our particular case “534C3043” is the hexadecimal conversion of “SL0C” and “41525054” the hexadecimal conversion of “ARPT”, directly performed by means of the “Hex Converter” tool being part of Clover Configurator.

Note that the DSDT ACPI replacement cannot be performed in both, config.plist and system SSDT! Just choose one of two possible methods!

With the config.plist ACPI replacement, the respective SSDT ARPT PCI device implementation would look the following:

DefinitionBlock ("", "SSDT", 1, "KGP", "X299VEGA", 0x00000000)
{
     External (_SB_.PC03.BR3D.ARPT, DeviceObj)    // (from opcode)
     External (DTGP, MethodObj)    // 5 Arguments (from opcode)

        Scope (ARPT)
        {
            Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
            {

Now we can continue with the SSDT ARPT PCI device property definitions.

In Fig.1 above, we can derive further OSXWIFI ARPT device properties from the IOREG Screenshot, i.e. “device-id”, “vendor-id” “sub-system-vendor-ID”, “compatible”, “build-in”, etc.”, which can be considered within the further _DSM ARPT PCI device implementation and usually even extended by adding further known device properties like “AAPL, slot-name” (Slot-3), “model” (OSX WIFI Broadcom BCM94360CD 802.11 a/b/g/n/ac + Bluetooth 4.0 Controller), “name” (AirPort Extreme), or “device-type” (AirPort Controller), which are in this case but not always rather cosmetic modifications.

DefinitionBlock ("", "SSDT", 1, "KGP", "X299VEGA", 0x00000000)
{
     External (_SB_.PC03.BR3D.ARPT, DeviceObj)    // (from opcode)
     External (DTGP, MethodObj)    // 5 Arguments (from opcode)

    Scope (_SB.PC03.BR3D)
    {
        Scope (SL0C)
        {
            Name (_STA, Zero)  // _STA: Status
        }

        Scope (PEGP)
        {
            Name (_STA, Zero)  // _STA: Status
        }

        Device (ARPT)
        {
            Name (_ADR, Zero)  // _ADR: Address
            Method (_DSM, 4, NotSerialized)  // _DSM: Device-Specific Method
            {
                Store (Package (0x0E)
                    {
                        "built-in",
                        Buffer (One)
                        {
                             0x00
                        },

                        "device-id",
                        Buffer (0x04)
                        {
                             0xA0, 0x43, 0x00, 0x00
                        },

                        "AAPL,slot-name",
                        Buffer (0x07)
                        {
                            "Slot-3"
                        },

                        "device_type",
                        Buffer (0x13)
                        {
                            "AirPort Controller"
                        },

                        "model",
                        Buffer (0x4A)
                        {
                            "OSX WIFI Broadcom BCM94360CD 802.11 a/b/g/n/ac + Bluetooth 4.0 Controller"
                        },

                        "compatible",
                        Buffer (0x0D)
                        {
                            "pci14e4,43a0"
                        },

                        "name",
                        Buffer (0x10)
                        {
                            "AirPort Extreme"
                        }
                    }, Local0)
                DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0))
                Return (Local0)
            }
        }
    }
}

For Method _DSM to work, one requires another config.plist ACPI replacement, i.e. “_DSM -> XDSM”

As the result we obtain a modified ARPT ACPI table, which ones more can be investigated by means of IOREG:

After successfully execution of the ARPT SSDT during system boot, all respective ARPT PCI properties are once more revealed in section “PCI” of Apple’s System Report, including some info about whether or not the ARPT SSDT also successfully loads the respective ARPT PCI driver.

I guess that the “PCI” snapshot of Apple’s System report above impressively reveals the true PCI device complexity of my iMacPro i9-7980XE, ASUS Prime X299 Deluxe, Nitro+ Radeon Vega 64 8GB, OSXWIFI, ASUS Aquantia 10GB NIC and GB TB3 Alpine Ridge system.

It might rapidly become evident that the correct PCI Device implementation cannot be outlined and explained for each individual “build-in” or “slot-specific” PCI device. The complexity and effort would just exceed by far all available capacities. I therefore hope on your skills and flexibility to extend and apply the approach and methodology detailed above to any other “build-in” or “slot-specific” PCI device yet to be adopted or implemented, e.g. HDEF and HDAU (Audio), GFX0 (Display), XHCI (XHC USB 3.0) + XHC1 + XHC2 + XHC3 + XHC4 (all USB 3.1), XGBE+ETH0+ETH1 (10Gb + 1Gb LAN), UPSB + NHI0 + XHC5 (TB) etc.

Enjoy and have fun,