332 lines
10 KiB
C++
Executable File
332 lines
10 KiB
C++
Executable File
//
|
|
// kern_iokit.hpp
|
|
// Lilu
|
|
//
|
|
// Copyright © 2016-2017 vit9696. All rights reserved.
|
|
//
|
|
|
|
#ifndef kern_iokit_hpp
|
|
#define kern_iokit_hpp
|
|
|
|
#include <Headers/kern_config.hpp>
|
|
#include <Headers/kern_util.hpp>
|
|
#include <Headers/kern_patcher.hpp>
|
|
|
|
#include <libkern/c++/OSSerialize.h>
|
|
#include <IOKit/IORegistryEntry.h>
|
|
|
|
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 <typename T>
|
|
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<const T *>(data->getBytesNoCopy());
|
|
DBGLOG("iokit", "getOSData %s has %llX value", name, static_cast<uint64_t>(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 <typename AS, typename T>
|
|
inline bool getOSDataValue(const OSObject *obj, const char *name, T &value) {
|
|
AS tmp;
|
|
if (getOSDataValue(obj, name, tmp)) {
|
|
value = static_cast<T>(tmp);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Read typed OSData from IORegistryEntry
|
|
*
|
|
* @see getOSDataValue
|
|
*/
|
|
template <typename T>
|
|
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 <typename AS, typename T>
|
|
inline bool getOSDataValue(const IORegistryEntry *sect, const char *name, T &value) {
|
|
return getOSDataValue<AS>(sect->getProperty(name), name, value);
|
|
}
|
|
|
|
/**
|
|
* Read typed OSData from IORegistryEntry
|
|
*
|
|
* @see getOSDataValue
|
|
*/
|
|
template <typename T>
|
|
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 <typename AS, typename T>
|
|
inline bool getOSDataValue(const OSDictionary *dict, const char *name, T &value) {
|
|
return getOSDataValue<AS>(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 */
|