// // kern_iokit.hpp // Lilu // // Copyright © 2016-2017 vit9696. All rights reserved. // #ifndef kern_iokit_hpp #define kern_iokit_hpp #include #include #include #include #include namespace WIOKit { /** * AppleHDAEngine::getLocation teaches us to use loop infinitely when talking to IOReg * This feels mad and insane, since it may prevent the system from booting. * Although this had never happened, we will use a far bigger fail-safe stop value. */ static constexpr size_t bruteMax {40000000}; /** * Read typed OSData * * @param obj read object * @param value read value * @param name propert name * * @return true on success */ template inline bool getOSDataValue(const OSObject *obj, const char *name, T &value) { if (obj) { auto data = OSDynamicCast(OSData, obj); if (data && data->getLength() == sizeof(T)) { value = *static_cast(data->getBytesNoCopy()); DBGLOG("iokit", "getOSData %s has %llX value", name, static_cast(value)); return true; } else { SYSLOG("iokit", "getOSData %s has unexpected format", name); } } else { DBGLOG("iokit", "getOSData %s was not found", name); } return false; } /** * Read typed OSData through a temp type * * @param obj read object * @param value read value * @param name propert name * * @return true on success */ template inline bool getOSDataValue(const OSObject *obj, const char *name, T &value) { AS tmp; if (getOSDataValue(obj, name, tmp)) { value = static_cast(tmp); return true; } return false; } /** * Read typed OSData from IORegistryEntry * * @see getOSDataValue */ template inline bool getOSDataValue(const IORegistryEntry *sect, const char *name, T &value) { return getOSDataValue(sect->getProperty(name), name, value); } /** * Read typed OSData from IORegistryEntry * * @see getOSDataValue */ template inline bool getOSDataValue(const IORegistryEntry *sect, const char *name, T &value) { return getOSDataValue(sect->getProperty(name), name, value); } /** * Read typed OSData from IORegistryEntry * * @see getOSDataValue */ template inline bool getOSDataValue(const OSDictionary *dict, const char *name, T &value) { return getOSDataValue(dict->getObject(name), name, value); } /** * Read typed OSData from IORegistryEntry * * @see getOSDataValue */ template inline bool getOSDataValue(const OSDictionary *dict, const char *name, T &value) { return getOSDataValue(dict->getObject(name), name, value); } /** * Retrieve property object * * @param entry IORegistry entry * @param property property name * * @return property object (must be released) or nullptr */ EXPORT LIBKERN_RETURNS_RETAINED OSSerialize *getProperty(IORegistryEntry *entry, const char *property); /** * Model variants */ struct ComputerModel { enum { ComputerInvalid = 0x0, ComputerLaptop = 0x1, ComputerDesktop = 0x2, ComputerAny = ComputerLaptop | ComputerDesktop }; }; /** * PCI GPU Vendor identifiers */ struct VendorID { enum : uint16_t { ATIAMD = 0x1002, AMDZEN = 0x1022, NVIDIA = 0x10DE, Intel = 0x8086, VMware = 0x15AD, QEMU = 0x1B36, }; }; /** * PCI class codes */ struct ClassCode { enum : uint32_t { VGAController = 0x030000, // I have never seen this one, but laptops are evil. XGAController = 0x030100, // Some laptops use this for Optimus GPUs. Ex3DController = 0x030200, DisplayController = 0x038000, PCIBridge = 0x060400, // HDA device on some laptops like Acer Aspire VN7-592G (INSYDE). HDAMmDevice = 0x040100, // Watch out for PCISubclassMask, 0x040380 is common on laptops. HDADevice = 0x040300, // This does not seem to be documented. It works on Haswell at least. IMEI = 0x078000, // To ignore device subclasses. PCISubclassMask = 0xFFFF00, }; }; /** * Definitions of PCI Config Registers */ enum PCIRegister : uint8_t { kIOPCIConfigVendorID = 0x00, kIOPCIConfigDeviceID = 0x02, kIOPCIConfigCommand = 0x04, kIOPCIConfigStatus = 0x06, kIOPCIConfigRevisionID = 0x08, kIOPCIConfigClassCode = 0x09, kIOPCIConfigCacheLineSize = 0x0C, kIOPCIConfigLatencyTimer = 0x0D, kIOPCIConfigHeaderType = 0x0E, kIOPCIConfigBIST = 0x0F, kIOPCIConfigBaseAddress0 = 0x10, kIOPCIConfigBaseAddress1 = 0x14, kIOPCIConfigBaseAddress2 = 0x18, kIOPCIConfigBaseAddress3 = 0x1C, kIOPCIConfigBaseAddress4 = 0x20, kIOPCIConfigBaseAddress5 = 0x24, kIOPCIConfigCardBusCISPtr = 0x28, kIOPCIConfigSubSystemVendorID = 0x2C, kIOPCIConfigSubSystemID = 0x2E, kIOPCIConfigExpansionROMBase = 0x30, kIOPCIConfigCapabilitiesPtr = 0x34, kIOPCIConfigInterruptLine = 0x3C, kIOPCIConfigInterruptPin = 0x3D, kIOPCIConfigMinimumGrant = 0x3E, kIOPCIConfigMaximumLatency = 0x3F, kIOPCIConfigGraphicsControl = 0x50 }; /** * Fixed offsets for PCI Config I/O virtual methods */ struct PCIConfigOffset { enum : size_t { ConfigRead32 = 0x10A, ConfigWrite32 = 0x10B, ConfigRead16 = 0x10C, ConfigWrite16 = 0x10D, ConfigRead8 = 0x10E, ConfigWrite8 = 0x10F, GetBusNumber = 0x11D, GetDeviceNumber = 0x11E, GetFunctionNumber = 0x11F }; }; /** * PCI Config I/O method prototypes */ using t_PCIConfigRead32 = uint32_t (*)(IORegistryEntry *service, uint32_t space, uint8_t offset); using t_PCIConfigRead16 = uint16_t (*)(IORegistryEntry *service, uint32_t space, uint8_t offset); using t_PCIConfigRead8 = uint8_t (*)(IORegistryEntry *service, uint32_t space, uint8_t offset); using t_PCIConfigWrite32 = void (*)(IORegistryEntry *service, uint32_t space, uint8_t offset, uint32_t data); using t_PCIConfigWrite16 = void (*)(IORegistryEntry *service, uint32_t space, uint8_t offset, uint16_t data); using t_PCIConfigWrite8 = void (*)(IORegistryEntry *service, uint32_t space, uint8_t offset, uint8_t data); using t_PCIGetBusNumber = uint8_t (*)(IORegistryEntry *service); using t_PCIGetDeviceNumber = uint8_t (*)(IORegistryEntry *service); using t_PCIGetFunctionNumber = uint8_t (*)(IORegistryEntry *service); /** * Await for device publishing in IOService plane * * @param obj wait for (PCI) object publishing * * @retval true on success */ EXPORT bool awaitPublishing(IORegistryEntry *obj); /** * Read PCI Config register * * @param service IOPCIDevice-compatible service. * @param reg PCI config register * @param space adress space * @param size read size for reading custom registers * * @return value read */ EXPORT uint32_t readPCIConfigValue(IORegistryEntry *service, uint32_t reg, uint32_t space = 0, uint32_t size = 0); /** * Retrieve PCI device address * * @param service IOPCIDevice-compatible service. * @param bus bus address * @param device device address * @param function function address */ EXPORT void getDeviceAddress(IORegistryEntry *service, uint8_t &bus, uint8_t &device, uint8_t &function); /** * Retrieve the computer type * * @return valid computer type or ComputerAny */ EXPORT int getComputerModel() DEPRECATE("Use BaseDeviceInfo"); /** * Retrieve computer model and/or board-id properties * * @param model model name output buffer or null * @param modelsz model name output buffer size * @param board board identifier output buffer or null * @param boardsz board identifier output buffer size * * @return true if relevant properties already are available, otherwise buffers are unchanged */ EXPORT bool getComputerInfo(char *model, size_t modelsz, char *board, size_t boardsz) DEPRECATE("Use BaseDeviceInfo"); /** * Retrieve an ioreg entry by path/prefix * * @param path an exact lookup path * @param prefix entry prefix at path * @param plane plane to lookup in * @param proc process every found entry with the method * @param brute kick ioreg until a value is found * @param user pass some value to the callback function * * @return entry pointer (must NOT be released) or nullptr (on failure or in proc mode) */ EXPORT LIBKERN_RETURNS_NOT_RETAINED IORegistryEntry *findEntryByPrefix(const char *path, const char *prefix, const IORegistryPlane *plane, bool (*proc)(void *, IORegistryEntry *)=nullptr, bool brute=false, void *user=nullptr); /** * Retrieve an ioreg entry by path/prefix * * @param entry an ioreg entry to look in * @param prefix entry prefix at path * @param plane plane to lookup in * @param proc process every found entry with the method * @param brute kick ioreg until a value is found * @param user pass some value to the callback function * * @return entry pointer (must NOT be released) or nullptr (on failure or in proc mode) */ EXPORT LIBKERN_RETURNS_NOT_RETAINED IORegistryEntry *findEntryByPrefix(IORegistryEntry *entry, const char *prefix, const IORegistryPlane *plane, bool (*proc)(void *, IORegistryEntry *)=nullptr, bool brute=false, void *user=nullptr); /** * Check if we are using prelinked kernel/kexts or not * * @return true when confirmed that we definitely are */ EXPORT bool usingPrelinkedCache(); /** * Properly rename the device * * @param entry device to rename * @param name new name * @param compat correct compatible * * @return true on success */ EXPORT bool renameDevice(IORegistryEntry *entry, const char *name, bool compat=true); } #endif /* kern_iokit_hpp */