Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Минидрайвер или минипорт-драйвер выступает в качестве половины пары драйверов. Пары драйверов, такие как (минипорт, порт), могут упростить разработку драйверов. В паре драйверов один драйвер обрабатывает общие задачи, которые являются общими для всей коллекции устройств, а другой драйвер обрабатывает задачи, относящиеся к отдельному устройству. Драйверы, обрабатывающие задачи, относящиеся к устройству, называются по-разному, включая драйвер минипорта, драйвер миникласса и минидрайвер.
Корпорация Майкрософт предоставляет общий драйвер, и, как правило, независимый поставщик оборудования предоставляет конкретный драйвер. Прежде чем прочитать этот раздел, вы должны понять идеи, представленные в узлах устройств и стеках устройств и пакетах запросов ввода-вывода.
Каждый драйвер в режиме ядра должен реализовать функцию с именем DriverEntry , которая вызывается вскоре после загрузки драйвера. Функция driverEntry заполняет определенные элементы структуры DRIVER_OBJECT указателями на несколько других функций, которые реализует драйвер. Например, функция DriverEntry заполняет элемент выгрузки структуры DRIVER_OBJECT указателем на функцию выгрузки драйвера, как показано на следующей схеме.
MajorFunction элемент структуры DRIVER_OBJECT представляет собой массив указателей на функции, обрабатывающие пакеты запросов ввода-вывода (IRP), как показано на следующей схеме. Как правило, драйвер заполняет несколько членов массива MajorFunction указателями на функции (реализованные драйвером), которые обрабатывают различные виды IRP.
IRP можно классифицировать в соответствии с основным кодом функции, который определяется константой, например IRP_MJ_READ, IRP_MJ_WRITEили IRP_MJ_PNP. Константы, определяющие основной код функции, служат индексами в массиве MajorFunction. Например, предположим, что драйвер реализует диспетчерскую функцию для обработки IRP с основным кодом функции IRP_MJ_WRITE. В этом случае драйвер должен заполнить элемент MajorFunction[IRP_MJ_WRITE] массива указателем на функцию диспетчера.
Обычно драйвер заполняет некоторые элементы массива MajorFunction и оставляет оставшиеся элементы, заданные диспетчером ввода-вывода по умолчанию. В следующем примере показано, как использовать расширение отладчика !drvobj для проверки указателей функции для драйвера parport.
0: kd> !drvobj parport 2
Driver object (fffffa80048d9e70) is for:
\Driver\Parport
DriverEntry: fffff880065ea070 parport!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: fffff880065e131c parport!PptUnload
AddDevice: fffff880065d2008 parport!P5AddDevice
Dispatch routines:
[00] IRP_MJ_CREATE fffff880065d49d0 parport!PptDispatchCreateOpen
[01] IRP_MJ_CREATE_NAMED_PIPE fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE fffff880065d4a78 parport!PptDispatchClose
[03] IRP_MJ_READ fffff880065d4bac parport!PptDispatchRead
[04] IRP_MJ_WRITE fffff880065d4bac parport!PptDispatchRead
[05] IRP_MJ_QUERY_INFORMATION fffff880065d4c40 parport!PptDispatchQueryInformation
[06] IRP_MJ_SET_INFORMATION fffff880065d4ce4 parport!PptDispatchSetInformation
[07] IRP_MJ_QUERY_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL fffff880065d4be8 parport!PptDispatchDeviceControl
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880065d4c24 parport!PptDispatchInternalDeviceControl
[10] IRP_MJ_SHUTDOWN fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP fffff880065d4af4 parport!PptDispatchCleanup
[13] IRP_MJ_CREATE_MAILSLOT fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER fffff880065d491c parport!PptDispatchPower
[17] IRP_MJ_SYSTEM_CONTROL fffff880065d4d4c parport!PptDispatchSystemControl
[18] IRP_MJ_DEVICE_CHANGE fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP fffff880065d4840 parport!PptDispatchPnp
В выходных данных отладчика можно увидеть, что parport.sys реализует GsDriverEntry, точку входа для драйвера. GsDriverEntry, который был создан автоматически при создании драйвера, выполняет некоторую инициализацию, а затем вызывает DriverEntry, которая была реализована разработчиком драйвера.
Вы также можете видеть, что драйвер parport (в своей функции DriverEntry) предоставляет указатели на функции диспетчеризации для этих основных кодов функций:
- IRP_MJ_CREATE
- IRP_MJ_CLOSE
- IRP_MJ_READ
- IRP_MJ_WRITE
- IRP_MJ_QUERY_INFORMATION
- IRP_MJ_SET_INFORMATION
- IRP_MJ_DEVICE_CONTROL
- Внутренний контроль устройства IRP_MJ
- IRP_MJ_CLEANUP
- IRP_MJ_POWER
- IRP_MJ_SYSTEM_CONTROL
- IRP_MJ_PNP
Остальные элементы MajorFunction массива содержат указатели на функцию отправки по умолчанию nt! IopInvalidDeviceRequest.
В выводе отладчика можно увидеть, что драйвер Parport предоставил указатели функций для Unload и AddDevice, но не предоставил указатель функции для StartIo. Функция AddDevice является необычной, так как ее указатель функции не хранится в структуре DRIVER_OBJECT. Вместо этого он хранится в члене расширения к структуре DRIVER_OBJECT в AddDevice. На следующей схеме показаны указатели на функции, предоставляемые драйвером парпорта в функции DriverEntry. Указатели функции, предоставляемые парпортом, затеняются.
Упрощение использования пар драйверов
В течение некоторого времени, как разработчики драйверов внутри и за пределами Майкрософт получили опыт работы с моделью драйвера Windows (WDM), они поняли несколько вещей о функциях диспетчеризации:
- Функции диспетчеризации в значительной степени являются стандартными. Например, большая часть кода в функции диспетчеризации для IRP_MJ_PNP одинакова для всех драйверов. Это лишь небольшая часть кода Plug and Play (PnP), относящуюся к отдельному драйверу, который управляет отдельным оборудованием.
- Функции диспетчеризации сложны и их трудно правильно выполнить. Реализация таких функций, как синхронизация потоков, очередь IRP и отмена IRP является сложной и требует глубокого понимания того, как работает операционная система.
Чтобы упростить работу разработчиков драйверов, корпорация Майкрософт создала несколько моделей драйверов для конкретных технологий. На первый взгляд, модели, относящиеся к технологии, кажутся совершенно разными друг от друга, но более близкий взгляд показывает, что многие из них основаны на этой парадигме:
- Драйвер разделен на две части: один, который обрабатывает общую обработку и тот, который обрабатывает обработку конкретного устройства.
- Общий фрагмент написан корпорацией Майкрософт.
- Конкретный фрагмент может быть написан корпорацией Майкрософт или независимым поставщиком оборудования.
Предположим, что proseware и компании Contoso делают игрушку робота, требующего драйвера WDM. Кроме того, предположим, что корпорация Майкрософт предоставляет общий драйвер робота с именем GeneralRobot.sys. Proseware и Contoso могут создавать небольшие драйверы, которые обрабатывают требования своих конкретных роботов. Например, Proseware может записывать ProsewareRobot.sys, а пара драйверов (ProsewareRobot.sys, GeneralRobot.sys) может быть объединена для формирования одного драйвера WDM. Аналогичным образом пара драйверов (ContosoRobot.sys, GeneralRobot.sys) может объединяться для формирования одного драйвера WDM. В самой общей форме идея заключается в том, что вы можете создавать драйверы с помощью пар (specific.sys, general.sys) .
указатели функций в парах драйверов
В паре (specific.sys, general.sys) Windows загружает specific.sys и вызывает функцию DriverEntry. Функция DriverEntry в specific.sys получает указатель на структуру DRIVER_OBJECT. Как правило, вы ожидаете, что DriverEntry заполняет несколько элементов массива MajorFunction указателями на функции обработки. Кроме того, вы ожидаете, что DriverEntry заполнит член Unload (и, возможно, член StartIo) структуры DRIVER_OBJECT и член AddDevice расширения объекта драйвера. Однако в модели пары драйверов DriverEntry не обязательно делает это. Вместо этого функция DriverEntry specific.sys передает структуру DRIVER_OBJECT к функции инициализации, реализованной general.sys. В следующем примере кода показано, как функция инициализации может вызываться в паре (ProsewareRobot.sys, GeneralRobot.sys) .
PVOID g_ProsewareRobottCallbacks[3] = {DeviceControlCallback, PnpCallback, PowerCallback};
// DriverEntry function in ProsewareRobot.sys
NTSTATUS DriverEntry (DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath)
{
// Call the initialization function implemented by GeneralRobot.sys.
return GeneralRobotInit(DriverObject, RegistryPath, g_ProsewareRobottCallbacks);
}
Функция инициализации в GeneralRobot.sys записывает указатели на соответствующие элементы структуры DRIVER_OBJECT (и его расширения) и соответствующие элементы массива MajorFunction. Идея заключается в том, что когда диспетчер ввода-вывода отправляет IRP в пару драйверов, IRP сначала переходит в функцию диспетчеризации, реализованную GeneralRobot.sys. Если GeneralRobot.sys может обрабатывать IRP самостоятельно, то конкретный драйвер, ProsewareRobot.sys, не должен быть вовлечен. Если GeneralRobot.sys может обрабатывать некоторые, но не все IRP, она получает помощь от одной из функций обратного вызова, реализованных в ProsewareRobot.sys. GeneralRobot.sys получает указатели на обратные вызовы ProsewareRobot при вызове GeneralRobotInit.
В какой-то момент после того, как DriverEntry завершит выполнение, для узла устройства Proseware Robot будет построен стек устройств. Стек устройств может выглядеть следующим образом.
Как показано на предыдущей схеме, стек устройств для Proseware Robot содержит три объекта устройства. Верхний объект устройства — это объект фильтр-устройства (Filter DO), связанный с драйвером фильтра AfterThought.sys. Средний объект устройства — это функциональный объект устройства (FDO), связанный с парой драйверов (ProsewareRobot.sys, GeneralRobot.sys). Пара драйверов служит драйвером функции для стека устройств. Нижний объект устройства — это физический объект устройства (PDO), связанный с Pci.sys.
Обратите внимание, что пара драйверов занимает только один уровень в стеке устройств и связана только с одним объектом устройства: FDO. Когда GeneralRobot.sys обрабатывает IRP, он может вызвать ProsewareRobot.sys для помощи, но это не так же, как передача запроса вниз стеку устройств. Пара драйверов формирует один драйвер WDM, который находится на одном уровне в стеке устройств. Пара драйверов либо завершает IRP, либо передает его по иерархии устройств в PDO, который связан с Pci.sys.
Пример пары драйверов
Предположим, у вас есть беспроводная сетевая карта на ноутбуке, и, глядя в диспетчере устройств, вы определяете, что netwlv64.sys является драйвером сетевой карты. Вы можете использовать расширение отладчика !drvobj для проверки указателей функций для netwlv64.sys.
1: kd> !drvobj netwlv64 2
Driver object (fffffa8002e5f420) is for:
\Driver\netwlv64
DriverEntry: fffff8800482f064 netwlv64!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: fffff8800195c5f4 ndis!ndisMUnloadEx
AddDevice: fffff88001940d30 ndis!ndisPnPAddDevice
Dispatch routines:
[00] IRP_MJ_CREATE fffff880018b5530 ndis!ndisCreateIrpHandler
[01] IRP_MJ_CREATE_NAMED_PIPE fffff88001936f00 ndis!ndisDummyIrpHandler
[02] IRP_MJ_CLOSE fffff880018b5870 ndis!ndisCloseIrpHandler
[03] IRP_MJ_READ fffff88001936f00 ndis!ndisDummyIrpHandler
[04] IRP_MJ_WRITE fffff88001936f00 ndis!ndisDummyIrpHandler
[05] IRP_MJ_QUERY_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[06] IRP_MJ_SET_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[07] IRP_MJ_QUERY_EA fffff88001936f00 ndis!ndisDummyIrpHandler
[08] IRP_MJ_SET_EA fffff88001936f00 ndis!ndisDummyIrpHandler
[09] IRP_MJ_FLUSH_BUFFERS fffff88001936f00 ndis!ndisDummyIrpHandler
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[0b] IRP_MJ_SET_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[0c] IRP_MJ_DIRECTORY_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[0e] IRP_MJ_DEVICE_CONTROL fffff8800193696c ndis!ndisDeviceControlIrpHandler
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880018f9114 ndis!ndisDeviceInternalIrpDispatch
[10] IRP_MJ_SHUTDOWN fffff88001936f00 ndis!ndisDummyIrpHandler
[11] IRP_MJ_LOCK_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[12] IRP_MJ_CLEANUP fffff88001936f00 ndis!ndisDummyIrpHandler
[13] IRP_MJ_CREATE_MAILSLOT fffff88001936f00 ndis!ndisDummyIrpHandler
[14] IRP_MJ_QUERY_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler
[15] IRP_MJ_SET_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler
[16] IRP_MJ_POWER fffff880018c35e8 ndis!ndisPowerDispatch
[17] IRP_MJ_SYSTEM_CONTROL fffff880019392c8 ndis!ndisWMIDispatch
[18] IRP_MJ_DEVICE_CHANGE fffff88001936f00 ndis!ndisDummyIrpHandler
[19] IRP_MJ_QUERY_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler
[1a] IRP_MJ_SET_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler
[1b] IRP_MJ_PNP fffff8800193e518 ndis!ndisPnPDispatch
В выходных данных отладчика можно увидеть, что netwlv64.sys реализует GsDriverEntry, точку входа для драйвера. GsDriverEntry, который был автоматически создан при создании драйвера, выполняет некоторую инициализацию, а затем вызывает DriverEntry, которая была написана разработчиком драйвера.
В этом примере netwlv64.sys реализует DriverEntry, но ndis.sys реализует AddDevice, Unloadи несколько функций диспетчеризации. Netwlv64.sys называется мини-драйвером NDIS, а ndis.sys называется библиотекой NDIS. Вместе два модуля образуют пару (минипорт NDIS, библиотека NDIS).
На этой схеме показан стек устройств для беспроводной сетевой карты. Обратите внимание, что пара драйверов (netwlv64.sys, ndis.sys) занимает только один уровень в стеке устройств и связан только с одним объектом устройства: FDO.
пары доступных драйверов
Различные модели драйверов, относящиеся к технологии, используют различные имена для конкретных и общих частей пары драйверов. Во многих случаях определенная часть пары имеет префикс "mini". Ниже приведены некоторые из (конкретных, общих) пар, доступных:
- (драйвер минипорта дисплея, драйвер дисплейного порта)
- (драйвер минипорта аудиоустройства, драйвер аудиопорта)
- (драйвер минипорта хранилища, драйвер порта хранилища)
- (драйвер миникласса батареи, драйвер класса батареи)
- (Минидрайвер HID, класс-драйвер HID)
- (драйвер миникласса для меняющегося класса, драйвер порта смены)
- (минипортный драйвер NDIS, библиотека NDIS)
Примечание Как показано в списке, некоторые модели используют термин драйвер класса для общей части пары драйверов. Этот тип драйвера класса отличается от автономного драйвера класса и отличается от драйвера фильтра классов.
связанные разделы
основные понятия для всех разработчиков драйверов