Вопрос 8. Общие принципы разработки драйверов в ОС Windows . Общие принципы функционирования драйверов в ОС Windows .


Добавил:DMT
Дата создания:30 декабря 2007, 18:58
Дата обновления:10 января 2008, 0:02
Просмотров:21067 последний вчера, 9:55
Комментариев: 0
Вопрос 8. Общие принципы разработки драйверов в ОС Windows . Общие принципы функционирования драйверов в ОС Windows .

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

Фактически, пользовательские программы либо системные утилиты не могут напрямую обращаться к аппаратуре, используя порты ввода-вывода, DMA либо подобные низкоуровневые механизмы напрямую. Все программы пользователя и часть ОС работают в 3-м кольце защиты компьютера (наименее привилегированном). При этом любая команда обращения к порту из данной программы может быть замаскирована и повлечет за собой аппаратное исключение ( Exception ). Напрямую к аппаратуре может обратится программа, работающая в самом приоритетном, 0-м кольце защиты.

В настоящее время практически все устройства используют технологию автоматического распределения ресурсов - Plug and Play ( PnP ). Когда новое устройство будет добавлено в систему, ему будут выделены свободные ресурсы - незадействованные линии запросов на прерывание ( IRQ ), свободные адреса портов ввода-вывода. Поэтому драйвер изначально "не знает", какие именно адреса портов и IRQ ему будут выделены - эти данные будут различными для разных компьютеров. При этом задача распределения ресурсов ложится на ОС.

 

Система ввода-вывода в Windows

Окружение Win 2000 включает компоненты, которые работают в режиме пользователя ( User mode ) и в режиме ядра ( Kernel mode ). В режиме пользователя работают подсистема защиты, подсистема Win 32-архитектуры (обеспечивает стандартные API - вызовы Windows ), подсистема POSIX (обеспечение кроссплатформенности ). В режиме ядра работают все основные компоненты системы: диспетчер ввода-вывода ( I / O manager ), диспетчер конфигурации ( Configuration Manager ), подсистема PnP , диспетчер управления энергопотреблением ( Power Manager ), диспетчер памяти ( Memory Manager ) и прочие жизненно необходимые службы. Драйвера в Win 2000 включены в подсистему ввода-вывода. При этом драйвера тесно взаимодействуют практически со всеми компонентами ядра. Драйвера взаимодействуют с аппаратурой при помощи HAL (уровень абстракции аппаратуры). HAL - программный компонент ядра Win 2000, который обеспечивает интерфейс ядра (в том числе и некоторых драйверов) с аппаратурой. Т.к. Win 2000 - платформенно независимая система, то HAL избавляет ядро от непосредственного общения с кэшем , прерываниями, шинами ввода-вывода и большинством прочих устройств, оставляя эту работу драйверам, специально написанным для данной системы. Таким образом, ядро системы представляется набором отдельных изолированных модулей с четко определенными внешними интерфейсами.

Все драйвера NT имеют множество стандартных методов драйвера, определенных системой, и, возможно, несколько специфических методов, определенных разработчиком. Драйвера Windows 2000 используют архитектуру WDM ( Windows Driver Model ). В Windows 2000 драйвера бывают следующих типов:

  • Kernel mode drivers ( драйверы режима ядра ). Основной тип драйвера. Такие драйвера используются для решения общих задач: управление памятью, шинами, прерываниями, файловыми системами, устройствами хранения данных и т.п.
  • Graphics drivers ( драйверы видеокарт ). Как правило, создаются одновременно с самой видеокартой. Очень сложны в написании, так как должны учитывать множество противоречивых требований и поддерживать множество стандартов. Скорее всего, вам не потребуется создавать ничего подобного.
  • Multimedia drivers ( мультимедиа-драйверы ). Драйверы для : Аудиоустройств - считывание, воспроизведение и компресс ия ау диоданных. Устройств работы с видео - захват и компрессия видеоданных. Позиционных устройств - джойстики, световые перья, планшеты и пр.
  • Network drivers (сетевые драйвера) - работа с сетью и сетевыми протоколами на всех уровнях.
  • Virtual DOS Drivers - драйверы для виртуальных машин MS - DOS . Постепенно переходят в раздел рудиментарных .

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

  • Device drivers (драйвера устройств), такие как драйвер клавиатуры или дисковый драйвер, напрямую общающийся с дисковым контроллером. Эти драйвера называются драйверами низкого уровня, т. к. они находятся в самом низу цепочки драйверов Windows NT .
  • Intermediate drivers (промежуточные драйвера), такие как драйвер виртуального диска. Они используют драйверы устрой ств дл я обращения к аппаратуре.
  • File system drivers ( FSDs ). Драйверы файловых систем , таких как FAT, NTFS, CDFS, для доступа к аппаратуре используют Intermediate drivers и Device drivers.

Драйвера Windows 2000 должны удовлетворять следующим требованиям:

  • Переносимы с одной платформы на другую.
  • Конфигурируемые программно.
  • Всегда прерываемые.
  • Поддерживающие мультипроцессорные платформы.
  • Объектно-ориентированные.
  • Поддерживать пакетный ввод-вывод с использванием I / O request packets ( IRPs , запросы ввода-вывода).
  • Поддерживать асинхронный ввод-вывод.

Система ввода-вывода Windows 2000 имеет следующие особенности:

Менеджер ввода-вывода NT представляет интерфейс для всех kernel - mode драйверов, включая драйвера физических устройств, драйвера логических устройств и драйвера файловых систем.

Операции ввода-вывода послойные. Это значит, что вызов, сделанный пользователем, проходит через несколько драйверов, генерируя несколько пакетов запросов на ввод-вывод и "по пути" обращаясь к необходимым драйверам. К примеру, когда приложение пытается открыть файл, подсистема ввода-вывода Windows делает запрос к драйверу файловой системы; драйвер файловой системы обращается к промежуточному драйверу; и лишь промежуточный драйвер обращается непосредственно к винчестеру. Такая архитектура построения системы существенно повышает ее гибкость и снижает общую стоимость разработки.

Системная служба Windows NT - это фоновый процесс, который может запускаться и работать без участия интерактивного пользователя. В этом смысле системные службы похожи на демоны Unix и резидентные программы MS-DOS. Как правило, системные службы стартуют при загрузке системы и продолжают работать, пока система не будет остановлена, хотя возможны запуск и остановка служб уже в процессе работы.

Основное отличие драйвера от службы заключается в том, что драйвер может работать в 0 кольце и в пользовательском режиме, а служба работает только в пользовательском режиме. Установка службы осуществляется через SCM менеджер, а драйвер через . inf файл, однако драйвер может быть установлен через SCM менеджер, но не все типы драйверов могут установлены через SCM менеджер.


Второй вариант ответа на вопрос

Драйвер устройства является файлом PE-формата, таким же как обычные exe и dll . Только загружается и работает по другим правилам. Драйверы можно рассматривать как DLL режима ядра, предназначенные для выполнения задач не решаемых из пользовательского режима. Принципиальная разница здесь (не считая уровня привилегий) в том, что мы не сможем напрямую обращаться к драйверу, ни к его коду, ни к его данным, а будем пользоваться специальным механизмом предоставляемым диспетчером ввода-вывода ( Input / Output Manager ). Диспетчер ввода-вывода обеспечивает среду для функционирования драйверов, а также предоставляет механизмы для их загрузки, выгрузки и управления ими.

Многоуровневые драйверы

Большинство драйверов управляющих физическими устройствами являются многоуровневыми ( layered drivers ). Обработка запроса ввода-вывода разделяется между несколькими драйверами. Каждый выполняет свою часть работы. Например, запрос на чтение файла передается драйверу файловой системы, который, выполнив некоторые операции (например, разбиение запроса на несколько частей ), передает его "ниже" - драйверу диска, а тот, в свою очередь, отправляет запрос драйверу шины. Кроме того между этими драйверами можно добавить любое количество драйверов-фильтров (например, шифрующих данные). Выполнив запрос нижестоящий драйвер ( lower-level driver ) передает его результаты "наверх" - вышестоящему ( higher-level driver ).

Driver Development Kit

Первое, что необходимо для разработки драйвера - это Комплект разработки драйверов устройств ( Windows 2000 Driver Development Kit , 2KDDK ). В этот пакет входит документация, которая содержит информацию о внутренних структурах данных и внутрисистемных функциях используемых драйверами устройств. Помимо документации в DDK входит набор библиотечных файлов (*. lib ), которые необходимы при компоновке.

Отладка драйверов

Отладчики драйвера – отладчики, которые позволяют отлаживать код режима ядра. Самым лучшим выбором будет SoftICE . Или можно воспользоваться Kernel Debugger входящим в состав DDK.

Существует два метода установки драйвера:

  1. При наличии . inf файла, установка драйвера производиться с помощью стандартного менеджера установки оборудования OC Windows . Инсталляция при помощи inf-файла позволяет выполнить все действия по копированию файлов, относящихся к драйверу, и внесению изменений в Системный Рее стр пр актически без участия пользователя.
  2. C помощью функций SCM Менеджера возможно установить драйвер непосредственно из приложения, которое также может выполнить как остановку, так и выгрузку драйвера. Следует, однако, признать, что не все драйверы поддаются работе через сервисы SCM Менеджера. Этот удобный (особенно при экспериментах по изучению системных вызовов режима ядра).

Порядок функционирования драйвера в ОС

Обычно принята двухуровневая схема организации драйверов виртуальных устройств. На самом нижнем уровне (уровень ядра операционной системы) работает собственно драйвер виртуального устройства. Который должен выполнять все операции ввода/вывода, которые может осуществлять устройство, реализовывать интерфейс IOCTL и взаимодействовать с системой. По возможности данная часть ПО должна быть небольшой и занимать минимум процессорного времени.

Рис. 1 Схема взаимодействия пользовательской программы с драйвером

Второй уровень – уровень DLL, предоставляющей API прикладным программам (далее уровень API). Под API понимается набор функций, которые могут вызывать клиентские программы, для доступа к нашему виртуальному устройству. Клиентские приложения, которые желают работать с драйвером, также могут использовать интерфейс IOCTL.

Третий уровень – уровень клиентских приложений он уже не относится к драйверу.

Пример простейшего драйвера:

Вид файла driver.h:

Код на C++
  1. #ifdef __cplusplus
  2. extern "C"
  3. {
  4. #endif
  5. #include "ntddk.h"
  6. #ifdef __cplusplus
  7. }
  8. #endif
  9. // Определяем структуру расширения устройства. Включим в нее
  10. // указатель на FDO и имя символьной ссылки в формате UNOCODE_STRING.
  11. typedef struct _EXAMPLE_DEVICE_EXTENSION
  12. {
  13. PDEVICE_OBJECT fdo;
  14. UNICODE_STRING ustrSymLinkName; // L"\\DosDevices\\Example"
  15. } EXAMPLE_DEVICE_EXTENSION, *PEXAMPLE_DEVICE_EXTENSION;
  16.  
При использовании обязательна ссылка на http://DMTSoft.ru

Текст init.cpp:

Код на C++
  1.  
  2. #include "Driver.h"
  3. // Предварительные объявления функций:
  4. VOID UnloadRoutine(IN PDRIVER_OBJECT DriverObject);
  5. NTSTATUS Create_File_IRPprocessing(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
  6. NTSTATUS Close_Handle_IRPprocessing(IN PDEVICE_OBJECT fdo, IN PIRP Irp);
  7. #pragma code_seg("INIT") // начало секции INIT
  8. // DriverEntry - инициализация драйвера и необходимых объектов
  9. // Аргументы: указатель на объект драйвера
  10. // раздел реестра (driver service key) в UNICODE
  11. // Возвращает: STATUS_Xxx
  12. extern "C"
  13. NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
  14. IN PUNICODE_STRING RegistryPath )
  15. {
  16. NTSTATUS status = STATUS_SUCCESS;
  17. PDEVICE_OBJECT fdo;
  18. UNICODE_STRING devName;
  19. // Экспорт точек входа в драйвер
  20. DriverObject->DriverUnload = UnloadRoutine;
  21. DriverObject->MajorFunction[IRP_MJ_CREATE]= Create_File_IRPprocessing;
  22. DriverObject->MajorFunction[IRP_MJ_CLOSE] = Close_Handle_IRPprocessing;
  23. // Действия по созданию символьной ссылки
  24. RtlInitUnicodeString( &devName, L"\\Device\\EXAMPLE" );
  25. // Создаем наш Functional Device Object (FDO) и получаем
  26. // указатель на созданный FDO в нашей переменной fdo.
  27. status = IoCreateDevice(DriverObject,
  28. sizeof(EXAMPLE_DEVICE_EXTENSION),
  29. &devName, // может быть и NULL
  30. FILE_DEVICE_UNKNOWN,
  31. 0,
  32. FALSE, // без эксклюзивного доступа
  33. &fdo);
  34. if(!NT_SUCCESS(status)) return status;
  35. // Получаем указатель на область, предназначенную под
  36. // структуру расширение устройства
  37. PEXAMPLE_DEVICE_EXTENSION dx =
  38. (PEXAMPLE_DEVICE_EXTENSION)fdo->DeviceExtension;
  39. dx->fdo = fdo; // Сохраняем обратный указатель
  40. UNICODE_STRING symLinkName; // Сформировать символьное имя:
  41. // Для того, чтобы ссылка работала в и Windows 98 и в NT,
  42. // необходимо поступать следующим образом :
  43. #define SYM_LINK_NAME L"\\DosDevices\\Example"
  44. RtlInitUnicodeString( &symLinkName, SYM_LINK_NAME );
  45. dx->ustrSymLinkName = symLinkName;
  46. // Создаем символьную ссылку
  47. status = IoCreateSymbolicLink( &symLinkName, &devName );
  48. if (!NT_SUCCESS(status))
  49. { // при неудаче - удалить Device Object и вернуть управление
  50. IoDeleteDevice( fdo );
  51. return status;
  52. } // Теперь можно вызывать CreateFile("\\\\.\\Example",...);
  53. // в пользовательских приложениях
  54. return status;
  55. }
  56. #pragma code_seg() // end INIT section
  57. // CompleteIrp: Устанавливает IoStatus и завершает обработку IRP
  58. // Первый аргумент - указатель на объект нашего FDO.
  59. NTSTATUS CompleteIrp( PIRP Irp, NTSTATUS status, ULONG info)
  60. {
  61. Irp->IoStatus.Status = status;
  62. Irp->IoStatus.Information = info;
  63. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  64. return status;
  65. }
  66. // Create_File_IRPprocessing: Берет на себя обработку запросов с
  67. // кодом IRP_MJ_CREATE.
  68. // Аргументы:
  69. // Указатель на объект нашего FDO
  70. // Указатель на структуру IRP, поступившего от Диспетчера ВВ
  71. //
  72. NTSTATUS Create_File_IRPprocessing(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
  73. {
  74. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  75. return CompleteIrp(Irp,STATUS_SUCCESS,0); // Успешное завершение
  76. }
  77. // Close_File_IRPprocessing: Берет на себя обработку запросов с кодом IRP_MJ_CLOSE.
  78. // Аргументы:
  79. // Указатель на объект нашего FDO
  80. // Указатель на структуру IRP, поступившего от Диспетчера
  81. // ввода/вывода
  82. NTSTATUS Close_Handle_IRPprocessing(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
  83. {
  84. return CompleteIrp(Irp,STATUS_SUCCESS,0);// Успешное завершение
  85. }
  86. // UnloadRoutine: Выгружает драйвер, освобождая оставшиеся объекты
  87. // Вызывается системой, когда необходимо выгрузить драйвер.
  88. // Arguments: указатель на объект драйвера
  89. #pragma code_seg("PAGE")
  90. // Допускает размещение в странично организованной памяти
  91. VOID UnloadRoutine(IN PDRIVER_OBJECT pDriverObject)
  92. {
  93. PDEVICE_OBJECT pNextDevObj;
  94. int i;
  95. // Проходим по всем объектам устройств, контролируемым
  96. // драйвером
  97. pNextDevObj = pDriverObject->DeviceObject;
  98. for(i=0; pNextDevObj!=NULL; i++)
  99. {
  100. PEXAMPLE_DEVICE_EXTENSION dx =
  101. (PEXAMPLE_DEVICE_EXTENSION)pNextDevObj->DeviceExtension;
  102. // Удаляем символьную ссылку и уничтожаем FDO:
  103. UNICODE_STRING *pLinkName = & (dx->ustrSymLinkName);
  104. // сохраняем указатель:
  105. pNextDevObj = pNextDevObj->NextDevice;
  106. IoDeleteSymbolicLink(pLinkName);
  107. IoDeleteDevice( dx->fdo);
  108. }
  109. }
  110. #pragma code_seg()
При использовании обязательна ссылка на http://DMTSoft.ru
up