Расширения устройств

Для большинства драйверов среднего и самого низкого уровня расширение устройства является наиболее важной структурой данных, связанной с объектом устройства. Его внутренняя структура определяется драйвером и обычно используется для:

  • Ведение сведений о состоянии устройства.

  • Предоставьте хранилище для всех объектов, определенных ядром, или других системных ресурсов, таких как спин-блокировки, используемых драйвером.

  • Храните все данные, которые драйвер должен иметь в системном пространстве и в системном пространстве для выполнения операций ввода-вывода.

Так как большинство драйверов шины, функций и фильтров (драйверов низкого и среднего уровня) выполняются в произвольном контексте потока (в любом потоке), расширение устройства является основным местом для каждого драйвера для поддержания состояния устройства и всех других данных, необходимых драйверу. Например, любой драйвер, реализующий подпрограмму 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 в разделе Флаги объектов устройств драйверов съемного носителя нижнего уровня.

  • Никогда не пытайтесь получить доступ к расширению устройства нижнего драйвера по следующим причинам:

    • Нет безопасного способа синхронизации доступа к одному расширению устройства между двумя драйверами.

    • Пару драйверов, реализующих такую схему взаимодействия с backdoor, нельзя обновить по отдельности, между ними не может быть вставлен промежуточный драйвер, не изменяя существующий источник драйвера, и их нельзя легко перекомпилировать и переместить с одной платформы Windows на другую.

Чтобы обеспечить взаимодействие с драйверами более низкого уровня от одной платформы Или версии Windows к другой, драйверы более высокого уровня должны либо повторно использовать предоставленные им поставщики интеграции, либо создавать новые поставщики irP, а также использовать IoCallDriver для передачи запросов драйверам более низкого уровня.