Сценарий Драйвер шины программирует мост и инициализирует устройство так, что



Скачать 170.29 Kb.
Pdf просмотр
Дата22.12.2016
Размер170.29 Kb.
Просмотров294
Скачиваний0

1
Windows Driver
Model
Сидякин И.М.
sidiakin@iu3.bmstu.ru
Кафедра Информационные системы и телекоммуникации ИУ-3,
МГТУ им. Н.Э. Баумана
2006 год.
Этот документ находится в процессе подготовки. Он не закончен, содержит рабочий материал, и не предназначен для публикации.
Дата последнего изменения: 17 апреля 2006 г.
Содержание
Многоуровневая архитектура драйверов
Объекты
Код
Ввод/вывод
Многоуровневая архитектура драйверов
Драйвер шины
Драйвер устройства
Системная шина
Шина
Устройство
Мост
ЦПУ
Память
Многоуровневая архитектура драйверов
Драйвер устройства
Аккумулирует функциональную нагрузку реализует “высокоуровневый” протокол управления устройством
Не заботится о том, как данные передаются через мост
(мосты) от устройства к ЦПУ (памяти) и обратно.
Драйвер шины
Управляет мостом
Реализует специфические для шины “низкоуровневые”
протоколы обмена данными между устройством и процессором (памятью)
Многоуровневая архитектура драйверов
Сценарий 1. Драйвер шины программирует мост и инициализирует устройство так, что драйвер получает “прямой” доступ к устройству
PCI
Сценарий 2. Драйвер шины обеспечивает низкоуровневый программный интерфейс чтения/записи для драйвера устройства
USB

2
Шина PCI + i386
ЦПУ
Физическое адресное пространство процессора (4GB)
ОЗУ/ПЗУ
Мост
PCI
Память на устр-ве
Устройство
PCI
Память на устр-ве
Устройство
PCI
Трансляция адреса контролируется драйвером шины PCI
Адресное пространство шины PCI
Шина PCI + i386
ЦПУ
Физическое адресное пространство процессора (4GB)
Виртуальное адресное пространство процессора (4GB)
Трансляция адреса контролируется ЦПУ
(таблицы страниц)
После инициализации драйвер устройства прямо обращается к памяти на устройстве:
Mov Edi,
vbase
Mov Eax, [Edi]
vb
a
se
Шина USB
Хост контроллер
Концентра тор
Устройство
Концентра тор
Устройство
Устройство
Драйвер устройства
Драйвер концентратора (USBHUB.SYS)
Драйвер хост контроллера
Порт ы
в простран ст ве во д
а
/вы вод а
проц ессо ра
Многоуровневая архитектура драйверов
Пользовательское приложение Win32
Драйвер фильтр
Драйвер устройства
Драйвер шины
Драйвер фильтр
Кольцо-3
Кольцо-0
Дополнительная обработка IRP
(сжатие данных, шифрация и т.п.)
необязателен
Управление устройством необязателен
Передача данных и команд и другие операции связанные с шиной
ОБЪЕКТЫ
DRIVER_OBJECT
представляет драйвера устройства
DEVICE_OBJECT
представляет устройство
FILE_OBJECT
Представляет сессию ввода вывода
IRP (Input/Output Request Packet)
представляет одну операцию ввода/вывода

3
DRIVER_OBJECT
Частично документированная системная структура
Экземпляр создаётся системой при загрузке драйвера
Удаляется при выгрузке драйвера
Используется для контроля операций драйвера диспетчеризация IRP, и т.п.
Поля DRIVER_OBJECT
DeviceObject
Указатель на первый объект устройства
созданный драйвером
DriverExtension
Указатель на расширение драйвера (driver
extension)
AddDevice
Адрес функции AddDevice (используется в PnP)
Поля DRIVER_OBJECT
DriverInit
Адрес точки входа драйвера вызывается при загрузке драйвера
DriverUnload
Адрес функции DriverUnload вызывается при выгрузке драйвера
DriverStartIo
Адрес функции DriverStartIo инициализирует аппаратуру для выполнения операции ввода/вывода
Поля DRIVER_OBJECT
MajorFuction[]
Массив указателей на обработчики IRP
таблица для диспетчеризации пакетов запросов ввода/вывода (IRP)
DEVICE_OBJECT
Частично документированная системная структура
Один объект устройства создаётся для каждого аппаратного устройства, которое контролируется драйвером
Создаётся в функции AddDevice которая вызывается при обнаружении нового устройства
IoCreateDevice
Удаляется при удалении устройства
IoDeleteDevice
Используется для контроля операций с устройством
Обработка запросов ввода/вывода, управление аппаратурой и т.п.
Поля DEVICE_OBJECT
DriverObject
Указатель на объект драйвера
NextDevice
Указатель на следующий объект устройства
созданный драйвером
CurrentIRP
Указатель на текущий IRP (во время обработки)
Flags
Битовые флаги определяющие некоторые свойства устройства

4
Поля DEVICE_OBJECT
DeviceExtension (расширение)
Указатель на частные данные устройства
Память под расширение выделяется
IoCreateDevice
Вы можете задать размер освобождается IoDeleteDevice
Используется для хранения различных настроек и параметров устройства
Выделенный диапазон памяти, номер прерывания и т.п.
Поля DEVICE_OBJECT
DeviceExtension
Вы определяете размер и содержимое
Вы объявляете структуру которая накрывает память выделенную под расширение для удобства работы
typedef struct _DEVICE_EXTENSION {
int irq_number;
void * mem_base;
int mem_size;

} DEVICE_EXTENSION, * PDEVICE_EXTENSION;
Поля DEVICE_OBJECT
StackSize
Количество драйверов в цепочке обработки IRP ниже драйвера (считая сам драйвер)
Снова многоуровневая архитектура драйверов
Win32 user mode application
Драйвер фильтр
Драйвер устройства
Драйвер шины
Драйвер фильтр
Win32 user mode application
Filter Device Object (FiDO)
Functional Device Object (FDO)
Physical Device Object PDO
Filter Device Object (FiDO)
(Объект устройства фильтра)
(Функциональный объект устройства)
(Объект устройства фильтра)
(Физический объект устройства)
FILE_OBJECT
Частично документированная системная структура
Создаётся при создании новой ссылки на устройство
CreateFile (API)
ZwCreateFile (SPI)
Удаляется когда ссылка на устройство закрывается
CloseHandle (API)
ZwClose (SPI)
Используется для контроля сеанса ввода/вывода между драйвером устройства и пользовательским приложением или другим WDM драйвером.
Для одного сеанса создаётся один объект
Драйвер устройства может одновременно поддерживать несколько сеансов.
Поля FILE_OBJECT
DeviceObject
Указатель на объект устройства
FsContext, FsContext2
Необязательные поля ассоциированные с объектом file object

5
Картина в целом
Драйвер фильтр
Объект драйвера
FiDO
устр1
FiDO
устр2
Драйвер устройства
Объект драйвера
FDO
устр1
FDO
устр2
Драйвер шины
Объект драйвера
PDO
устр1
PDO
устр2
FDO
моста(хаба)
Менеджер ввода/вывода
File Object устр1,1
File Object устр2,1
File Object устр2,1
Приложение Win32
Пакет запроса ввода/вывода
Input/Output Request Packet (IRP)
Частично документированная системная структура
Поддерживает запросы ввода/вывода к устройству
Посылка команд и сообщений, запись данных в устройство, чтение данных из устройства.
Содержит информацию необходимую для диспетчеризации и обработки запросов ввода/вывода.
Может содержать ссылки на буфера данных.
Обычно создаётся для каждого запроса и удаляется после завершения обработки запроса
Сопровождается массивом структур
IO_STACK_LOCATION
Поля IRP
Ссылки на буферы данных
MdlAddress
Прямой метод, Direct (Memory descriptor list)
AssociatedIrp.SystemBuffer
Метод с буферизацией, Buffered (system buffer)
UserBuffer
Метод с пользовательским буфером, Neither
(данные передаются в буфере пользовательского режима)
Поля IRP
IoStatus
Содержит статус завершения IRP (код ошибки)
Cancel
True, если исполнение IRP отменено
CancelRoutine
Указатель на процедуру отмены IRP
Поля IRP
Tail.Overlay.CurrentStackLocation
Указатель на текущий элемент стека устройств
Недокументированное поле
CurrentLocation
Индекс (номер) текущего элемента стека устройств
Недокументированное поле
Другие поля будут рассмотрены позднее …
IO_STACK_LOCATION
IRP не содержит всей информации требующейся для обработки запроса ввода/вывода
Часть информации хранится в массиве структур типа IO_STACK_LOCATION
При создании IRP менеджер ввода/вывода создаёт так же этот массив
Элементы массива стека используются для поддержки многоуровневой архитектуры драйверов

6
IO_STACK_LOCATION
Число элементов в массиве равно количеству драйверов, которые участвуют в обработке запроса
DeiverObject->StackSize
Каждый элемент массива используется одним из драйверов в цепи обработки IRP
В начале поле
IRP->Tail.Overlay.CurrentStackLocation указывает на первый элемент массива
(первый элемент стека)
IO_STACK_LOCATION
Каждый раз при передаче IRP следующему драйверу в цепи
CurrentStackLocation перемежается на следующий элемент стека
Первый элемент стека инициализируется вызывающей программой
Драйвером WDM или менеджером ввода/вывода
Каждый драйвер в цепи (кроме последнего) отвечает за инициализацию следующего элемента стека перед передачей
IRP нижерасположенному драйверу
Обычно это простое копирование
IoCopyCurrentIrpStackLocationToNext(Irp)
Или совместное со следующим драйвером использование своего элемента стека
IoSkipCurrentIrpStackLocation
IO_STACK_LOCATION
Win32 user mode application
Драйвер фильтра
Драйвер устройства
Драйвер шины
Драйвер фильтра
IO_STACK_LOCATION
IRP
Инициатор IRP (I/O М-р, д-р WDM д-р)
Создаёт и инициализирует использует
IO_STACK_LOCATION
IO_STACK_LOCATION
IO_STACK_LOCATION
инициализирует инициализирует инициализирует использует использует использует
Поля IO_STACK_LOCATION
MajorFunction
Тип запроса вода/вывода
IRP_MJ_...
MinorFunction
Подтип запроса ввода/вывода
IRP_MN_...
Примеры IRP MJ&MN
IRP_MJ_READ – чтение данных из устройства
IRP_MJ_WRITE – запись данных в устройство
IRP_MJ_PNP – сообщения plug and play
IRP_MN_START_DEVICE – устройство запущено или перезапущено
IRP_MN_STOP_DEVICE – устройство остановлено
IRP_MJ_POWER – события управления питанием
IRP_MN_SET_POWER – режим питания изменился
Поля IO_STACK_LOCATION
Parameters
Объединение структур
Каждая структура соответствует одному из типов IRP

7
Parameters
union {

struct {
ULONG OutputBufferLength;
ULONG InputBufferLength;
ULONG IoControlCode;
ULONG Type3InputBuffer;
} DeviceIoControl; //параметры для IRP_MJ_DEVCIE_CONTROL

struct
{
ULONG Length; //длина входного буфера

}
Write
; //параметры для IRP_MJ_WRITE

}
Parameters;
КОД
Драйвер должен содержать набор функций имеющих заданные спецификацией WDM
интерфейсы
Каждая функция играет определённую роль в управлении драйвером или устройством
Адреса большинства функций хранятся в объекте Driver Object система (менеджер в/в) вызывает функции, как реакцию на определённые системные события или для выполнения операций ввода/вывода
Имена функций определяются разработчиком драйвера
Большинство функций необязательны
Функции
DriverEntry
Точка входа драйвера (обязательна)
DriverUnload
Вызывается при выгрузке драйвера (необязательна)
AddDevice
Вызывается при обнаружении нового устройства (обязателна)
Обработчики IRP
Набор функций которые обрабатывают различные типы запросов ввода/вывода (обязательны только обработчики запросов plug and play и управления питанием)
DriverStartIo
Инициализирует асинхронную операцию ввода/вывода
(необязателна)
Точка входа драйвера
DriverEntry имя по умолчанию link /entry:DriverEntry@8
Вызывается при загрузке драйвера
Выполняет инициализацию драйвера
Инициализирует поля объекта драйвера значениями адресов различных функций драйвера
Пример DriverEntry
extern "C" NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
//указатель на объект драйвера
IN PUNICODE_STRING RegistryPath
//раздел драйвера в реестре
)
{
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DispatchControl;
DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
return STATUS_SUCCESS;
}

8
Диспетчеризация IRP
#define IRP_MJ_CLOSE 0x02
DriverObject
Массив MajorFunction
0
2
1

NTSTATUS DispatchClose(
PDEVICE_OBJECT pdo,
PIRP Irp)
{

}
IRP
Текущий элемент стека
MajorFunction =
IRP_MJ_CLOSE
AddDevice
Вызывается системой при обнаружении нового устройства, которое обслуживает драйвер
Создаёт новый объект устройства и расширение
Подключает объект устройства к стеку устройств
Регистрирует интерфейс устройства
Какой нужен драйвер? (PCI)
Регистры конфигурации
VendorId
= 0x
10EC
(Realtek)
DeviceId
= 0x
8139
(RTL8139 PCI Network
Interface Card)
HKEY_LOCAL_MACHINE
\System
\CurrentControlSet
\Enum
\PCI
\VEN_
10EC
&DEV_
8139
Service = rtl3189
HKEY_LOCAL_MACHINE
\System
\CurrentControlSet
\Services
\rtl3189
ImagePath =
“..\RTL8139.SYS”
VID
&
PID
for USB
Загрузка драйвера устройства
Обнаружено
новое устройство PCI
VEN_10EC DEV_8139
\VEN_10EC&DEV_8139
Есть ключ в реестре?
Запрос пользователю
на установку драйвера
(нужен .inf файл)
Rtl8139.sys
уже загружен?
Загрузка rtl8139.sys и
вызов DriverEntry
Вызов AddDevice
Да
Нет
Да
Нет
AddDevice
NTSTATUS AddDevice(
IN PDRIVER_OBJECT DriverObject,
//объект драйвера
IN PDEVICE_OBJECT pdo
//физический объект устройства
)
{

NTSTATUS status = IoCreateDevice(…);
[1]

LowerDeviceObject = IoAttachDeviceToDeviceStack(…);
[2]

status = IoRegisterDeviceInterface(…);
[3]

}
IoCreateDevice
Создаёт новый объект устройства и выделяет память под расширение
NTSTATUS IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);
PDEVICE_OBJECT fdo;
status = IoCreateDevice(DriverObject, sizeof(PDEVICE_EXTENSION),
NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);

9
IoAttachDeviceToDeviceStack
Подключает объект устройства к вершине стека устройств обычно прямо к PDO
PDEVICE_OBJECT IoAttachDeviceToDeviceStack(
IN PDEVICE_OBJECT SourceDevice,
IN PDEVICE_OBJECT TargetDevice
);
fdo->DeviceExtension->NextDevice = IoAttachDeviceToDeviceStack(
fdo, pdo );
NextDevice не обязательно pdo!
IoRegisterDeviceInterface
Регистрирует класс интерфейса и создаёт новый экземпляр класса
Экземпляр используется приложениями или драйверами для доступа к драйверу
Допускается регистрация нескольких интерфейсов
NTSTATUS status = IoRegisterDeviceInterface(
pdo, &GUID_MYDEVICE_INTERFACE, NULL, &pdx->ifname);
Обработчики IRP
Все обработчики имеют одинаковый интерфейс
Аргументы pdo – указатель на объект устройства
Irp – указатель на пакет запроса ввода/вывода
Возвращает код ошибки типа NTSTATUS
Одна из констант STATUS_...
OK = STATUS_SUCCESS
Один обработчик может обслуживать запросы ко всем устройствам, которые обслуживает драйвер
Устройство идентифицируется ссылкой на pdo
Данные устройства доступны по указателю на расширение pdo-
>DeviceExtension
NTSTATUS DispatchIrp(PDEVICE_OBJECT pdo,PIRP Irp);
Диспетчеризация IRP
Код MajorFunction
Используется для выбора процедуры обработчика IRP
Код MinorFunction
Проверяется для некоторых типов IRP внутри обработчика (например IRP_MJ_PNP)

PIO_STACK_LOCATION ps = IoGetCurrentIrpStackLocation(Irp);
switch(ps->MinorFunction) {
case IRP_MN_x:

case IRP_MN_y:

Исполнение IRP
Сценарии исполнения IRP:
A.
Обработать и завершить запрос
B.
Передать запрос следующему драйверу в стеке
C.
Запустить асинхронную обработку запроса
A – синхронная обработка
C – асинхронная обработка
B – синхр. или асинхр. В зависимости от поведения нижерасположенных в стеке драйверов
Синхронная и асинхронная обработка IRP
Синхронная обработка
Завершается до возврата из обработчика IRP
IoCompleteRequest вызывается внутри обработчика
Вызывающая программа получает результат операции, когда драйвер возвращает управление
Асинхронная обработка
Запускается фоновая (обычно аппаратная) операция
Запрос может быть незавершён в момент, когда обработчик
IRP возвращает управление
Вызывающая программа получает код ошибка “запрос отложен” (request is pending)
Вызывающая программа должна позаботится о том, чтобы дождаться завершения исполнения запроса и получить его результат, если он требуется.

10
Синхронная обработка IRP
NTSTATUS DispatchIrp(PDEVICE_OBJECT pdo,PIRP Irp)
{
NTSTATUS status;
//обрабатываем запрос

//сохраняем код статуса в элементе стека
Irp->IoStatus.Status = status;
//завершаем запрос
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//возвращаем код статуса
return status;
}
Передача IRP следующему в стеке драйверу.
NTSTATUS DispatchIrp(PDEVICE_OBJECT pdo,PIRP Irp)
{
NTSTATUS status;
// получаем указатель на расширение
(PDEVICE_EXTENSION)pdx =
(PDEVICE_EXTENSION)pdo->DeviceExtension;
//обрабатываем запрос (если надо)

//инициализируем следующий элемент стека
//(можно использовать IoSkipCurrentIrpStackLocation)
IoCopyCurrentIrpStackLocationToNext(Irp);
//вызываем драйвер (помните AddDevice!)
status = IoCallDriver(pdx->NextDevice , Irp);
return status;
}
Как инициализировать следующий элемент стека
Драйвер отвечает за инициализацию следующего элемента стека перед вызовом следующего в стеке драйвера (IoCallDriver).
Вы можете копировать текущий элемент стека в следующий с помощью макроопределения IoCopyCurrentIrpLocationToNext
Или вы можете воспользоваться IoSkipCurrentIrpStackLocation
IoCallDriver автоматически перемещает указатель текущего элемента стека на следующий элемент массива.
Это макроопределение просто перемещает указатель на предыдущий элемент и IoCallDriver при вызове устанавливает его обратно на текущий элемент стека.
Таким образом текущий элемент стека совместно используется двумя (или более) драйверами
Эта техника позволяет избежать копирования памяти, если для обоих драйверов нужны одинаковые значения полей элемента стека
Регистрация процедуры завершения обработки IRP
Драйвер в стеке, если он не последний, может установить процедуру завершения обработки IRP перед вызовом IoCallDriver
вызывается, когда последний драйвер в стеке вызывает IoCompleteRequest
Драйвер в середине стека может добавить свою постобработку IRP
Драйвер не должен использовать макроопределение
IoSkipCurrentIrpStackLocation
Указатель на процедуру завершения драйвера хранится в следующем элементе стека и вы можете перезаписать процедуру установленную вышестоящим драйвером.
Можно добавить условия вызова процедуры (двоичные флаги)
Если обработка IRP завершена без ошибок
Если обработка IRP завершилась с ошибкой
Если обработка IRP завершена
IoSetCompletionRoutine(Irp, CompletionRoutine, context, InvokeOnSuccess,
InvokeOnError, InvokeOnCancel);
Процедура завершения
(Completion routine)
Context произвольное значение указанное в аргументе вызова IoSetCompletionRooutine.
Сохраняется в элементе стека и передаётся процедуре завершения
NTSTATUS IoCompletion(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context );
Асинхронная обработка IRP.
1.
Вызывающая программа посылает запрос драйверу
2.
Драйвер программирует аппаратуру и запускает операцию
3.
Драйвер возвращает код ошибки STATUS_PENDING
4.
Драйвер используют объект Event (событие) для передачи сообщения о завершении операции вызывающей программе.
5.
Вызывающая программа ждёт событие
6.
Проходит время …
7.
Аппаратура вырабатывает аппаратное прерывание по линии
IRQ для того, что бы сообщить оь окончании операции
8.
Драйвер обрабатывает IRQ и устанавливает объект event в состояние signaled
9.
Вызывающая программа выходит из состояния ожидания и возвращает результат операции.

11
Вызывающая программа. Драйвер.

KEVENT event;
//iosb сохраняет статус асинхронного запроса
IO_STATUS_BLOCK iosb;
//инициализируем объект усройства
KeInitializeEvent(&event, ...);
//создаём пакет запроса ввода/вывода
PIRP Irp = IoBuildDeviceIoControlRequest(..., &event, &iosb);
//вызываем драйвер
status = IoCallDriver(targetDevice , Irp);
//если targetDevice обрабатывает запрос асинхронно
If (status == STATUS_PENDING) {
//ждём
KeWaitForSingleObject(&event, ...);
//получаем результат
status = iosb.Status;
}

Обработчик IRP драйвера
IoMarkIrpPending – уст. флаг
SL_PENDING_RETURNED в поле Flags текущего элемента стека.
Теперь IRP помечено как отложенное (pending)
IoStartPacket проверяет свободно устройство или нет
Занято: помещает IRP в очередь. Если Key == 0 IRP в конец.
Свободно: вызывается
DriverObject->DriverStartIo
Обработчик IRP возвращает STATUS_PENDING
NTSTATUS DispatchIrp(PDEVICE_OBJECT pdo, PIRP Irp) {

IoMarkIrpPending(Irp);
ULONG key = 0;
IoStartPacket(pdo, Irp, &key, CancelRoutine);
return STATUS_PENDING;
}
Функция DriverStartIo
Программирует аппаратную операцию
Не вызывается драйвером напрямую
Вы должны написать её и зарегистрировать в
DriverObject
VOID StartIo(PDEVICE_OBJECT pdo, PIRP Irp) {
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION pdx =
(PDEVICE_EXTENSION) pdo->DeviceExtension;
//инициализирует аппаратную операцию

}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject …) {

DriverObject->DriverStartIo = StartIo;
}
Обработчик прерывания
(Interrupt Service Routine)
Драйвер должен зарегистрировать ISR
Аппаратура выставляет прерывание для того, чтобы сообщить о завершении операции
Вспомогательная функция MyDeviceInterrupted(…) реализует ваш собственный протокол проверки того, что источником прерывания было именно ваше устройство. Несколько устройств могут совместно использовать одну линию аппаратного прерывания.
BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject,
PDEVICE_EXENSION pdx)
{
if (MyDeviceInterrupted(…)) {
IoRequestDpc(pdx->DeviceObject, NULL, pdx);
return TRUE;
}
return FALSE;
}
IoConnectInterrupt(…, OnInterrupt, …);
Отложенный вызов процедур
Deferred Procedure Call (DPC)
IoCompleteRequest и некоторые другие системные функции запрещено вызывать из ISR
Причина: ISR работает на высоком уровне приоритета. Она должна быть как можно короче.
Время завершения запроса в общем случае трудно определить.
Решение: Вы можете заказать вызов произвольной процедуры, когда уровень приоритета понизится
(Уже после того как ISR [точнее все ISR] завершатся)
IoRequestDpc
Dpc следует зарегистрировать (обычно в AddDevice)
NTSTATUS AddDevice(…) {

IoCreateDevice(..., &fdo);
IoInitializeDpcRequest(fdo, DpcForIsr); }
DPC (Продолжение)
Указатель на текущий IRP извлекается из объекта устройства
IoStartNextPacket проверяет очередь IRP. Если она не пуста следующий запрос извлекается и передаётся DriverObject->DriverStartIo
IoCompleteRequest устанавливает объект event в состояние signaled
VOID DpcForIsr(PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk,
PDEVICE_EXTENSION pdx)
{
PIRP Irp = fdo->CurrentIrp;
IoStartNextPacket(fdo, false);
IoCompleteRequest(Irp, 0);
}

12
Асинхронная обработка IRP
DispatchIrp
StartIo
Очередь
Устр-во занято?
Нет
Да
ISR
DPC
Вызывающая
программа
Запрос выполнен
Зледующий IRP
Аппаратура
Асинхронная обработка IRP
Вы никогда не вызываете напрямую обработчики IRP.
IoCallDriver вызывает нужный обработчик IRP
нижерасположенного в стеке драйвра.
IoStartPacket (или IoStartNextPacket) вызывает
DriverStartIo
IoRequestDpc вызывает DPC
IoCompleteRequest вызывает процедуру завершения, если она установлена
Обработка Irp в многоуровневой архитектуре драйверов
Вызывающая программа (Win32 приложение или драйвер)
Драйвер на самом низком уровне
Промежуточный
драйвер
CompletionRoutine2
DispatchIrp
StartIo
ISR
DPC
DispatchIrp
Промежуточный
драйвер
CompletionRoutine1
DispatchIrp
завершено необязательно необязательно
ВВОД/ВЫВОД
1.
Открыть сеанс
2.
Выполнить операции ввода/вывода
Чтение данных из устройства
Запись данных в устройство
Отправка команд устройству
3.
Закрыть сеанс
Открытие сеанса (функции Win32
API)
DevicePath - имя устройства
CreateFile открывает сеанс ввода/вывода и возвращает значение типа HANDLE
указатель на созданный FILE_OBJECT
Драйвер получает пакет запроса
IRP_MJ_CREATE
HANDLE hDevice = CreateFile(DevicePath, 0, 0, 0, dwFlags, 0);

13
(DevicePath, …
Доступ к драйверу через зарегистрированный интерфейс
Используются функции SETUPAPI.LIB
devList
= SetupDiGetClassDevs(
GUID_MYDEVICE_INTERFACE
,…);
для каждого устройства в списке вызывается
1.
SetupDiEnumDeviceInterfaces(devList, …,
interfaceData
);
2.
SetupDiGetInterfaceDeviceDetail(devList, interfaceData,
deviceDetail
,..);
3.
CreateFile(deviceDetail->
DevicePath
, …);
Подробности в MSDN
… ,dwFlags, …
Флаг FILE_FLAG_OVERLAPPED
должен быть установлен, если устройство поддерживает асинхронные операции
Закрытие сеанса
Закрывает сеанс и уничтожает объект
FILE_OBJECT
Драйвер получает пакет запроса
IRP_MJ_CLOSE
CloseHandle(hDevice);
Обмен данными с драйвером
Функции Win32 API
ReadFile
WriteFile
DeviceIoControl
ReadFile
Читает данные из устройства
Подставляет адрес буфера чтения и его размер.
Последний параметр lpOverlapped определяет тип операции.
NULL = синхронная
Пакет запроса IRP_MJ_READ
Драйвер должен указать в поле IoStatus.Information количество байт которые записываются в выходной буфер
ReadFile(hDevice, lpBuf, bufSize, &cbReaden, NULL);
WriteFile
Пишет данные в устройство
Подставляет адрес буфера записи и его размер.
Последний параметр lpOverlapped определяет тип операции.
NULL = синхронная
Пакет запроса IRP_MJ_WRITE
WriteFile(hDevice, lpBuf, bufSize, &cbWritten, NULL);

14
DeviceIoControl
Одновременно предаёт данные (команды) из устройства и в устройство
Один или оба буфера могут не использоваться
Вместе с данными передаётся код команды ioctl (I/O Control
Code, DWORD)
Действия драйвера зависят от значения этого кода
Список команд определяется разработчиком драйвера
Последний параметр lpOverlapped определяет тип операции.
NULL = синхронная
Пакет запроса IRP_MJ_DEVICE_IO_CONTROL
Драйвер должен указать в поле IoStatus.Information количество байт которые записываются в выходной буфер
DeviceIoControl(hDevice, ioctl, lpInBuf, ibSize, lpOutBuf, obSize, &cbRet, NULL);
IOCTL
Двойное слово состоящее из четырёх битовых полей
DeviceType – тип устройства
FILE_DEVICE_CDROM, …, FILE_DEVICE_UNKNOWN
Access - тип доступа
FILE_READ_ACCESS, FILE_WRITE_ACCESS,
FILE_ANY_ACCESS
Method – метод передачи данных
METHOD_BUFFERED, METHOD_DIRECT, METHOD_NEITHER
Function – номер функции задаётся разработчиком в диапазоне от 2048 до 4095.
31..16 DeviceType
15..14 Access 13..2 Function
1..0 Method
Определение IOCTL
Значение битового поля задаётся с помощью макроопределения CTL_CODE
Это объявление помещается в .h файл и используется для компиляции программ, которые взаимодействуют с драйвером
#include
#define IOCTL_MY_FUNCTION CTL_CODE(FILE_DEVICE_UNKNOWN, \
2048, METHOD_BUFFERED, FILE_ANY_ACCESS)
Обработка IOCTL
NTSTATUS OnDeviceControl(PDEVICE_OBJECT pdo, PIRP Irp)
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(Irp);
switch (sl->Parameters.DeviceIoControl.IoControlCode) {

case: IOCTL_MY_FUNCTION: … break;

default: ntStatus = STATUS_NOT_SUPPORTED; break;
}

return ntStatus;
}
Методы передачи данных
Через пользовательский буфер
METHOD_NEITHER
Через системный буфер
METHOD_BUFFERED
Через MDL
METHOD_DIRECT
Определение метода передачи
Для IRP_MJ_READ, IRP_MJ_WRITE
Флаги DeviceObject->Flags
DO_BUFFERED_IO
DO_DIRECT_IO
Задаётся для всех операций
Для IRP_MJ_DEVICE_IO_CONTROL
IOCTL
Битовое поле Method
Указывается для каждой отдельной операции

15
Драйвер
Пользовательская память
METHOD_NEITHER
DeviceIoControl(… Type3InputBuffer … UserBuffer …)
InputBuf = StackLocation->Parameters.DeviceIoControl.Type3InputBuffer;
OutputBuf = Irp->UserBuffer;
UserBuffer
Type3InputBuffer
ReadFile(… UserBuffer …)
WriteFile(… UserBuffer …)
METHOD_NEITHER
Виртуальный адрес в пользовательском диапазоне действителен только в контексте памяти вызывающего приложения
Если операция выполняется асинхронно контекст памяти (схема отображения виртуальных адресов в физические) может измениться
Данные должны храниться в системном диапазоне адресов
Контекст памяти не изменяется
Системная память
Драйвер
Пользовательская память
METHOD_BUFFERED
DeviceIoControl(… InputBuffer … OutputBuffer …)
SystemBuf = Irp->AssociatedIrp.SystemBuffer
InputBuffer
OutputBuffer
ReadFile(… OutputBuffer …)
WriteFile(… InputBuffer …)
SystemBuffer
METHOD_BUFFERED
Данные в обоих направлениях передаются через системный буфер
Перед началом обработки запроса данные автоматически копируются из входного пользовательского буфера в системный
После завершения обработки запроса данные автоматически копируются из системного буфера в выходной пользовательский буфер
Адрес системного буфера не зависит от контекста
IRP_MJ_DEVICE_IO_CONTROL
Драйвер должен сначала считать входные данные из буфера, а затем записывать на их место выходные данные
Размер системного буфера равен максимальному из двух
StackLocation->Parameters.DeviceIoControl.InputBufferLength
StackLocation->Parameters.DeviceIoControl.OutputBufferLength
IRP_MJ_READ, IRP_MJ_WRITE
StackLocation->Parameters.Read.Length
StackLocation->Parameters.Write.Length
Виртуальная память
Физическая память
Драйвер
METHOD_DIRECT
SysAddr = MmGetSystemAddressForMdl(Irp->MdlAddress);
BufferSize = MmGetMdlByteCount(Irp->MdlAddress);
Страница
Страница
Страница
Страница
Страница
Страница
SysAddr
MDL
DeviceIoControl, ReadFile, WriteFile
Страница
Страница
Страница
UserAddr
METHOD_DIRECT
Менеджер в/в создаёт MDL который описывает пользовательский буфер
Memory Descriptor List
MDL содержит список физических страниц в которых располагается буфер и его размер
Драйвер отображает эти страницы в диапазон системных виртуальных адресов
MmGetSystemAddressForMdl
IRP_MJ_DEVICE_IO_CONTROL
Ioctl.Method = METHOD_IN_DIRECT
или METHOD_OUT_DIRECT

16
Plug&Play
Обработка IRP_MJ_PNP обязательна для драйвера
WDM
Пакет запроса PnP должен быть передан вниз по стеку
Обработка запроса PnP в драйвере, как правило происходит после того, как запрос обработан драйверами ниже в стеке
NTSTATUS DispatchPnp(…) {

KeInitializeEvent(&kEvent, …);
IoSetCompletionRoutine(OnPnpRequestComplete, &kEvent, …);
If (IoCallDriver(NextDevice, …) == STATUS_PENDING)
KeWaitForSingleObject(&kEvent);
// … Обработка Irp
}
NTSTATUS OnPnpRequestComplete(…, PKEVENT kEvent) {
KeSetEvent(kEvent, …);
return STATUS_MORE_PROCESSING_REQUIRED;
}
Схема вызова запросов PnP
Устройство физически
установлено
Устройство обнаружено
драйвером шины
Драйвер
загружен
Драйвер выполнил
инициализацию
Создан
FDO
Устройство
работает
Устройство готово
к удалению
Устройство готово
к остановке
Устройство
удалено
Устройство
остановлено
DriverEntry
AddDevice
C
D
G
A
E
F
A
G
A. IRP_MN_START_DEVICE
B. IRP_MN_STOP_DEVICE
C. IRP_MN_QUERY_REMOVE_DEVICE
D. IRP_MN_CANCEL_REMOVE_DEVICE
E. IRP_MN_QUERY_STOP_DEVICE
F. IRP_MN_CANCEL_STOP_DEVICE
G. IRP_MN_REMOVE_DEVICE
A


Поделитесь с Вашими друзьями:


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал