关于黑苹果的 USB 映射

Hacks Apr 19, 2020

随便写写经验,毕竟授人以鱼不如授人以渔。这玩意还挺复杂的,淘宝店都搞不定。

说到淘宝店也是气。这台电脑的 USB 2.0 一直搞不定,本着刺激经济节约时间的原则找了淘宝店解决。结果不仅没解决还嘲讽我「USB 总线,懂不懂?」

素质真的差,👴写 Verilog 串口的时候你都不知道在哪……当我大学白读的咯

会搞一台黑苹果的原因很简单,Mac mini 2018 实在是不太行。磁盘满了没有升级空间(这个能忍)。最重大的问题还是显卡。祖传 UHD 630 性能实在是太烂了,launchpad 都卡。eGPU 我也有,华硕的 RX580 Gaming Box。但是噪音实在是太大,休眠后不会自动关闭风扇,而那个 PSU 的风扇声音实在是过于尖锐,晚上吵得真的难受。

再加上各种 bug,比如接着 eGPU 开机会白屏/绿屏以及 Boot Camp 糟糕的支持。苹果花了整整半年才让 Boot Camp Assistant 支持 4GB 以上的 install.wim。eGPU 在 Windows 下也很玄学,必须在 boot 阶段一个特定的时间插入才能正确识别。

所以组了台黑果。如果白果根本不能让我省心那我为啥要忍呢……

我选择的是华擎 B450M Pro 4 主板,CPU 用的是 3600(硬盘是从 homelab 里拆出来的 SN500,内存显卡是 Kijiji 收的二手)。大家不要学我,这算是超级 budget build 了。我当时也是纯粹为了娱乐,看看在满足需求的情况下到底预算能被压到多低。

这块主板使用 macOS 自带的 iMacPro1,1 映射会导致所有的 USB 2.0 端口(包括 internal header)不能识别。虽然我真的不在乎,但是由于蓝牙是接在 USB 2.0 header 下的,这基本就导致所有 continuity 功能废掉。

小结:如果 USB 有端口不能用,需要自己做 USB 映射。一个常见的原因是 macOS 不允许一个 USB 控制器下有超过 15 个 ACPI Port (以下用端口代指)

DSDT 是一台电脑的硬件描述。我这台电脑的 DSDT 比较神奇,里面并没有列出所有的 USB 端口。DSDT 可以通过 MaciASL 软件看到,打开后会默认加载当前的 DSDT。搜索 XHC (USB 3.0)或者 EHC (USB 2.0) 可以看到 USB 控制器和端口。

Screen-Shot-2020-04-19-at-3.24.23-AM

一台电脑虽然看起来 USB 端口不多,但是一个物理的 USB 3.0 端口是分别算作一个 2.0 和 3.0 设备的,所以这个 15 设备每控制器的限制还是很容易超过的。(这也是为啥 USB 3.0 设备慢慢插入会变成 2.0 设备的理由,USB 3.0 前 4 pin 接的是控制器的 2.0)。

大部分情况下,可能是一个控制器下有超过 15 个端口。这种情况很好搞,用 IORegistryExplorer 看看具体有哪些端口需要被使用。找一个 USB 3.0 Hub,挨个端口插进去试试,分别记录下 USB 2.0 和 3.0 的端口路径。以后做映射的时候需要用到。

也有可能是控制器的名字冲突了(比如 XHC1 就会冲突,在我印象里)。这种情况比较简单,重命名就好了,Mapping 也很好写,基本一致,只是改个控制器名字。

我这种情况就比较难受,因为主板自带的 DSDT 有点问题。解决方式是保存一个 dump,删除 USB 控制器下的所有描述并且用 OpenCore 加载这个 DSDT。这样一来 macOS 就会重建 DSDT。

同样的,在 IOReg 配合 USB3.0 Hub 看看具体需要哪些端口,记录下端口路径和类型。类型有如下几种:

0: USB 2.0 Type-A connector
3: USB 3.0 Type-A connector
8: Type C connector - USB 2.0-only
9: Type C connector - USB 2.0 and USB 3.0 with Switch, flipping the device **doesn't** change the ACPI port
10: Type C connector - USB 2.0 and USB 3.0 without Switch, flipping the device **does** change the ACPI port
255: Proprietary connector - For Internal USB ports like Bluetooth

Screen-Shot-2020-04-19-at-4.10.01-AM
用 USB Hub 的原因是它同时是一个 USB 2.0 和 3.0 设备,比如这里我们就很容易判断 PRT4 是 2.0 端口,PRT8 是 3.0 端口。

注意 Type-C 分 switch 和 non-switch,区别是 switch 在翻转设备后还是同一个 ACPI Port,non-switch 则不是。

接下来就可以开始写自己的 kext 了。放上我自己的,大家照葫芦画瓢即可。

需要注意的是这里的 IONameMatch 键值是控制器的名字(可以自定义),port-count 是每个控制器下最大的端口路径。别的都挺顾名思义的。

$ cat USBMap.kext/Contents/Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>English</string>
	<key>CFBundleGetInfoString</key>
	<string>ASRock B450m Pro 4 USB map</string>
	<key>CFBundleIdentifier</key>
	<string>com.asrock.B450mPro4.USBmap</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>ASRock B450m Pro 4 USB map</string>
	<key>CFBundlePackageType</key>
	<string>KEXT</string>
	<key>CFBundleShortVersionString</key>
	<string>1.2</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>1.2</string>
	<key>IOKitPersonalities_x86_64</key>
	<dict>
		<key>iMacPro1,1-PTXH</key>
		<dict>
			<key>CFBundleIdentifier</key>
			<string>com.apple.driver.AppleUSBHostMergeProperties</string>
			<key>IOClass</key>
			<string>AppleUSBHostMergeProperties</string>
			<key>IONameMatch</key>
			<string>PTXH</string>
			<key>IOProviderClass</key>
			<string>AppleUSBXHCIPCI</string>
			<key>IOProviderMergeProperties</key>
			<dict>
				<key>port-count</key>
				<data>DgAAAA==</data>
				<key>ports</key>
				<dict>
					<key>PRT1</key>
					<dict>
						<key>Comment</key>
						<string>Front USB 2.0 port, middle</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>DAAAAA==</data>
					</dict>
					<key>PRT10</key>
					<dict>
						<key>Comment</key>
						<string>Front USB bottom, 2.0</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>BgAAAA==</data>
					</dict>
					<key>PRT11</key>
					<dict>
						<key>Comment</key>
						<string>Front USB bottom, 3.0</string>
						<key>UsbConnector</key>
						<integer>3</integer>
						<key>port</key>
						<data>BAAAAA==</data>
					</dict>
					<key>PRT2</key>
					<dict>
						<key>Comment</key>
						<string>Front USB 2.0 port, top</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>DQAAAA==</data>
					</dict>
					<key>PRT3</key>
					<dict>
						<key>Comment</key>
						<string>Back USB 2.0 port, Top left</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>CgAAAA==</data>
					</dict>
					<key>PRT4</key>
					<dict>
						<key>Comment</key>
						<string>Back USB 2.0 port, Top right</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>CQAAAA==</data>
					</dict>
					<key>PRT5</key>
					<dict>
						<key>Comment</key>
						<string>Back USB 3.0 Port, second row</string>
						<key>UsbConnector</key>
						<integer>3</integer>
						<key>port</key>
						<data>AgAAAA==</data>
					</dict>
					<key>PRT6</key>
					<dict>
						<key>Comment</key>
						<string>Back USB 2.0 Port, second row</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>CAAAAA==</data>
					</dict>
					<key>PRT7</key>
					<dict>
						<key>Comment</key>
						<string>Back USB Type C 2.0 Port</string>
						<key>UsbConnector</key>
						<integer>9</integer>
						<key>port</key>
						<data>BQAAAA==</data>
					</dict>
					<key>PRT8</key>
					<dict>
						<key>Comment</key>
						<string>Back USB Type C 3.0 Port</string>
						<key>UsbConnector</key>
						<integer>9</integer>
						<key>port</key>
						<data>AQAAAA==</data>
					</dict>
					<key>PRT9</key>
					<dict>
						<key>Comment</key>
						<string>Internal BT Interface, USB2.0</string>
						<key>UsbConnector</key>
						<integer>255</integer>
						<key>port</key>
						<data>DgAAAA==</data>
					</dict>
				</dict>
			</dict>
			<key>model</key>
			<string>iMacPro1,1</string>
		</dict>
		<key>iMacPro1,1-XHC0</key>
		<dict>
			<key>CFBundleIdentifier</key>
			<string>com.apple.driver.AppleUSBHostMergeProperties</string>
			<key>IOClass</key>
			<string>AppleUSBHostMergeProperties</string>
			<key>IONameMatch</key>
			<string>XHC0</string>
			<key>IOProviderClass</key>
			<string>AppleUSBXHCIPCI</string>
			<key>IOProviderMergeProperties</key>
			<dict>
				<key>port-count</key>
				<data>CAAAAA==</data>
				<key>ports</key>
				<dict>
					<key>PRT1</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 2.0 port, fourth row left</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>AQAAAA==</data>
					</dict>
					<key>PRT2</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 2.0 port, fourth row right</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>AgAAAA==</data>
					</dict>
					<key>PRT3</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 2.0 port, third row right</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>AwAAAA==</data>
					</dict>
					<key>PRT4</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 2.0 port, third row left</string>
						<key>UsbConnector</key>
						<integer>0</integer>
						<key>port</key>
						<data>BAAAAA==</data>
					</dict>
					<key>PRT5</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 3.0 port, fourth row left</string>
						<key>UsbConnector</key>
						<integer>3</integer>
						<key>port</key>
						<data>BQAAAA==</data>
					</dict>
					<key>PRT6</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 3.0 port, fourth row right</string>
						<key>UsbConnector</key>
						<integer>3</integer>
						<key>port</key>
						<data>BgAAAA==</data>
					</dict>
					<key>PRT7</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 3.0 port, third row right</string>
						<key>UsbConnector</key>
						<integer>3</integer>
						<key>port</key>
						<data>BwAAAA==</data>
					</dict>
					<key>PRT8</key>
					<dict>
						<key>Comment</key>
						<string>Rear USB 3.0 port, third row left</string>
						<key>UsbConnector</key>
						<integer>3</integer>
						<key>port</key>
						<data>CAAAAA==</data>
					</dict>
				</dict>
			</dict>
			<key>model</key>
			<string>iMacPro1,1</string>
		</dict>
	</dict>
	<key>LSMinimumSystemVersion</key>
	<string>10.15</string>
	<key>OSBundleCompatibleVersion</key>
	<string>1.0</string>
	<key>OSBundleLibraries</key>
	<dict>
		<key>com.apple.driver.AppleUSBHostMergeProperties</key>
		<string>1.2</string>
	</dict>
	<key>OSBundleRequired</key>
	<string>Root</string>
</dict>
</plist>

One more thing

尽量不要组 AMD 黑果,大问题没有,小问题蛮多。比如 vm.hypervisor 框架用不了(导致 Docker、PD、VMware 都不能用)。还有就是随航不能用(需要 iGPU)以及显卡性能贼烂(这个比较致命,和 AMD 的 PCI-e 有点关系)。

建议用 git 管理 efi 分区,托管到 GitHub。太方便了,翻车直接回滚。

Bibliography

https://aplus.rs/2020/usb-mapping-how/
https://github.com/AMD-OSX/AMD_Vanilla
https://github.com/khronokernel/Opencore-Vanilla-Desktop-Guide/blob/master/AMD/AMD-USB-map.md

aLPHAtOAD

太年轻,太简单,有时候幼稚。