** Patch Theory **
Fixing WiFi and Ethernet in macOS 13.3 with AppleVTD
Purpose:
As requested by some, this post explains how the patch was found and what the patch does.
Discovery:
Sometimes it is helpful to participate in the Apple public beta program. When the first 13.3 public beta was released we found some issues related to CPU topology that affected (a) Intel processors with P-cores and E-cores, and (b) all AMD processors. But WiFi and Ethernet worked properly.
In the last two 13.3 public betas, however, WiFi and Ethernet were adversely impacted. The problem was limited to kexts (not to dexts) when AppleVTD was enabled and the system had more than 16GB memory.
Discovery Stage 1:
Not knowing where the problem lay, it was first necessary to isolate the root cause. The first question was,
is the problem in one of the kernel extensions or is it deeper within the kernel itself or some other part of the OS? To answer this, the following was done:
- Late beta of 13.3 was installed on a spare SSD
- All files in
/System/Library/Extensions
were replaced by those from an early 13.3 beta build
- A Frankenstein hybrid was thereby created and it booted and worked perfectly
Discovery Stage 2:
The next question was,
which kext or kexts is the culprit? There are hundreds of kexts, but only a handful are responsible for WiFi and Ethernet. The steps of
Discovery Stage 1 were repeated, but instead of replacing all kexts, one or two were replaced at a time:
- Replaced IONetworkingFamily.kext
- Result: No good -- WiFi and Ethernet still down
Then:
- Replaced IO80211FamilyLegacy.kext that governs Broadcom WiFi
- Result: No good -- WiFi still down
Then:
- Replaced all 5 Broadcom firmware kexts
- Result: No good -- WiFi still down
Then:
- Realizing that WiFi and Ethernet are down, there must be a common higher-level kext that affects them both. Because the problem occurs only when AppleVTD is enabled, and because AppleVTD is managed by IOPCIFamily, the next step was:
- Replace IOPCIFamily.kext
- Result: Everything works!
Discovery Stage 3:
Now it was a matter of comparing
IOPCIFamily between early and late builds of 13.3. This effort was greatly facilitated by the
Ghidra disassembler, which has an option to generate C-like pseudo code from a compiled x86 binary.
Comparing the disassembled code revealed two new functions:
addMemoryRange and
reserveRanges. The latter was examined first. It turns out that
reserveRanges is the result of some minor refactoring of existing code, but it contains a little bit of new code as well. The first inclination was to patch-out the
new code from this function, which is shown in the dotted box:
This did not work: The first patch failed and was discarded. Attention turned to the other new function
addMemoryRange. To determine where this function is called from, it was simply a matter of searching the pseudo-code file in
BBEdit:
We can see that
addMemoryRange is newly added in late 13.3. Interesting. So what would happen if we magically
erased this call? That was done by finding the relevant section in
Hopper disassembler and replacing it with a series of No-Operations:
After applying this patch and rebooting,
success.