2.1.3 Функция DriverUnload
Функция DriverUnload необходима для того, чтобы сделать драйвер выгружаемым. В унаследованных драйверах на эту функцию возложен весь процесс выгрузки драйвера: удаление символьных ссылок, объектов устройств драйвера, отключение прерываний от объектов, освобождение выделенной памяти. В WDM‑драйверах все эти действия возложены на функцию-обработчик пакетов с кодом IRP_MJ_PNP.
2.1.4 Функция DispatchRoutine
На эту функцию возложены обязанности по обработке IRP‑пакетов с различными кодами, хотя в разрабатываемом драйвере существует необходимость в обработке только двух типов запросов. Все запросы с кодом, отличным от IRP_MJ_PNP передаются по стеку драйверов без изменений. Запросы же IRP_MJ_PNP диспетчеризуются по суб-кодам в функции PnP_Dispatch. Необходимость диспетчеризации по суб-кодам запросов IRP_MJ_PNP вызвана тем, что драйвер не должен нарушать порядка работы операционной системы и обязан подчиняться PnP‑менеджеру, то есть в драйвере должны корректно обрабатываться события старта и удаления устройства.
2.1.5 Функция DispatchInternalDeviceControl
Запросы ввода / вывода к USB‑накопителю передаются в составе IRP‑пакетов с кодом IRP_MN_INTERNAL_DEVICE_CONTROL. Этот пакет содержит полную информацию о направлении и характере передаваемых данных. То есть для протоколирования обмена информацией с USB‑носителем следует перехватывать пакеты именно этого типа.
Для того чтобы перехватывать информацию, передаваемую в обоих направлениях, следует установить функцию обратного вызова диспетчера ввода / вывода. Методика установки этой функции была описана в разделе 1.7. При наличии этой функции разрабатываемый драйвер-фильтр получит возможность перехвата данных, передаваемых от устройства к хосту.
Для сохранения протоколируемой информации используется, как уже было сказано в разделе 1.10, MDL‑список. Этот MDL‑список создается в функции AddDevice. Объем памяти, выделяемой под список, совпадает с максимальным размером лог-файла, задаваемым в пользовательском приложении. После создания список фиксируется в страничной памяти, что предотвращает его выгрузку на жесткий диск во время работы драйвера. После этих подготовительных действий список используется в функции DispatchInternalDeviceControl – он заполняется перехватываемой информацией.
Запись накопленного буфера в лог-файл происходит при удалении устройства.
Такая методика выбрана из-за того, что функция DispatchInternalDeviceControl работает на уровне запроса прерываний, равном DISPATCH_LEVEL, что сильно затрудняет использование механизмов синхронизации, которые могли бы позволить перейти на уровень запроса прерываний, равный PASSIVE_LEVEL, где становятся доступными функции работы с файлами. Если бы это было достигнуто в разрабатываемом драйвере, то отпала бы необходимость выделения больших объемов нестраничной памяти для хранения протокола.
Запись файла на диск в момент удаления устройства возможна, так как это событие инициализируется PnP‑менеджером, запросы которого всегда происходят на уровне IRQL, равном PASSIVE_LEVEL.
2.2 Размещение кода драйвера в памяти
Некоторые функции драйвера, например те, которые выполняют инициализацию, выгодно выполнить и освободить память, занимаемую ими. В языке C есть специальная директива #pragma_alloc_text (<тип секции>, <имя размещаемой функции>), позволяющая управлять размещением кода. В качестве типа секции могут указываться значения «INIT» или «PAGE».
Функции с размещением в секции «INIT» выгружаются, и память, занимаемая ими, освобождается сразу по завершении их работы. В разрабатываемом драйвере в секции «INIT» размещена точка входа DriverEntry, поскольку она выполняется единожды при загрузке драйвера.
Точки входа AddDevice и DriverUnload располагаются в секции «PAGE», то есть в страничной памяти, поскольку они гарантированно вызываются на уровне привилегий, равном PASSIVE_LEVEL и, даже оказавшись выгруженными на диск, будут немедленно загружены в физическую память менеджером страничной памяти (который способен работать только на уровне PASSIVE_LEVEL).
Остальные же точки входа (DispatchRoutine и DispatchInternalDeviceControl) располагаются по умолчанию, в нестраничной памяти, поскольку их работа зависит от клиентского драйвера USB‑устройства, под которым в стеке драйверов располагается разрабатываемый драйвер-фильтр. Уровень привилегий его запросов слабо предсказуем и может быть равен DISPATCH_LEVEL. На этом уровне подкачка страниц невозможна, что при обращении к выгруженной функции приведет к краху системы.
2.3 Установка драйвера в системе
Для установки драйвера следует создать его ключ в системном реестре.
Имя ключа должно иметь следующий вид:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\driver_name.
Последняя часть имени специфична для устанавливаемого драйвера. Создаваемый ключ должен содержать следующие параметры:
· DisplayName – значение этого параметра описывает текст, используемый в служебных программах;
· ErrorControl – этот параметр предписывает операционной системе способ поведения в той ситуации, когда при загрузке драйвера произошла ошибка;
· ImagePath – описывает полный путь к файлу с исполняемым кодом драйвера;
· Start – описывает стадию загрузки операционной системы, когда следует загружать драйвер;
· Type – определяет тип драйвера.
Возможные значения указанных параметров можно узнать из документации MSDN.
Таким образом, первая стадия установки драйвера в систему заключается
в том, что должен быть создан ключ драйвера в реестре, а сам драйвер
скопирован в каталог, описываемый строкой ImagePath (как правило -%SystemRoot%\System32\Drivers\driver_name.sys).
Далее должно быть выбрано устройство, на которое будет установлен фильтр. Выбранному устройству в системном реестре соответствует ключ с именем вида HKLM\CurrentControlSet\Enum\USB\XXX\YYY.
Последняя часть ключа (XXX\YYY) определяется именем устройства. При установке драйвера фильтра нижнего уровня в разделе YYY создается строковый параметр LowerFilters, которому присваивается значение, совпадающее с именем драйвера, для которого был создан ключ в …\Services. Таким образом, при подключении устройства к системе для него будет создан стек драйверов, в состав которого в качестве фильтра нижнего уровня будет загружен устанавливаемый драйвер.
Кроме того, в ключе, связанном с устройством, при установке драйвера создается дополнительный раздел MyFilterParams, который хранит два параметра:
· MaxLogSize – максимальный размер лог-файла;
· LogFileName – имя лог-файла.
3. Технологический раздел
3.1 Выбор языка и средств программирования
Разрабатываемый программный комплекс состоит из двух частей:
· Драйвера-фильтра;
· Управляющего приложения для установки фильтра и ввода параметров протоколирования.
Каждая из программ, осуществляет общение с операционной системой на разном уровне. Соответственно необходим разный подход к этим задачам и специальный подбор средств разработки.
... системы и их особенностями в целом, мы разобрались, теперь самое время приступить к более детальному, конкретному рассмотрению многообразия ОС, которое обычно начинается с рассмотрения краткой истории появления и развития. Операционная система Unix Считается, что в появлении Юникса в частности виновата... компьютерная игра. Дело в том, что Кен Томпсон непонятно чего ради создал игрушку «Space ...
0 комментариев