BSOD при записи/чтении
От: Ivan_83  
Дата: 04.12.11 19:34
Оценка:
Здравствуйте.

Пишу драйвер батареи: для APC smart на ком порту.
Драйвер легаси, но с пнп кодом: через devcon добавляю устройство, а дальше обычный пнп.
В AddDevice атачусь к тому что приходит, дальше открываю компорт через IoGetDeviceObjectPointer — но в стёк к нему не добавляюсь.
Порт открывается, IRP_MJ_DEVICE_CONTROL с IOCTL_SERIAL_* проходят вроде нормально — без ошибок.
А на IRP_MJ_WRITE ухожу в BSOD.

Пожалуйста помогите, уже неделю не могу осилить!



RtlInitUnicodeString(&ObjectName, L"\\DosDevices\\COM1");
Status = IoGetDeviceObjectPointer(&ObjectName, STANDARD_RIGHTS_ALL, &FileObject, &ComPdo);
...
pDeviceData->WriteBuffSize = OEM_SERIAL_BUFFSIZE;
pDeviceData->WriteBuff = ExAllocatePoolWithTag(NonPagedPool, pDeviceData->WriteBuffSize, DRIVER_TAG);
...
RtlCopyMemory(pDeviceData->WriteBuff, "Y", 1);//(*WriteBuff) = 'Y';
Status = SmBatt_SerialPortWrite(pDeviceData->ComPdo, pDeviceData->ComFileObject, pDeviceData->WriteBuff, 1);

...

NTSTATUS
IOSyncRequestCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
    UNREFERENCED_PARAMETER(Irp);
    UNREFERENCED_PARAMETER(DeviceObject);

    // If the lower driver didn't return STATUS_PENDING, we don't need to
    // set the event because we won't be waiting on it.
    // This optimization avoids grabbing the dispatcher lock and improves perf.
    if (Irp->PendingReturned == TRUE)
        KeSetEvent((PKEVENT)Context, 0, FALSE);
//  We don't want IO to get our IRP and free it.
return(STATUS_MORE_PROCESSING_REQUIRED);
}


NTSTATUS
IOSyncRequest(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    NTSTATUS Status;
    KEVENT Event;

    DebugPrint("IOSyncRequest...");

    KeInitializeEvent(&Event, NotificationEvent, FALSE);
    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
    Irp->IoStatus.Information = 0;
    IoSetCompletionRoutine(Irp, IOSyncRequestCompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE); 

    // Call the device to do the read and wait for it to finish.
    Status = IoCallDriver(DeviceObject, Irp);
    if (Status == STATUS_PENDING) { // Wait for the IRP
        Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
        if (Status == STATUS_SUCCESS)
            Status = Irp->IoStatus.Status;
    }
    KeClearEvent(&Event);
    DebugPrint("IOSyncRequest - DONE!!!");

return(Status);
}


NTSTATUS
SendDevIoControlReq(ULONG IoControlCode, BOOLEAN Internal, PDEVICE_OBJECT DeviceObject, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, ULONG_PTR *pnBytesReturned)
{
    NTSTATUS Status;
    PIRP Irp;
    PIO_STACK_LOCATION IrpSp;

    PAGED_CODE();
    
    DebugPrint("SendDevIoControlReq...");

    Irp = IoAllocateIrp((DeviceObject->StackSize + 1), FALSE);
     if (Irp == NULL) {
        DebugPrint("SendDevIoControlReq: Failed to allocate IRP");
        return(STATUS_INSUFFICIENT_RESOURCES);
    }

    IrpSp = IoGetNextIrpStackLocation(Irp);
    IrpSp->MajorFunction = ((TRUE == Internal) ? IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL);
    IrpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
    IrpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
    IrpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
    Irp->UserBuffer = OutputBuffer;
    Irp->AssociatedIrp.SystemBuffer = InputBuffer;

    // Call the device to do the read and wait for it to finish.
    Status = IOSyncRequest(DeviceObject, Irp);
    IoFreeIrp(Irp);
    DebugPrint("SendDevIoControlReq - DONE!!!");

    if (pnBytesReturned)
        *pnBytesReturned = Irp->IoStatus.Information;

return(Status);
}


NTSTATUS
SmBatt_SerialPortWrite(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, PVOID Buffer, ULONG NumberOfBytesToWrite)
{
    NTSTATUS Status;
    PIRP Irp;
    PIO_STACK_LOCATION IrpSp;

    PAGED_CODE();
    
    DebugPrint("SmBatt_SerialPortWrite...");

    Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, Buffer  OPTIONAL, NumberOfBytesToWrite, NULL, NULL);
    //Irp = IoAllocateIrp((DeviceObject->StackSize + 1), FALSE);
     if (Irp == NULL) {
        DebugPrint("SerialPortWrite: Failed to allocate IRP");
        return(STATUS_INSUFFICIENT_RESOURCES);
    }

    /*IrpSp = IoGetNextIrpStackLocation(Irp);
    IrpSp->MajorFunction = IRP_MJ_WRITE;
    IrpSp->Parameters.Write.Length = NumberOfBytesToWrite;
    IrpSp->FileObject = FileObject;
    Irp->AssociatedIrp.SystemBuffer = Buffer;*/

    // Call the device to do the read and wait for it to finish.
    Status = IOSyncRequest(DeviceObject, Irp);
    IoFreeIrp(Irp);
    DebugPrint("SmBatt_SerialPortWrite - DONE!!!");

return(Status);
}
Re: BSOD при записи/чтении
От: Аноним  
Дата: 05.12.11 07:54
Оценка:
I_>Пожалуйста помогите, уже неделю не могу осилить!

I_>

I_>    // Call the device to do the read and wait for it to finish.
I_>    Status = IOSyncRequest(DeviceObject, Irp);
I_>    IoFreeIrp(Irp);

I_>


Нельзя так делать. Нужно установить Completion Routine и в ней освобождать IRP.
Re[2]: BSOD при записи/чтении
От: Ivan_83  
Дата: 05.12.11 08:55
Оценка:
Здравствуйте, Аноним, Вы писали:


I_>>Пожалуйста помогите, уже неделю не могу осилить!


I_>>

I_>>    // Call the device to do the read and wait for it to finish.
I_>>    Status = IOSyncRequest(DeviceObject, Irp);
I_>>    IoFreeIrp(Irp);

I_>>


А>Нельзя так делать. Нужно установить Completion Routine и в ней освобождать IRP.



Можете более подробно и аргументированно? (что бы я понял свою ошибку)

В моём случае IoFreeIrp вызывается после отработки Completion Routine, потому что вызывающий поток ждёт на KEVENT сигнала, а сигнал посылается из Completion Routine.
Re[3]: BSOD при записи/чтении
От: Аноним  
Дата: 05.12.11 09:28
Оценка:
I_>В моём случае IoFreeIrp вызывается после отработки Completion Routine, потому что вызывающий поток ждёт на KEVENT сигнала, а сигнал посылается из Completion Routine.

А, это я не доглядел )
Re: BSOD при записи/чтении
От: Аноним  
Дата: 05.12.11 10:19
Оценка:
Здравствуйте, Ivan_83, Вы писали:

I_>Здравствуйте.


I_>Порт открывается, IRP_MJ_DEVICE_CONTROL с IOCTL_SERIAL_* проходят вроде нормально — без ошибок.

I_>А на IRP_MJ_WRITE ухожу в BSOD.

I_>Пожалуйста помогите, уже неделю не могу осилить!


!analyze -v что показывает?
Re[2]: BSOD при записи/чтении
От: Ivan_83  
Дата: 05.12.11 10:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Ivan_83, Вы писали:


I_>>Здравствуйте.


I_>>Порт открывается, IRP_MJ_DEVICE_CONTROL с IOCTL_SERIAL_* проходят вроде нормально — без ошибок.

I_>>А на IRP_MJ_WRITE ухожу в BSOD.

I_>>Пожалуйста помогите, уже неделю не могу осилить!


А>!analyze -v что показывает?



К какой программе/утилите относится эта команда?
(это мой первый драйвер под винду — тонкостей и сленга я ещё не знаю)
Re[3]: BSOD при записи/чтении
От: Аноним  
Дата: 05.12.11 11:05
Оценка:
Здравствуйте, Ivan_83, Вы писали:

А>>!analyze -v что показывает?


I_>К какой программе/утилите относится эта команда?

I_>(это мой первый драйвер под винду — тонкостей и сленга я ещё не знаю)

При падении системы в папке x:\Windows\Minidump создается .dmp файл с датой падения в имени файла. Этот файл надо открыть в WinDbg (CTRL + D) и выполнить команду !analyze -v При этом желательно настроить символы: CTRL + S, там указать: SRV*f:\localsymbols*http://msdl.microsoft.com/download/symbols , где f:\localsymbols -- путь к директории, куда WinDbg скачает символы. Символы надо настроить перед использованием !analyze -v
Re[4]: BSOD при записи/чтении
От: -prus-  
Дата: 05.12.11 12:46
Оценка: 2 (1)
Здравствуйте, Аноним, Вы писали:

А>При падении системы в папке x:\Windows\Minidump создается .dmp файл с датой падения в имени файла. Этот файл надо открыть в WinDbg (CTRL + D) и выполнить команду !analyze -v При этом желательно настроить символы: CTRL + S, там указать: SRV*f:\localsymbols*http://msdl.microsoft.com/download/symbols , где f:\localsymbols -- путь к директории, куда WinDbg скачает символы. Символы надо настроить перед использованием !analyze -v


Дополню немного...
Думаю, не лишним будет установить формирование дампа памяти ядра ("Загрузка и восстановление"->"Запись отладочной информации"->"Дамп памяти ядра") и в WinDBG указать еще путь до символов разрабатываемого драйвера + указать путь к исходникам для получения наиболее полной картины происходящего.
С уважением,
Евгений
Re[5]: BSOD при записи/чтении
От: x64 Россия  
Дата: 05.12.11 13:47
Оценка: +1
P>Дополню немного...

Ну коли так, то и сюда не лишним будет заглянуть.

P>...указать путь к исходникам для получения наиболее полной картины происходящего.


А это необязательно, WinDbg сам найдёт, если дамп смотреть на той же машине, где всё это и собиралось.
Re[6]: BSOD при записи/чтении
От: Ivan_83  
Дата: 05.12.11 17:44
Оценка:
Здравствуйте, x64, Вы писали:

P>>Дополню немного...


x64>Ну коли так, то и сюда не лишним будет заглянуть.


P>>...указать путь к исходникам для получения наиболее полной картины происходящего.


x64>А это необязательно, WinDbg сам найдёт, если дамп смотреть на той же машине, где всё это и собиралось.


Пришлось всё таки руками указать все пути, у меня фрибилд, видимо поэтому.
Также сделал полный дамп, он оказался более информативным.
Вот результаты:




0: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

ATTEMPTED_SWITCH_FROM_DPC (b8)
A wait operation, attach process, or yield was attempted from a DPC routine.
This is an illegal operation and the stack track will lead to the offending
code and original DPC routine.
Arguments:
Arg1: fffffa80053dc230, Original thread which is the cause of the failure
Arg2: fffffa80043f5060, New thread
Arg3: 0000000000000000, Stack address of the original thread
Arg4: 0000000000000000

Debugging Details:
------------------


FAULTING_THREAD: fffffa80053dc230

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

BUGCHECK_STR: 0xB8

PROCESS_NAME: svchost.exe

CURRENT_IRQL: 2

LAST_CONTROL_TRANSFER: from fffff80001ae0f32 to fffff80001ade4da

STACK_TEXT:
fffff800`01830460 fffff800`01ae0f32 : fffffa80`049047d0 fffffa80`053dc230 fffffa80`00000000 fffffa80`04903a40 : nt!KiSwapContext+0x7a
fffff800`018305a0 fffff800`01ae374f : fffffa80`0503a500 fffffa80`04c7beb0 00000000`00000000 fffff880`013d2527 : nt!KiCommitThreadWait+0x1d2
fffff800`01830630 fffff880`1514c0b9 : fffffa80`04c7bd00 00000000`00000000 fffffa80`04c7bd00 fffff800`01c66400 : nt!KeWaitForSingleObject+0x19f
fffff800`018306d0 fffff880`151517f7 : fffffa80`0490b010 fffffa80`0503a500 fffffa80`04c7bd60 00000000`00000002 : APCBatt!IOSyncRequest+0x85 [c:\users\rozhuk_im\documents\programmer\vc\apcbatt\apcbatt.c @ 536]
fffff800`01830730 fffff880`15151760 : fffffa80`05a9e520 00000000`00000001 00000000`00000001 fffff800`01b19f30 : APCBatt!SmBatt_UpdateData+0x7f [c:\users\rozhuk_im\documents\programmer\vc\apcbatt\apcbatt.c @ 785]
fffff800`01830770 fffff800`01ae75fc : 00000000`00000001 fffffa80`00000000 fffffa80`40740088 00000000`00000001 : APCBatt!UpdTimerDPC+0x3c [c:\users\rozhuk_im\documents\programmer\vc\apcbatt\apcbatt.c @ 663]
fffff800`018307a0 fffff800`01ae7496 : fffffa80`05a9e578 00000000`00000d33 00000000`00000000 fffff880`01b22f5c : nt!KiProcessTimerDpcTable+0x6c
fffff800`01830810 fffff800`01ae737e : 00000000`1f6dab1e fffff800`01830e88 00000000`00000d33 fffff800`01c548e8 : nt!KiProcessExpiredTimerList+0xc6
fffff800`01830e60 fffff800`01ae7167 : fffff800`01c51ec1 00000000`00000d33 fffffa80`03987050 00000000`00000033 : nt!KiTimerExpiration+0x1be
fffff800`01830f00 fffff800`01ade765 : 00000000`00000000 fffffa80`053dc230 00000000`00000000 fffff880`01180f5c : nt!KiRetireDpcList+0x277
fffff800`01830fb0 fffff800`01ade57c : 00000000`00000001 fffff800`01a20895 fffff800`01a463c0 fffff880`047b7700 : nt!KyRetireDpcList+0x5
fffff880`047b7640 fffff800`01b27993 : fffff800`01ad81a0 fffff800`01ad820c 00000000`00000000 00000000`00000000 : nt!KiDispatchInterruptContinue
fffff880`047b7670 fffff800`01ad820c : 00000000`00000000 00000000`00000000 00000068`00000101 00000000`00000000 : nt!KiDpcInterruptBypass+0x13
fffff880`047b7680 fffff800`01c0aab5 : fffffa80`0395d280 00000000`000000b3 00000000`00000001 00000000`000007ff : nt!KiInterruptDispatchNoLock+0x1fc
fffff880`047b7810 fffff800`01dd5a5f : 00000000`00000001 fffffa80`0398ad08 fffffa80`05839550 00000000`00000000 : nt!ExAllocatePoolWithTag+0x9d5
fffff880`047b7900 fffff800`01dd587b : fffffa80`00000000 fffffa80`039b3300 00000000`00000050 fffff880`047b79a8 : nt!ObpAllocateObject+0x12f
fffff880`047b7970 fffff800`01da3e54 : fffff880`047b7b20 00000000`00000002 fffff8a0`01ef6c00 fffff8a0`01ae2060 : nt!ObCreateObject+0xdb
fffff880`047b79e0 fffff800`01dafb5a : 00000000`00000000 00000000`019def28 00000000`00000001 fffffa80`053dc230 : nt!SepDuplicateToken+0xf4
fffff880`047b7a80 fffff800`01dafdd5 : fffffa80`053dc230 fffff880`0000000a 00000000`00000001 00000000`019defa0 : nt!NtOpenThreadTokenEx+0x33a
fffff880`047b7ba0 fffff800`01adaed3 : fffffa80`053dc230 00000000`019defa0 00000000`00000000 fffffa80`0555ce60 : nt!NtOpenThreadToken+0x11
fffff880`047b7be0 00000000`7787155a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
00000000`019dee48 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x7787155a


STACK_COMMAND: .thread 0xfffffa80053dc230 ; kb

FOLLOWUP_IP:
APCBatt!IOSyncRequest+85 [c:\users\rozhuk_im\documents\programmer\vc\apcbatt\apcbatt.c @ 536]
fffff880`1514c0b9 8bd8 mov ebx,eax

FAULTING_SOURCE_CODE:

   532: 
   533:     // Call the device to do the read and wait for it to finish.
   534:     Status = IoCallDriver(DeviceObject, Irp);
   535:     if (Status == STATUS_PENDING) { // Wait for the IRP
>  536:         Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
   537:         if (Status == STATUS_SUCCESS)
   538:             Status = Irp->IoStatus.Status;
   539:     }
   540:     KeClearEvent(&Event);
   541:     DebugPrint("IOSyncRequest - DONE!!!");




SYMBOL_STACK_INDEX: 3

SYMBOL_NAME: APCBatt!IOSyncRequest+85

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: APCBatt

IMAGE_NAME: APCBatt.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 4edcf5b3

FAILURE_BUCKET_ID: X64_0xB8_APCBatt!IOSyncRequest+85

BUCKET_ID: X64_0xB8_APCBatt!IOSyncRequest+85

Followup: MachineOwner
---------

0: kd> lmvm APCBatt
start end module name
fffff880`1514b000 fffff880`15156000 APCBatt (private pdb symbols) c:\users\rozhuk_im\documents\programmer\vc\apcbatt\objfre_win7_amd64\amd64\APCBatt.pdb
Loaded symbol image file: APCBatt.sys
Image path: \SystemRoot\system32\DRIVERS\APCBatt.sys
Image name: APCBatt.sys
Timestamp: Tue Dec 06 01:47:47 2011 (4EDCF5B3)
CheckSum: 0000AA29
ImageSize: 0000B000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4


в адддевайс:

KeInitializeTimerEx(&pDeviceData->UpdTimer, NotificationTimer);
KeInitializeDpc(&pDeviceData->UpdTimerDpc, UpdTimerDPC, pDeviceData);
...
dueTime.QuadPart = Int32x32To64(INFO_UPDATE_TIME, ((-10) * 1000));
KeSetTimerEx(&pDeviceData->UpdTimer, dueTime, INFO_UPDATE_TIME, &pDeviceData->UpdTimerDpc);





VOID
UpdTimerDPC(PRKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
    SM_BATT_DRV_DEV_EXT_DATA *pDeviceData = (SM_BATT_DRV_DEV_EXT_DATA *)DeferredContext;
    LONG TimerStatus;

    PAGED_CODE();

    DebugPrint("UpdTimerDPC...");
    TimerStatus = InterlockedCompareExchange(&pDeviceData->UpdTimerProcess, 1, 0);
    if (1 == TimerStatus)
        return; // allready running

    //...
    DebugPrint("UpdTimerDPC: updating...");
    SmBatt_UpdateData(pDeviceData->Fdo);

    InterlockedExchange(&pDeviceData->UpdTimerProcess, 0);
}




SmBatt_UpdateData
просто вызывает:

RtlCopyMemory(pDeviceData->WriteBuff, "Y", 1);//(*WriteBuff) = 'Y';
Status = SmBatt_SerialPortWrite(pDeviceData->ComPdo, pDeviceData->ComFileObject, pDeviceData->WriteBuff, 1);
Re[7]: BSOD при записи/чтении
От: x64 Россия  
Дата: 05.12.11 17:56
Оценка: 3 (1)
I_>Вот результаты:

Надо было сразу написать, что SmBatt_SerialPortWrite() вызываешь из DPC.
DPC выполняются на DISPATCH_LEVEL, а там ждать нельзя (например, вызовом KeWaitForSingleObject).
Другими словами, этот вызов у тебя должен быть асинхронным (а результат будет в функции завершения).
Re[8]: BSOD при записи/чтении
От: Ivan_83  
Дата: 05.12.11 18:09
Оценка:
Здравствуйте, x64, Вы писали:

I_>>Вот результаты:


x64>Надо было сразу написать, что SmBatt_SerialPortWrite() вызываешь из DPC.

x64>DPC выполняются на DISPATCH_LEVEL, а там ждать нельзя (например, вызовом KeWaitForSingleObject).
x64>Другими словами, этот вызов у тебя должен быть асинхронным (а результат будет в функции завершения).


Закоментил старт таймера и оно записало в порт, бесперебойник пикнул (наконец то! — команда диагностики до него дошла)
Я подозревал что какая то мелочь всё портит, но думал что там что то с директ_ио/буфферед_ио.

СПАСИБО ВСЕМ!
Re[9]: BSOD при записи/чтении
От: x64 Россия  
Дата: 05.12.11 18:31
Оценка:
I_>СПАСИБО ВСЕМ!

Да на кой ж мне "пасибы"-то ваши — оценочки давай, и побольше!
Re[10]: BSOD при записи/чтении
От: Ivan_83  
Дата: 05.12.11 18:46
Оценка:
Здравствуйте, x64, Вы писали:

I_>>СПАСИБО ВСЕМ!


x64>Да на кой ж мне "пасибы"-то ваши — оценочки давай, и побольше!


done


Ещё вопрос: как потом дистрибутить дрова, чтобы у юзера без лишних вопросов вставали, те без включения тестмоде на х64?
Обязательно покупать сертификат?
Сколько стоит? Где? У мс нужно что то регать/спрашивать/тестить?

(DPInst я видел, для инсталяции, врочем inf + devcon + cmd файл тоже меня устраивают)
Re[11]: BSOD при записи/чтении
От: x64 Россия  
Дата: 05.12.11 18:54
Оценка: 2 (1)
I_>Обязательно покупать сертификат?

Да.

I_>Сколько стоит?


$500 в год.
Вроде и дешевле можно.

I_>Где?


Например, VeriSign.
Или другой ЦС из списка.

I_>У мс нужно что то регать/спрашивать/тестить?


В общем случае — нет, для обычных драйверов не требуется.
Но для драйверов железок принято проходить Windows Logo тесты.
Re[8]: BSOD при записи/чтении
От: Аноним  
Дата: 06.12.11 07:12
Оценка: -1
Здравствуйте, x64, Вы писали:

I_>>Вот результаты:


x64>Надо было сразу написать, что SmBatt_SerialPortWrite() вызываешь из DPC.

x64>DPC выполняются на DISPATCH_LEVEL, а там ждать нельзя (например, вызовом KeWaitForSingleObject).
x64>Другими словами, этот вызов у тебя должен быть асинхронным (а результат будет в функции завершения).

лолшто?

Callers of KeWaitForSingleObject must be running at IRQL <= DISPATCH_LEVEL.
Re[9]: BSOD при записи/чтении
От: ABar Украина  
Дата: 06.12.11 08:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>лолшто?


А>Callers of KeWaitForSingleObject must be running at IRQL <= DISPATCH_LEVEL.



Там же прям следующее предложение.

However, if Timeout = NULL or *Timeout != 0, the caller must be running at IRQL <= APC_LEVEL and in a nonarbitrary thread context.

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.