Программирование драйверов Windows

Процедура DriverEntry


Диспетчер ввода/вывода вызывает данную процедуру при загрузке драйвера. Возможно, это произойдет в процессе загрузки операционной системы, но драйвер может быть загружен и динамически в любое время, как это было сделано с драйвером Example.sys в главе 3. Процедура DriverEntry решает первоочередные задачи, в частности, регистрацию в специальном массиве адресов других драйверных процедур (для того, чтобы Диспетчер ввода/вывода имел возможность позже производить их вызов по адресу). В случае если драйвер не работает по модели WDM (legacy драйвер, драйвер "в-стиле-NT"), то в этой же начальной процедуре можно провести локализацию оборудования, которое будет обслуживать драйвер, выделить или подтвердить использование аппаратных ресурсов (портов ввода/вывода, прерываний, каналов DMA) и предоставить имя, видимое всей остальной системе, для каждого обнаруженного устройства. Для WDM драйверов, поддерживающих спецификацию PnP, процесс определения аппаратных ресурсов откладывается на более позднее время и выполняется драйверной процедурой AddDevice.

Строго говоря, определенное имя (то есть DriverEntry) должно быть только лишь у этой "входной" процедуры. Имена остальных драйверных процедур не столь жестко определены, поскольку они не будут никому известны, за исключением обладателя исходного текста или хакера-исследователя, работающего с отладочной версией. От остальных процедур в системе остаются только их адреса, и к ним предъявляется требование иметь определенный интерфейс вызова, согласованный по типу получаемых и возвращаемых параметров. Поэтому все приведенные в книге имена драйверных процедур можно рассматривать как "говорящие фамилии", кратко описывающие назначение этих процедур. При разработке собственных драйверов можно использовать любые названия.


Здесь все запросы будут приводить к вызову функции myPassIrpDown, которая занимается только лишь переадресацией запросов нижним драйверам в стеке WDM драйверов. Исключение составит функция-обработчик IOCTL запросов, которые будут поступать в функцию DeviceControlRoutine фильтр-драйвера.

Помимо регистрации функций, процедура DriverEntry драйвера "в-стиле-NT" может выполнять следующую работу:

  • DriverEntry определяет аппаратное обеспечение, которое драйвер будет контролировать. Это аппаратное обеспечение выделяется драйверу, то есть помечается как находящееся под управлением данного драйвера.


  • Если драйвер управляет многокомпонентным (multiunit) или многофункциональным контроллером, используется IoCreateController для создания объекта контроллера, после чего инициализируется структура расширения контроллера.


  • Выполняет вызов IoCreateDevice для создания объекта устройства для каждого физического или логического устройства под управлением данного драйвера, в процессе которого инициализируется структура расширения устройства для каждого созданного объекта устройства. Рекомендуется сразу же после этого вызова явно установить флаги (поле Flags в объекте устройства), описывающие способ буферизации, используемый данным устройством.




  • Созданные устройства затем делаются видимыми для приложений пользовательского режима путем выполнения вызова IoCreateSymbolicLink.


  • Устройство подключается к объекту прерываний. В случае, если ISR процедура требуют использования объекта DPC (отложенного процедурного вызова), то он создается и инициализируется на этом этапе.


  • Шаги с 3 по 5 повторяются для каждого физического или логического устройства, работающего под управлением данного драйвера.


  • В случае успешного завершения, функция DriverEntry должна возвратить Диспетчеру ввода/вывода значение STATUS_SUCCESS.


  • В случае, если процедура DriverEntry обнаружила, что некоторые действия, которые она должна выполнить как часть подготовки к запуску драйвера, не могут быть выполнены сейчас, но в будущем (после загрузки некоторых других драйверов, например) это станет возможным, то DriverEntry должна зарегистрировать собственную процедуру, которая завершит инициализацию чуть позже.


    Регистрация такой процедуры выполняется системным вызовом IoRegisterDriverReinitialization (см. таблицу 8.2).

    Таблица 8.2. Параметры системного вызова IoRegisterDriverReinitialization

    VOID IoRegisterDriverReinitialization IRQL == PASSIVE_LEVEL
    Параметры Регистрирует функцию драйвера для отложенной инициализации
    IN PDRIVER_OBJECT pDriverObject Указатель на объект драйвера
    IN PDRIVER_REINITIALIZE DriverReinitializationRoutine Указатель на процедуру реинициализации, предоставляемую драйвером (см. таблицу 8.3 ниже).
    IN PVOID Context Контекстный указатель, который получит регистрируемая функция при вызове
    Возвращаемое значение void
    Таблица 8.3. Описание параметров вызова myReinitializeFunction

    VOID myReinitializeFunction IRQL == PASSIVE_LEVEL
    Параметры Функция драйвера, регистрируемая для выполнения отложенной инициализации
    IN PDRIVER_OBJECT pDriverObject Указатель на объект драйвера
    IN PVOID Context Контекстный блок, указанный при регистрации
    IN ULONG Количество вызовов процедуры ре-инициализации (отсчет от 0)
    Возвращаемое значение void
    Как было указано в главе 7, процедуру DriverEntry можно разместить в "отстреливающемся" сегменте кода INIT.


    Содержание раздела