#include <DriverKit/DriverKit.h>
#include <PCIDriverKit/IOPCIDevice.h>
#include <PCIDriverkit/IOPCIFamilyDefinitions.h>
#include <PCIDriverKit/PCIDriverKitPrivate.h>
#define debugLog(fmt, args...) os_log(OS_LOG_DEFAULT, "IOPCIDevice::%s: " fmt, __FUNCTION__,##args)
struct IOPCIDevice_IVars
{
IOMemoryMap** deviceMemoryMappings;
IOService* deviceClient;
uint32_t numDeviceMemoryMappings;
};
bool
IOPCIDevice::init()
{
if(super::init() != true)
{
return false;
}
ivars = IONewZero(IOPCIDevice_IVars, 1);
if(ivars == NULL)
{
return false;
}
return true;
}
void
IOPCIDevice::free()
{
IOSafeDeleteNULL(ivars, IOPCIDevice_IVars, 1);
super::free();
}
kern_return_t
IOPCIDevice::Open(IOService* forClient,
IOOptionBits options)
{
kern_return_t result;
if((result = _ManageSession(forClient, true, options)) == kIOReturnSuccess)
{
ivars->deviceClient = forClient;
ivars->deviceClient->retain();
OSContainer* deviceMemoryContainer = NULL;
if(SearchProperty(kIOPCIDeviceMemoryArrayKey, "IOService", 0, &deviceMemoryContainer) == kIOReturnSuccess)
{
OSArray* deviceMemoryArray = OSDynamicCast(OSArray, deviceMemoryContainer);
if(deviceMemoryArray != NULL)
{
ivars->numDeviceMemoryMappings = deviceMemoryArray->getCount();
ivars->deviceMemoryMappings = reinterpret_cast<IOMemoryMap**>(IOMallocZero(sizeof(IOMemoryMap*) * ivars->numDeviceMemoryMappings));
for(uint32_t memoryIndex = 0; memoryIndex < ivars->numDeviceMemoryMappings; memoryIndex++)
{
IOMemoryDescriptor* deviceMemoryDescriptor = NULL;
if(_CopyDeviceMemoryWithIndex(memoryIndex, &deviceMemoryDescriptor, ivars->deviceClient) == kIOReturnSuccess)
{
if(deviceMemoryDescriptor != NULL)
{
deviceMemoryDescriptor->CreateMapping(0, 0, 0, 0, 0, &(ivars->deviceMemoryMappings[memoryIndex]));
if(ivars->deviceMemoryMappings[memoryIndex] == NULL)
{
result = kIOReturnNoMemory;
break;
}
}
}
OSSafeReleaseNULL(deviceMemoryDescriptor);
}
}
OSSafeReleaseNULL(deviceMemoryContainer);
}
}
return result;
}
void
IOPCIDevice::Close(IOService* forClient,
IOOptionBits options)
{
if(ivars->deviceClient == forClient)
{
_ManageSession(ivars->deviceClient, false, options);
if(ivars->deviceMemoryMappings != NULL)
{
for(uint8_t i = 0; i < ivars->numDeviceMemoryMappings; i++)
{
OSSafeReleaseNULL(ivars->deviceMemoryMappings[i]);
}
IOFree(ivars->deviceMemoryMappings, sizeof(IOMemoryMap*) * ivars->numDeviceMemoryMappings);
ivars->numDeviceMemoryMappings = 0;
}
OSSafeReleaseNULL(ivars->deviceClient);
}
}
#pragma mark Memory Accessors
void
IOPCIDevice::ConfigurationRead32(uint64_t offset, uint32_t* readData)
{
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationConfigurationRead | kPCIDriverKitMemoryAccessOperation32Bit,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint32_t>(bounceData);
}
}
void
IOPCIDevice::ConfigurationRead16(uint64_t offset, uint16_t* readData)
{
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationConfigurationRead | kPCIDriverKitMemoryAccessOperation16Bit,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint16_t>(bounceData);
}
}
void
IOPCIDevice::ConfigurationRead8(uint64_t offset, uint8_t* readData)
{
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationConfigurationRead | kPCIDriverKitMemoryAccessOperation8Bit,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint8_t>(bounceData);
}
}
void
IOPCIDevice::ConfigurationWrite32(uint64_t offset,
uint32_t data)
{
_MemoryAccess(kPCIDriverKitMemoryAccessOperationConfigurationWrite | kPCIDriverKitMemoryAccessOperation32Bit,
offset,
data,
NULL,
ivars->deviceClient,
0);
}
void
IOPCIDevice::ConfigurationWrite16(uint64_t offset,
uint16_t data)
{
_MemoryAccess(kPCIDriverKitMemoryAccessOperationConfigurationWrite | kPCIDriverKitMemoryAccessOperation16Bit,
offset,
data,
NULL,
ivars->deviceClient,
0);
}
void
IOPCIDevice::ConfigurationWrite8(uint64_t offset,
uint8_t data)
{
_MemoryAccess(kPCIDriverKitMemoryAccessOperationConfigurationWrite | kPCIDriverKitMemoryAccessOperation8Bit,
offset,
data,
NULL,
ivars->deviceClient,
0);
}
void
IOPCIDevice::MemoryRead64(uint8_t memoryIndex,
uint64_t offset,
uint64_t* readData)
{
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
*readData = *reinterpret_cast<volatile uint64_t*>(deviceMemory->GetAddress() + offset);
#else
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationDeviceRead | kPCIDriverKitMemoryAccessOperation64Bit,
offset,
0,
readData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
#endif
}
void
IOPCIDevice::MemoryRead32(uint8_t memoryIndex,
uint64_t offset,
uint32_t* readData)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
if( (deviceMemory == NULL)
&& (memoryIndex < ivars->numDeviceMemoryMappings))
{
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationIORead | kPCIDriverKitMemoryAccessOperation32Bit | memoryIndex,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint32_t>(bounceData);
}
}
else
{
*readData = *reinterpret_cast<volatile uint32_t*>(deviceMemory->GetAddress() + offset);
}
#else
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationDeviceRead | kPCIDriverKitMemoryAccessOperation32Bit,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint32_t>(bounceData);
}
#endif
}
void
IOPCIDevice::MemoryRead16(uint8_t memoryIndex,
uint64_t offset,
uint16_t* readData)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
if( (deviceMemory == NULL)
&& (memoryIndex < ivars->numDeviceMemoryMappings))
{
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationIORead | kPCIDriverKitMemoryAccessOperation16Bit | memoryIndex,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint16_t>(bounceData);
}
}
else
{
*readData = *reinterpret_cast<volatile uint16_t*>(deviceMemory->GetAddress() + offset);
}
#else
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationDeviceRead | kPCIDriverKitMemoryAccessOperation16Bit,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint16_t>(bounceData);
}
#endif
}
void
IOPCIDevice::MemoryRead8(uint8_t memoryIndex,
uint64_t offset,
uint8_t* readData)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
if( (deviceMemory == NULL)
&& (memoryIndex < ivars->numDeviceMemoryMappings))
{
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationIORead | kPCIDriverKitMemoryAccessOperation8Bit | memoryIndex,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint8_t>(bounceData);
}
}
else
{
*readData = *reinterpret_cast<volatile uint8_t*>(deviceMemory->GetAddress() + offset);
}
#else
uint64_t bounceData;
if(_MemoryAccess(kPCIDriverKitMemoryAccessOperationDeviceRead | kPCIDriverKitMemoryAccessOperation8Bit,
offset,
0,
&bounceData,
ivars->deviceClient,
0) != kIOReturnSuccess)
{
*readData = -1;
}
else
{
*readData = static_cast<uint8_t>(bounceData);
}
#endif
}
void
IOPCIDevice::MemoryWrite64(uint8_t memoryIndex,
uint64_t offset,
uint64_t data)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
volatile uint64_t* memoryAddress = reinterpret_cast<volatile uint64_t*>(deviceMemory->GetAddress() + offset);
*memoryAddress = data;
}
void
IOPCIDevice::MemoryWrite32(uint8_t memoryIndex,
uint64_t offset,
uint32_t data)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
if( (deviceMemory == NULL)
&& (memoryIndex < ivars->numDeviceMemoryMappings))
{
_MemoryAccess(kPCIDriverKitMemoryAccessOperationIOWrite | kPCIDriverKitMemoryAccessOperation32Bit | memoryIndex,
offset,
data,
NULL,
ivars->deviceClient,
0);
}
else
#endif
{
volatile uint32_t* memoryAddress = reinterpret_cast<volatile uint32_t*>(deviceMemory->GetAddress() + offset);
*memoryAddress = data;
}
}
void
IOPCIDevice::MemoryWrite16(uint8_t memoryIndex,
uint64_t offset,
uint16_t data)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
if( (deviceMemory == NULL)
&& (memoryIndex < ivars->numDeviceMemoryMappings))
{
_MemoryAccess(kPCIDriverKitMemoryAccessOperationIOWrite | kPCIDriverKitMemoryAccessOperation16Bit | memoryIndex,
offset,
data,
NULL,
ivars->deviceClient,
0);
}
else
#endif
{
volatile uint16_t* memoryAddress = reinterpret_cast<volatile uint16_t*>(deviceMemory->GetAddress() + offset);
*memoryAddress = data;
}
}
void
IOPCIDevice::MemoryWrite8(uint8_t memoryIndex,
uint64_t offset,
uint8_t data)
{
IOMemoryMap* deviceMemory = ivars->deviceMemoryMappings[memoryIndex];
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
if( (deviceMemory == NULL)
&& (memoryIndex < ivars->numDeviceMemoryMappings))
{
_MemoryAccess(kPCIDriverKitMemoryAccessOperationIOWrite | kPCIDriverKitMemoryAccessOperation8Bit | memoryIndex,
offset,
data,
NULL,
ivars->deviceClient,
0);
}
else
#endif
{
volatile uint8_t* memoryAddress = reinterpret_cast<volatile uint8_t*>(deviceMemory->GetAddress() + offset);
*memoryAddress = data;
}
}