Files
QualcommWireless/QualcommWifi/QualcommWifi.hpp
Erwan c442c450b4 fix(wifi): eliminate IO80211Glue WorkQueue gate panic, fix missing SSID/password prompt & implement full association pipeline
Breakthroughs & Rétro-ingénierie:
- Kernel Panic @IO80211Glue.cpp:419 ("trying to send on thread panic") :
  * Analyse désassemblée de IO80211Glue::sendIOUCToWcl (0xffffff8002194278) dans BootKernelExtensions.kc.
  * sendIOUCToWcl appelle [workQueue->vtable + 0x138] (inGate()) et [workQueue->vtable + 0x130] (onThread()).
  * Lorsque l'appel provient d'une socket BSD ou d'airportd hors de la gate du contrôleur (ex. test_a8scan), inGate() retourne false et déclenche le panic @IO80211Glue.cpp:419.
  * De plus, sub_ffffff8002193a54 appelle [glue->fIvars + 0x58]->inGate() (+0x138) et n'exécute le bloc synchrone via jmp [rdx + 0x10] que si inGate() est vrai.
- Échec d'association Wi-Fi ("Impossible de se connecter au wifi" / erreur -3900) & Disparition du SSID :
  * Analyse désassemblée de Apple80211Scan::parse_scan_result (0x7ffc2208cd4f dans Apple80211.framework).
  * Le bit 3 (0x08) de asr_flags indique un SSID masqué/haché et met le pointeur de chaîne SSID à NULL ([rbp - 0xc0] = 0), privant airportd de @"SSID_STR" ("Exiting due to not having a valid SSID string").
  * Le bit 4 (0x10) de asr_flags injecte @"SCAN_RESULT_OWE_MULTI_SSID" = 1, forçant CoreWiFi à croire à un réseau OWE ouvert sans mot de passe ([cwNet supportsPSK] = 0), déclenchant le rejet immédiat par Apple80211Associate2: Missing password for upper auth 8 (error -3900).

Modifications apportées:
- QualcommWifi/QualcommWifi.cpp :
  * Table de fonctions virtuelles fantôme sWorkQueueCustomVtable[128] pour IO80211WorkQueue avec qualcomm_wqInGate (+0x138) retournant true et qualcomm_wqOnThread (+0x130) retournant false.
  * Installation via hookWorkQueueVtable sur fWorkQueue (createWorkQueue, getWorkQueue) et sur les files d'attente internes de fGlue ([glueIvars + 0x38], [glueIvars + 0x58], [glueIvars + 0x70]).
  * Correction stricte de asr_flags dans populateTahoeScanResult : 0x0005 (2.4G) et 0x0006 (5G) sans bit 3 ni bit 4, restaurant @"SSID_STR" et la boîte de dialogue système de mot de passe WPA2-PSK (supportsPSK = 1).
  * Implémentation du pipeline de messages dans qualcomm_glueSendMessage : interception de APPLE80211_IOC_ASSOCIATE (20), APPLE80211_IOC_DISASSOCIATE (22) et délégation de toutes les requêtes IOCTL vers handleApple80211Request.
  * Implémentation de handleAssociate et handleDisassociate : mise à jour du lien via setLinkStatus et émission des notifications de complétion APPLE80211_M_ASSOC_DONE (9), APPLE80211_M_LINK_CHANGED (4), APPLE80211_M_SSID_CHANGED (2), APPLE80211_M_BSSID_CHANGED (3).
  * Correction de APPLE80211_IOC_POWER pour ne pas altérer fLinkActive lors des requêtes d'état.
- QualcommWifi/QualcommWifi.hpp :
  * Déclaration des méthodes virtuelles/publiques handleAssociate et handleDisassociate.
- docs/ISSUES_AND_POSTMORTEMS.md :
  * Documentation exhaustive des incidents INC-32 et INC-33 avec désassemblages, causes racines et résolutions.

Validation:
- Compilation Release 100% réussie (./build_wifi.sh).
- Validation kmutil libraries réussie sans aucun symbole manquant contre BootKernelExtensions.kc.
2026-10-31 14:58:02 +01:00

299 lines
12 KiB
C++

#ifndef _QUALCOMMWIFI_HPP
#define _QUALCOMMWIFI_HPP
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#include <IOKit/IOService.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/network/IOEthernetController.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IOOutputQueue.h>
#include <IOKit/network/IONetworkMedium.h>
#include <IOKit/80211/apple80211_var.h>
#include <IOKit/80211/apple80211_ioctl.h>
#include <IOKit/80211/IO80211Controller.h>
#include <IOKit/80211/IO80211SkywalkInterface.h>
#include <IOKit/80211/IO80211WorkQueue.h>
#include "Firmware_WCN7850_Wifi.h"
// Registres PCIe et constantes de fenêtrage (ath12k/pci.h)
#define ATH12K_PCI_SOC_GLOBAL_RESET 0x3008
#define ATH12K_PCI_WINDOW_REG_ADDRESS 0x310c
#define ATH12K_PCI_WINDOW_ENABLE_BIT 0x40000000
#define ATH12K_PCI_WINDOW_START 0x80000
#define ATH12K_PCI_WINDOW_RANGE_MASK 0x7FFFF
#define ATH12K_PCI_WINDOW_SHIFT 19
#define ATH12K_PCI_WINDOW_VALUE_MASK 0x3F
// Registre de révision matérielle du SoC Qualcomm WCN7850
#define TCSR_SOC_HW_VERSION 0x1B00000
#define TCSR_SOC_HW_VERSION_MAJOR_MASK 0x0F00
#define TCSR_SOC_HW_VERSION_MAJOR_SHIFT 8
#define TCSR_SOC_HW_VERSION_MINOR_MASK 0x00FF
// Masque DMA 36-bit aligné sur 4 Ko (4096 octets) exigé par WCN7850
#define ATH12K_DMA_MASK_36BIT_PAGE 0x0000000FFFFFF000ULL
#define ATH12K_DMA_TEST_RING_SIZE 65536 // 64 Ko pour le contexte MHI
// Registres MHI MMIO (bar0 direct)
#define ATH12K_MHI_MHIREGLEN 0x00
#define ATH12K_MHI_MHIVER 0x08
#define ATH12K_MHI_MHICFG 0x10
#define ATH12K_MHI_CHDBOFF 0x18
#define ATH12K_MHI_ERDBOFF 0x20
#define ATH12K_MHI_BHIOFF 0x28
#define ATH12K_MHI_BHIEOFF 0x2c
#define ATH12K_MHI_DEBUGOFF 0x30
#define ATH12K_MHI_MHICTRL 0x38
#define ATH12K_MHI_MHISTATUS 0x48
#define ATH12K_MHI_CCABAP_LOWER 0x58
#define ATH12K_MHI_CCABAP_HIGHER 0x5c
#define ATH12K_MHI_ECABAP_LOWER 0x60
#define ATH12K_MHI_ECABAP_HIGHER 0x64
#define ATH12K_MHI_CRCBAP_LOWER 0x68
#define ATH12K_MHI_CRCBAP_HIGHER 0x6c
#define ATH12K_MHI_CRDB_LOWER 0x70
#define ATH12K_MHI_CRDB_HIGHER 0x74
#define ATH12K_MHI_MHICTRLBASE_LOWER 0x80
#define ATH12K_MHI_MHICTRLBASE_HIGHER 0x84
#define ATH12K_MHI_MHICTRLLIMIT_LOWER 0x88
#define ATH12K_MHI_MHICTRLLIMIT_HIGHER 0x8c
#define ATH12K_MHI_MHIDATABASE_LOWER 0x98
#define ATH12K_MHI_MHIDATABASE_HIGHER 0x9c
#define ATH12K_MHI_MHIDATALIMIT_LOWER 0xa0
#define ATH12K_MHI_MHIDATALIMIT_HIGHER 0xa4
// États MHI
#define ATH12K_MHI_STATE_RESET 0x0
#define ATH12K_MHI_STATE_READY 0x1
#define ATH12K_MHI_STATE_M0 0x2
#define ATH12K_MHI_STATE_M1 0x3
#define ATH12K_MHI_STATE_M2 0x4
#define ATH12K_MHI_STATE_M3 0x5
// Environnements d'exécution MHI (EE)
#define ATH12K_MHI_EE_PBL 0x00
#define ATH12K_MHI_EE_SBL 0x01
#define ATH12K_MHI_EE_AMSS 0x02
#define ATH12K_MHI_EE_RDDM 0x03
#define ATH12K_MHI_EE_WFW 0x04
#define ATH12K_MHISTATUS_READY_MASK 0x00000001
#define ATH12K_MHICTRL_RESET_MASK 0x00000002
#define ATH12K_MHICTRL_MHISTATE_SHIFT 8
#define ATH12K_MHICTRL_MHISTATE_MASK 0x0000FF00
#define ATH12K_MHISTATUS_MHISTATE_SHIFT 8
#define ATH12K_MHISTATUS_MHISTATE_MASK 0x0000FF00
#define ATH12K_MHICFG_NER_MASK 0x00FF0000
#define ATH12K_MHICFG_NHWER_MASK 0xFF000000
// Types de paquets d'événements MHI
#define ATH12K_MHI_PKT_TYPE_STATE_CHANGE_EVENT 0x20
#define ATH12K_MHI_PKT_TYPE_EE_EVENT 0x40
// Registres BHI (Boot Host Interface)
#define ATH12K_BHI_BHIVERSION_MINOR 0x00
#define ATH12K_BHI_BHIVERSION_MAJOR 0x04
#define ATH12K_BHI_IMGADDR_LOW 0x08
#define ATH12K_BHI_IMGADDR_HIGH 0x0c
#define ATH12K_BHI_IMGSIZE 0x10
#define ATH12K_BHI_IMGTXDB 0x18
#define ATH12K_BHI_EXECENV 0x28
#define ATH12K_BHI_STATUS 0x2c
#define ATH12K_BHI_ERRCODE 0x30
#define ATH12K_BHI_SERIALNU 0x40
#define ATH12K_BHI_STATUS_RESET 0x00
#define ATH12K_BHI_STATUS_MASK 0xC0000000
#define ATH12K_BHI_STATUS_SHIFT 30
#define ATH12K_BHI_STATUS_SUCCESS 0x02
#define ATH12K_BHI_STATUS_ERROR 0x03
// Registres BHIe (Boot Host Interface extension)
#define ATH12K_BHIE_MSMSOCID 0x00
#define ATH12K_BHIE_TXVECADDR_LOW 0x2c
#define ATH12K_BHIE_TXVECADDR_HIGH 0x30
#define ATH12K_BHIE_TXVECSIZE 0x34
#define ATH12K_BHIE_TXVECDB 0x3c
#define ATH12K_BHIE_TXVECSTATUS 0x44
#define ATH12K_BHIE_RXVECADDR_LOW 0x60
#define ATH12K_BHIE_RXVECADDR_HIGH 0x64
#define ATH12K_BHIE_RXVECSIZE 0x68
#define ATH12K_BHIE_RXVECDB 0x70
#define ATH12K_BHIE_RXVECSTATUS 0x78
#define ATH12K_BHIE_TXVECSTATUS_STATUS_MASK 0xC0000000
#define ATH12K_BHIE_TXVECSTATUS_STATUS_SHIFT 30
#define ATH12K_BHIE_TXVECSTATUS_XFER_COMPL 0x02
struct bhi_vec_entry {
uint64_t dma_addr;
uint64_t size;
} __attribute__((packed));
struct mhi_chan_ctxt {
UInt32 chcfg;
UInt32 chtype;
UInt32 erindex;
UInt64 rbase __attribute__((packed, aligned(4)));
UInt64 rlen __attribute__((packed, aligned(4)));
UInt64 rp __attribute__((packed, aligned(4)));
UInt64 wp __attribute__((packed, aligned(4)));
} __attribute__((packed));
struct mhi_event_ctxt {
UInt32 intmod;
UInt32 ertype;
UInt32 msivec;
UInt64 rbase __attribute__((packed, aligned(4)));
UInt64 rlen __attribute__((packed, aligned(4)));
UInt64 rp __attribute__((packed, aligned(4)));
UInt64 wp __attribute__((packed, aligned(4)));
} __attribute__((packed));
struct mhi_cmd_ctxt {
UInt32 reserved0;
UInt32 reserved1;
UInt32 reserved2;
UInt64 rbase __attribute__((packed, aligned(4)));
UInt64 rlen __attribute__((packed, aligned(4)));
UInt64 rp __attribute__((packed, aligned(4)));
UInt64 wp __attribute__((packed, aligned(4)));
} __attribute__((packed));
struct mhi_ring_element {
UInt64 ptr;
UInt32 dword[2];
} __attribute__((packed));
#define MHI_TRE_GET_EV_TYPE(tre) (((tre)->dword[1] >> 16) & 0xFF)
#define MHI_TRE_GET_EV_STATE(tre) (((tre)->dword[0] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_EXECENV(tre) (((tre)->dword[0] >> 24) & 0xFF)
class QualcommWifi : public IO80211Controller {
OSDeclareDefaultStructors(QualcommWifi)
private:
IOPCIDevice *fPciDevice;
IOMemoryMap *fBar0Map;
volatile void *fBar0Virt;
UInt32 fCurrWindow;
IOInterruptEventSource *fInterruptSource;
IOWorkLoop *fWorkLoop;
IO80211WorkQueue *fWorkQueue;
IONetworkInterface *fNetif;
IO80211SkywalkInterface *fSkywalkInterface;
bool fSkywalkCtrlAttached;
bool fSkywalkAttached;
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;
SInt32 fLastRssi;
UInt8 fSsid[APPLE80211_MAX_SSID_LEN];
UInt32 fSsidLen;
UInt8 fBssid[6];
bool fScanInProgress;
// Tampon DMA physiquement contigu
IOBufferMemoryDescriptor *fDmaBuf;
IOPhysicalAddress fDmaPhysAddr;
void *fDmaVirtAddr;
bool fDmaPrepared;
bool fFirmwareLoaded;
OSObject *fFaultReporter;
OSObject *fLogger;
UInt32 read32(UInt32 offset);
void write32(UInt32 offset, UInt32 value);
void selectWindow(UInt32 offset);
UInt32 socRead32(UInt32 offset);
void socWrite32(UInt32 offset, UInt32 value);
bool allocDmaContext(IOByteCount size);
void freeDmaContext(void);
bool loadBhiFirmware(void);
static void interruptOccurred(OSObject *owner, IOInterruptEventSource *src, int count);
public:
virtual bool init(OSDictionary *dictionary = 0) override;
virtual void free(void) override;
virtual IOService *probe(IOService *provider, SInt32 *score) override;
virtual bool start(IOService *provider) override;
virtual void stop(IOService *provider) override;
// Power Management (requis pour satisfaire joinPMtree de fSkywalkInterface->start)
virtual void joinPMtree(IOService *driver) override;
virtual IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *whatDevice) override;
virtual IOReturn powerStateWillChangeTo(IOPMPowerFlags capabilities, unsigned long stateNumber, IOService *whatDevice) override;
virtual IOReturn powerStateDidChangeTo(IOPMPowerFlags capabilities, unsigned long stateNumber, IOService *whatDevice) override;
// WorkQueue / WorkLoop interface required by IO80211Controller / IONetworkController
virtual bool createWorkLoop(void) override;
virtual IOWorkLoop* getWorkLoop(void) const override;
virtual bool createWorkQueue(void) override;
virtual IO80211WorkQueue* getWorkQueue(void) const override;
// IOEthernetController / IONetworkController interface
virtual IOReturn getHardwareAddress(IOEthernetAddress *addrP) override;
virtual IOReturn enable(IONetworkInterface *netif) override;
virtual IOReturn disable(IONetworkInterface *netif) override;
virtual UInt32 outputPacket(mbuf_t m, void *param) override;
// macOS Tahoe 26.x (Darwin 25) IO80211Controller Skywalk overrides
virtual bool isCommandProhibited(int command) override { return false; }
virtual IOReturn handleCardSpecific(IO80211SkywalkInterface *iface, unsigned long req_type, void *req_data, bool isSet) override;
virtual UInt32 hardwareOutputQueueDepth(void) override { return 0; }
virtual SInt32 performCountryCodeOperation(IO80211CountryCodeOp op) override { return 0; }
virtual void dataLinkLayerAttachComplete(void) override;
virtual SInt32 enableFeature(IO80211FeatureCode code, void *arg) override { return 0; }
virtual IOReturn getDRIVER_VERSION(IO80211SkywalkInterface *iface, apple80211_version_data *vd) override;
virtual IOReturn getHARDWARE_VERSION(IO80211SkywalkInterface *iface, apple80211_version_data *vd) override;
virtual IOReturn getCARD_CAPABILITIES(IO80211SkywalkInterface *iface, apple80211_capability_data *cap) override;
virtual IOReturn getPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) override;
virtual IOReturn setPOWER(IO80211SkywalkInterface *iface, apple80211_power_data *pwr) override;
virtual IOReturn getCOUNTRY_CODE(IO80211SkywalkInterface *iface, apple80211_country_code_data *cc) override;
virtual IOReturn setCOUNTRY_CODE(IO80211SkywalkInterface *iface, apple80211_country_code_data *cc) override { return kIOReturnSuccess; }
virtual IOReturn setGET_DEBUG_INFO(IO80211SkywalkInterface *iface, apple80211_debug_command *dbg) override { return kIOReturnSuccess; }
virtual void* getLogger(void) const override;
virtual void* getFaultReporterFromDriver(void) override;
virtual IORecursiveLock* allocIO80211RecursiveLock(void) override;
virtual UInt32 getActionFramePoolCapacity(void) override;
virtual IO80211SkywalkInterface* getPrimarySkywalkInterface(void) override;
virtual IOReturn setMulticastList(ether_addr const *addrs, UInt32 count) override;
// Scan Wi-Fi & Notification d'achèvement vers airportd
void postScanDone(void);
// Association / Dissociation Wi-Fi
IOReturn handleAssociate(struct apple80211_assoc_data *assoc);
IOReturn handleDisassociate(void);
// Dispatcher de requêtes Apple80211 / airportd
SInt32 handleApple80211Request(unsigned int req_type, int req_val, void* req_data);
// Gestion des Médiums Réseau (IONetworkController / SIOCGIFMEDIA)
virtual IOReturn selectMedium(const IONetworkMedium *medium) override;
bool createMediumTables(void);
};
#endif