Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Для большинства промежуточных и самых низких драйверов расширение устройства является самой важной структурой данных, связанной с объектом устройства. Внутренняя структура определяется драйвером и обычно используется для следующих целей:
Поддерживать информацию о состоянии устройства.
Обеспечьте хранилище для определённых ядром объектов или других системных ресурсов, таких как ситуационные блокировки, используемые драйвером.
Удерживайте все данные, которые драйвер должен иметь резидент и в системном пространстве для выполнения операций ввода-вывода.
Так как большинство драйверов шины, функций и фильтров (водителей низкого уровня и промежуточных драйверов) выполняются в произвольном контексте потока (что бы ни было текущим потоком), расширение устройства является основным местом для поддержания состояния устройства и всех остальных данных, необходимых драйверу. Например, любой драйвер, реализующий подпрограмму CustomTimerDpc или CustomDpc , обычно предоставляет хранилище для требуемого таймера ядра и (или) объектов DPC в расширении устройства.
Каждый драйвер, имеющий ISR, должен предоставлять хранилище для указателя на набор объектов прерываний, определенных ядром, и большинство драйверов устройств хранят этот указатель в расширении устройства. Каждый драйвер определяет размер расширения устройства при создании объекта устройства, а каждый драйвер определяет содержимое и структуру собственных расширений устройств.
Подпрограммы IoCreateDevice и IoCreateDeviceSecure диспетчера операций ввода-вывода выделяют память для объекта устройства и расширения из нестраничного пула памяти.
Каждая стандартная подпрограмма драйвера, получающая IRP, также получает указатель на объект устройства, представляющий целевое устройство для запрошенной операции ввода-вывода. Эти подпрограммы драйверов могут получить доступ к соответствующему расширению устройства с помощью этого указателя. Как правило, указатель DeviceObject также является входным параметром для ISR драйвера низкого уровня.
На следующем рисунке показан репрезентативный набор данных, определенных драйвером, для расширения объекта устройства самого нижнего уровня. Драйвер более высокого уровня не предоставляет хранилище для указателя объекта прерывания, возвращенного IoConnectInterrupt и переданного в KeSynchronizeExecution и IoDisconnectInterrupt. Однако драйвер более высокого уровня предоставляет хранилище для объектов таймера и DPC, показанных на следующем рисунке, если драйвер имеет подпрограмму CustomTimerDpc . Драйвер более высокого уровня также может предоставить хранилище для спин-блокировки исполнительного уровня и взаимоблокированного рабочего очереди.
Помимо предоставления хранилища для указателя объекта прерывания, драйвер устройства низкого уровня должен предоставить хранилище для блокировки прерывания, если его ISR обрабатывает прерывания для двух или нескольких устройств на разных векторах или если он имеет более одного ISR. Дополнительные сведения о регистрации ISR см. в разделе "Регистрация ISR".
Как правило, драйверы хранят указатели на объекты устройства в расширениях устройств, как показано на рисунке. Драйвер также может хранить копию списка ресурсов для устройства в расширении.
Драйвер более высокого уровня обычно сохраняет указатель на объект устройства следующего уровня драйвера в расширении устройства. Драйвер более высокого уровня должен передать указатель на объект устройства драйвера следующего уровня в IoCallDriver, после того как он настроил местоположение стека ввода-вывода следующего уровня драйвера в IRP, как описано в разделе "Обработка IRP".
Обратите внимание также, что любой драйвер более высокого уровня, который выделяет IRP для драйверов нижнего уровня, должен указывать количество уровней стека новых IRP. В частности, если драйвер более высокого уровня вызывает IoMakeAssociatedIrp, IoAllocateIrp или IoInitializeIrp, он должен получить доступ к целевому объекту устройства следующего нижнего уровня драйвера для чтения значения StackSize , чтобы предоставить правильный StackSize в качестве аргумента для этих подпрограмм поддержки.
Хотя драйвер более высокого уровня может считывать данные из объекта устройства драйвера следующего уровня с помощью указателя, возвращаемого IoAttachDeviceToDeviceStack, такой драйвер должен следовать этим рекомендациям по реализации:
Никогда не пытайтесь записывать данные в объект устройства низшего драйвера.
Единственными исключениями в этом руководстве являются файловые системы, которые задают и очищают DO_VERIFY_VOLUME в флагах объектов устройств драйверов съемных носителей нижнего уровня.
Никогда не пытайтесь получить доступ к расширению устройства нижнего драйвера по следующим причинам:
Нет безопасного способа синхронизации доступа к одному расширению устройства между двумя драйверами.
Пара драйверов, реализующих такую схему обмена внутренними данными, не может быть обновлена по отдельности, не позволяет вставку промежуточного драйвера между ними без изменения исходного кода существующих драйверов, не может быть перекомпилирована и без труда перемещена с одной платформы Windows на другую.
Чтобы сохранить совместимость с драйверами нижнего уровня от одной платформы или версии Windows до следующей, драйверы более высокого уровня должны либо повторно использовать предоставленные им IRP, либо создавать новые IRP и использовать IoCallDriver для обмена запросами с драйверами нижнего уровня.