Introduce IORegistryEntry, work on supporting a plane-based hierarchy

This commit is contained in:
Lubos Dolezel 2020-02-11 22:18:13 +01:00
parent 31fe24a002
commit cf97f7a4ba
12 changed files with 304 additions and 99 deletions

View File

@ -24,14 +24,17 @@ include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src/external/libcxx/include ${CMA
mig(iokitmig.defs)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
set(iokitd_sources
src/main.mm
src/stubs.c
src/iokitd.cpp
src/Registry.mm
src/ServiceRegistry.mm
src/IOObject.cpp
src/IOIterator.cpp
src/IOService.mm
src/IORegistryEntry.mm
src/IODisplayConnect.mm
src/IODisplayConnectX11.mm
${CMAKE_CURRENT_BINARY_DIR}/iokitmigServer.c

View File

@ -1,7 +1,7 @@
#ifndef IOKITD_IODISPLAYCONNECTX11_H
#define IOKITD_IODISPLAYCONNECTX11_H
#include "IODisplayConnect.h"
#include "Registry.h"
#include "ServiceRegistry.h"
#include <vector>
#include <X11/Xlib.h>
#import <Foundation/NSData.h>
@ -13,13 +13,15 @@ private:
IODisplayConnectX11(int index, NSDictionary* props);
public:
~IODisplayConnectX11();
static void discoverDevices(Registry* targetRegistry);
static void discoverDevices(ServiceRegistry* targetRegistry);
NSDictionary* getProperties() override;
private:
static Display* m_display;
// Index of the corresponding XrandR output
int m_index;
NSDictionary* m_props;
static IORegistryEntry* m_root;
};
#endif

View File

@ -3,9 +3,11 @@
#include <X11/extensions/Xrandr.h>
#include <IOKit/graphics/IOGraphicsTypes.h>
#include <CoreFoundation/CFByteOrder.h>
#include <dispatch/dispatch.h>
#include <cstdio>
Display* IODisplayConnectX11::m_display;
IORegistryEntry* IODisplayConnectX11::m_root;
IODisplayConnectX11::IODisplayConnectX11(int index, NSDictionary* props)
: m_index(index)
@ -18,8 +20,20 @@ IODisplayConnectX11::~IODisplayConnectX11()
[m_props release];
}
void IODisplayConnectX11::discoverDevices(Registry* targetRegistry)
NSDictionary* IODisplayConnectX11::getProperties()
{
return m_props;
}
void IODisplayConnectX11::discoverDevices(ServiceRegistry* targetServiceRegistry)
{
static dispatch_once_t once;
dispatch_once(&once, ^{
m_root = new IORegistryEntry;
m_root->registerInPlane(kIOServicePlane, "X11Display", IORegistryEntry::root());
});
if (!m_display)
{
m_display = XOpenDisplay(NULL);
@ -89,11 +103,18 @@ void IODisplayConnectX11::discoverDevices(Registry* targetRegistry)
[props setObject: [NSNumber numberWithInt: year]
forKey: @(kDisplayYearOfManufacture)];
}
else
{
[props setObject: [NSNumber numberWithInt: i+1]
forKey: @(kDisplaySerialNumber)];
}
XRRFreeCrtcInfo(crtc);
}
targetRegistry->registerService(new IODisplayConnectX11(i, props));
IODisplayConnectX11* ioDisplay = new IODisplayConnectX11(i, props);
targetServiceRegistry->registerService(ioDisplay);
ioDisplay->registerInPlane(kIOServicePlane, oinfo->name, m_root);
XRRFreeOutputInfo(oinfo);
}

View File

@ -1,6 +1,7 @@
#include "IOObject.h"
#include "iokitd.h"
#include <stdexcept>
#include <cstring>
#include <os/log.h>
#include <dispatch/private.h>
extern "C" {
@ -74,6 +75,11 @@ IOObject* IOObject::lookup(mach_port_t port)
return nullptr;
}
bool IOObject::conformsTo(const char* className)
{
return std::strcmp(className, this->className());
}
boolean_t IOObject::deathNotify(mach_msg_header_t *request, mach_msg_header_t *reply)
{
mach_no_senders_notification_t* Request = (mach_no_senders_notification_t*) request;
@ -106,3 +112,32 @@ boolean_t IOObject::deathNotify(mach_msg_header_t *request, mach_msg_header_t *r
return false;
}
}
kern_return_t is_io_object_get_class
(
mach_port_t object,
io_name_t className
)
{
IOObject* o = IOObject::lookup(object);
if (!o)
return KERN_INVALID_ARGUMENT;
strlcpy(className, o->className(), sizeof(io_name_t));
return KERN_SUCCESS;
}
kern_return_t is_io_object_conforms_to
(
mach_port_t object,
io_name_t className,
boolean_t *conforms
)
{
IOObject* o = IOObject::lookup(object);
if (!o)
return KERN_INVALID_ARGUMENT;
*conforms = o->conformsTo(className);
return KERN_SUCCESS;
}

View File

@ -12,6 +12,7 @@ public:
virtual ~IOObject();
virtual const char* className() const = 0;
virtual bool conformsTo(const char* className);
void retain();
void release();

31
src/IORegistryEntry.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef IOKIT_IOREGISTRYENTRY_H
#define IOKIT_IOREGISTRYENTRY_H
#include "IOObject.h"
#include <unordered_map>
#include <string>
#include <string_view>
#include <set>
#import <Foundation/NSDictionary.h>
class IORegistryEntry : public IOObject
{
public:
virtual NSDictionary* getProperties();
const char* className() const override;
std::string_view getPathName(const char* plane);
std::string getPath(const char* plane);
std::set<IORegistryEntry*> getParents(const char* plane);
std::set<IORegistryEntry*> getChildren(const char* plane);
static IORegistryEntry* root();
void registerInPlane(const char* plane, const char* pathName, IORegistryEntry* parent);
protected:
// The key is the plane name, e.g. kIOServicePlane (as declared in IOKit/IOKitKeys.h)
std::unordered_map<std::string_view, std::string> m_name;
std::unordered_map<std::string_view, std::set<IORegistryEntry*>> m_parents, m_children;
};
#endif

164
src/IORegistryEntry.mm Normal file
View File

@ -0,0 +1,164 @@
#include "IORegistryEntry.h"
#include <stack>
#include <IOCFSerialize.h>
#include <cstring>
extern "C" {
#include "iokitmigServer.h"
}
NSDictionary* IORegistryEntry::getProperties()
{
return @{};
}
const char* IORegistryEntry::className() const
{
return "IORegistryEntry";
}
std::string_view IORegistryEntry::getPathName(const char* plane)
{
auto it = m_name.find(plane);
if (it != m_name.end())
return it->second;
return "?";
}
std::set<IORegistryEntry*> IORegistryEntry::getParents(const char* plane)
{
auto it = m_parents.find(plane);
if (it != m_parents.end())
return it->second;
return std::set<IORegistryEntry*>();
}
std::set<IORegistryEntry*> IORegistryEntry::getChildren(const char* plane)
{
auto it = m_children.find(plane);
if (it != m_children.end())
return it->second;
return std::set<IORegistryEntry*>();
}
void IORegistryEntry::registerInPlane(const char* plane, const char* pathName, IORegistryEntry* parent)
{
m_name[plane] = pathName;
auto it = m_parents.find(plane);
if (it == m_parents.end())
it = m_parents.insert(std::make_pair(std::string_view(plane), std::set<IORegistryEntry*>())).first;
it->second.insert(parent);
it = parent->m_children.find(plane);
if (it == parent->m_children.end())
it = parent->m_children.insert(std::make_pair(std::string_view(plane), std::set<IORegistryEntry*>())).first;
it->second.insert(this);
}
std::string IORegistryEntry::getPath(const char* plane)
{
std::stack<std::string> components;
IORegistryEntry* cur = this;
while (true)
{
std::set<IORegistryEntry*> parents = cur->getParents(plane);
if (parents.empty())
{
if (cur != root())
return "?unsup_plane?";
break;
}
IORegistryEntry* parent = *parents.begin();
components.push(parent->getPath(plane));
cur = parent;
}
std::string path = plane;
path += ":";
while (!components.empty())
{
path += "/";
path += components.top();
components.pop();
}
return path;
}
IORegistryEntry* IORegistryEntry::root()
{
static IORegistryEntry e;
return &e;
}
kern_return_t is_io_registry_entry_get_path
(
mach_port_t registry_entry,
io_name_t plane,
io_string_t path
)
{
IORegistryEntry* e = dynamic_cast<IORegistryEntry*>(IOObject::lookup(registry_entry));
if (!e)
return KERN_INVALID_ARGUMENT;
std::string mypath = e->getPath(plane);
strlcpy(path, mypath.c_str(), sizeof(io_string_t));
return KERN_SUCCESS;
}
kern_return_t is_io_registry_entry_create_iterator
(
mach_port_t registry_entry,
io_name_t plane,
uint32_t options,
mach_port_t *iterator
)
{
puts("STUB is_io_registry_entry_create_iterator");
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_get_properties_bin
(
mach_port_t registry_entry,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
)
{
IORegistryEntry* e = dynamic_cast<IORegistryEntry*>(IOObject::lookup(registry_entry));
if (!e)
return KERN_INVALID_ARGUMENT;
NSDictionary* props = e->getProperties();
CFDataRef data = IOCFSerialize(props, kIOCFSerializeToBinary);
*propertiesCnt = CFDataGetLength(data);
kern_return_t kr = vm_allocate(mach_task_self(), (vm_address_t*) properties, *propertiesCnt, true);
if (kr == KERN_SUCCESS)
{
memcpy(*properties, CFDataGetBytePtr(data), *propertiesCnt);
}
CFRelease(data);
return kr;
}
// STUB called: is_io_registry_entry_get_property_bin
// STUB called: is_io_registry_entry_create_iterator
// STUB called: is_io_registry_entry_get_properties_bin
// STUB called: is_io_registry_get_root_entry
// STUB called: is_io_registry_entry_from_path

View File

@ -1,9 +1,9 @@
#ifndef IOKITD_IOSERVICE_H
#define IOKITD_IOSERVICE_H
#include <Foundation/NSDictionary.h>
#include "IOObject.h"
#include "IORegistryEntry.h"
class IOService : public IOObject
class IOService : public IORegistryEntry
{
public:
IOService();

View File

@ -5,12 +5,12 @@
#import <Foundation/NSDictionary.h>
#include "IOIterator.h"
class Registry
class ServiceRegistry
{
private:
Registry() {}
ServiceRegistry() {}
public:
static Registry* instance();
static ServiceRegistry* instance();
void registerService(IOService* service);
IOIterator* iteratorForMatchingServices(NSDictionary* criteria) const;
private:

View File

@ -1,5 +1,5 @@
#include "iokitd.h"
#include "Registry.h"
#include "ServiceRegistry.h"
#include <IOCFUnserialize.h>
#include <CoreFoundation/CFString.h>
#include <os/log.h>
@ -10,13 +10,13 @@ extern "C" {
#include "iokitmigServer.h"
}
Registry* Registry::instance()
ServiceRegistry* ServiceRegistry::instance()
{
static Registry reg;
static ServiceRegistry reg;
return &reg;
}
IOIterator* Registry::iteratorForMatchingServices(NSDictionary* criteria) const
IOIterator* ServiceRegistry::iteratorForMatchingServices(NSDictionary* criteria) const
{
std::vector<IOObject*> matching;
@ -29,7 +29,7 @@ IOIterator* Registry::iteratorForMatchingServices(NSDictionary* criteria) const
return new IOIterator(matching);
}
void Registry::registerService(IOService* service)
void ServiceRegistry::registerService(IOService* service)
{
m_registeredServices.push_back(service);
}
@ -67,7 +67,7 @@ kern_return_t is_io_service_get_matching_services_bin
// Criteria example:
// IOProviderClass -> IODisplayConnect
IOIterator* iterator = Registry::instance()->iteratorForMatchingServices((NSDictionary*) criteria);
IOIterator* iterator = ServiceRegistry::instance()->iteratorForMatchingServices((NSDictionary*) criteria);
CFShow(criteria);
CFRelease(criteria);

View File

@ -3,6 +3,7 @@
#include <liblaunch/bootstrap.h>
#include <dispatch/dispatch.h>
#include <dispatch/private.h>
#include <IOKit/IOKitKeys.h>
#include <cstdlib>
#include "iokitd.h"
#include "iokitmig.h"
@ -77,6 +78,6 @@ int main(int argc, const char** argv)
static void discoverAllDevices()
{
Registry* registry = Registry::instance();
ServiceRegistry* registry = ServiceRegistry::instance();
IODisplayConnectX11::discoverDevices(registry);
}

View File

@ -3,27 +3,6 @@
#define STUB() os_log(OS_LOG_DEFAULT, "%d STUB called: %s", getpid(), __FUNCTION__); printf("STUB called: %s\n", __FUNCTION__)
kern_return_t is_io_object_get_class
(
mach_port_t object,
io_name_t className
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_object_conforms_to
(
mach_port_t object,
io_name_t className,
boolean_t *conforms
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_service_get_matching_services
(
mach_port_t master_port,
@ -266,26 +245,6 @@ kern_return_t is_io_connect_method_structureI_structureO
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_get_path
(
mach_port_t registry_entry,
io_name_t plane,
io_string_t path
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_get_root_entry
(
mach_port_t master_port,
mach_port_t *root
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_set_properties
(
@ -340,18 +299,6 @@ kern_return_t is_io_service_wait_quiet
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_create_iterator
(
mach_port_t registry_entry,
io_name_t plane,
uint32_t options,
mach_port_t *iterator
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_catalog_send_data
(
mach_port_t master_port,
@ -904,30 +851,6 @@ kern_return_t is_io_server_version
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_get_properties_bin
(
mach_port_t registry_entry,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_get_property_bin
(
mach_port_t registry_entry,
io_name_t plane,
io_name_t property_name,
uint32_t options,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_service_get_matching_service_bin
(
@ -985,13 +908,24 @@ kern_return_t is_io_service_add_notification_bin_64
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_get_path_ool
kern_return_t is_io_registry_entry_get_property_bin
(
mach_port_t registry_entry,
io_name_t plane,
io_string_inband_t path,
io_buf_ptr_t *path_ool,
mach_msg_type_number_t *path_oolCnt
io_name_t property_name,
uint32_t options,
io_buf_ptr_t *properties,
mach_msg_type_number_t *propertiesCnt
)
{
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_get_root_entry
(
mach_port_t master_port,
mach_port_t *root
)
{
STUB();
@ -1011,3 +945,16 @@ kern_return_t is_io_registry_entry_from_path_ool
STUB();
return KERN_NOT_SUPPORTED;
}
kern_return_t is_io_registry_entry_get_path_ool
(
mach_port_t registry_entry,
io_name_t plane,
io_string_inband_t path,
io_buf_ptr_t *path_ool,
mach_msg_type_number_t *path_oolCnt
)
{
STUB();
return KERN_NOT_SUPPORTED;
}