Наконец, если вы изучаете аварийный дамп (или «снимок» работающей системы) с помощью отладчика ядра, то можете получить аналогичные сведения командой Im kv:
Структура драйвера
Выполнением драйверов устройств управляет подсистема ввода-вывода. Драйвер устройства состоит из набора процедур, вызываемых на различных этапах обработки запроса ввода-вывода. Основные процедуры драйвера показаны на рис. 9–5.
• Инициализирующая процедура Диспетчер ввода-вывода выполняет инициализирующую процедуру драйвера (которая обычно называется DriverEntry) при загрузке этого драйвера в операционную систему. Данная процедура регистрирует остальные процедуры драйвера в диспетчере ввода-вывода, заполняя соответствующей информацией системные структуры данных, и выполняет необходимую глобальную инициализацию драйвера.
• Процедура добавления устройства Такие процедуры реализуются в драйверах, поддерживающих Plug and Play. Через эту процедуру диспетчер PnP посылает драйверу уведомление при обнаружении устройства, за которое отвечает данный драйвер. Выполняя эту процедуру, драйвер обычно создает объект «устройство», представляющий аппаратное устройство.
• Процедуры диспетчеризации Это основные функции, предоставляемые драйвером устройства, например для открытия, закрытия, чтения, записи и реализации других возможностей устройства, файловой системы или сети. Диспетчер ввода-вывода, вызванный для выполнения операции ввода-вывода, генерирует IRP и обращается к драйверу через одну из его процедур диспетчеризации.
• Процедура инициации ввода-вывода C помощью этой процедуры драйвер может инициировать передачу данных как на устройство, так и с него. Эта процедура определяется лишь в драйверах, использующих поддержку диспетчера ввода-вывода для помещения входящих запросов в очередь. Диспетчер ввода-вывода ставит в очередь IRP для драйвера, гарантируя одновременную обработку им только одного IRP Большинство драйверов обрабатывают сразу несколько IRP, но создание очереди имеет смысл для некоторых драйверов, в частности для драйвера клавиатуры.
• Процедура обслуживания прерываний (ISR) Когда устройство генерирует прерывание, диспетчер прерываний ядра передает управление этой процедуре. B модели ввода-вывода Windows процедуры ISR работают на уровне DIRQL (Device IRQL), поэтому они выполняют минимум действий во избежание слишком продолжительной блокировки прерываний более низкого уровня (подробнее об IRQL см. главу 3). Для выполнения остальной части обработки прерывания ISR ставит в очередь DPC (deferred procedure call), выполняемый при более низком IRQL (уровня «DPC/ dispatch»). ISR имеются лишь в драйверах устройств, управляемых прерываниями, — например в драйвере файловой системы ISR нет.
• DPC-процедура обработки прерываний DPC-процедура выполняет основную часть обработки прерывания, оставшуюся после выполнения ISR. Она работает при более низком IRQL (уровня «DPC/dispatch»), чем ISR, чтобы не блокировать без необходимости другие прерывания. DPC-процедура инициирует завершение текущей операции ввода-вывода и выполнение следующей операции ввода-вывода из очереди на данном устройстве. У многих драйверов устройств имеются процедуры, не показанные на рис. 9–5.
• Одна или несколько процедур завершения ввода-вывода У драйвера могут быть процедуры завершения ввода-вывода, уведомляющие его об окончании обработки IRP драйвером более низкого уровня. Например, диспетчер ввода-вывода вызывает процедуру завершения ввода-вывода драйве-
pa файловой системы, когда драйвер устройства заканчивает передачу данных в файл или из него. Эта процедура уведомляет драйвер файловой системы об удачном или неудачном завершении операции или о ее отмене, а также позволяет драйверу файловой системы освободить ресурсы.
• Процедура отмены ввода-вывода Если операция ввода-вывода может быть отменена, драйвер определяет одну или более процедур отмены ввода-вывода. Получив IRP для запроса ввода-вывода, который может быть отменен, драйвер связывает с IRP процедуру отмены. Если поток, выдавший запрос на ввод-вывод, завершается до окончания обработки запроса или отменяет операцию (например, вызовом Windows-функции CancelIo), диспетчер ввода-вывода выполняет процедуру отмены, связанную с IRP (если таковая есть). Процедура отмены отвечает за выполнение любых действий, необходимых для освобождения всех ресурсов, выделенных при обработке IRP, а также за завершение IRP со статусом отмены.
• Процедура выгрузки Эта процедура освобождает все системные ресурсы, задействованные драйвером, после чего диспетчер ввода-вывода может удалить их из памяти. При выполнении процедуры выгрузки обычно освобождаются ресурсы, выделенные процедурой инициализации. Драйвер может загружаться и выгружаться во время работы системы.
• Процедура уведомления о завершении работы системы Эта процедура позволяет драйверу проводить очистку при завершении работы системы.
• Процедуры регистрации ошибок При возникновении неожиданных ошибок (например, когда на диске появляется поврежденный блок), процедуры регистрации ошибок, принадлежащие драйверу, уведомляют о них диспетчер ввода-вывода. Последний записывает эту информацию в файл журнала ошибок.
ПРИМЕЧАНИЕ Большинство драйверов устройств написано на С. Применение языка ассемблера крайне не рекомендуется из-за его сложности и из-за того, что он затрудняет перенос драйвера между аппаратными архитектурами вроде x86, х64 и IА64.
Объекты «драйвер» и «устройство»
Когда поток открывает описатель объекта «файл» (этот процесс описывается в разделе «Обработка ввода-вывода» далее в этой главе), диспетчер ввода-вывода, исходя из имени этого объекта, должен определить, к какому драйверу (или драйверам) нужно обратиться для обработки запроса. Более того, диспетчер ввода-вывода должен знать, где найти эту информацию, когда в следующий раз поток вновь воспользуется тем же описателем файла. Для этого предназначены следующие объекты.
• Объект «драйвер», представляющий отдельный драйвер в системе. Именно от этого объекта диспетчер ввода-вывода получает адрес процедуры диспетчеризации (точки входа) драйвера.
• Объект «устройство», представляющий физическое или логическое устройство в системе и описывающий его характеристики, например границы выравнивания буферов и адреса очередей для приема IRP, поступающих на это устройство.
Диспетчер ввода-вывода создает объект «драйвер» при загрузке в систему соответствующего драйвера и вызывает его инициализирующую процедуру (например, DriverEntry), которая записывает в атрибуты объекта точки входа этого драйвера.
После загрузки драйвер может создавать объекты «устройство» для представления устройств или даже для формирования интерфейса драйвера (вызовом IoCreateDevice или IoCreateDeviceSecure). Однако большинство PnP-драйверов создают объекты «устройство» с помощью своих процедур добавления устройств, когда диспетчер PnP информирует их о присутствии управляемого ими устройства. C другой стороны, драйверы, не отвечающие спецификации Plug and Play, создают объекты «устройство» при вызове диспетчером ввода-вывода их инициализирующих процедур. Диспетчер ввода-вывода выгружает драйвер после удаления его последнего объекта «устройство», когда ссылок на устройство больше нет.
Создавая объект «устройство», драйвер может присвоить ему имя. Тогда этот объект помещается в пространство имен диспетчера объектов. Драйвер может определить имя этого объекта явно или позволить диспетчеру ввода-вывода сгенерировать его автоматически (о пространстве имен диспетчера объектов см. главу 3). По соглашению объекты «устройство» помещаются в каталог Device пространства имен, недоступный приложениям через Windows API.
ПРИМЕЧАНИЕ Некоторые драйверы размещают объекты «устройство» в каталогах, отличных от Device. Так, диспетчер томов Logical Disk Manager создает объекты «устройство», представляющие разделы жесткого диска, в каталоге DeviceHarddiskDmVolumes (подробнее на эту тему см. главу 10).
Чтобы сделать объект «устройство» доступным для приложений, драйвер должен создать в каталоге Global?? (или в каталоге ?? в Windows 2000) символьную ссылку на имя этого объекта в каталоге Device. Драйверы, не поддерживающие Plug and Play, и драйверы файловой системы обычно создают символьную ссылку с общеизвестным именем (скажем, DeviceHardware2). Поскольку общеизвестные имена не срабатывают в средах с динамически меняющимся составом оборудования, PnP-драйверы предоставляют один или несколько интерфейсов через функцию IoRegisterDeviceInterface, передавая ей GUID, определяющий тип предоставляемой функциональности. GUID являются 128-битными числами, которые можно генерировать с помощью утилиты Guidgen, входящей в состав DDK и Platform SDK. Диапазон чисел, который может быть представлен 128 битами, гарантирует, что каждый GUID, созданный этой утилитой, всегда будет глобально уникальным.