Теория разработки драйверов

Автор работы: Пользователь скрыл имя, 04 Января 2011 в 19:53, курсовая работа

Описание работы

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

Файлы: 1 файл

Курсовик.docx

— 112.28 Кб (Скачать файл)

     Ring 3 – это наименее привилегированное кольцо, в котором есть множество ограничений по работе с памятью, устройствами и т.д. Например, в третьем кольце приложения не могут видеть адресное пространство других приложений без особого на то разрешения, выполнять привилегированные команды процессора, напрямую общаться к оборудованию и т.д.

     Режим ядра (защищенный режим) – это основной режим работы процессора (32-разрядного). Главные механизмы, регулируемые режимом  ядра:

     - механизм защиты памяти и ввода/вывода, состоящий из 4 уровней

     - механизм переключения задач (любая задача имеет состояние – состояние всех регистров процессора, с ней связанных. Это состояние хранится на сегментах)

     - особая организация памяти. При этой организации памяти используется 2 способа ее преобразования: разбивка на страницы и сегментация (сегмент – это отдельный блок общего пространства памяти, в 32-разрядной адресации максимальный размер сегмента – 4 Гбайт, а максимальное количество сегментов 8192). Сегментация обеспечивает неплохую защиту данных. Страничный же способ организации помогает использовать большее количество памяти, чем сегментация. Базируется она также на 32-разрядной адресации, но в качестве базового объекта использует отдельный блок памяти размером 4 Кбайт.

     - механизм защиты из 4 уровней

     Драйверы  уровня ядра (режима ядра) работают в  привилегированном контексте. Соответственно, плохо написанный драйверный код  может оказаться вредоносным  для операционной системы. Разработчик  должен с особым вниманием относиться к создаваемому коду, чтобы не обрушить все здание операционной системы. Фирма Microsoft пытается решить проблему надежности драйверов, поставляемых в составе  дистрибутива Windows, через механизм тестирования и подписания драйверов.

     Переносимость.

     В качестве способа решения задачи переносимости конструкторы Windows выбрали многослойную архитектуру.

             

     Слой  аппаратных абстракций (Hardware Abstraction Layer, HAL) изолирует процессорные и платформенные  особенности от кода операционной системы. Его услугами Microsoft предлагает пользоваться и разработчику драйверного кода. Вполне возможно так написать драйвер, что для перенесения его на другую платформу потребуется разве  что перекомпилировать его. Как  можно это сделать, если изначально драйвер есть такая программная  единица, которая жестко привязана  и к своему устройству, и к конкретному  процессору, и к конкретной платформе?! Просто драйвер должен обратиться к  использованию средств уровня HAL для взаимодействия с аппаратными регистрами и аппаратной поддержкой шин. В отдельных случаях разработчик драйвера может опереться на код, предоставляемый Диспетчером ввода/вывода, для работы с совместно используемыми аппаратными ресурсами. Например, при DMA операциях (прямого доступа к памяти) используется такая абстракция программирования, как объект адаптера

     Расширяемость.

     Ядро несет ответственность за планировку активности программных потоков (threads). Поток является всего лишь "независимой тропинкой" в выполнении программного кода. Чтобы сохранить независимость от деятельности других потоков, для каждого из них необходимо сохранять уникальный потоковый контекст (thread context). Потоковый контекст состоит из состояния регистров процессора (включая также изолированный стек и счетчик инструкций, Program Counter), сохраненного ID (идентификатора потока, так называемого Thread ID или TID), значения приоритета, распределения памяти, связанной с потоком (Thread Local Storage), и другой информации, имеющей отношение к данному потоку.

     Обязанностью  планировщика потоков является определение, какой поток должен выполняться  в данный момент. В среде с единственным процессором, в каждый момент времени  только один поток получает в свое распоряжение процессор. В многопроцессорной  конфигурации разные потоки могут выполняться  на разных процессорах, реализуя настоящую  параллельность выполнения кода. Планировщик  в большинстве случаев выделяет потоку процессор на фиксированный  временной интервал, известный под  названием thread time quantum (потоковый временной  квант). Предоставление процессора происходит, главным образом, на основе величины приоритета потока.

     Так как основной задачей ядра является управление потоками, работа по управлению памятью, вопросами доступа (security) и  действиями по вводу/выводу возлагается  на другие компоненты операционной системы. Эти компоненты известны под собирательным  названием 'Executive', Исполнительные Компоненты. Они сконструированы как модульное  программное обеспечение (хотя, Диспетчер  ввода/вывода сам является существенным исключением из этого правила).

     Идея  поддержания ядра как "маленького и чистого", при сохранении модульности  исполнительных компонентов, обеспечивает основу заявления Microsoft o сохранении курса на расширяемость. По крайней мере, следует признать, что эта операционная система выдержала более десяти лет переработок и регулировок, значительно улучшив свои показатели.

     Производительность.

     Поскольку многие участники сложных программных  проектов хорошо знакомы с такой  особенностью многослойного программного обеспечения как его "невзрачная" производительность, то особое внимание со стороны разработчиков Windows было уделено быстрому межслойному взаимодействию.

     Во-первых, все слои, обсуждаемые далее, выполняются  в одном аппаратном режиме — режиме ядра. Следовательно, межслойные вызовы не используют ничего сложнее, чем инструкция процессора CALL. Средства же, предоставляемые  уровнем HAL, в основном, представляет собой макроопределения, являющиеся inline-включаемым кодом.

     Во-вторых, разработчики предприняли много  усилий, направленных на то, чтобы заставить  работать параллельно максимально  возможное число программных  потоков исполнительных компонентов. Вспомогательные процедуры редко  блокируются или находятся в  состоянии ожидания, что минимизирует время простоя процессора.

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

     Часть 3. Архитектура WDM

     WDM (Windows Driver Model) – это драйверная модель от Microsoft для ОС Windows, пришедшая на смену предыдущей среде написания драйверов для ОС Windows – VxD (Virtual Device Driver).

     WDM в настоящий момент – одна из важнейших концепций в написании драйверов.  Ее главные особенности:

     - совместимость на уровне двоичных кодов между драйверами для систем Windows 98 и Windows NT

     - поддержка управления питанием

     - поддержка Plug and Play

     - поддержка «продвинутого» шинного управления (advanced bus management)

     «Жизненный  цикл» среднестатистического WDM – драйвера:

  1. Драйвер шины обнаруживает устройство.
  2. Plug and Play Manager определяет местонахождение ключа устройства в ветке Enum реестра. Этот ключ содержит указатель на другой ключ реестра, определяющий функциональный драйвер (который управляет отдельным устройством и является основным драйвером устройства). Pnp-менеджер динамически загружает функциональный драйвер.
  3. PnP-менеджер вызывает функцию драйвера AddDevice для того, чтобы создать DRIVER_OBJECT. Если драйвер соответствует больше, чем одному фактическому устройству, PnP-менеджер вызывает AddDevice для каждого из них. С этого момента вся коммуникация драйвера с внешним миром осуществляется с использованием IRP (I/O Request Packet) – пакетов.
  4. PnP-менеджер выделяет все необходимые драйверу ресурсы ввода/вывода (запросы на прерывание, номера портов и т.д.) и посылает запрос для инициализации устройства.
  5. Некоторые устройства могут быть удалены из системы без выключения компьютера. Если устройство – одно из таких, то PnP-менеджер посылает драйверу специальный IRP-пакет, в результате чего созданный функцией AddDevice объект устройства уничтожается.
  6. Когда все устройства удалены, то менеджер ввода/вывода (I/O Manager) вызывает функцию DriverUnload, которая удаляет образ драйвера из памяти.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

     Часть 4. Структура драйвера.

     Фактически  драйвер можно представить как  довольно-таки обычную DLL-библиотеку уровня ядра. Таким образом, далее можно представить драйвер просто как набор процедур, периодически вызываемых внешними программами. Несмотря на то, что процедуры драйверов для разных устройств сильно отличаются, есть общая структура и общие функции для всех драйверов.

     DriverEntry – ключевая функция драйвера. Функция инициализации. Ее основные задачи – произвести все необходимые действия по инициализации и определить точки входа для остальных функций драйвера. Эта функция вызывается при загрузке драйвера. 

     NSTATUS

     DriverEntry{

     IN PDRIVER_OBJECT DriverOBject,

     IN PUNICODE_STRING RegistryPath

     };

     Она принимает 2 аргумента: первый – указатель на объект DriverObject типа PDRIVER_OBJECT. Он позволяет функции DriverEntry определить указатели на функции Dispatch, AddDevice, StartIo, а также на функцию выгрузки драйвера в объекте драйвера. Аргумент  RegistryPath передает функции DriverEntry указатель на Unicode строку, содержащую путь к ключу драйвера в реестре.

     Каждый  драйвер должен иметь, по крайней  мере, одну процедуру Dispatch

     NTSTATUS

     XxxDispatchpnP{

           IN PDEVICE_OBJECT DeviceObject,

         IN PIRP Irp

     };

     Если  драйвер устройства не может завершить  все возможные запросы ввод/вывода

     В его Dispatch-процедуре, он должен иметь либо процедуру StartIo, либо заводить одну или более внутренних очередей и управлять собственным механизмом отложенных запросов на прерывание.

     VIOD

     XxxStartIo{

           IN PDEVICE_OBJECT DeviceObject,

         IN PIRP Irp

     };

     В зависимости от уровня, занимаемого  драйвером в сетке обработки  запроса на прерывание, драйвер может  обладать следующими процедурами.

     Вдобавок  к процедуре DriverEntry драйвер может иметь процедуру Reinitialize, вызываемую один или несколько раз в процессе загрузки системы после того, как DriverEntry вернет управление.

     VOID

     Reinitialize{

           IN PDRIVER_OBJECT DriverObject,

           IN PVOID Context,

         IN ULONG Count

     };

     Любой драйвер физического устройства, который генерирует прерывания, должен иметь эту процедуру. Этот драйвер  всегда самый низкий в стеке.

     BOOLEAN

     InterruptService{

           IN PKINTERRUPT Iterrupt,

           IN PVOID ServiceContext

     };

     Любой драйвер, имеющий ISR , должен иметь DpcForIsr или CustomDpc

     OID

     DpcForIsr{

           IN PKDPC Dpc,

           IN struct _DEVICE_OBJECT *DeviceObject,

           IN struct _IRP *Irp,

     IN PVOID Context

     };

     VOID

     CustomDpc{

           IN struct _KDPC *Dpc,

           IN PVOID DeferredContext,

           IN PVOID SystemArgument1,

           IN PVOID SystemArgument2

     };

     Любой низкоуровневый драйвер устройства, данные которого или регистры сопряженного устройства могут изменяться в его  ISR и других процедурах драйвера, должен иметь одну или более процедур SynchCritSection

     BOOLEAN

     SynchCritSection{

           IN PVOID SynchronizeContext

     };

     Любой драйвер устройства, исользующий DMA, должен иметь процедуру AdapterControl. Любой драйвер устройства, который должен синхронизировать операции с физическим контроллером для нескольких устройств или каналов устройства, должен иметь ControllerControl.

     IO_ALLOCATION_ACTION

     AdapterControl{

Информация о работе Теория разработки драйверов