tuiui
Участник
Offline
|
|
« Ответ #30 : 27-04-2010 10:27 » |
|
Спасибо. После долгих стараний наконец что-то родилось: NTSTATUS MultiplierCWriteDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PMULTIPLIERC_DEVICE_EXTENSION deviceExtension; NTSTATUS status; PIO_STACK_LOCATION irpStack; PVOID writeBuffer; ULONG writeLength; ULONG byteOffset; PVOID Address; deviceExtension = (PMULTIPLIERC_DEVICE_EXTENSION)DeviceObject->DeviceExtension; status = MultiplierCCheckIoLock(&deviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { return status; }
irpStack = IoGetCurrentIrpStackLocation(Irp); //Получаем количество данных для записи writeLength = irpStack->Parameters.Write.Length; if (writeLength == 0) { status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); MultiplierCDecrementIoCount(&deviceExtension->IoLock); return status; }
//Получаем адрес буфера для чтения writeBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
//Получаем смещение байта byteOffset = irpStack->Parameters.Write.ByteOffset.LowPart;
//Получаем адрес для записи Address = deviceExtension->DataMemoryBase+byteOffset*4;
//Запись memcpy(Address, writeBuffer, writeLength*4);
//Возвращаем количество записанных слов status = STATUS_SUCCESS; Irp->IoStatus.Information = writeLength; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); MultiplierCDecrementIoCount(&deviceExtension->IoLock); return status; } И вот опять пришли к тому, с чего все началось. Только теперь имеем чистый C. Драйвер установился, прекрасно пишет небольшие объемы данных. Но при попытке записать в устройство более 150 двойных слов - синий экран ((( В синем экране: 0x50 PAGE_FAULT_IN_NONPAGED_AREA Ошибочное обращение к области памяти в системном адресном пространстве Параметры Описание 1 Адрес, обращение по которому вызвало сбой (некоторое значение) 2 Код доступа при возникновении ошибки 0 — чтение, 1 — запись (у меня 0) 3 Адрес инструкции, из которой был осуществлен ошибочный доступ (некоторое значение) 4 Зарезервировано (0) Значит ошибка при ЧТЕНИИ. При чтении буфера, очевидно ) Наверняка я с синтаксисом накосячил.
|
|
« Последнее редактирование: 27-04-2010 12:46 от tuiui »
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #31 : 27-04-2010 13:42 » |
|
memcpy(Address, writeBuffer, writeLength*4); Я постов предыдущих много пропустил, и возможно поэтому не пойму, откуда тут взялся memcpy. Ошибка не из-за этого, но всё-равно надо писать RtlCopyMemory. По поводу самой ошибки. Вопрос - зачем умножать на 4 ?
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #32 : 27-04-2010 16:34 » |
|
//Получаем смещение байта byteOffset = irpStack->Parameters.Write.ByteOffset.LowPart; -> это что? и зачем?)
и почему действительно *4?
при доступе обязательно проверяйте выход за пределы выделенной вам памяти. в драйвере ВСЕГДА надо проверять все что приходит от приложения. в не зависимости от того что приложение тоже вами написано)
RtlCopyMemory - справедливо. действительно лучше пользовать ее.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #33 : 27-04-2010 20:44 » |
|
Ну не дожидаясь ответа от ТС, я сам себе так понимаю, что writeLength это размер write-буфера. Умножаем на 4 (зачем? а зачем тигру полоски? он же не зебра) и оказываемся за пределами буфера
|
|
« Последнее редактирование: 27-04-2010 20:55 от resource »
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #34 : 28-04-2010 05:12 » |
|
1. ByteOffset - это смещение относительно начала памяти устройства. Другими словами, это адрес в памяти устройства, с которого начинается запись. Передается этот параметр через структуру overlapped при вызове WriteFile (последний параметр). Мне же надо как-то из приложения передавать этот адрес.
2. Умножение на 4. Дело в том, что плата обменивается с памятью 4-байтными словами. А смещение поступает в байтах. Я хочу, чтобы смещение тоже задавалось двойными словами. То есть если напишем WriteFile(п1,п2,п3,8), то запись должна начинаться с 8-го двойного слова. Поэтому умножаю на 4. С размером буфера - то же самое. Если пишу 20, то он записывает 20 байт. А мне надо 20 двойных слов.
3. RtlCopyMemory - пробовал. Тот же результат.
Может указатель на буфер пользователя делать такого типа, чтобы RtlCopyMemory понимала, что речь идет о буфере а двойными словами
ЗЫ Скорее всего, как раз в этом *4 ошибка и есть. Но не должно же быть, вроде... Думаю, надо разобраться подробно, что происходит при вызове WriteFile, кто и как наращивает счетчики адресов. Может, если в качестве источника в WriteFile указывать массив двойных слов, то не надо умножать на 4.
|
|
« Последнее редактирование: 28-04-2010 05:32 от tuiui »
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #35 : 28-04-2010 05:59 » |
|
Про слова, двойные слова, тройные или еще какие - это вариант гиблый, т.к. менеджеру ввода/вывода глубоко наплевать на все эти слова (это к вопросу о том, что происходит при вызове WriteFile). Честно говоря, такой фокус вижу впервые. На будущее, если в документации написано "размер в байтах", значит надо передавать размер в байтах. Ну можно же написать себе макрос и спокойно им пользоваться
|
|
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #36 : 28-04-2010 07:50 » |
|
Благодарю за помощь. Сделал все в байтах. Теперь при записи по адресу d1048575 все ок. А при записи по адресу d1048576 синий экран )) На борту платы 1 Мб памяти. Отсюда вывод: надо в драйвере сделать защиту от дурака. То бишь как-то отлавливать возможные выходы за диапазон, отведенный плате в памяти.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #37 : 28-04-2010 08:46 » |
|
d1048575 -шо за адрес? невыровненный... как-то подозрительно.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Ochkarik
|
|
« Ответ #38 : 28-04-2010 09:33 » |
|
вы по одному байту записываете? а плата это поддерживает?)
PS пардон. случайно ваше предыдущее сообщение удалил(((
PPS аааа! дошло.... я привык что адреса обычно в шеснадцатиричном формате выкладывают) "d" - не заметил) а проверять естественно. проверять надо все что приходит от приложения. ОБЯЗАТЕЛЬНО
|
|
« Последнее редактирование: 28-04-2010 09:37 от Ochkarik »
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #39 : 28-04-2010 09:36 » |
|
PS пардон. случайно ваше предыдущее сообщение удалил(((
инстинкт сработал
|
|
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #40 : 28-04-2010 09:38 » |
|
))) пришлось переделать проект под плис, чтобы поддерживала. Можно вас попросить код набросать, как бы мне отлавливать эти ошибки дурака.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #41 : 28-04-2010 09:39 » |
|
а чего там набрасывать... это как проверка выхода за пределы массива. все исходные данные у вас уже есть...
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #42 : 28-04-2010 09:49 » |
|
все хорошо. Ошибки, связанные с выходом за границу адресов, отлавливаются, возвращается 0. Но вот когда пишем данные в количестве, равном 0, синий экран ) В драйвере есть такая вещь: //Получаем количество данных для записи writeLength = irpStack->Parameters.Write.Length; if (writeLength == 0) { status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); MultiplierCDecrementIoCount(&deviceExtension->IoLock); return status; }
Почему она не отлавливает запись нулевого количества??? А может отлавливает, но сама вызывает ошибку!
|
|
« Последнее редактирование: 28-04-2010 11:38 от tuiui »
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #43 : 28-04-2010 11:59 » |
|
попробуйте Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; // Irp->IoStatus.Information не присваивать. .. IoCompleteRequest(Irp, IO_NO_INCREMENT); MultiplierCDecrementIoCount(&deviceExtension->IoLock); return STATUS_SUCCESS;
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #44 : 28-04-2010 12:08 » |
|
хммм, интересно... Information то в 0 выставляется. Странно. Не знаю почему такая. Точно не должно такого быть. Тут надо смотреть отладчиком. Там всё сразу видно будет.
Но тут просто больше не из за чего падать кроме как.......... IoLock'и я бы закомментарил.
Уверен, что дело именно в этом. Что там за функции такие? Покажите код.
|
|
« Последнее редактирование: 28-04-2010 12:13 от resource »
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #45 : 28-04-2010 12:38 » |
|
Тот код, что я привел, генерирует студия. В комментариях написано "просто завершить запрос нулевой длины". Что интересно, точно такие же конструкции используются для завершения запроса при выходе за диапазон адресов. Прям скопировал тупо эти 6 строчек везде, где нужно "аварийно" завершить работу.
resource, какой код вы просите показать?
|
|
« Последнее редактирование: 28-04-2010 12:42 от tuiui »
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #46 : 28-04-2010 13:03 » |
|
MultiplierCCheckIoLock и MultiplierCDecrementIoCount
|
|
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #47 : 28-04-2010 13:11 » |
|
/////////////////////////////////////////////////////////////////////////////////////////////////// // MultiplierCCheckIoLock // checks if IRP is allowed to proceed. // // Arguments: // IN IoLock // io lock for our device // // IN Irp // new IRP // // Return Value: // Status // NTSTATUS MultiplierCCheckIoLock( IN PMULTIPLIERC_IO_LOCK IoLock, IN PIRP Irp ) { NTSTATUS status; KIRQL oldIrql; PMULTIPLIERC_DEVICE_EXTENSION deviceExtension;
deviceExtension = (PMULTIPLIERC_DEVICE_EXTENSION)IoLock->DeviceObject->DeviceExtension;
KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);
// check if device has been removed if (IoLock->ErrorStatus != STATUS_SUCCESS) { status = IoLock->ErrorStatus; KeReleaseSpinLock(&IoLock->IoLock, oldIrql);
Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status; }
// check if io is stalled if (IoLock->StallCount > 0) { // check if Irp is not the one sent by MultiplierCUnlockIo if (IoLock->CurrentIrp != Irp) { // save device extension into the IRP Irp->Tail.Overlay.DriverContext[0] = IoLock;
// stall the IRP InsertTailList(&IoLock->StallIrpList, &Irp->Tail.Overlay.ListEntry);
// insert our queue cancel routine into the IRP IoSetCancelRoutine(Irp, MultiplierCPendingIoCancelRoutine);
// see if IRP was canceled if (Irp->Cancel && (IoSetCancelRoutine(Irp, NULL) != NULL)) { // IRP was canceled RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
// drop the lock KeReleaseSpinLock(&IoLock->IoLock, oldIrql);
// cancel the IRP status = STATUS_CANCELLED; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status; }
// mark irp pending since STATUS_PENDING is returned IoMarkIrpPending(Irp); status = STATUS_PENDING;
// drop the lock KeReleaseSpinLock(&IoLock->IoLock, oldIrql);
// io is stalled. Make sure it is not because of // device is powered down.
if (deviceExtension->DevicePowerState > PowerDeviceD0) { POWER_STATE powerState;
powerState.DeviceState = PowerDeviceD0; status = PoRequestPowerIrp( deviceExtension->PhysicalDeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL ); }
return status; } else { IoLock->CurrentIrp = NULL; } }
// increment active io count ++IoLock->ActiveIrpCount;
// drop the lock KeReleaseSpinLock(&IoLock->IoLock, oldIrql);
status = STATUS_SUCCESS; return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // MultiplierCDecrementIoCount // decrements active io count. // // Arguments: // IN IoLock // io lock for our device // // Return Value: // None // VOID MultiplierCDecrementIoCount( IN PMULTIPLIERC_IO_LOCK IoLock ) { KIRQL oldIrql;
KeAcquireSpinLock(&IoLock->IoLock, &oldIrql);
if (--IoLock->ActiveIrpCount == 0) { KeSetEvent(&IoLock->StallCompleteEvent, IO_NO_INCREMENT, FALSE); }
KeReleaseSpinLock(&IoLock->IoLock, oldIrql);
return; }
|
|
« Последнее редактирование: 28-04-2010 13:14 от tuiui »
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #48 : 28-04-2010 14:02 » |
|
код приложения еще можно посмотреть? тот, что вызывает эту функцию драйвера
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #49 : 28-04-2010 19:30 » |
|
Ну это уже гадание на кофейной гуще. Есть бсод - есть дамп. Глянуть отладчиком и всё сразу ясно станет
|
|
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #50 : 29-04-2010 05:05 » |
|
Ochkarik, если я правильно понимаю, от приложения не должна зависеть стабильность драйвера. Он ведь должен быть защищен от любого дурака. А с отладчиком не умею работать (
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #51 : 29-04-2010 05:14 » |
|
Про приложение это совершенно верно подмечено. Но думаю, что Ochkarik хотел на него глянуть, так, на всякий случай.
С отладчиком дружить надо. По-другому никак. Собственно для анализа дампа даже не надо второй машины. Я бы даже не обломился и посмотрел бы ваш дамп. Мне канал позволяет сливать такие объемы. Но бесплатные файлообменники вряд ли позволять забирать его с нормальной скоростью. Да и у вас канал, возможно не такой широкий, чтоб заливать столько. Так что, без отладчика никуда.
|
|
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #52 : 29-04-2010 05:32 » |
|
Я просто не совсем даже и понимаю принцип его работы и что он позволяет сделать... Простите мне мое дилетантство, но можно ли в код драйвера встроить некие контрольные точки? Чтоб, например, выводилась в файл информация о том, куда зашли, какую ошибку отловили? А пока вот что я могу сказать. В драйвере последовательность проверок такая: 1. Проверка на слишком большой (маленький) адрес 2. Проверка на нулевую длину Вызываю WriteFile с нормальным адресом и нулевым количеством - BSOD Вызываю WriteFile с некорректным адресом и нормальным количеством. Все нормально. Возвращает ноль, ничего не вылетает. Вызываю WriteFile с некорректным адресом и нулевым количеством - BSOD !! Отсюда вывод, что он даже не доходит до проверки на нулевую длину. Он даже не доходит до проверки на адрес. Иначе бы на первой проверке обработка завершилась. Куда же тогда смотреть?
|
|
« Последнее редактирование: 29-04-2010 06:13 от tuiui »
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #53 : 29-04-2010 06:28 » |
|
Контрольные точки то можно, но нужны они как раз при работе под отладчиком. И это логично, иначе как еще остановить драйвер, этож надо всю систему останавливать. И оно так и происходит, поэтому нужны 2 машины. Но чтоб дамп анализировать, 2 не надо.
В вашем случае, можно воспользоваться функцией DbgPrint. Такая софтина как, например, DebugView покажет всё, что выводится при помощи DbgPrint. Арсенал не богатый, но без отладчика не приходится расчитывать на что-то серьезное.
|
|
|
Записан
|
|
|
|
Ochkarik
|
|
« Ответ #54 : 29-04-2010 10:41 » |
|
offtopic: "Ochkarik, если я правильно понимаю, от приложения не должна зависеть стабильность драйвера. Он ведь должен быть защищен от любого дурака. " - да! НО! если при написании драйвера осуществлены все возможные проверки и отслежены все не корректные запросы. в противном случае...) не думайте что ЛЮБОЙ драйвер защищен. вся его защита от падения - это работа программиста. ОС за этим не следит.
|
|
|
Записан
|
RTFM уже хоть раз наконец! :[ ну или хотя бы STFW...
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #55 : 29-04-2010 12:58 » |
|
Нашел, в чем была проблема. Оказывается, ошибка возникала при получении ссылки на буфер с данными ) Почему - объяснить не могу. Видимо, когда нулевая длина, система не передает ссылку на буфер. Так что сначала надо проверять длину буфера данных. И только если она больше нуля, пытаться получить ссылку на этот буфер: //Получаем стек IRP irpStack = IoGetCurrentIrpStackLocation(Irp); //Получаем количество данных для записи writeLength = irpStack->Parameters.Write.Length;
//Завершение запроса при нулевом количестве данных if (writeLength == 0) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } //Получаем адрес буфера для чтения writeBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
Так что пока все нормально. Буду гонять еще драйвер. Если что-то всплывет - сообщу ))
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #56 : 29-04-2010 19:43 » |
|
Что-то вы уж совсем какие-то сказки выдумываете про буфер. В посте #30 точно такая же обработка идет. Разница (как видно) в том, что вы убрали IoLock'и (что собственно и было рекомендовано в #44)
|
|
|
Записан
|
|
|
|
tuiui
Участник
Offline
|
|
« Ответ #57 : 30-04-2010 05:36 » |
|
В посте #30 не было проверки на адреса. Там вылетало из-за этого )) А тут черт теперь разберешь. Но помню точно, что комментил IoLock, как вы рекомендовали. Не помогло тогда. Но я его все же убрал ) Наверно, не зря. Но даже без него вылетало, если пытаться буфер получать раньше обработки его длины.
В любом случае, большое всем вам спасибо. Вы мне очень помогли!
|
|
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #58 : 30-04-2010 06:13 » |
|
Да действительно, в #30 не было проверки. Ну так и в коде, приведенном в #55 ее тоже нет. Проверять, что возвращает MmGetSystemAddressForMdlSafe полюбому надо. Но если дело было в этом, то интересно почему она возвращала NULL для буфера ненулевой длины. Или чего она возвращала вообще. Ну да ладно...
|
|
|
Записан
|
|
|
|
|