fix(wifi): initialiser l'arborescence Power Management IOKit pour le Stade 6 (joinPMtree)
- Breakthroughs & Rétro-ingénierie : * Analyse désassemblée complète de IO80211SkywalkInterface::start (0xffffff80022f5792) dans BootKernelExtensions.kc. * Découverte de l'appel interne à QualcommWifi->joinPMtree(fSkywalkInterface) (slot 244 de IOService, offset +0x7a0). * Cause racine identifiée : QualcommWifi n'initialisait pas Power Management (PMinit non appelé), laissant son pointeur pm_vars à NULL. L'accès à pm_vars dans gIOPMrootDomain provoquait un Kernel Trap Page Fault immédiat. * Détection d'un gestionnaire d'erreur destructeur dans start() qui appelait detachInterface(IONetworkInterface*) et provoquait des corruptions mémoire en cas d'échec transitoire. - Modifications apportées : * QualcommWifi/QualcommWifi.hpp : déclaration de la méthode virtuelle setPowerState override. * QualcommWifi/QualcommWifi.cpp : initialisation complète du cycle Power Management (PMinit, joinPMtree, registerPowerDriver sur 2 états Off/On, changePowerStateToPriv), implémentation de setPowerState et PMstop(). * QualcommWifi/QualcommWifi.cpp : sécurisation des blocs d'erreur dans start() (suppression des detachInterface/release brutaux d'objets enregistrés dans l'IORegistry). * docs/ISSUES_AND_POSTMORTEMS.md : consignation détaillée de l'incident INC-20. - Validation : * Compilation clang++ réussie sans erreur. * Validation kmutil libraries à 100% contre BootKernelExtensions.kc. * Kext déployé sur /Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext. * OpenCore armé avec boot-arg qcom_step=6 dans config.plist.
This commit is contained in:
1 parent
cfdbaaa676
commit
6a1af27d4f
3 files changed
+85
-18
No files matched your search
@@ -717,6 +717,18 @@ bool QualcommWifi::start(IOService *provider) {
|
||||
}
|
||||
logNvramStage("pci_open_ok");
|
||||
|
||||
// Initialisation complète de l'arborescence Power Management (requis pour fSkywalkInterface->joinPMtree(this))
|
||||
logNvramStage("pm_init");
|
||||
PMinit();
|
||||
joinPMtree(provider);
|
||||
static IOPMPowerState sPowerStates[2] = {
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 1, IOPMDeviceUsable | IOPMPowerOn, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
registerPowerDriver(this, sPowerStates, 2);
|
||||
changePowerStateToPriv(1);
|
||||
IOLog("QualcommWifi: Power Management initialise avec succes (PMinit + joinPMtree + registerPowerDriver) !\n");
|
||||
|
||||
// La gestion de l'espace mémoire PCIe et du Bus Master est gérée automatiquement par IOKit
|
||||
// (Éviter les écritures de configuration brutes risquant de déstabiliser le root port AMD)
|
||||
logNvramStage("pci_ready");
|
||||
@@ -841,32 +853,17 @@ bool QualcommWifi::start(IOService *provider) {
|
||||
}
|
||||
} else {
|
||||
logNvramStage("skywalk_start_err");
|
||||
IOLog("QualcommWifi: Erreur - fSkywalkInterface->start(this) a échoué !\n");
|
||||
if (fSkywalkAttached) {
|
||||
fSkywalkInterface->detach(this);
|
||||
fSkywalkAttached = false;
|
||||
}
|
||||
if (fSkywalkCtrlAttached) {
|
||||
detachInterface(fSkywalkInterface, false);
|
||||
fSkywalkCtrlAttached = false;
|
||||
}
|
||||
OSSafeReleaseNULL(fSkywalkInterface);
|
||||
IOLog("QualcommWifi: AVERTISSEMENT - fSkywalkInterface->start(this) a echoue (interface preservee pour diagnostic) !\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logNvramStage("skywalk_attach_err");
|
||||
IOLog("QualcommWifi: Erreur - fSkywalkInterface->attach(this) a échoué !\n");
|
||||
if (fSkywalkCtrlAttached) {
|
||||
detachInterface(fSkywalkInterface, false);
|
||||
fSkywalkCtrlAttached = false;
|
||||
}
|
||||
OSSafeReleaseNULL(fSkywalkInterface);
|
||||
IOLog("QualcommWifi: Erreur - fSkywalkInterface->attach(this) a echoue !\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logNvramStage("skywalk_init_err");
|
||||
IOLog("QualcommWifi: Erreur - fSkywalkInterface->init(...) a échoué !\n");
|
||||
OSSafeReleaseNULL(fSkywalkInterface);
|
||||
IOLog("QualcommWifi: Erreur - fSkywalkInterface->init(...) a echoue !\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -936,6 +933,7 @@ void QualcommWifi::stop(IOService *provider) {
|
||||
OSSafeReleaseNULL(fWorkQueue);
|
||||
}
|
||||
|
||||
PMstop();
|
||||
super::stop(provider);
|
||||
}
|
||||
|
||||
@@ -1295,3 +1293,9 @@ SInt32 QualcommWifi::handleApple80211Request(unsigned int req_type, int req_val,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
IOReturn QualcommWifi::setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) {
|
||||
IOLog("QualcommWifi: setPowerState(ordinal=%lu, device=%s)\n",
|
||||
powerStateOrdinal, whatDevice ? whatDevice->getName() : "null");
|
||||
return IOPMAckImplied;
|
||||
}
|
||||
@@ -233,6 +233,9 @@ public:
|
||||
virtual bool start(IOService *provider) override;
|
||||
virtual void stop(IOService *provider) override;
|
||||
|
||||
// Power Management (requis pour satisfaire joinPMtree de fSkywalkInterface->start)
|
||||
virtual IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) override;
|
||||
|
||||
// WorkQueue / WorkLoop interface required by IO80211Controller / IONetworkController
|
||||
virtual bool createWorkLoop(void) override;
|
||||
virtual IOWorkLoop* getWorkLoop(void) const override;
|
||||
|
||||
@@ -554,6 +554,66 @@ Ce document répertorie de manière exhaustive l'ensemble des anomalies, blocage
|
||||
7. **Armement du Stade 6 (`qcom_step=6`)** :
|
||||
- `boot-args` configuré sur `qcom_step=6` dans `/Volumes/EFI/EFI/OC/config.plist` pour démarrer le sous-système Skywalk (`fSkywalkInterface->start(this)` : initialisation PMtree, PeerManager, IO80211Glue et association au WorkQueue).
|
||||
|
||||
---
|
||||
|
||||
### INC-20 : Analyse de l'Échec du Stade 6 (`qcom_step=6`) & Résolution par Implémentation du Power Management IOKit
|
||||
* **Date** : 18 Octobre 2026
|
||||
* **Composant** : `QualcommWifi.kext` / `IO80211SkywalkInterface::start(IOService *controller)`
|
||||
* **Symptômes & Constats** :
|
||||
- Lors du test initial de `qcom_step=6`, la machine a rencontré un redémarrage en boucle (bootloop).
|
||||
- L'utilisateur est revenu temporairement sur `qcom_step=5`, qui a redémarré de manière 100% stable jusqu'au bureau avec `IO80211SkywalkInterface` parfaitement attaché (`IO80211InterfaceRole` = "Infrastructure").
|
||||
* **Causes Racines (Breakthroughs & Rétro-ingénierie du Kernel Collection)** :
|
||||
1. **Analyse de la séquence interne de `IO80211SkywalkInterface::start(IOService *provider)` (`0xffffff80022f5792`)** :
|
||||
- Le désassemblage Capstone direct de `BootKernelExtensions.kc` a révélé les étapes précises :
|
||||
1. Vérification `ivars + 0x28 == NULL` (protection contre appel réentrant : panic `"Calling start twice in a row is not allowed"`).
|
||||
2. Appel de `super::start(provider)` (`IOService::start(provider)`).
|
||||
3. Cast dynamique du contrôleur via `OSDynamicCast(IO80211Controller, provider)`.
|
||||
4. Récupération et conservation de `controller->getWorkQueue()`.
|
||||
5. Création des canaux CoreCapture `CCPipe` et flux de journalisation `CCStream`.
|
||||
6. Instanciation du `IO80211PeerManager` via `createPeerManager()` (`0xffffff80022f7be6`) qui alloue le verrou récursif `controller->allocIO80211RecursiveLock()` (slot 435 / offset `+0xd98`) et le `IO80211CommandGate`.
|
||||
7. **Étape critique de gestion de l'énergie (Power Management)** :
|
||||
```assembly
|
||||
0xffffff80022f5c6c: mov rax, qword ptr [r12]
|
||||
0xffffff80022f5c70: mov rdi, r12
|
||||
0xffffff80022f5c73: call qword ptr [rax + 0x790] ; fSkywalkInterface->PMinit() (slot 242)
|
||||
0xffffff80022f5c79: mov rax, qword ptr [r15] ; r15 = QualcommWifi (contrôleur)
|
||||
0xffffff80022f5c7c: mov rdi, r15
|
||||
0xffffff80022f5c7f: mov rsi, r12 ; rsi = fSkywalkInterface
|
||||
0xffffff80022f5c82: call qword ptr [rax + 0x7a0] ; QualcommWifi->joinPMtree(fSkywalkInterface) (slot 244)
|
||||
0xffffff80022f5c88: mov rax, qword ptr [r12]
|
||||
0xffffff80022f5c8c: lea rdx, [rip + 0x19564d] ; tableau des 2 états IOPMPowerState
|
||||
0xffffff80022f5c93: mov ecx, 2
|
||||
0xffffff80022f5c98: mov rdi, r12
|
||||
0xffffff80022f5c9b: mov rsi, r12
|
||||
0xffffff80022f5c9e: call qword ptr [rax + 0x7a8] ; fSkywalkInterface->registerPowerDriver(...) (slot 245)
|
||||
0xffffff80022f5ca4: mov esi, 1
|
||||
0xffffff80022f5ca9: mov rdi, r12
|
||||
0xffffff80022f5cac: call 0xffffff8000abbb80 ; changePowerStateToPriv(1)
|
||||
0xffffff80022f5cb1: mov rdi, r12
|
||||
0xffffff80022f5cb4: xor esi, esi
|
||||
0xffffff80022f5cb6: call 0xffffff8000abbaf0 ; changePowerStateTo(0)
|
||||
```
|
||||
2. **Origine du Panic / Page Fault : Absence de PM sur le Contrôleur Parent** :
|
||||
- À `0xffffff80022f5c82`, `IO80211SkywalkInterface` invoque `QualcommWifi->joinPMtree(fSkywalkInterface)` afin d'intégrer l'interface réseau dans l'arbre d'alimentation du pilote hôte.
|
||||
- Dans le noyau XNU (`0xffffff8000ab9a00`), `IOService::joinPMtree` transmet à `gIOPMrootDomain->joinPMtree(QualcommWifi, fSkywalkInterface)`.
|
||||
- Cette méthode manipule obligatoirement le contexte de puissance du parent (`QualcommWifi->pm_vars` à l'offset `+0x60`).
|
||||
- Puisque `QualcommWifi` n'avait jamais exécuté `PMinit()`, son pointeur `pm_vars` était nul (`0x0`), provoquant un déréférencement immédiat de pointeur nul et un Kernel Trap Page Fault (`CR2: 0x00000000000000d8` / `_IOLockLock`).
|
||||
3. **Dangerosité du gestionnaire d'erreur de `QualcommWifi.cpp`** :
|
||||
- En cas de retour `false` de `start()`, l'ancien code de repli appelait `detachInterface(fSkywalkInterface, false)` (qui est une méthode d'`IOEthernetController` attendant un `IONetworkInterface*`) et libérait `fSkywalkInterface` alors qu'il était déjà enregistré dans l'IORegistry et dans `controller->ivars + 0x188`, garantissant un panic même si `start()` échouait proprement.
|
||||
* **Résolutions Techniques Appliquées** :
|
||||
1. **Intégration du cycle de vie Power Management complet dans `QualcommWifi`** :
|
||||
- Ajout de `PMinit()` et `joinPMtree(provider)` dans `QualcommWifi::start()` dès l'ouverture du périphérique PCIe.
|
||||
- Enregistrement du modèle standard d'alimentation à 2 états (State 0: Off, State 1: On / `IOPMDeviceUsable | IOPMPowerOn`) via `registerPowerDriver(this, sPowerStates, 2)` et transition initiale vers l'état actif (`changePowerStateToPriv(1)`).
|
||||
- Surcharge de `setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice)` dans `QualcommWifi.hpp` et `QualcommWifi.cpp` renvoyant `IOPMAckImplied`.
|
||||
- Appel de `PMstop()` dans `QualcommWifi::stop()`.
|
||||
2. **Sécurisation du gestionnaire d'erreur de `start()`** :
|
||||
- Suppression de tous les appels destructeurs `detachInterface()` et `OSSafeReleaseNULL()` dans les branches d'erreur de `skywalk_start`, `skywalk_attach` et `skywalk_init` : l'interface est préservée intacte pour analyse des journaux système sans déstabiliser le noyau.
|
||||
3. **Validation et Déploiement** :
|
||||
- Recompilation avec `./build_wifi.sh` : validation à 100% avec `kmutil libraries` contre `BootKernelExtensions.kc`.
|
||||
- Déploiement du nouveau kext sur `/Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext`.
|
||||
- Configuration du boot-arg dans `/Volumes/EFI/EFI/OC/config.plist` : `qcom_step=6` prêt pour test en direct.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user