【中文教程】ROG笔记本黑苹果

自从在远景论坛发了一个帖子之后,好多人找到我,询问一些关于这次黑苹果细节。

痛点

我们都知道,这款ROG笔记本是代表了华硕最高端性能的系列笔记本产品,在黑苹果圈的人看来,最难搞定的几个痛点在于:

  • 原厂阉割掉的核显
  • Intel厂的WiFi模块
  • ROG Macro Key编程键

核显

苹果电脑自2008年前后转投Intel阵营以后,便尽可能多地采用处理器+显卡都用I家产品的模式配置Macintosh。对于高端定位,NVIDIA和ATI两家的显卡都用过,但是现在已经多年使用AMD(原ATI)系列显卡,并看不出未来会有改变的迹象。

尽管如此,老黄仍然为自己家的N卡适配了Mac系统的驱动程序。我已经好多年没有碰过白果了,只能猜测这大概是为了老MacPro用户自己安装N卡,以及为其他Mac用户安装外接显卡而适配的吧。
下面我要讲两个news。

  • The good news is that,老黄家自己开发的驱动可以为黑苹果用户顺利驱动他家的显卡。
  • The bad news is that,因为大多数笔记本都是双显卡设计,而笔记本上面的黑苹果又无法在驱动核显的情况下驱动独显,于是圈内99%的人都必须屏蔽核显,所以网上的黑苹果教程99.999%都是关于先屏蔽独显再驱动核显的。

而ROG作为高端系列产品,出厂时就已经原生屏蔽了核显,BIOS里也找不到他的身影。我们要对他实施黑苹果的“手术”,就不得不驱动独显。

WiFi

我不是很清楚每一款ROG笔记本的配置,但是我这个系列(G751)的本子里,配的都是Intel 7260无线模块,自带WiFi和蓝牙。在MacOS下面,只能驱动蓝牙,而不能享受airport带来的遍历,走到哪里都得插网线。

看到这里,有人可能会说,那我去换一个兼容的不就行了吗?呵呵,想法是美好的,现实是残酷的。后面我会说到为什么ROG不能直接像其他笔记本一样换无线网卡。

Macro Key

快捷键设计的初衷,一定是很美好的,希望能替代人的一些繁琐的动作,一键实现复杂的功能,从而节省时间。可是,在MacOS里,ROG按键却成了阻碍系统启动的时间杀手。

这是因为,苹果系统里并没有,也根本不可能为他而做出驱动。这又是一个单独的USB模块,并不是和键盘在一起的,所以在开机自检时,系统会在这儿卡很久,从十几秒到一两分钟不等,so annoying.

下面,我来带大家一起,推翻这三座大山,顺利黑上苹果。


思路

简单地画了画,大致就是这么回事,其实跟装Windows的过程相差并不是太大。

安装系统

系统安装与Windows简直一模一样,都是烧录到存储设备,然后从硬盘引导安装。

但是在这里,之所以我把“准备独立SSD”单列出来,是因为,ROG笔记本的可扩展性非常丰富,对于初学者来说,没有必要冒着数据丢失的风险,在已有的磁盘里分区。苹果的生态是封闭的,非专业人士不要随意把Windows下的经验带过来,引起不必要的麻烦。ROG笔记本一般自带至少两个硬盘接口,另外还有光驱,建议把光驱卸掉,安装一块SSD上去,不仅扩大了容量,而且大大减小了本本重量,详细拆装教程看这里

Clover是一款黑苹果引导工具,因为它具有开源,免费,不破坏系统,扩展性强,迭代频次高等优点,早已取代了奇美拉,成为圈内爱好者的不二选择。强烈建议初学者首先阅读Clover的英文原版说明书以及中文wiki翻译。读个大概以后,你应该就知道哪些是必选项,哪些是可选项。第一次安装,把必选项选中或屏蔽,再放入FakeSMC.kext必备的)等驱动到Clover的others里。

制作安装程序,必须要用到苹果系统,你可以像我一样使用虚拟机,也可以选择下载别人制作好的,无论你做出哪种决定,绝对没有人为你承担责任的,请提前做好备份! 自从OSX 10.9 Mavericks起往后,苹果系统都是完全免费的,推荐注册一个苹果账号,从商店下载。

进入安装程序,即可选择语言,先选择磁盘工具对目标硬盘进行全盘格式化,再进行安装。安装过程中可能会重启一两次,这是正常的。

基础驱动

独显

苹果每一次升级,对应的NVIDIA驱动都必须改变,除非你知道该如何去破解。而对于MacOS来说,不仅版本号10.13.3->10.13.4才叫升级,有时发布的一些安全更新也会引起黄先生的不适。

因此,最稳妥的办法,是进入系统以后,点开左上角里的系统信息,点击一次版本字样,后面会出现开发版本号,然后对照着这个网页,去下载对应的显卡驱动,进行安装。

安装完成之后,先不要重启。

  • 检查CLOVER的配置文件,其参数中,不能出现nv_disable=1,且必须要有nvda_drv=1。否则驱动无效。
  • 下载LiluNvidiaGraphicsFixup两个KEXT,放到others中。否则重启会黑屏。

Lilu是一款可用于底层进行系统修改的扩展内核,它不会破坏原生系统,你可以把NvidiaGraphicsFixup理解成是它的一款“插件”,想要使后者工作,则离不开前者。想了解更多,可以去Lilu的Repo阅读说明,这里也有一个翻译的不错的中文说明

声卡

声卡的驱动有很多种方式。

  1. 手动
    这是最激进的,有朋友亲自去Linux下提取dump,然后拆解node节点,制作关联图,最后驱动。我不反对你这样做,并且我对这样做的玩家是非常佩服的,请受在下深深一拜。

  2. 改动系统
    曾经帮助无数人包括我驱动成功的,是toleda针对Realtek系列声卡制作的audio_RealtekALC补丁。这个补丁要求一个原版的HDA,然后对其备份之后,再修改和驱动。

  3. 无损注入
    时下最流行的,包括我自己也在用的,是vit9696制作的AppleALC补丁。该补丁的优点包括:

声卡的睡眠唤醒后无声问题,我的解决方案是彻底禁用睡眠。因为睡眠除了占用硬盘大量空间之外,并没有显而易见的好处。如果你坚持要睡眠,又想解决声卡问题,可以看看这个repo

网卡

好吧,终于要说到这个问题了。

有线网卡

很简单,看这里就行。如果你不愿意看英文,直接在这里下载放进CLOVER即可。

无线网卡

一般来讲,不兼容的笔记本,只需要把原装网卡换成BCM94352系列无线网卡及其衍生品就行了。例如我的G751,是NGFF接口的Intel 7260无线模块,想换成DW1830,淘宝上一搜一大堆。

但问题在于,买回来装上去,却压根儿找不到模块,哪怕在Windows下面也是如此。为此,我还一度错怪了一位闲鱼买家,直到看到一位玩家po出的“血泪史”。问题产生的原因,由于我们不是厂家,所以不得而知。但解决思路很清晰——那根螺丝不要拧紧!确切的说,拧不要超过两圈就行了,再拧就一定会找不到模块。但是这样一来,模块就是半悬着的,非常不安全。我的解决方案是,找一张不超过25平方厘米的薄纸片,对折5-8次,再垫到模块下面。自己去试就行了,具体细节每个人肯定都不一样。

一旦系统能识别就好办了。一开始我并不知道上面的原因,把1830给退了,又买了1560,所以我的就是1560驱动,教程在这里。1830一直挺缺货,但是驱动更简单,论坛和博客里都有很多,在此就不赘述了。

键盘和触摸板

非常感谢EMlyDinEsH为我们华硕笔记本开发的一系列驱动。Very nice!

截止写这篇文章的时候,最新版仍然是SmartTouchpad v4.7 beta 5,作者去年年底因为家里有事,所以至今仍然停更。但是这款驱动并没有太大的问题,驱动很好,可定制性也很强。具体参数,大家可以右键进入kext包,打开content里的info.plist进行修改,会几个单词基本上就知道是什么意思。

配合后期的高级驱动完成之后,最终效果如下图。

高级驱动

基础驱动完成之后,不客气地说,这台本本拿出去,一般人是发现不了它有什么奇怪的地方的。

USB

USB设备本不是问题,因为ROG的功能多了,所以便有了问题。ROG Macro Key是一个USB连接到主板的独立于键盘之外的外接设备,每次启动进入MacOS,都会因此而占用大量的时间。唯一的解决办法是彻底禁用这个USB端口,使得系统在自检扫描时,可以快速地自动跳过去。

这就要用到Rehabman为黑苹果玩家开发的补丁,具体用法如下:

  1. 首先在CLOVER中注入KextsToPatch补丁。
  2. 然后在CLOVER目录里放入相应的FakePCIID文件进行debug。
  3. 再重启系统,打开ioreg,对自己本本上的每一个接口进行热插拔测试,记录端口位置和速率(2.0或3.0),3.0端口需要同时测试2.0设备和3.0设备。
  4. 最后安装repo里给出的模板,制作自己的ACPI文件(记得注释掉ROG Macro Key的端口),编译出来,放入CLOVER目录。
  5. 最后,禁用KextsToPatch补丁(除非你的实际端口数量超过了限制),移除FakePCIID相关文件,但是要保留USBInjectAll.kext,重启即可正常使用。

电量显示

Rehabman其实还为我们ROG玩家制作了专门的电量DSDT补丁,理论上讲,只需要载入打好补丁的DSDT,系统就能正确识别电量了。

如果出现问题,一般来说都是一些数据量拆分不对。

关于这方面的问题,强烈推荐阅读我朋友写的佳作:

显示屏内建

可能你会感到奇怪,屏幕内建有什么干系,反正显卡都已经驱动了呀!其实不是这样的。老黄家的显卡只是让显卡被MacOS识别,但屏幕如果不被识别,后面的功能是实现不了的。要想内建屏幕,只需要修改相应的SSDT(通常ROG笔记本的显卡ACPI都在SSDT里),添加一些代码即可。

在此,我不想让事情变得复杂,所以提前说一下用hotpatch实现的简单方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
DefinitionBlock ("", "SSDT", 2, "HACK", "NVDA", 0)
{
External (_SB.PCI0.PEG0, DeviceObj)
External (_SB.PCI0.PEG0.GFX0, DeviceObj)

Scope (\_SB.PCI0.PEG0.GFX0)
{
Method (_DSM, 4, NotSerialized)
{
If (LEqual (Arg2, Zero))
{
Return (Buffer() { 0x03 } )
}

Return (Package()
{
"@0,AAPL,boot-display", Buffer() { 0x01 },
"@0,backlight-control", Buffer() { 0x01, 0x00, 0x00, 0x00 },
"@0,built-in", Buffer() { 0x01 },
"@0,connector-type", Buffer() { 0x00, 0x04, 0x00, 0x00 }, // internal: eDP 00 04 00 00
"@1,connector-type", Buffer() { 0x00, 0x04, 0x00, 0x00 },
"@2,connector-type", Buffer() { 0x00, 0x04, 0x00, 0x00 }, // external: HDMI 00 08 00 00
"@3,connector-type", Buffer() { 0x00, 0x04, 0x00, 0x00 },
"@4,connector-type", Buffer() { 0x00, 0x04, 0x00, 0x00 },
"@5,connector-type", Buffer() { 0x00, 0x04, 0x00, 0x00 },
"@0,pwm-info", Buffer () { 0x01, 0x14, 0x00, 0x64, 0xA8, 0x61, 0x00, 0x00, 0x1E, 0x02, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 },
"hda-gfx", Buffer() { "onboard-2" }
})
}
}

Scope (\_SB.PCI0.PEG0)
{
Device (HDAU)
{
Name (_ADR, One)
Method (_DSM, 4, NotSerialized)
{
If (LEqual (Arg2, Zero))
{
Return (Buffer() { 0x03 } )
}

Return (Package()
{
"layout-id", Buffer () { 0x01, 0x00, 0x00, 0x00 },
"hda-gfx", Buffer() { "onboard-2" }
})
}
}
}
}

将上面的代码,保存为SSDT-NVDA.dsl文件,编译后放入CLOVER,重启即可看到下图。

没有AirPlay?对呀,因为这是苹果使用Intel的QuickSync技术实现的。

亮度调节

亮度调节,俗称“小太阳”,是黑苹果玩家最喜爱的功能之一,也是不少人比较纠结的一项挑战,因为实现它只需要两个ACPI文件,几十行代码,却往往很难实现。

其实读到这里,如果上面的一些外链都阅读过,那么你应该已经成功驱动起亮度调节这项终极功能了(再次感谢EMlyDinEsH)。具体方法如下:

  1. 确保前文所述的功能你都已经正确驱动。
  2. SmartTouchpad驱动替换成ApplePS2SmartTouchPad.kextAsusNBFnKeys.kext这两个文件,可以保留你自己的配置,重新设定info.plist即可。
  3. 编译并加载亮度调节ACPI驱动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    DefinitionBlock ("", "SSDT", 2, "HACK", "PNLF ", 0)
    {
    External (_SB.LBTN, FieldUnitObj)
    External (_SB.PCI0, DeviceObj)
    External (_SB.PCI0.PEG0, DeviceObj)
    External (_SB.PCI0.PEG0.GFX0, DeviceObj)
    External (_SB.PCI0.PEG0.GFX0.LCDD, DeviceObj)
    External (_SB.PCI0.PEG0.GFX0._DOS, MethodObj)
    External (_SB.PCI0.PEG0.GFX0.LCDD._BCL, MethodObj)
    External (_SB.PCI0.PEG0.GFX0.LCDD._BQC, MethodObj)
    External (_SB.PCI0.PEG0.GFX0.GCBL, MethodObj)
    External (_SB.PCI0.GFX0.BCMD, IntObj)
    External (_SB.PCI0.LPCB.EC0.STBR, MethodObj)

    Scope (\_SB)
    {
    Device (PNLF)
    {
    Name (_ADR, Zero)
    Name (_HID, EisaId ("APP0002"))
    Name (_CID, "backlight")
    Name (_UID, 0x0E)
    Name (_STA, 0x0B)
    Method (_BCL, 0, NotSerialized)
    {
    Return (^^PCI0.PEG0.GFX0.LCDD._BCL ())
    }
    Method (_BCM, 1, NotSerialized)
    {
    Store (One, ^^PCI0.GFX0.BCMD)
    Store (^^PCI0.PEG0.GFX0.GCBL (Arg0), Local0)
    Subtract (0x0A, Local0, LBTN)
    ^^PCI0.LPCB.EC0.STBR ()
    }
    Method (_BQC, 0, NotSerialized)
    {
    Return (^^PCI0.PEG0.GFX0.LCDD._BQC ())
    }
    Method (_DOS, 1, NotSerialized)
    {
    ^^PCI0.PEG0.GFX0._DOS (Arg0)
    }
    }
    }
    }
  4. 编译并加载相应按键的ACPI驱动(通常是F5和F6),以及注释内的CLOVER patch。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    // Keyboard configuration
    // Only necessary if using ApplePS2SmartTouchpad + AsusNBFnKeys
    // change _Q0E to XQ0E 5F 51 30 45 58 51 30 45
    // change _Q0F to XQ0F 5F 51 30 46 58 51 30 46

    DefinitionBlock("", "SSDT", 2, "HACK", "PS2K", 0)
    {
    External (_SB.ATKD, DeviceObj)
    External (_SB.KBLV, FieldUnitObj)
    External (_SB.ATKD.PWKB, BuffObj)
    External (_SB.ATKD.IANE, MethodObj)
    External (_SB.PCI0.LPCB.EC0, DeviceObj)
    External (_SB.PCI0.LPCB.EC0.ATKP, IntObj)
    External (_SB.PCI0.LPCB.EC0.XQ0E, MethodObj)
    External (_SB.PCI0.LPCB.EC0.XQ0F, MethodObj)
    External (_SB.PCI0.LPCB.EC0.WRAM, MethodObj)

    Scope(_SB.PCI0.LPCB.EC0)
    {
    Method (_Q0E)
    {
    If (ATKP)
    {
    \_SB.ATKD.IANE (0x20) // For brightness
    }
    XQ0E() // Call the previous method
    }

    Method (_Q0F)
    {
    If (ATKP)
    {
    \_SB.ATKD.IANE (0x10) // For brightness
    }
    XQ0F() // Call the previous method
    }
    }

    Scope (_SB.ATKD) // To change keyboard backlight this needs to be injected
    {
    Name (BOFF, Zero)
    Method (SKBL, 1, NotSerialized)
    {
    If (Or (LEqual (Arg0, 0xED), LEqual (Arg0, 0xFD)))
    {
    If (And (LEqual (Arg0, 0xED), LEqual (BOFF, 0xEA)))
    {
    Store (Zero, Local0)
    Store (Arg0, BOFF)
    }
    Else
    {
    If (And (LEqual (Arg0, 0xFD), LEqual (BOFF, 0xFA)))
    {
    Store (Zero, Local0)
    Store (Arg0, BOFF)
    }
    Else
    {
    Return (BOFF)
    }
    }
    }
    Else
    {
    If (Or (LEqual (Arg0, 0xEA), LEqual (Arg0, 0xFA)))
    {
    Store (KBLV, Local0)
    Store (Arg0, BOFF)
    }
    Else
    {
    Store (Arg0, Local0)
    Store (Arg0, KBLV)
    }
    }
    Store (DerefOf (Index (PWKB, Local0)), Local1)
    ^^PCI0.LPCB.EC0.WRAM (0x04B1, Local1)
    Return (Local0)
    }

    Method (GKBL, 1, NotSerialized)
    {
    If (LEqual (Arg0, 0xFF))
    {
    Return (BOFF)
    }
    Return (KBLV)
    }
    }
    }
  5. 备份系统原驱动:AppleBacklight.kext

  6. 下载该驱动(密码: 4you),用Kext Utility安装到SLE。
  7. 重启即可

hotpatch

原理

这是近两年在圈内迅速火起来的一项新玩法。它的原理在于,完全不改动原生的DSDT,通过人工手写的SSDT辅之以CLOVER的十六进制补丁进行“热修改”,从而迅速达到目的。你可以把它想象成“微创手术”,只针对“靶细胞”动作,幅度小,速度快,效果优。

前面或多或少也用到了hotpatch技术,例如“显示器内建”和“亮度调节”,是不是感觉很爽呢?它不要求你看太多繁琐的代码,不需要你做无数个备份、到最后自己都记不住。它就像一台兼容机一样灵活,哪怕以后升级更细换代,也可以把有效的部分文件直接copy给新电脑驱动。

教程

关于hotpatch的教程有很多,特别是国内,各种个人博客和一些论坛里都有花样翻译,我都看过,内容大同小异,甚至有的直接拿Google机翻,实在是有失水准。

强烈推荐hotpatch的祖师级教程:[Guide] Using Clover to “hotpatch” ACPI

如果你执意要拒绝英文,那也可以。不过据我的阅读体验,这些中文教程的精确程度很难说,而且绝大多数都是翻译自上面的雄文,在此我不妨推荐几篇,仅供参考

需要指出的是,无论你阅读的是中文教程,还是英文教程,都请仔细阅读后再做决定。因为哪怕Rehabman所写的原版教程,里面一些内容是我们的ROG笔记本所用不到的,例如Rename GFX0 to IGPU。哪怕是Rehabman,他也不是神,天下没有两片完全一样的树叶,相信自己的判断,尊重事实。

示范

文件规范

一个hotpatch的SSDT源文件,通常起名为SSDT-xxxx.dsl。xxxx通常是四个英文字母,用来表示它的作用。文件格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
DefinitionBlock("", "SSDT", 2, "HACK", "xxxx", 0)
{
// 双斜杠开头的行内内容都是注释,可以随便写,方便自己记录,不会被编译
// 通常这里会注释所需要在CLOVER中用到的hex patch内容

// 这里是对文件内要用到的变量进行声明,一般都是引用自外部其他文件内容
// 大部分MaciASL的报错,都可通过声明来解决
External (abcd, DeviceObj)
External (efgh, MethodObj)

// 这里是可以用Device的,只不过这样一来,就会覆盖掉源函数内容
// 使用Scope+External声明的形式,可以保留原函数,并进行修改
Scope (abcd)
{
...
// 这里直接写了一个“方法”,如果原函数有同名方法,将被直接覆盖
Method (efgh, ...)
{
// 函数内容很简单,花一个小时看看C语言慕课就会了
...
}
}
}

制作流程

拿比较复杂的电量来举例,进行hotpatch,思路如下:

  1. 准备好DSDT源文件,拷贝为1.dsl
  2. 打补丁,验证有效,拷贝为2.dsl
  3. 比较两个文件的不同之处,通常都是_SB.PCI0.LPCB.EC0_SB.PCI0.BAT0这两个设备函数里的内容起了变化和作用
  4. 提取DSDT内所有与这两个函数有关的内容,整理,合并
  5. 制作SSDT-BATT.dsl
  6. 重启,验证有效性,否则继续修改

模板集合

这里有基本上所有人都用得到的hotpatch成品样式,相同硬件的可以直接使用,不同的只需稍加改动。

一点参考

下面给出一张表,罗列我所用到的hotpatch文件。

文件名 功能
SSDT-BATT 电池电量
SSDT-GPRW USB设备唤醒相关
SSDT-HDEF 板载声卡
SSDT-NVDA NVIDIA独立显卡,包括显示驱动和HDMI音频驱动
SSDT-PNLF 启动亮度调节的Apple驱动
SSDT-PS2K 启动亮度调节的键盘快捷键
SSDT-UIAC 自定义USB端口
SSDT-UPRW USB设备唤醒相关
SSDT-XOSI 伪装成win系统被主板识别

结尾

给ROG笔记本进行黑苹果的课程,到这里全部结束了。黑苹果之所以令人激动,不仅是因为它华丽的系统界面,高端大气上档次的名称,更是因为这个过程中,我们可以锻炼信息搜索,数据整理,简单编程等能力,实在是体力和脑力的双重盛宴。

最后,祝大家都能早日黑进苹果,败家境界更上一层楼^_^

0%