Files
QualcommWireless/docs/RESEARCH_AND_REVERSE_ENGINEERING.md
T
Erwan d152d81d79 docs: dump comprehensive research, kernel reverse-engineering and post-mortems
- Breakthroughs & Rétro-ingénierie :
  * Création de docs/RESEARCH_AND_REVERSE_ENGINEERING.md : synthèse exhaustive
    de toutes les recherches théoriques, des contraintes matérielles du WCN7850
    (MMIO BAR0 windowing 0x310c, DMA 36-bit page mask, désactivation ASPM L0s/L1),
    de la machine d'état du protocole MHI/BHIe (bootloader 2-étapes FBC, anneaux
    CR/ER/TR, environnement d'exécution AMSS/WFW), ainsi que du reverse-engineering
    complet de l'ABI et de la vtable IO80211Controller (3728 octets, 466 entrées,
    graphe d'appels de start(), slots purs et ivars dans BootKernelExtensions.kc).
  * Création de docs/ISSUES_AND_POSTMORTEMS.md : historique détaillé et
    chronologique de l'ensemble des 9 incidents, bugs et panics rencontrés
    depuis le début du projet (erreurs de link KPI, padslot mismatch OpenCore,
    panique explicite Apple _panic("No ivars->_faultReporter"), échec RNGAgent,
    cycle Kext OSBundleRequired Network-Root, et reboots intempestifs), avec
    symptômes, analyses de cause racine, et résolutions techniques validées.
  * Mise à jour de docs/ARCHITECTURE.md : référencement croisé des nouveaux
    documents d'ingénierie et de post-mortems.

- Validation :
  * Arborescence documentaire consolidée et intègre.
  * Validation syntaxique et liens Markdown vérifiés.
2026-10-17 20:00:22 +02:00

9.9 KiB

Recherche Approfondie & Rétro-Ingénierie : Qualcomm WCN7850 & macOS Tahoe (Darwin 25)

Ce document consigne l'ensemble des recherches théoriques, des analyses matérielles, du reverse-engineering binaire du noyau macOS et des découvertes d'ABI effectuées pour le développement du pilote Wi-Fi natif QualcommWifi.


1. Matériel & Architecture PCIe du Qualcomm WCN7850

1.1. Identification Matérielle

  • Puce : Qualcomm FastConnect 7800 (WCN7850)
  • Identifiants PCI :
    • Vendor ID : 0x17cb (Qualcomm Inc.)
    • Device ID : 0x1107 (WCN7850 Wi-Fi 7 PCIe Adapter)
    • Subsystem Vendor : 0x0000, Subsystem ID : 0x0000
  • Architecture Dual-Radio :
    • La puce intègre sur le même die le contrôleur Wi-Fi 7 (connecté via bus PCIe Gen 3/4) et le contrôleur Bluetooth 5.4 (connecté via bus USB interne 0x0cf3:0xe005 / 0xe007 / 0xe300).
    • Le Bluetooth fonctionne de manière autonome via QualcommWireless.kext (transport USB HCI + patches BlueToolFixup).

1.2. Espace Mémoire MMIO BAR0 & Mécanisme de Fenêtrage PCIe

Le contrôleur PCIe n'expose qu'une région BAR0 de 512 Ko (0x80000 octets). L'architecture interne du WCN7850 (SoC, processeurs AMSS, mémoires partagées, registres MHI) nécessite un adressage sur plus de 8 Mo.

  • Registre de sélection de fenêtre BAR0 : 0x310c (ATH12K_PCI_WINDOW_REG_ADDRESS).
  • Algorithme de fenêtrage dynamique : Pour tout offset matériel A \ge \text{0x80000} : \text{window} = (A \gg 19) \ \& \ 0x3F \text{window\_reg\_val} = 0x80000000 \ | \ \text{window} \text{bar0\_target\_offset} = 0x80000 \ | \ (A \ \& \ 0x7FFFF)
  • Observation : Le bit 31 (0x80000000) valide la sélection de la fenêtre active. Le pilote maintient un cache fCurrWindow pour éviter des écritures redondantes sur le bus PCIe.

1.3. Contraintes DMA 36-bit sur Architecture AMD x86_64

  • Le moteur DMA interne du WCN7850 utilise des pointeurs physiques limités à 36 bits d'adresse (ATH12K_DMA_MASK_36BIT_PAGE = 0xFFFFFF000ULL, soit 64 Go d'espace physique adressable).
  • Tout tampon alloué sans masque physique au-delà de 64 Go entraîne des écritures DMA tronquées, provoquant des corruptions de mémoire ou des redémarrages instantanés.
  • Règle absolue : Les buffers DMA d'anneaux MHI et de transfert firmware doivent impérativement être instanciés via :
    IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
        kernel_task,
        kIODirectionInOut | kIOMemoryPhysicallyContiguous,
        taille,
        0xFFFFFF000ULL
    );
    

1.4. ASPM (Active State Power Management)

  • Pendant le transfert du Secondary Boot Loader (SBL) ou de l'image AMSS, le passage automatique du lien PCIe en mode basse consommation (L0s ou L1) entraîne la perte de synchronisation des horloges MMIO et le blocage de la machine d'état BHIe.
  • Solution : Désactivation explicite d'ASPM dans le registre Link Control de la capacité PCIe (pciCapOffset + 0x10) en masquant les bits 0 et 1 (linkCtrl &= ~0x3).

2. Protocole MHI (Modem Host Interface) & Bootloader BHI/BHIe

Le WCN7850 s'amorce à travers le protocole matériel Qualcomm MHI (Modem Host Interface) :

2.1. Environnements d'Exécution (Execution Environments - EE)

  • 0x00 - PBL : Primary Boot Loader (ROM interne au SoC).
  • 0x01 - SBL : Secondary Boot Loader (chargé par l'hôte en RAM interne).
  • 0x02 - AMSS : Advanced Mobile Subscriber Software (Firmware principal Mission Mode Wi-Fi 7).
  • 0x03 - RDDM : RAM Dump Collect (mode crash/debug).
  • 0x04 - WFW : WLAN Firmware Active.

2.2. Séquence de Démarrage 2-Étapes (FBC - Full Boot Flow)

  1. Découverte des offsets BHI/BHIe : Lecture des registres de configuration MHI :
    • ATH12K_MHI_BHIOFF (0x24) : contient l'offset relatif de base de la BHI.
    • ATH12K_MHI_BHIEOFF (0x28) : contient l'offset relatif de base de la BHIe.
  2. Chargement de l'étape 1 (SBL) :
    • Configuration de ATH12K_BHI_IMGADDR_LOW et _HIGH avec l'adresse physique du chunk initial de 512 Ko.
    • Écriture de la taille dans ATH12K_BHI_IMGSIZE.
    • Déclenchement par sonnette BHI : écriture de 1 dans ATH12K_BHI_IMGTXDB.
    • Attente du statut dans ATH12K_BHI_STATUS (vérification du masque 0xC0000000 == 0x80000000).
  3. Configuration des Anneaux MHI (MHI Data Structures) :
    • Channel Context Array (CCABAP) : tableau des 64 contextes de canaux (direction, type de transfert, buffers).
    • Event Ring Context Array (ECABAP) : anneaux d'événements matériels (ER0 pour les événements généraux, ER1 pour les paquets de données).
    • Command Ring Context Array (CRCBAP) : anneau de commandes WMI/MHI.
    • Doorbells MHI : programmation des adresses matérielles de sonnette pour notifier le matériel de nouveaux descripteurs.
  4. Chargement de l'étape 2 (AMSS FBC via BHIe) :
    • Allocation d'une table vectorielle Scatter-Gather (struct bhi_vec_entry).
    • Découpage de l'image AMSS complète (~6 Mo) en segments de 512 Ko.
    • Programmation des registres ATH12K_BHIE_TXVECADDR_LOW/HIGH, ATH12K_BHIE_TXVECSIZE, et écriture de 1 dans ATH12K_BHIE_TXVECDB.
  5. Transition vers l'état Mission M0 :
    • Écriture de l'état ATH12K_MHI_STATE_M0 (2) dans ATH12K_MHI_MHICTRL.
    • Surveillance des interruptions MSI et des événements d'anneau MHI (PKT_TYPE_STATE_CHANGE_EVENT vers M0 et PKT_TYPE_EE_EVENT vers AMSS).

3. Reverse-Engineering d'Apple IO80211Controller (macOS Tahoe Darwin 25)

L'analyse a été menée par rétro-ingénierie binaire directe de la Kernel Collection de production : /System/Library/KernelCollections/BootKernelExtensions.kc.

3.1. Structure de la Vtable IO80211Controller

  • Emplacement Vtable : 0xffffff8002461148 à 0xffffff8002461fd8.
  • Taille exacte : 0xe90 octets (3728 octets) = 466 entrées (2 mots d'en-tête RTTI + 464 slots de méthodes virtuelles).
  • Alignement OpenCore : OpenCore valide la taille exacte de la vtable lors du chargement des Kexts (Vtables.c). Tout Kext dérivant d'IO80211Controller sous macOS Tahoe doit impérativement avoir une table virtuelle de 3728 octets sous peine d'échec immédiat (padslot mismatch).

3.2. Méthodes Virtuelles Pures d'Apple (___cxa_pure_virtual)

Le noyau macOS définit 6 slots virtuels purs dans IO80211Controller qui doivent obligatoirement être implémentés par le sous-classeur :

  1. Slot 410 (*0xcc0) : IONetworkController::getPacketFilters
  2. Slot 411 (*0xcc8) : IONetworkController::enable(IONetworkInterface*)
  3. Slot 412 (*0xcd0) : IONetworkController::disable(IONetworkInterface*)
  4. Slot 413 (*0xcd8) : IONetworkController::outputPacket(mbuf_t, void*)
  5. Slot 414 (*0xce0) : IONetworkController::getHardwareAddress(IOEthernetAddress*)
  6. Slot 426 (*0xd40(%rax)) : virtual void* getLogger(void) const = 0;
  7. Slot 434 (*0xd80(%rax)) : virtual void* getFaultReporterFromDriver(void) = 0;

3.3. Déroulement Interne de IO80211Controller::start(provider) (0xffffff8002291f30)

L'analyse désassemblée révèle le graphe d'appels complet exécuté lors de super::start(provider) :

  1. +0x03b : Invoque IONetworkController::start(provider) (0xffffff80026f34dc).
    • Initialise le WorkLoop réseau et publie les interfaces.
    • Exigence : Nécessite que createWorkQueue() soit surchargé et valide, sinon start retourne false immédiatement.
  2. +0x17e : Appelle this->getLogger() (callq *0xd40(%rax), Slot 426).
    • Stocke le résultat à l'offset 0x70 des ivars internes (ivars->_logger).
  3. +0x191 : Appelle createIOReporters(provider).
  4. +0x25a : Appelle setupControlPathLogging().
    • Vérifie les flags d'événements et de métriques LQML.
  5. +0x272 : Appelle findAndAttachToFaultReporter() (0xffffff8002292628).
    • Invoque this->getFaultReporterFromDriver() (callq *0xd80(%rax), Slot 434).
    • Si le pointeur renvoyé est non-nul : appelle obj->retain() (callq *0x20(%rax)), et le stocke dans ivars->_faultReporter (0x58(%ivars)).
    • Comportement si NULL : À 0xffffff8002292737, exécute l'instruction de panic explicite : panic("\"No ivars->_faultReporter\" @IO80211Controller.cpp:2877") !
  6. +0x2d0 : Appelle IO80211RangingManager::initWithController(this).
  7. +0x2e3 : Appelle this->getWorkQueue() (callq *0xc68(%rax)).
  8. +0x2f0 : Instancie IO80211CommandGate::allocWithParams(this, workQueue).
  9. +0x471 : Appelle this->CreatePostOffice().
    • Crée la boîte aux lettres d'événements Wi-Fi associée à la workQueue.
  10. +0x4ac : Instancie IO80211TimerSource::allocWithParams(2, this, workQueue).
  11. +0x4e3 : Instancie IO80211TimerFactory::allocWithParams(workQueue).
  12. +0x502 : Appelle IO80211RNGAgent::withOptions(this) (0xffffff80022dd55c).
    • Invoque à son tour this->getLogger(). Si nul, abandonne et renvoie NULL.
    • Si non-nul : appelle logger->retain().
  13. +0x521 : Appelle this->allocFramePool().
    • Récupère la taille de trame via le slot 440 (retourne 0x100 = 256).
    • Alloue le pool de buffers réseau via IO80211MallocBufferPool::withOptions().
  14. +0x555 : Retourne true (kIOReturnSuccess).

4. Intégration Skywalk & airportd sous macOS Tahoe

  • Suppression des interfaces réseau Ethernet pour le Wi-Fi : Sous macOS 26.x, le démon airportd ignore les interfaces Wi-Fi déclarées sous forme d'IOEthernetInterface. L'association et la gestion du lien s'effectuent via IO80211SkywalkInterface.
  • Méthodes clés de gestion d'état :
    • handleCardSpecific : réceptionne l'ensemble des requêtes APPLE80211_IOC_* provenant d'airportd et du Centre de Contrôle.
    • dataLinkLayerAttachComplete : notifie le pilote dès que la couche Skywalk de transport est connectée.
    • setPOWER / getPOWER : gestion logicielle de l'alimentation de l'émetteur radio.
    • getCARD_CAPABILITIES : publication des capacités matérielles (chiffrements AES/WPA3, largeurs de bande, 802.11be EHT).