windows kdmf驱动程序virtio调用virtqueue_add_buf导致系统致命错误

时间:2016-04-25 11:37:07

标签: windbg drivers kmdf

我有一个Windows VM驱动程序,允许用户空间应用程序通过IOCTL进行通信。我需要向主机公开一个结构(使用virtio),并且在使用virtqueue_add_buf函数初始化EvtDevicePrepareHardware中的virt设备后,我尝试使用VirtIODeviceInitialize。在致电virtqueue_add_buf时,我收到致命错误。

以下是一段代码

int TellHost(WDFOBJECT WdfDevice, VirtioQArg *virtioArg)
{
    VIO_SG              sg;
    PDEVICE_CONTEXT     context = GetDeviceContext(WdfDevice);
    sg.physAddr = MmGetPhysicalAddress(virtioArg);
    sg.length = sizeof(VirtioQCArg);

    WdfSpinLockAcquire(context->VirtQueueLock);
    error = virtqueue_add_buf(context->VirtQueue, &sg, 1, 0, virtioArg, NULL, 0);
    // more code ....
    WdfSpinLockRelease(context->VirtQueueLock);
}

我得到的错误是致命系统错误:0x000000d1(0x0000000000000014,0x0000000000000002,0x0000000000000000,0xFFFFF80109FC0637)

中断指令异常 - 代码80000003(第一次机会)

然后windbg无法加载符号和崩溃,使我的调试会话无用。我有什么想法可以调试这个或者我可能缺少什么?

1 个答案:

答案 0 :(得分:1)

0x000000d1是DRIVER_IRQL_NOT_LESS_OR_EQUAL,这几乎总是意味着在DPC IRQL或更高版本上引用无效地址或寻址分页内存。

0x0000000000000000是对IRQL 2(DPC)的无效地址(0x0000000000000014)的读访问。

我没有初始化队列。感谢Redhat的Vadim RozenFeld指出我的错误和他的确切解释。

我检查了气球virtio驱动程序,它使用以下函数初始化virtio队列。

PVIOQUEUE FindVirtualQueue(VIODEVICE *dev, ULONG index)
{
    PVIOQUEUE  pq = NULL;
    PVOID p;
    ULONG size, allocSize;
    VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize);
    if (allocSize)
    {
        PHYSICAL_ADDRESS HighestAcceptable;
        HighestAcceptable.QuadPart = 0xFFFFFFFFFF;
        p = MmAllocateContiguousMemory(allocSize, HighestAcceptable);
        if (p)
        {
            pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE);
        }
    }
    return pq;
}