SSDT简要解析,以华硕Z490为例
前言
目前第六代酷睿之后的平台,安装黑苹果是非常容易的,但小众配置和笔记本机型也有一些不容易解决的问题,这类问题一般无法用引导工具或 Kext 文件解决,此时就是 SSDT 发光发热证明自己的时候了。虽然 SSDT 也不是任何问题都能够解决,但在特定条件下使用 SSDT 比 Kext 要更加灵活易用。本文接下来主要以定制华硕 Z490 SSDT 文件来进行简要的思路和方法解析。
「注意」SSDT 编写需要编程基础和 ACPI 知识,本文只做解析,不做新手式教学。
ACPI、DSDT 和 SSDT
- ACPI:Advanced Configuration and Power Management Interface,一般翻译成高级配置与电源管理接口,由英特尔、惠普、微软、Phoenix 和东芝制订提出,其中最为广泛认可的就是电源管理标准。ACPI 中包含了 DSDT 和 SSDT 信息,每套个人电脑理论上都具有不同的 ACPI,有时候即使是同一厂家的同一产品,也会因为 BIOS 版本、内存大小、设置差异等,造成 ACPI 的不同,因此 ACPI 文件需要自行提取。苹果公司的 Mac 产品并不完全支持 ACPI 规范,但其中 DSDT 功能是完整支持的,对于黑苹果来说,ACPI 里会有涉及硬件兼容和驱动/睿频/休眠/显卡控制等重要功能。ACPI 文件可以在 Windows、Linux 下提取,黑苹果也可以通过 Clover 或 DPCIManager 软件提取。
- DSDT:Secondary System Description Table,字面翻译是“差异系统描述表”,是 ACPI 规范的一部分。其包含了所有除基本系统以外所有不同设备的信息,也就是每台计算机设备的基本系统是相同的,而不相同的设备用 DSDT 来描述。
- 初始设备制造厂家(OEM)必须提供一个 DSDT 给 ACPI 以兼容操作系统。DSDT 包含差异定义块(DefinitionBlock),它提供关于基本系统(Base System)的执行和配置信息。操作系统总是在系统启动时将 DSDT 信息插入到 ACPI 命名空间(NameSpace)并且不移除。
- 基本上,可以把 DSDT 归结为来描述你的系统配置的。它包括所有 ACPI 支持的设备的定义并描述它们的兼容性。例如,它描述电池、交流适配器、嵌入式控制器、风扇、发热区。它以分级形式呈现这些信息,所以 ACPI(和兼容操作系统)能够了解系统硬件之间的依存关系。DSDT 在启动时加载。基本上,它告诉 ACPI 驱动要注意些什么。
- 简单说 DSDT 就是包含了所有和基本系统(Base System)不同的设备的信息,Base System 每台机器都是一样的,这个是在 ACPI 规范里指定的,但是每台机器都是不相同的,所以不相同的设备大都是由 DSDT 表来描述。它包含了很多 AML 代码。标准的 DSDT 编译器是英特尔的 iASL,而很多 DSDT 是由微软的编译器编译出来。问题是,微软的 DSDT 编译器对源代码的标准比较宽松(比如说 iASL 的很多 Error 到微软这里就只是 Warning 了),从而导致一个不标准的、充满 BUG 的 DSDT。因此这些 DSDT 可以在 Windows 下正常工作,而到了 macOS、Linux 就不行了。
- SSDT:System Services Descriptor Table,字面翻译是“系统服务描述符表”,是 ACPI 规范的一部分。SSDT 相当于系统内部 API(Application Programming Interface,应用程序接口)的指向标,作用就是告诉系统,需要调用的 API 在什么地方。黑苹果主要通过新增或修改 SSDT 文件进行 ACPI 的打补丁操作。
- SSDT 是 DSDT 的延续。多个 SSDT 可以用来作为平台描述的一部分。在 DSDT 被加载到 ACPI 命名空间后,每个 RSDT/XSDT 列举的 SSDT 和它唯一的 OEM 表识别号被加载。这允许 OEM 在一个表里提供基本支持,同时添加在其他表里添加小的系统选项。
- 注意:附加的表只能添加数据,不能覆盖之前表里的数据。一台电脑可能有多个 SSDT 表。也就是说,DSDT 可能只含有设备(Device)的基本信息,然后将详细信息放在具有唯一识别号的 SSDT 中,这也是为什么我们有时候需要让 Clover/OpenCore 加载 SSDT 实现 CPU 睿频或者让 Thunderbolt 3 接口正常工作。
- .dsl:Disassembled ASL File,ASL 指的是 ACPI Source Language,就是没有编译的 SSDT 源文件后缀名,可以理解为源代码。
- .aml:ACPI Machine Language Binary,这是编译好的 SSDT 文件后缀名,可以直接使用引导工具(Clover/OpenCore)加载使用。
- MaciASL.app 是用于编辑/编译 dsl 和 aml 文件的编辑工具,这个软件仅支持 macOS,Windows 里应该也有编辑 dsl 文件的工具,可是笔者没有在 Windows 下编辑过,所以也不清楚。第六代酷睿以后的黑苹果大部分情况下可以只使用 OpenCore 提供的标准 ssdt 文件,进入系统后根据自己硬件的需要再行编辑就好了。
SSDT 文件解析
定义块(DefinitionBlock)
「注意」以下所有代码仅供参考不可直接编译,下同。
SSDT 所有的内容都包含在定义块中:
DefinitionBlock ("", "SSDT", 2, "Asus", "Z490", 0x00001000)
{
Name ( xxx ) { xxx }
Device ( xxx ) { xxx }
Scope (xxx) { xxx }
Method (xxx) { xxx }
}
解决 OC 引导 Windows 的冲突
由于 OpenCore 采用了全局 API,因此引导其他系统时会将 Windows 不需要的 SSDT 一同加载,为解决这个问题,需要将针对 macOS 的 ssdt 添加一个判断语句,即系统是 macOS 时,SSDT 内容生效,否则无效。
If (_OSI ("Darwin")) {
//判断如果操作系统是macOS,生效此行为
}
如果其中的方法没有返回(Return)时,可能需要 else 部分:
If (_OSI ("Darwin")) {
//判断如果操作系统是macOS,生效此行为
} else {
//如果之后没有 Return,则需要 else 这个部分
}
下面以 GPRW(6D0D)「睡了即醒」补丁为例介绍了 OpenCore 下编写和修改 SSDT 的思路。
//
// In config ACPI, GPRW to XPRW
// Find: 47505257 02
// Replace: 58505257 02
//
// 需要注意的是,ACPI 里不支持非 ASCII 字符注释,这里仅做示例,不可直接用于编译
DefinitionBlock ("", "SSDT", 2, "OCLT", "GPRW", 0)
{
External(XPRW, MethodObj) // 对 XPRW 函数的外部引用
Method (GPRW, 2, NotSerialized)
{
If (_OSI ("Darwin")) // 如果当前的操作系统是 macOS,生效以下行为
{
If ((0x6D == Arg0)) // 如果第一个参数是 0x6D
{
Return (Package () // 返回 06D,0x00 函数结束
{
0x6D,
Zero
})
}
If ((0x0D == Arg0)) // 如果第一个参数是 0x0D
{
Return (Package () // 返回 0x0D,0x00 函数结束
{
0x0D,
Zero
})
}
}
// 否则,直接返回 XPRW 函数。由于这个函数是以 Return 结束,所以 If 后面可以不带 Else。
// 只有三种情况下会走到这一步:第一个参数不是 0x6D;第一个参数不是 0x0D;当前操作系统不是 macOS
// XPRW 是 DSDT 中原始的 GPRW 函数重命名而来,实际上是调用了原始 DSDT 中原始的 GPRW 函数
Return (XPRW (Arg0, Arg1))
}
}
引用外部对象(Objects)
如果不在开始进行引用,会造成错误。
/* 引用其他表中的对象 */
External (_SB_.PCI0, DeviceObj)
External (_SB_.PCI0.HDAS, DeviceObj)
External (_SB_.PCI0.LPCB, DeviceObj)
External (_SB_.PCI0.LPCB.EC0_, DeviceObj)
External (_SB_.PCI0.SBUS.BUS0, DeviceObj)
External (_SB_.PCI0.WMI1, DeviceObj)
External (_SB_.PR00, ProcessorObj)
External (_SB_.WFDE, DeviceObj)
External (_SB_.WFTE, DeviceObj)
External (_SB_.WMTF, DeviceObj)
External (_TZ_.FAN0, DeviceObj)
External (_TZ_.FAN1, DeviceObj)
External (_TZ_.FAN2, DeviceObj)
External (_TZ_.FAN3, DeviceObj)
External (_TZ_.FAN4, DeviceObj)
External (_TZ_.TZ00, PkgObj)
External (ABAW, DeviceObj)
External (ACCE, DeviceObj)
External (AMW0, DeviceObj)
External (ATW0, DeviceObj)
External (AWW0, DeviceObj)
移除 macOS 不需要的设备
移除 macOS 运行不使用的设备,增加稳定性。
Name (_SB.STAS, One)
Name (\_TZ.FAN0._STA, Zero) // _STA: Status
Name (\_TZ.FAN1._STA, Zero) // _STA: Status
Name (\_TZ.FAN2._STA, Zero) // _STA: Status
Name (\_TZ.FAN3._STA, Zero) // _STA: Status
Name (\_TZ.FAN4._STA, Zero) // _STA: Status
Name (_SB.PCI0.WMI1._STA, Zero) // _STA: Status
Name (ABAW._STA, Zero) // _STA: Status
Name (ACCE._STA, Zero) // _STA: Status
Name (AMW0._STA, Zero) // _STA: Status
Name (ATW0._STA, Zero) // _STA: Status
Name (AWW0._STA, Zero) // _STA: Status
Name (_SB.WFDE._STA, Zero) // _STA: Status
Name (_SB.WMTF._STA, Zero) // _STA: Status
Name (_SB.WFTE._STA, Zero) // _STA: Status
HDAS 替换为 HDEF
这个其实可以不做,因为根据 AppleALC 文档说明,它可以自动处理好这个问题。以下内容删除了 HDAS 在原位置添加了 HDEF,并注入了 AppleALC 的 layout-id。
Name (_SB.PCI0.HDAS._STA, Zero) // _STA: Status
Device (_SB.PCI0.HDEF)
{
Name (_ADR, 0x001F0003) // _ADR: Address
Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
{
If ((Arg2 == Zero))
{
Return (Buffer (One)
{
0x03 // .
})
}
Return (Package (0x06)
{
"hda-gfx",
Buffer (0x0A)
{
"onboard-1"
},
"layout-id",
Buffer (0x04)
{
0x07, 0x00, 0x00, 0x00 // ....
},
"PinConfigurations",
Buffer (Zero){}
})
}
}
伪造白果中的设备
以下内容添加了白苹果中存在的设备 DMA Controller。
Device (_SB.PCI0.LPCB.DMAC)
{
Name (_HID, EisaId ("PNP0200") /* PC-class DMA Controller */) // _HID: Hardware ID
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
IO (Decode16,
0x0000, // Range Minimum
0x0000, // Range Maximum
0x01, // Alignment
0x20, // Length
)
IO (Decode16,
0x0081, // Range Minimum
0x0081, // Range Maximum
0x01, // Alignment
0x11, // Length
)
IO (Decode16,
0x0093, // Range Minimum
0x0093, // Range Maximum
0x01, // Alignment
0x0D, // Length
)
IO (Decode16,
0x00C0, // Range Minimum
0x00C0, // Range Maximum
0x01, // Alignment
0x20, // Length
)
DMA (Compatibility, NotBusMaster, Transfer8_16, )
{4}
})
}
以下添加了白果中的设备 Firmware Hub Device。
Device (_SB.PCI0.LPCB.FWHD)
{
Name (_HID, EisaId ("INT0800") /* Intel 82802 Firmware Hub Device */) // _HID: Hardware ID
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadOnly,
0xFF000000, // Address Base
0x01000000, // Address Length
)
})
}
以下添加了白果中的设备 Intel PCH PMC。
Device (_SB.PCI0.LPCB.PMCR)
{
Name (_HID, EisaId ("APP9876")) // _HID: Hardware ID
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadWrite,
0xFE000000, // Address Base
0x00010000, // Address Length
)
})
}
以下添加了白果中的设备 SMBUS。
Device (_SB.PCI0.MCHC)
{
Name (_ADR, Zero) // _ADR: Address
}
Device (_SB.PCI0.SBUS.BUS0)
{
Name (_CID, "smbus") // _CID: Compatible ID
Name (_ADR, Zero) // _ADR: Address
Device (DVL0)
{
Name (_ADR, 0x57) // _ADR: Address
Name (_CID, "diagsvault") // _CID: Compatible ID
Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
{
If ((Arg2 == Zero))
{
Return (Buffer (One)
{
0x57 // W
})
}
Return (Package (0x02)
{
"address",
0x57
})
}
}
}
关闭 EC0 设备
因为让 macOS 直接调用 EC0(Embeded Controller)比较危险,因此关闭原设备。
Name (_SB.PCI0.LPCB.EC0._STA, Zero) // _STA: Status
添加 EC 设备
关闭 EC0 后,添加一个 macOS 能识别和正常调用的 EC(Embeded Controller)设备。
Device (_SB.PCI0.LPCB.EC)
{
Name (_HID, EisaId ("PNP0C09") /* Embedded Controller Device */) // _HID: Hardware ID
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
IO (Decode16,
0x0062, // Range Minimum
0x0062, // Range Maximum
0x00, // Alignment
0x01, // Length
)
IO (Decode16,
0x0066, // Range Minimum
0x0066, // Range Maximum
0x00, // Alignment
0x01, // Length
)
})
Name (_GPE, 0x16) // _GPE: General Purpose Events
}
注入 USB 供电参数
这部分内容在 OpenCore 附带的 ACPI 样本 SSDT-USBX.aml 中有,注入供电参数以让 EC 设备正确工作。
Device (_SB.USBX)
{
Name (_ADR, Zero) // _ADR: Address
Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
{
If ((Arg2 == Zero))
{
Return (Buffer (One)
{
0x03 // .
})
}
Return (Package (0x08)
{
"kUSBSleepPowerSupply",
0x13EC,
"kUSBSleepPortCurrentLimit",
0x0834,
"kUSBWakePowerSupply",
0x13EC,
"kUSBWakePortCurrentLimit",
0x0834
})
}
}
添加 CPU 电源管理
添加 plugin-type 1 以开启 XCPM,使用 macOS 的 CPU 原生电源管理,这个部分在 OpenCore 附带的 ACPI 样本 SSDT-PLUG.aml 中有。
Scope (_SB.PR00)
{
Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
{
If ((Arg2 == Zero))
{
Return (Buffer (One)
{
0x03 // .
})
}
Return (Package (0x02)
{
"plugin-type",
One
})
}
}
如果你的 CPU 电源管理存在问题,可通过添加合并 ssdtPRGen.sh 和 CPUFriend.kext 的数据尝试解决。
尾声
在黑苹果进入 OpenCore 时代后,SSDT 和 DSDT 的编辑修改几乎成了黑果必修课,难的是这个东东门槛实在有点高,对小白非常不友好。好在 OpenCore 团队意识到了这个问题,并提供了大量的 ACPI 样本可供参考甚至直接使用;另外由国内几位大神维护的 OC-little 热补丁库也是宝藏。
如果你愿意深入学习了解运作原理,以下几个链接非常具有参考价值:
- How to fix common ACPI problems:虽然文章写于 2004 年,但文章内容对理解 ACPI 有非常有益;
- ACPI 6.3 Jan 30 2019:目前 MaciASL 编译器支持的稳定通道 ACPI 版本。
1. 本站资源收集于网络,仅做学习和交流使用,请于下载后24小时内删除。如果你喜欢我们推荐的软件,请购买正版支持作者。
2. 如有无法下载的链接,联系:admin#heipg.cn,或到QQ群进行反馈,我们将及时进行处理。
3. 本站发布的内容若侵犯到您的权益,请联系站长删除,联系方式:admin#heipg.cn,我们将第一时间配合处理!
黑苹果星球 » SSDT简要解析,以华硕Z490为例
dsdt的英文描述The Differentiated System Description Table吧?