diff --git a/QualcommWifi/Info.plist b/QualcommWifi/Info.plist index ddef963..b155d31 100644 --- a/QualcommWifi/Info.plist +++ b/QualcommWifi/Info.plist @@ -44,6 +44,8 @@ 1.5.0 com.apple.iokit.IOPCIFamily 1.0.0 + com.apple.iokit.IOSkywalkFamily + 1.0 com.apple.kpi.bsd 16.7 com.apple.kpi.iokit diff --git a/QualcommWifi/QualcommWifi.cpp b/QualcommWifi/QualcommWifi.cpp index d3b571f..0c12efb 100644 --- a/QualcommWifi/QualcommWifi.cpp +++ b/QualcommWifi/QualcommWifi.cpp @@ -186,6 +186,37 @@ extern "C" { bool _ZN23IO80211SkywalkInterface9initIvarsEv(void *thisPtr); bool _ZN23IO80211SkywalkInterface4initEv(void *thisPtr); extern const void * const _ZN23IO80211SkywalkInterface10gMetaClassE; + + // Skywalk Ethernet Datapath & Queues API (com.apple.iokit.IOSkywalkFamily) + bool _ZN26IOSkywalkEthernetInterface20initRegistrationInfoEPNS_16RegistrationInfoEjm(void *thisPtr, void *info, UInt32 version, unsigned long size); + IOReturn _ZN26IOSkywalkEthernetInterface25registerEthernetInterfaceEPKNS_16RegistrationInfoEPP20IOSkywalkPacketQueuejP25IOSkywalkPacketBufferPoolS7_j( + void *thisPtr, const void *info, void **queues, UInt32 numQueues, void *rxPool, void *txPool, UInt32 flags); + IOReturn _ZN26IOSkywalkEthernetInterface27deregisterEthernetInterfaceEj(void *thisPtr, UInt32 flags); + void* _ZN25IOSkywalkPacketBufferPool8withNameEPKcP8OSObjectjPKNS_11PoolOptionsE(const char *name, void *owner, UInt32 type, const void *opts); + void* _ZN26IOSkywalkTxSubmissionQueue8withPoolEP25IOSkywalkPacketBufferPooljjP8OSObjectPFjS3_PS_PKP15IOSkywalkPacketjPvES9_j( + void *pool, UInt32 capacity, UInt32 queueId, void *owner, void *action, void *context, UInt32 flags); + void* _ZN26IOSkywalkRxCompletionQueue8withPoolEP25IOSkywalkPacketBufferPooljjP8OSObjectPFjS3_PS_PP15IOSkywalkPacketjPvES8_j( + void *pool, UInt32 capacity, UInt32 queueId, void *owner, void *action, void *context, UInt32 flags); +} + +struct SkywalkPoolOptions { + uint32_t min_capacity; + uint32_t max_capacity; + uint32_t buffer_size; + uint32_t align; + uint32_t reserved1; + uint32_t flags; + void *segment; + uint64_t reserved2; + uint64_t reserved3; +}; + +static UInt32 skywalkTxAction(OSObject *owner, void *queue, const void **packets, UInt32 count, void *context) { + return count; +} + +static UInt32 skywalkRxAction(OSObject *owner, void *queue, void **packets, UInt32 count, void *context) { + return count; } static IO80211SkywalkInterface* createSkywalkInterface(void) { @@ -276,6 +307,11 @@ bool QualcommWifi::init(OSDictionary *dictionary) { fSkywalkCtrlAttached = false; fSkywalkAttached = false; fSkywalkStarted = false; + bzero(fSkywalkRegInfo, sizeof(fSkywalkRegInfo)); + fSkywalkPool = nullptr; + fSkywalkTxQueue = nullptr; + fSkywalkRxQueue = nullptr; + fEthernetRegistered = false; // Adresse MAC par défaut (OUI Qualcomm 00:03:7F) en attendant la lecture BHI fMacAddress.bytes[0] = 0x00; fMacAddress.bytes[1] = 0x03; @@ -303,6 +339,15 @@ bool QualcommWifi::init(OSDictionary *dictionary) { void QualcommWifi::free(void) { logNvramStage("free_enter"); + if (fSkywalkTxQueue) { + OSSafeReleaseNULL(fSkywalkTxQueue); + } + if (fSkywalkRxQueue) { + OSSafeReleaseNULL(fSkywalkRxQueue); + } + if (fSkywalkPool) { + OSSafeReleaseNULL(fSkywalkPool); + } OSSafeReleaseNULL(fSkywalkInterface); OSSafeReleaseNULL(fFaultReporter); OSSafeReleaseNULL(fLogger); @@ -1026,6 +1071,105 @@ bool QualcommWifi::start(IOService *provider) { IOLog("QualcommWifi: Publication du contrôleur contournée (qcom_step < 7 et qcom_register=0).\n"); } + if (skywalk_step >= 8) { + int substep8 = 0; + PE_parse_boot_argn("qcom_substep", &substep8, sizeof(substep8)); + IOLog("QualcommWifi: ========================================================\n"); + IOLog("QualcommWifi: >>> ETAPE 8 : Enregistrement Skywalk Ethernet & Client BSD (substep=%d) <<<\n", substep8); + IOLog("QualcommWifi: ========================================================\n"); + + if (substep8 >= 1) { + logNvramStage("s8_0_init_reginfo"); + IOSleep(100); + bzero(fSkywalkRegInfo, sizeof(fSkywalkRegInfo)); + bool regInit = _ZN26IOSkywalkEthernetInterface20initRegistrationInfoEPNS_16RegistrationInfoEjm( + fSkywalkInterface, fSkywalkRegInfo, 1, sizeof(fSkywalkRegInfo) + ); + if (regInit) { + // Configuration de l'adresse MAC physique et MTU + memcpy(fSkywalkRegInfo + 0x108, fMacAddress.bytes, 6); + *(uint32_t*)(fSkywalkRegInfo + 0x48) = 1500; + logNvramStage("s8_1_reginfo_ok"); + IOLog("QualcommWifi: [s8_1] initRegistrationInfo réussi et MAC configurée !\n"); + } else { + logNvramStage("s8_1_reginfo_err"); + IOLog("QualcommWifi: [s8_1] ERREUR initRegistrationInfo !\n"); + } + } + + if (substep8 >= 2) { + logNvramStage("s8_2_pool_alloc"); + IOSleep(100); + SkywalkPoolOptions poolOpts; + bzero(&poolOpts, sizeof(poolOpts)); + poolOpts.min_capacity = 256; + poolOpts.max_capacity = 256; + poolOpts.buffer_size = 2048; + poolOpts.align = 1; + poolOpts.flags = 1; + + fSkywalkPool = (OSObject*)_ZN25IOSkywalkPacketBufferPool8withNameEPKcP8OSObjectjPKNS_11PoolOptionsE( + "QualcommWifi_Pool", this, 1, &poolOpts + ); + if (fSkywalkPool) { + logNvramStage("s8_2_pool_ok"); + IOLog("QualcommWifi: [s8_2] IOSkywalkPacketBufferPool alloué avec succès (0x%p) !\n", fSkywalkPool); + } else { + logNvramStage("s8_2_pool_err"); + IOLog("QualcommWifi: [s8_2] ERREUR allocation IOSkywalkPacketBufferPool !\n"); + } + } + + if (substep8 >= 3 && fSkywalkPool) { + logNvramStage("s8_3_queues_alloc"); + IOSleep(100); + fSkywalkTxQueue = (OSObject*)_ZN26IOSkywalkTxSubmissionQueue8withPoolEP25IOSkywalkPacketBufferPooljjP8OSObjectPFjS3_PS_PKP15IOSkywalkPacketjPvES9_j( + fSkywalkPool, 256, 0, this, (void*)skywalkTxAction, this, 0 + ); + fSkywalkRxQueue = (OSObject*)_ZN26IOSkywalkRxCompletionQueue8withPoolEP25IOSkywalkPacketBufferPooljjP8OSObjectPFjS3_PS_PP15IOSkywalkPacketjPvES8_j( + fSkywalkPool, 256, 1, this, (void*)skywalkRxAction, this, 0 + ); + if (fSkywalkTxQueue && fSkywalkRxQueue) { + logNvramStage("s8_3_queues_ok"); + IOLog("QualcommWifi: [s8_3] Queues Skywalk allouées (Tx: 0x%p, Rx: 0x%p) !\n", fSkywalkTxQueue, fSkywalkRxQueue); + } else { + logNvramStage("s8_3_queues_err"); + IOLog("QualcommWifi: [s8_3] ERREUR allocation Queues Skywalk (Tx: 0x%p, Rx: 0x%p) !\n", fSkywalkTxQueue, fSkywalkRxQueue); + } + } + + if (substep8 >= 4 && fSkywalkTxQueue && fSkywalkRxQueue) { + logNvramStage("s8_4_reg_eth"); + IOSleep(100); + void *queues[2] = { fSkywalkTxQueue, fSkywalkRxQueue }; + IOReturn regRes = _ZN26IOSkywalkEthernetInterface25registerEthernetInterfaceEPKNS_16RegistrationInfoEPP20IOSkywalkPacketQueuejP25IOSkywalkPacketBufferPoolS7_j( + fSkywalkInterface, fSkywalkRegInfo, queues, 2, fSkywalkPool, fSkywalkPool, 0 + ); + if (regRes == kIOReturnSuccess) { + fEthernetRegistered = true; + logNvramStage("s8_4_reg_eth_ok"); + IOLog("QualcommWifi: ========================================================\n"); + IOLog("QualcommWifi: >>> [SUCCES MAJEUR] registerEthernetInterface A REUSSI ! <<<\n"); + IOLog("QualcommWifi: ========================================================\n"); + } else { + logNvramStage("s8_4_reg_eth_err"); + IOLog("QualcommWifi: [s8_4] registerEthernetInterface a échoué (0x%x) !\n", regRes); + } + } + + if (substep8 >= 5 && fEthernetRegistered) { + logNvramStage("s8_5_reg_svc_enter"); + IOSleep(100); + IOLog("QualcommWifi: ========================================================\n"); + IOLog("QualcommWifi: >>> [ATTACHEMENT BSD] Publication du service fSkywalkInterface ! <<<\n"); + IOLog("QualcommWifi: ========================================================\n"); + fSkywalkInterface->registerService(); + logNvramStage("s8_6_reg_svc_done"); + IOSleep(100); + IOLog("QualcommWifi: >>> [SUCCES TOTAL] Service Skywalk publié, création d'en1 imminente ! <<<\n"); + } + } + logNvramStage("start_done"); IOLog("QualcommWifi: Pilote Wi-Fi natif (IO80211Controller) demarre avec succes !\n"); return true; @@ -1034,6 +1178,20 @@ bool QualcommWifi::start(IOService *provider) { void QualcommWifi::stop(IOService *provider) { IOLog("QualcommWifi: Arret du pilote Wi-Fi natif, liberation MSI, DMA et BAR0.\n"); + if (fEthernetRegistered && fSkywalkInterface) { + _ZN26IOSkywalkEthernetInterface27deregisterEthernetInterfaceEj(fSkywalkInterface, 0); + fEthernetRegistered = false; + } + if (fSkywalkTxQueue) { + OSSafeReleaseNULL(fSkywalkTxQueue); + } + if (fSkywalkRxQueue) { + OSSafeReleaseNULL(fSkywalkRxQueue); + } + if (fSkywalkPool) { + OSSafeReleaseNULL(fSkywalkPool); + } + if (fSkywalkInterface) { if (fSkywalkCtrlAttached) { detachInterface(fSkywalkInterface, false); // slot 442 in IO80211Controller diff --git a/QualcommWifi/QualcommWifi.hpp b/QualcommWifi/QualcommWifi.hpp index e852e4e..3dffe10 100644 --- a/QualcommWifi/QualcommWifi.hpp +++ b/QualcommWifi/QualcommWifi.hpp @@ -194,6 +194,13 @@ private: bool fSkywalkStarted; IOEthernetAddress fMacAddress; + // Skywalk Ethernet Datapath & Queues (Étape 8) + uint8_t fSkywalkRegInfo[0x130]; + OSObject *fSkywalkPool; + OSObject *fSkywalkTxQueue; + OSObject *fSkywalkRxQueue; + bool fEthernetRegistered; + // État réseau Wi-Fi bool fLinkActive; UInt16 fCurrentChannel; diff --git a/docs/ISSUES_AND_POSTMORTEMS.md b/docs/ISSUES_AND_POSTMORTEMS.md index 379018a..9f68efd 100644 --- a/docs/ISSUES_AND_POSTMORTEMS.md +++ b/docs/ISSUES_AND_POSTMORTEMS.md @@ -962,3 +962,49 @@ Ce document répertorie de manière exhaustive l'ensemble des anomalies, blocage - Compilation réussie sans avertissement (`./build_wifi.sh`). - Validation des symboles et dépendances `kmutil libraries` à 100% contre `BootKernelExtensions.kc`. +--- + +### Postmortem 24 : Datapath Skywalk Ethernet, Allocation des Queues/Pools et Initialisation de `fLogicalLinks` pour l'Attachement BSD `en1` (Étape 8) + +* **Date** : 19 Octobre 2026 +* **Cible** : macOS Tahoe 26.x (Darwin 25.6.0 x86_64), AMD Ryzen 7 5800X3D, `QualcommWifi.kext` (WCN7850 `0x17cb:0x1107`) +* **Symptômes & Retours Utilisateur (/grill-me)** : + - L'Étape 7 (`this->registerService()`) a validé l'enregistrement d'`IO80211Controller` dans l'IORegistry sans crash (`IOServiceState = 30`), réveillant le démon `airportd`. + - Cependant, aucune interface BSD (`en1`) n'apparaissait encore dans `ifconfig` ni dans la barre de menus Wi-Fi macOS, car le datapath Skywalk sous-jacent n'avait pas encore enregistré ses queues et ses pools de paquets. +* **Breakthroughs & Rétro-ingénierie Binaire Exhaustive (`BootKernelExtensions.kc`)** : + 1. **Hiérarchie et Chaîne d'Héritage Skywalk dans le Noyau macOS Tahoe** : + - `IOService` -> `IOSkywalkInterface` -> `IOSkywalkNetworkInterface` -> `IOSkywalkEthernetInterface` -> `IO80211SkywalkInterface` -> `IO80211InfraInterface`. + - `IO80211SkywalkInterface` est une sous-classe directe d'`IOSkywalkEthernetInterface`. + 2. **Anatomie de `fLogicalLinks` (Offset `+0xc8`) et Prérequis de `IOSkywalkNetworkBSDClient::start`** : + - Lors du matching de `IOSkywalkNetworkBSDClient` sur `fSkywalkInterface`, `start` lit `interface->fLogicalLinks` à l'offset `+0xc8`. + - Si `fLogicalLinks == NULL`, le noyau subit un `#PF` inconditionnel sur Page 0 (`CR2: 0x0`). + - Dans le binaire `BootKernelExtensions.kc`, la méthode `IOSkywalkEthernetInterface::registerEthernetInterface` (`0xffffff8002b0c1e0`) alloue un `OSOrderedSet`, instancie un `IOSkywalkLogicalLink`, l'insère dans le set, et l'assigne à `fLogicalLinks` à l'offset `+0xc8`. + 3. **Prérequis Stricts d'`IOSkywalkEthernetInterface::registerEthernetInterface`** : + - Signature binaire : + `IOReturn registerEthernetInterface(RegistrationInfo *info, IOSkywalkPacketQueue **queues, UInt32 numQueues, IOSkywalkPacketBufferPool *rxPool, IOSkywalkPacketBufferPool *txPool, UInt32 flags)` + - Doit respecter : + * `info` : Version 1, taille `0x130` (304 octets), initialisé via `IOSkywalkEthernetInterface::initRegistrationInfo`. L'adresse MAC physique (6 octets) doit être copiée à l'offset `+0x108`, et le MTU à `+0x48`. + * `numQueues >= 1` et `queues != NULL` (validé par `IOSkywalkQueueSet::initWithQueues`, bornes 1..256). + * Au moins un pool (`rxPool` ou `txPool`) non nul, instancié via `IOSkywalkPacketBufferPool::withName`. + * Queues instanciées via `IOSkywalkTxSubmissionQueue::withPool` et `IOSkywalkRxCompletionQueue::withPool`. +* **Résolutions Techniques Appliquées dans `QualcommWifi`** : + 1. **Dépendance Kext** : + - Ajout de `com.apple.iokit.IOSkywalkFamily` (1.0) dans `OSBundleLibraries` de `QualcommWifi/Info.plist`. + 2. **Moteurs Datapath & Déclarations Manglées Extern "C"** : + - `initRegistrationInfo` (`_ZN26IOSkywalkEthernetInterface20initRegistrationInfoEPNS_16RegistrationInfoEjm`) + - `registerEthernetInterface` (`_ZN26IOSkywalkEthernetInterface25registerEthernetInterfaceEPKNS_16RegistrationInfoEPP20IOSkywalkPacketQueuejP25IOSkywalkPacketBufferPoolS7_j`) + - `deregisterEthernetInterface` (`_ZN26IOSkywalkEthernetInterface27deregisterEthernetInterfaceEj`) + - `withName` (`_ZN25IOSkywalkPacketBufferPool8withNameEPKcP8OSObjectjPKNS_11PoolOptionsE`) + - `withPool` Tx (`_ZN26IOSkywalkTxSubmissionQueue8withPoolEP25IOSkywalkPacketBufferPooljjP8OSObjectPFjS3_PS_PKP15IOSkywalkPacketjPvES9_j`) + - `withPool` Rx (`_ZN26IOSkywalkRxCompletionQueue8withPoolEP25IOSkywalkPacketBufferPooljjP8OSObjectPFjS3_PS_PP15IOSkywalkPacketjPvES8_j`) + 3. **Découpage Modulaire Sécurisé par Sous-Étapes (`qcom_substep`)** : + - `s8_0_init_reginfo` -> `s8_1_reginfo_ok` : Initialisation `RegistrationInfo` + MAC OUI `00:03:7F` + MTU 1500. + - `s8_2_pool_alloc` -> `s8_2_pool_ok` : Allocation `IOSkywalkPacketBufferPool("QualcommWifi_Pool", 256 paquets, 2048B)`. + - `s8_3_queues_alloc` -> `s8_3_queues_ok` : Allocation Tx Submission Queue (0) et Rx Completion Queue (1). + - `s8_4_reg_eth` -> `s8_4_reg_eth_ok` : `registerEthernetInterface` initialisant `fLogicalLinks` et les liaisons Skywalk. + - `s8_5_reg_svc_enter` -> `s8_6_reg_svc_done` : `fSkywalkInterface->registerService()`, attachement de `IOSkywalkNetworkBSDClient` et création de l'interface `en1`. + 4. **Validation Binaire & Déploiement** : + - Compilation `Release` validée à 100% sans aucun avertissement ni symbole manquant par `kmutil libraries`. + - Kext déployé sur l'EFI (`/Volumes/EFI/EFI/OC/Kexts/QualcommWifi.kext`). + - Configuration OpenCore activée : `qcom_step=8 qcom_substep=5`. +