Custom SSDTs for Legacy Hackintosh: Fixing EC, Ethernet, and CPU Power Management
Learn how to write custom SSDTs to fix kernel panics, battery status, Ethernet, and CPU power management on legacy Hackintosh systems with Clover. Practical scenarios for EC, PCI injection, and plugin-type.
If you've tried all the standard Clover hotpatches and your DSDT still causes kernel panics on macOS 10.10 or 10.11, it's time to write your own SSDTs. A well-crafted SSDT can override a broken device in the DSDT without touching the firmware itself—crucial for old motherboards where the vendor stopped providing UEFI updates years ago. This guide assumes you already know how to dump your DSDT with Clover's F4 key at the boot menu and have a basic understanding of ASL syntax. We'll focus on three concrete scenarios that pop up repeatedly on legacy hardware: fixing a misnamed embedded controller, injecting a missing PCI device for Ethernet, and creating a custom plugin-type SSDT for CPU power management on Sandy Bridge and Ivy Bridge systems.
Prerequisites and Tools
You need a macOS environment running at least 10.9, or a Linux live USB with iasl installed. The Intel ASL compiler (iasl) is the only tool you'll need. On macOS you can install it via MacPorts or Homebrew, but the safest route for a legacy build is to download the static binary from the ACPICA website and place it in /usr/local/bin. Keep a copy of your original DSDT.aml and any SSDTs that Clover already dumps—they live in /EFI/CLOVER/ACPI/origin after you press F4. Do not edit the DSDT directly; all your customisations go into separate SSDT files that you place in /EFI/CLOVER/ACPI/patched.
Scenario 1: Renaming the Embedded Controller (EC)
Many Gigabyte and ASUS boards from the LGA 1155 era name their embedded controller EC0 instead of the EC that macOS expects. Because of that, AppleSmartBatteryManager kext refuses to load, leaving you without battery status on laptops or, on desktops, cluttering the system log with ACPI errors. The simplest fix is an SSDT that performs a scope rename. Create a file named SSDT-EC.aml with the following ASL source:
DefinitionBlock ("", "SSDT", 2, "HACK", "EC", 0x00000000)
{
External (_SB_.PCI0.LPCB.EC0, DeviceObj)
Scope (_SB.PCI0.LPCB.EC0)
{
Name (_HID, EisaId ("PNP0C09"))
}
}
This does not actually rename the device—it simply ensures that the device object is recognised by macOS as a standard EC. If you need to suppress the EC entirely (for desktop builds that have no battery), use an SSDT that sets the device status to zero:
DefinitionBlock ("", "SSDT", 2, "HACK", "EC", 0x00000000)
{
External (_SB_.PCI0.LPCB.EC0, DeviceObj)
Scope (_SB.PCI0.LPCB.EC0)
{
Method (_STA, 0, NotSerialized)
{
Return (0)
}
}
}
Compile with iasl -ssdt SSDT-EC.dsl. If you get errors about unresolved symbols, add the corresponding External statements. Place the resulting SSDT-EC.aml in your patched folder and reboot.
Scenario 2: Injecting a Missing PCI Device for Ethernet
Some older Realtek PCIe Ethernet controllers (RTL8111/8168 variants) appear in the DSDT under a non-standard ACPI path or are completely absent from the DSDT device tree. macOS's IONetworkingFamily may then assign the wrong built-in property or fail to recognise the interface as built-in, which breaks iMessage and FaceTime. The solution is an SSDT that creates a synthetic PCI device at the correct address and assigns the built-in property.
First, identify the PCI bus address of your Ethernet controller. In macOS, run ioreg -l | grep IOName and look for pci10ec,8168. The address looks like PciRoot(0x0)/Pci(0x1C,0x4)/Pci(0x0,0x0). Translate that into ACPI format: bus 0, device 0x1C, function 0x4, and the device on the secondary bus at device 0, function 0. Your SSDT source should look like this:
DefinitionBlock ("", "SSDT", 2, "HACK", "RTL8111", 0x00000000)
{
External (_SB_.PCI0, DeviceObj)
Scope (_SB.PCI0)
{
Device (RP04)
{
Name (_ADR, 0x001C0004)
Device (ETH0)
{
Name (_ADR, Zero)
Method (_DSM, 4, NotSerialized)
{
If (LEqual (Arg2, Zero))
{
Return (Buffer (One, 0x03))
}
Return (Package()
{
"built-in", Buffer() { 0x01 }
})
}
}
}
}
}
The RP04 name is arbitrary but should not collide with existing device names in your DSDT. Check your original DSDT for RP01 through RP08—if they exist, pick one that is unused. After compiling and placing the SSDT, the Ethernet controller should appear as built-in. This is a prerequisite for the steps covered in Getting iMessage and iCloud Working on a Legacy Hackintosh with Clover.
Scenario 3: CPU Power Management Plugin-Type SSDT for Sandy/Ivy Bridge
Apple's X86PlatformPlugin expects a specific ACPI topology for Intel CPUs. On a real Mac, the DSDT contains a PluginType value of 0x01 inside the processor scope. Without it, macOS falls back to ACPI_SMC_PlatformPlugin, which does not support the full range of P-states and C-states on Sandy Bridge and later. You can generate a plugin-type SSDT using ssdtPRGen.sh on a running system, but the script often fails on legacy hardware because it cannot read the CPU frequency from the MSR registers. The manual method is more reliable.
Create SSDT-PLUG.aml with the following structure, adjusting the CPU0 scope path to match your DSDT:
DefinitionBlock ("", "SSDT", 2, "HACK", "CpuPlug", 0x00000000)
{
External (_SB_.CPU0, DeviceObj)
Scope (_SB.CPU0)
{
Name ("plugin-type", One)
Name ("aggressive", One)
}
}
If your DSDT uses PR00 or CPU1 instead of CPU0, change the External and Scope paths accordingly. Compile and add the SSDT. Then verify that X86PlatformPlugin is loaded with kextstat | grep -E "X86|ACPI_SMC". If you still see ACPI_SMC_PlatformPlugin, your CPU is not being matched—you may need to inject a model-specific board identifier via Clover's SMBIOS settings. For example, a Core i5-2500K works best with Macmini6,2 or iMac12,2.
Compilation Pitfalls and Debugging
The iasl compiler is strict about ASL 2.0 syntax. If you write Return (0) instead of Return (Zero), compilation fails on older versions of the compiler. Use iasl -d DSDT.aml to disassemble your original DSDT and study its naming conventions—that is the only reliable way to avoid path mismatches. Common errors include:
– Namespace lookup failure: You used _SB.PCI0 but the DSDT uses _SB_.PCI0 (two underscores after SB).
– Duplicate device name: Your SSDT defines a device that already exists in the DSDT. The SSDT will override it, but only if the path matches exactly.
– Missing External declaration: Every object referenced from outside the SSDT must be declared as External.
Test each SSDT individually. Place only one custom SSDT in the patched folder, reboot, and check the system log for ACPI errors (log show --predicate 'process == "kernel"' --last boot | grep -i acpi). If the machine fails to boot, remove the SSDT from the USB installer or from your backup EFI partition.
Organising Your Patched Folder
Name your SSDTs descriptively: SSDT-EC.aml, SSDT-ETH.aml, SSDT-PLUG.aml. Clover loads them in alphabetical order, so prefix with numbers if load order matters—for example, 0-SSDT-EC.aml, 1-SSDT-ETH.aml. The order matters only when two SSDTs modify the same scope; in practice, separate scopes do not conflict. Keep a plain-text copy of each source file alongside the compiled AML in a dedicated folder on your backup drive. If you ever need to rebuild the EFI from scratch, you will thank yourself.
One final note: SSDTs that inject built-in properties for Ethernet are also relevant when you want to use a Fusion Drive setup, because a properly recognised built-in network interface is required for the macOS recovery partition to download the OS. The procedure for combining drives is described in How to Create a Fusion Drive on a Hackintosh (Sierra, High Sierra, Mojave). Always test without the Fusion Drive first—get your SSDTs stable on a single disk before adding that complexity.
