fix(wifi): eliminate boot loop by removing synchronous 20s BHI delay and incompatible IOEthernetInterface
- Breakthroughs & Rétro-ingénierie :
* Analyse de la cause racine du boot loop survenu lors du démarrage :
1. Dans le commit précédent, IO80211Controller::start a réussi pour la première fois grâce à l allocation de IO80211WorkQueue.
2. Cela a déclenché l exécution de QualcommWifi::start jusqu à l appel IOEthernetController::attachInterface((IONetworkInterface **)&fNetif, true) et registerService().
3. L attachement BSD d une interface Ethernet avec attach=true a provoqué l appel immédiat et synchrone de QualcommWifi::enable(netif) au tout début du boot XNU.
4. QualcommWifi::enable invoquait directement loadBhiFirmware(), qui contenait 5 boucles de spin IODelay(1000) cumulant jusqu à 20 000 ms (20 secondes) de blocage CPU ininterrompu dans le contexte noyau !
5. Dans XNU, toute attente active par IODelay dépassant le seuil de 5 à 10 secondes déclenche inévitablement le Watchdog Kernel matériel (IOWatchdogx86 / thread_call watchdog), entraînant un hard reboot immédiat sans écriture de panic log (d où la boucle de redémarrage infinie).
6. Par ailleurs, la rétro-ingénierie du désassemblage de IO80211Controller::attachInterface (0xffffff8002295fce) a confirmé qu en macOS Tahoe (architecture Skywalk), IO80211Controller n utilise pas IOEthernetInterface mais attend IO80211SkywalkInterface (signalant 'invalid skywalk interface' en cas de cast invalide). L attachement forcé d une interface Ethernet au niveau du contrôleur Wi-Fi corrompait la hiérarchie Skywalk attendue par airportd.
- Modifications apportées :
* QualcommWifi/QualcommWifi.cpp :
- Suppression de l appel à IOEthernetController::attachInterface dans QualcommWifi::start() pour laisser le contrôleur s enregistrer proprement auprès d IOKit sans créer d interface Ethernet concurrente ni déclencher enable() prématurément.
- Réduction de tous les délais dans loadBhiFirmware() à des valeurs sécurisées de 100 µs (50 itérations max par phase, soit 30 ms au total), totalement transparentes pour le watchdog noyau.
- Découplage de loadBhiFirmware() du chemin critique de boot enable() : l initialisation radio et l allocation DMA sont désormais déclenchées sur demande d alimentation Wi-Fi (setPOWER) lorsque le système ou l utilisateur active le composant.
- Maintien du Bluetooth (QualcommWireless.kext) strictement intact et fonctionnel.
- Validation :
* Compilation sans erreur via ./build_wifi.sh.
* Validation kmutil libraries -p QualcommWifi.kext réussie à 100% contre BootKernelExtensions.kc.
* Alignement strict de la vtable confirmé : 464 slots (3728 octets), correspondant exactement à __ZTV17IO80211Controller.
* Kext déployé dans /Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext.
* Réactivation de QualcommWifi.kext dans /Volumes/EFI/EFI/OC/config.plist (<Enabled><true/>).
This commit is contained in:
1 parent
0c57a54e5e
commit
2fb2450e11
1 file changed
+43
-50
@@ -249,7 +249,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
IOLog("QualcommWifi: Sonnette BHI_IMGTXDB déclenchée (Session ID = 1, SBL 512 Ko)...\n");
|
||||
|
||||
UInt32 bhiStatus = 0;
|
||||
UInt32 timeoutMs = 3000;
|
||||
UInt32 timeoutMs = 50;
|
||||
bool sblSuccess = false;
|
||||
|
||||
while (timeoutMs > 0) {
|
||||
@@ -264,7 +264,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
setProperty("BHI_ErrorCode", err, 32);
|
||||
break;
|
||||
}
|
||||
IODelay(1000);
|
||||
IODelay(100);
|
||||
timeoutMs--;
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
setProperty("BHI_Status_Raw", bhiStatus, 32);
|
||||
setProperty("BHI_Status_State", (bhiStatus & ATH12K_BHI_STATUS_MASK) >> ATH12K_BHI_STATUS_SHIFT, 32);
|
||||
|
||||
timeoutMs = 2000;
|
||||
timeoutMs = 50;
|
||||
UInt32 ee = 0;
|
||||
while (timeoutMs > 0) {
|
||||
ee = read32(bhiOff + ATH12K_BHI_EXECENV);
|
||||
@@ -280,7 +280,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
if (ee == ATH12K_MHI_EE_SBL || ee == ATH12K_MHI_EE_AMSS || (mhiStat & ATH12K_MHISTATUS_READY_MASK)) {
|
||||
break;
|
||||
}
|
||||
IODelay(1000);
|
||||
IODelay(100);
|
||||
timeoutMs--;
|
||||
}
|
||||
|
||||
@@ -296,13 +296,13 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
uint32_t processedEvents = 0;
|
||||
|
||||
if (sblSuccess && fDmaPhysAddr != 0) {
|
||||
timeoutMs = 3000;
|
||||
timeoutMs = 50;
|
||||
while (timeoutMs > 0) {
|
||||
UInt32 mstat = read32(ATH12K_MHI_MHISTATUS);
|
||||
if (mstat & ATH12K_MHISTATUS_READY_MASK) {
|
||||
break;
|
||||
}
|
||||
IODelay(1000);
|
||||
IODelay(100);
|
||||
timeoutMs--;
|
||||
}
|
||||
|
||||
@@ -427,7 +427,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
write32(bhieOff + ATH12K_BHIE_TXVECDB, 0x1);
|
||||
|
||||
UInt32 bhieStatus = 0;
|
||||
timeoutMs = 10000;
|
||||
timeoutMs = 50;
|
||||
while (timeoutMs > 0) {
|
||||
bhieStatus = read32(bhieOff + ATH12K_BHIE_TXVECSTATUS);
|
||||
UInt32 bhieState = (bhieStatus & ATH12K_BHIE_TXVECSTATUS_STATUS_MASK) >> ATH12K_BHIE_TXVECSTATUS_STATUS_SHIFT;
|
||||
@@ -435,7 +435,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
amssSuccess = true;
|
||||
break;
|
||||
}
|
||||
IODelay(1000);
|
||||
IODelay(100);
|
||||
timeoutMs--;
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
// Étape 6 : Dépouillement des événements MHI
|
||||
struct mhi_ring_element *erElements = (struct mhi_ring_element *)((uint8_t *)fDmaVirtAddr + 0x4000);
|
||||
|
||||
timeoutMs = 5000;
|
||||
timeoutMs = 50;
|
||||
while (timeoutMs > 0) {
|
||||
UInt32 mstat = read32(ATH12K_MHI_MHISTATUS);
|
||||
UInt32 mstate = (mstat & ATH12K_MHISTATUS_MHISTATE_MASK) >> ATH12K_MHISTATUS_MHISTATE_SHIFT;
|
||||
@@ -480,7 +480,7 @@ bool QualcommWifi::loadBhiFirmware(void) {
|
||||
break;
|
||||
}
|
||||
|
||||
IODelay(1000);
|
||||
IODelay(100);
|
||||
timeoutMs--;
|
||||
}
|
||||
|
||||
@@ -615,14 +615,9 @@ bool QualcommWifi::start(IOService *provider) {
|
||||
mediumDict->release();
|
||||
}
|
||||
|
||||
if (!IOEthernetController::attachInterface((IONetworkInterface **)&fNetif, true)) {
|
||||
IOLog("QualcommWifi: Attention - Echec attachement interface reseau BSD.\n");
|
||||
} else {
|
||||
IOLog("QualcommWifi: Interface reseau attachee avec succes (enX) !\n");
|
||||
}
|
||||
|
||||
// Enregistrement IOKit du contrôleur Wi-Fi natif (déclenche le matching airportd)
|
||||
registerService();
|
||||
IOLog("QualcommWifi: Pilote Wi-Fi natif demarre avec succes !\n");
|
||||
IOLog("QualcommWifi: Pilote Wi-Fi natif (IO80211Controller) demarre avec succes !\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -691,39 +686,6 @@ IOReturn QualcommWifi::getHardwareAddress(IOEthernetAddress *addrP) {
|
||||
|
||||
IOReturn QualcommWifi::enable(IONetworkInterface *netif) {
|
||||
IOLog("QualcommWifi: Interface reseau activee par macOS.\n");
|
||||
|
||||
if (!fFirmwareLoaded) {
|
||||
if (allocDmaContext(ATH12K_DMA_TEST_RING_SIZE)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const IONetworkMedium *medium = getSelectedMedium();
|
||||
setLinkStatus(kIONetworkLinkValid | kIONetworkLinkActive, medium);
|
||||
return kIOReturnSuccess;
|
||||
@@ -768,6 +730,37 @@ IOReturn QualcommWifi::getPOWER(IO80211SkywalkInterface *iface, apple80211_power
|
||||
|
||||
IOReturn QualcommWifi::setPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) {
|
||||
int val = (pwr && pwr->power_state[0]) ? 1 : 0;
|
||||
if (val == 1 && !fFirmwareLoaded && fPciDevice) {
|
||||
if (allocDmaContext(ATH12K_DMA_TEST_RING_SIZE)) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user