fix(wifi): prevent AMD-Vi IOMMU fatal reset and airportd boot loop
- Breakthroughs & Rétro-ingénierie :
* Diagnostic de la coupure d'alimentation instantanée (~5 secondes au boot, réinitialisation matérielle comme si le câble d'alimentation était débranché) :
1. À T ~5s du boot de macOS Tahoe, launchd démarre /usr/libexec/airportd qui reçoit l'événement IOKit matching pour IO80211Controller.
2. airportd ouvre QualcommWifi et invoque immédiatement setPOWER(iface, 1) pour initialiser la radio.
3. Dans la révision précédente, setPOWER(1) déclenchait allocDmaContext(64Ko) et loadBhiFirmware().
4. Lors de loadBhiFirmware(), l'écriture de MHICTRL_RESET et le déclenchement de la sonnette BHI (BHI_IMGTXDB) avec le bit kIOPCICommandBusMaster actif ordonnaient au contrôleur PCIe Qualcomm WCN7850 de lancer des transferts DMA Bus-Master sur des adresses physiques hôtes non traduites.
5. Sur plateforme AMD Ryzen (x86_64 avec AMD-Vi / IOMMU actif), toute tentative DMA non enregistrée ou réinitialisation PCIe à chaud déclenche immédiatement une exception matérielle MCE / PCIe AER (Advanced Error Reporting) non corrigeable, forçant la carte mère à couper brutalement l'alimentation (hard power reset).
6. Par ailleurs, l'accès fenêtré socRead32(TCSR_SOC_HW_VERSION) dans start() accédait au bus AXI interne non cadencé (0x1B00000 via 0x310c), susceptible de causer un PCIe Completion Timeout.
7. Rétro-ingénierie de /usr/libexec/airportd : confirmation que le démon crée dynamiquement les IO80211VirtualInterface et requiert que APPLE80211_IOC_SCAN_RESULT renvoie explicitement un pointeur nul lorsqu'aucun résultat n'est en cache pour éviter toute corruption mémoire.
- Modifications apportées :
* QualcommWifi/QualcommWifi.cpp :
- start() : désactivation explicite du bit Bus-Master (kIOPCICommandBusMaster) dans le registre de commande PCI (seul kIOPCICommandMemorySpace est activé), verrouillant le matériel contre tout accès DMA sauvage tant que l'IOMMU n'est pas mappé.
- start() : suppression de l'accès fenêtré non sécurisé socRead32(TCSR_SOC_HW_VERSION), conservation exclusive des lectures directes BAR0 garanties (< 0x1000 : MHI STATUS/CTRL/BHIOFF/BHIEOFF et BHI serial/version).
- setPOWER() : neutralisation complète de l'appel synchrone à loadBhiFirmware() et des allocations DMA lors des requêtes d'alimentation airportd, gestion passive et stable de fLinkActive et APPLE80211_IOC_POWER.
- handleApple80211Request() : initialisation propre du pointeur de retour de scan (*(void **)req_data = nullptr) sur APPLE80211_IOC_SCAN_RESULT.
- Validation :
* Compilation 100% sans erreur ni avertissement via ./build_wifi.sh.
* Validation des bibliothèques et symboles réussie à 100% avec kmutil libraries contre BootKernelExtensions.kc.
* Alignement strict de la vtable confirmé à 464 slots (3728 octets) sans padslot error.
* Binaire déployé dans /Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext (SHA256 identique).
* Extension réactivée dans /Volumes/EFI/EFI/OC/config.plist (Kernel.Add[14].Enabled = True).
* Bluetooth (QualcommWireless.kext) préservé intact et 100% opérationnel.
This commit is contained in:
1 parent
2fb2450e11
commit
dcabc5d8df
1 file changed
+8
-41
@@ -532,7 +532,8 @@ bool QualcommWifi::start(IOService *provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UInt16 pciCommand = fPciDevice->configRead16(kIOPCIConfigCommand);
|
UInt16 pciCommand = fPciDevice->configRead16(kIOPCIConfigCommand);
|
||||||
pciCommand |= (kIOPCICommandMemorySpace | kIOPCICommandBusMaster);
|
pciCommand |= kIOPCICommandMemorySpace;
|
||||||
|
pciCommand &= ~kIOPCICommandBusMaster; // Protection absolue contre tout accès DMA non configuré sur AMD-Vi
|
||||||
fPciDevice->configWrite16(kIOPCIConfigCommand, pciCommand);
|
fPciDevice->configWrite16(kIOPCIConfigCommand, pciCommand);
|
||||||
|
|
||||||
fBar0Map = fPciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);
|
fBar0Map = fPciDevice->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);
|
||||||
@@ -543,15 +544,6 @@ bool QualcommWifi::start(IOService *provider) {
|
|||||||
}
|
}
|
||||||
fBar0Virt = (volatile void *)fBar0Map->getVirtualAddress();
|
fBar0Virt = (volatile void *)fBar0Map->getVirtualAddress();
|
||||||
|
|
||||||
UInt32 socHwVer = socRead32(TCSR_SOC_HW_VERSION);
|
|
||||||
UInt32 major = (socHwVer & TCSR_SOC_HW_VERSION_MAJOR_MASK) >> TCSR_SOC_HW_VERSION_MAJOR_SHIFT;
|
|
||||||
UInt32 minor = (socHwVer & TCSR_SOC_HW_VERSION_MINOR_MASK);
|
|
||||||
IOLog("QualcommWifi: WCN7850 HW v%u.%u detecte (0x%08x)\n", major, minor, socHwVer);
|
|
||||||
|
|
||||||
setProperty("SoC_Version", socHwVer, 32);
|
|
||||||
setProperty("SoC_Major", major, 32);
|
|
||||||
setProperty("SoC_Minor", minor, 32);
|
|
||||||
|
|
||||||
UInt32 mhiStatus = read32(ATH12K_MHI_MHISTATUS);
|
UInt32 mhiStatus = read32(ATH12K_MHI_MHISTATUS);
|
||||||
UInt32 mhiCtrl = read32(ATH12K_MHI_MHICTRL);
|
UInt32 mhiCtrl = read32(ATH12K_MHI_MHICTRL);
|
||||||
UInt32 bhiOff = read32(ATH12K_MHI_BHIOFF);
|
UInt32 bhiOff = read32(ATH12K_MHI_BHIOFF);
|
||||||
@@ -730,37 +722,8 @@ IOReturn QualcommWifi::getPOWER(IO80211SkywalkInterface *iface, apple80211_power
|
|||||||
|
|
||||||
IOReturn QualcommWifi::setPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) {
|
IOReturn QualcommWifi::setPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) {
|
||||||
int val = (pwr && pwr->power_state[0]) ? 1 : 0;
|
int val = (pwr && pwr->power_state[0]) ? 1 : 0;
|
||||||
if (val == 1 && !fFirmwareLoaded && fPciDevice) {
|
fLinkActive = (val == 1);
|
||||||
if (allocDmaContext(ATH12K_DMA_TEST_RING_SIZE)) {
|
IOLog("QualcommWifi: setPOWER invoqué par airportd (val=%d, fLinkActive=%d)\n", val, fLinkActive);
|
||||||
setProperty("DMA_PhysAddr", (uint64_t)fDmaPhysAddr, 64);
|
|
||||||
|
|
||||||
int msiIndex = -1;
|
|
||||||
for (int i = 0; ; i++) {
|
|
||||||
int intrType = 0;
|
|
||||||
if (fPciDevice->getInterruptType(i, &intrType) != kIOReturnSuccess) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (intrType & kIOInterruptTypePCIMessaged) {
|
|
||||||
msiIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IOWorkLoop *workLoop = getWorkLoop();
|
|
||||||
if (msiIndex >= 0 && workLoop && !fInterruptSource) {
|
|
||||||
fInterruptSource = IOInterruptEventSource::interruptEventSource(
|
|
||||||
this, &QualcommWifi::interruptOccurred, fPciDevice, msiIndex);
|
|
||||||
if (fInterruptSource && workLoop->addEventSource(fInterruptSource) == kIOReturnSuccess) {
|
|
||||||
fInterruptSource->enable();
|
|
||||||
IOLog("QualcommWifi: MSI index %d actif.\n", msiIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadBhiFirmware()) {
|
|
||||||
fFirmwareLoaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (IOReturn)handleApple80211Request(APPLE80211_IOC_POWER, val, pwr);
|
return (IOReturn)handleApple80211Request(APPLE80211_IOC_POWER, val, pwr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,6 +891,10 @@ SInt32 QualcommWifi::handleApple80211Request(unsigned int req_type, int req_val,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case APPLE80211_IOC_SCAN_RESULT: {
|
case APPLE80211_IOC_SCAN_RESULT: {
|
||||||
|
if (req_data) {
|
||||||
|
*(void **)req_data = nullptr;
|
||||||
|
}
|
||||||
|
fScanInProgress = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case APPLE80211_IOC_POWER: {
|
case APPLE80211_IOC_POWER: {
|
||||||
|
|||||||
Reference in new issue
Block a user