【问题标题】:DeviceIoControl error 1 incorrect functionDeviceIoControl 错误 1 ​​函数不正确
【发布时间】:2016-04-22 16:17:40
【问题描述】:

我在内核空间创建了一个设备,并使用CreateFile 在用户空间访问它我能够将ioctl 发送到驱动程序并且它们被正确执行。不知道如何跟踪WdfRequestComplete 之后发生的事情,返回时我以错误 1(无效函数)结束。在将其标记为 dup 之前,请注意与 this 的不同之处在于我编写了驱动程序 ioctl,并且我使用的是同步 io 而不是异步。

在用户空间:

fd = CreateFile(dev_path, 
    (FILE_GENERIC_READ | FILE_GENERIC_WRITE),
    (FILE_SHARE_READ | FILE_SHARE_WRITE),
    NULL, OPEN_EXISTING, 0, NULL);
// ... error checking code here
DeviceIoControl(fd, // device handler
    VIRTQC_CMD_MMAP, // command to send
    &inputBuffer,
    inputBufferLength,
    &outputBuffer,
    outputBufferLength,
    &returnLength,
    (LPOVERLAPPED)NULL); // overlapped structure not needed using sync io

在内核空间中

status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &inputBuffer, NULL);
if (!NT_SUCCESS(status)) 
{
    WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
    return;
}
inputVirtArg = (VirtioQCArg*)inputBuffer;

status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &outputBuffer, NULL);
if (!NT_SUCCESS(status))
{
    WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
    return;
}
outputVirtArg = (VirtioQCArg*)outputBuffer;

switch (IoControlCode)
{
case VIRTQC_CMD_MMAP:
    if (PsGetCurrentThread() == irp->Tail.Overlay.Thread)
    {
        status = CreateAndMapMemory(device, &(inputVirtArg), &(outputVirtArg));
        outputVirtArg->flag = (!NT_SUCCESS(status)) ? 0 : 1;
    } 
    else 
        status = STATUS_UNSUCCESSFUL;
    break;
default:
    status = STATUS_INVALID_DEVICE_REQUEST;
    break;
}
WdfRequestComplete(Request, status);

更新 1:

我尝试过WdfRequestCompleteWithInformation(Request, status, OutputBufferLength);,但结果相同。

另外,我注意到 inputBuffer 和 outputBuffer 的地址是一样的。

更新 2: 我试过做

temp = ExAllocatePoolWithTag(
    NonPagedPool,
    PAGE_SIZE,
    MEMORY_TAG
    );

// other code to
RtlCopyMemory((VirtioQCArg*)outputBuffer, temp, OutputBufferLength);

仍然出现错误 1

【问题讨论】:

  • 您需要从一些基本的故障排除开始:大量使用 DbgPrint 来查看哪个功能失败以及错误代码是什么。没有这些信息,我们不可能为您提供帮助。
  • 我可以在使用outputBuffer = irp->AssociatedIrp.SystemBuffer 而不是WdfRequestRetrieveOutputBuffer 后访问用户空间中的结果,但我不知道为什么。我使用了 DbgPrint 并使用 windbg 进行了跟踪,以检查为什么我仍然不断收到错误 1,但在 EvtIoDeviceControl 中似乎一切正常。
  • IOCTL使用什么数据传输类型,见msdn.microsoft.com/en-us/library/windows/hardware/…?
  • @HarryJohnston 谢谢!就是这样,我使用与我的 linux 驱动程序相同的代码并且没有指定 CTL_CODE 宏,因此它默认为 METHOD_BUFFERED
  • 您应该发布详细信息作为答案。

标签: windows driver kmdf wdf


【解决方案1】:

我在我的 linux 驱动程序中将我的 ioctl cmds 定义为枚举(工作正常),在 Windows 中实现驱动程序时,我使用了相同的枚举定义。

enum
{
    // Module & Execution control (driver API)
    VIRTIQC_SET = 200,
    VIRTIQC_UNSET,
    // more cmds.....
}

在 windows 中定义控制代码需要更多时间。正如here 解释的那样,应该使用 CTL_CODE 宏来定义新的 IOCTL 控制代码。

#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)

就我而言,我最终定义了这个:

#define VIRTQC_MAP CTL_CODE(FILE_DEVICE_NETWORK, 0xC8, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
#define VIRTQC_UNMAP CTL_CODE(FILE_DEVICE_NETWORK, 0xC9, METHOD_OUT_DIRECT, FILE_READ_DATA)

我知道小于 0x800 的功能代码是为 MS 保留的,但我主机上的设备需要此代码,所以我只是提供所要求的内容。

【讨论】:

  • 作为记录,IOCTL代码不必与硬件代码相对应,因此使用正确的编号可能是安全的。
猜你喜欢
  • 2021-05-16
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 2016-11-07
  • 2014-03-02
  • 1970-01-01
  • 1970-01-01
  • 2017-03-20
相关资源
最近更新 更多