Ошибка DeviceIoControl 1 неправильная функция

Я создал устройство в пространстве ядра и получил к нему доступ в пользовательском пространстве, используя CreateFile. Я могу отправить ioctl драйверу, и они выполняются правильно. Не знаю, как отследить, что происходит после WdfRequestComplete, и по возвращении я заканчиваю с ошибкой 1 (недопустимая функция). Прежде чем это будет помечено как дубликат, обратите внимание, что есть разница с этим в том, что я пишу свой драйвер ioctl, и в том, что я использую синхронизацию ввода-вывода, а не асинхронность.

В пространстве пользователя:

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


person Luis    schedule 22.04.2016    source источник
comment
Вам нужно начать с устранения основных неполадок: широко используйте DbgPrint, чтобы увидеть, какая функция дает сбой и с каким кодом ошибки. Без этой информации мы вряд ли сможем вам помочь.   -  person Harry Johnston    schedule 23.04.2016
comment
Я могу получить доступ к результату в пользовательском пространстве после использования outputBuffer = irp->AssociatedIrp.SystemBuffer вместо WdfRequestRetrieveOutputBuffer, но я не знаю, почему. Я использовал DbgPrint и проследил с помощью windbg, чтобы проверить, почему я все еще получаю ошибку 1, но все, кажется, выполняется правильно в EvtIoDeviceControl.   -  person Luis    schedule 24.04.2016
comment
Какой тип передачи данных использует IOCTL, см. msdn.microsoft.com/en-us/library/windows/hardware/ ?   -  person Harry Johnston    schedule 25.04.2016
comment
@HarryJohnston спасибо! Вот и все, я использую те же коды, что и для своего драйвера Linux, и не указал макрос CTL_CODE, поэтому по умолчанию используется METHOD_BUFFERED.   -  person Luis    schedule 25.04.2016
comment
Вы должны опубликовать детали в качестве ответа.   -  person Harry Johnston    schedule 26.04.2016


Ответы (1)


Я определил свои команды ioctl как перечисления в своем драйвере Linux (который отлично работает), и при реализации драйвера в Windows я использовал то же определение перечисления.

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

В окнах определение управляющих кодов занимает немного больше времени. Как описано здесь макрос 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, но устройство на моем хосте требует этих кодов, поэтому я просто предоставляю то, что спрашивают.

person Luis    schedule 26.04.2016
comment
Для справки, коды IOCTL не обязательно должны соответствовать кодам оборудования, поэтому, вероятно, будет безопасно использовать правильную нумерацию. - person Harry Johnston; 26.04.2016