DriverKit中IOConnectCallAsyncStructMethod未返回指定数据问题
DriverKit异步读取数据无返回的解决方案
你混淆了DriverKit异步调用与同步调用的数据返回逻辑:IOConnectCallAsyncStructMethod的output参数并非用于接收异步返回数据——同步调用时它直接承载结果,但异步场景下仅用于告知驱动输出缓冲区的最大容量,实际返回数据是通过你传入的callback_port以Mach消息形式发送到用户空间的。以下是具体修正步骤:
1. 用户空间监听回调Port,接收异步消息
需要在用户空间对callback_port进行持续监听,驱动调用AsyncCompletion后,系统会向该Port发送包含返回数据的Mach消息,解析后才能拿到结果:
// 初始化回调Port(调用IOConnectCallAsyncStructMethod前执行) mach_port_t callback_port = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE); mach_port_insert_right(mach_task_self(), callback_port, callback_port, MACH_MSG_TYPE_MAKE_SEND); // 启动后台线程监听消息 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (true) { struct __attribute__((packed)) { mach_msg_header_t header; mach_msg_body_t body; mach_msg_ool_descriptor_t ool_desc; IOAsyncCalloutMessage_t async_msg; } msg; mach_msg_return_t msg_ret = mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(msg), callback_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (msg_ret != MACH_MSG_SUCCESS) continue; // 解析并处理返回数据 if (async_msg.returnStatus == kIOReturnSuccess) { uint64_t* returned_data = (uint64_t*)ool_desc.address; uint32_t data_count = ool_desc.size / sizeof(uint64_t); // 此处处理returned_data,比如拷贝到业务缓冲区 // ... // 释放内核分配的内存 vm_deallocate(mach_task_self(), (vm_address_t)returned_data, ool_desc.size); } } });
2. 修正驱动端的AsyncCompletion调用
当前代码中asyncData是栈上内存,AsyncCompletion需要内核可访问的堆内存,且不能手动提前释放回调Action:
// 从USB设备读取到的内核空间数据指针 uint64_t *read; const uint32_t size = 32; // 用IOMalloc分配内核可访问的内存 uint64_t* asyncData = static_cast<uint64_t*>(IOMalloc(size * sizeof(uint64_t))); if (!asyncData) { AsyncCompletion(ivars->readSampleCallbackAction, kIOReturnNoMemory, nullptr, 0); return; } memcpy(asyncData, read, size * sizeof(uint64_t)); // 调用AsyncCompletion传递数据,无需手动release回调Action(系统会自动处理) AsyncCompletion(ivars->readSampleCallbackAction, kIOReturnSuccess, asyncData, size); // ivars->readSampleCallbackAction->release(); // 删除此行代码
3. 调整用户空间的异步调用参数
确保asynRequestRef正确传递,output参数仅用于声明缓冲区容量:
const uint32_t arraySize = 248; uint64_t output[arraySize] = {}; size_t outputSizeT = sizeof(uint64_t) * arraySize; IOAsyncRef32 asynRequestRef = 0; // 可用自增标识区分不同异步请求 IOReturn ret = IOConnectCallAsyncStructMethod( connection, MessageType_AsyncReadRequest, callback_port, &asynRequestRef, // 传入指针用于标识请求 kIOAsyncCalloutCount, nullptr, 0, output, &outputSizeT );
内容的提问来源于stack exchange,提问作者xarly
相关产品推荐
相关产品推荐

