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`.
+