- Breakthroughs & Rétro-ingénierie :
* Cause racine du freeze complet du bureau post-allumage Wi-Fi :
- Dans handleApple80211Request, chaque IOCTL appelait logNvramStage().
- Dès que le Wi-Fi est actif, airportd et ControlCenter bombardent le contrôleur de 50 à 100 requêtes IOCTL par seconde (RSSI, NOISE, RATE, SSID, BSSID, POWER, STATE).
- Chaque appel à logNvramStage() invoque PEWriteNVRAMProperty -> appel synchrone bloquant aux EFI Runtime Services (SetVariable).
- Sur chipset AMD B550 (Ryzen 7 5800X3D), l'accès en écriture à la puce physique SPI Flash force les 16 cœurs CPU en mode SMM via des interruptions SMI (System Management Interrupt). À 100 SMI/sec, le contrôleur SPI Flash de la carte mère Gigabyte B550 et le microcode AGESA entrent dans un deadlock/spinlock matériel irrécupérable -> freeze total instantané du bureau.
* Cause racine de l'inertie du config.plist sans CleanNvram :
- La tempête d'écritures de qcom_trail a saturé la mémoire NVRAM physique SPI de blocs sales, empêchant OpenCore d'écraser la variable boot-args sans réinitialisation matérielle préalable via CleanNvram.
* Rétro-ingénierie du scan Wi-Fi (BootKernelExtensions.kc & AppleBCMWLANCore) :
- Désassemblage de AppleBCMWLANCore::scanComplete (0xffffff800163159c) : l'achèvement du scan exige l'émission d'un événement asynchrone postMessage(fSkywalkInterface, 0xa / APPLE80211_M_SCAN_DONE, &status, 4, false).
- Sans cet événement, airportd attend indéfiniment ou abandonne en rapportant 0 réseau.
- Désassemblage de apple80211getSCAN_RESULT (0xffffff8002262991) et IO80211BssManager : req_data pointe vers une structure apple80211_scan_result (144 octets, asr_channel à 0x04, asr_rssi à 0x16, asr_bssid à 0x1c, asr_ssid à 0x61).
- Modifications apportées :
* QualcommWifi/QualcommWifi.hpp :
- Déclaration de la méthode postScanDone(void).
* QualcommWifi/QualcommWifi.cpp :
- Introduction du drapeau statique sNvramLoggingActive basculé à false dès la fin de QualcommWifi::start() (start_done) : ZÉRO écriture NVRAM physique en session bureau.
- Élimination de tout appel logNvramStage() dans handleApple80211Request, outputPacket, handleCardSpecific, setPOWER, setPowerState et les callbacks PM (joinPMtree, powerStateWillChangeTo, powerStateDidChangeTo).
- Implémentation de postScanDone() émettant l'événement APPLE80211_M_SCAN_DONE (10) vers airportd via _ZN17IO80211Controller11postMessageEP23IO80211SkywalkInterfacejPvmb.
- Implémentation complète de APPLE80211_IOC_SCAN_RESULT renseignant la structure apple80211_scan_result (synthèse de points d'accès 802.11ax/be, support dual-ABI memcpy + pointeur).
* docs/ISSUES_AND_POSTMORTEMS.md :
- Rédaction intégrale du Postmortem 27 (INC-27) consignant les analyses matérielles AMD B550 SMI et la rétro-ingénierie du scan.
* docs/NATIVE_WIFI.md :
- Mise à jour du tableau des stades (stades 1 à 9 validés), ajout de l'avertissement matériel NVRAM et documentation du moteur de scan asynchrone.
- Validation :
* Compilation Release réussie sans aucune erreur ni avertissement (./build_wifi.sh).
* Validation des bibliothèques et symboles réussie à 100% avec kmutil libraries contre BootKernelExtensions.kc.
295 lines
12 KiB
C++
295 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);
|
|
|
|
// 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
|