Вятский государственный гуманитарный университет
Опубликован: 27.05.2013 | Доступ: свободный | Студентов: 2689 / 585 | Длительность: 09:18:00
Лекция 10:

Управление устройствами

Аннотация: Подсистема ввода-вывода. Принцип управления устройствами. Структуры данных для ввода-вывода. Пример ввода-вывода.

Подсистема ввода-вывода

В компьютерных системах кроме процессора и оперативной памяти присутствует множество разнообразных устройств (device) – жесткие диски, приводы оптических дисков (CD, DVD, Blu-Ray Disk), устройства флеш-памяти, принтеры, сканеры, звуковые и видеокарты, модемы, сетевые карты и т. п.

Операционная система должна обеспечивать управление всеми этими устройствами, т. е. предоставлять способы обмена информацией между приложениями и устройствами.

Управление устройствами в Windows осуществляется подсистемой ввода вывода, включающей несколько компонентов (см. рис.4.1 в лекции 4 "Архитектура Windows"):

  • диспетчер ввода-вывода (I/O manager – Input/Output manager) – основной компонент; обеспечивает интерфейс между приложениями и устройствами;
  • диспетчер PnP (Plug and Play manager) – компонент, реализующий принцип Plug and Play ("подключи и работай") – автоматическое распознавание и конфигурацию подключаемых к системе устройств;
  • диспетчер электропитания (power manager) – обеспечивает поддержку различных режимов энергопотребления системы и устройств;
  • драйверы устройств – программы, реализующие операции ввода-вывода для конкретного устройства; драйверы больше других компонентов системы "знают" о специфике своего устройства;
  • HAL (Hardware Abstraction Layer) – уровень абстрагирования от аппаратных средств; скрывает от других компонентов особенности реализации конкретных процессоров, системных плат и контроллеров прерываний;
  • реестр (registry) – используется как база данных для параметров устройств и драйверов.

Далее будут рассмотрены общая схема ввода-вывода, функции и структуры данных диспетчера ввода-вывода, представленные в WRK, а также пример выполнения операции чтения.

Принцип управления устройствами

Рассмотрим схематично принцип управления внешними устройствами, а затем перейдем к изучению соответствующих структур и функций WRK.

Для пользовательских приложений операционная система представляет устройства в виде файлов. Такое представление позволяет единообразно работать с разными устройствами, используя одинаковые функции, не задумываясь о деталях реализации доступа к устройствам.

Файл (file) – совокупность данных, имеющих имя и допускающих операции чтения-записи. Типичная последовательность работы с файлом: открытие файла, выполнение команд чтения-записи, закрытие файла.

При открытии файла создается файловый объект типа FILE_OBJECT, который связан с объектом, представляющим конкретное устройство (DEVICE_OBJECT). В объекте-устройстве содержится информация о драйвере, который управляет этим устройством. Драйвер в системе описывается объектом типа DRIVER_OBJECT. Объекты DRIVER_OBJECT создаются при загрузке в систему нового драйвера. Затем объект DRIVER_OBJECT может создать несколько объектов DEVICE_OBJECT – по количеству управляемых драйвером устройств (рис.15.1).

Объекты для управления вводом-выводом

Рис. 15.1. Объекты для управления вводом-выводом

Как видно из рис.15.1, в объекте DRIVER_OBJECT содержится указатель на список объектов-устройств, а в каждом из этих объектов хранится ссылка на управляющий драйвер. Таким образом, имея информацию об объекте DRIVER_OBJECT, можно найти все устройства, которыми он управляет и, наоборот, по объекту DEVICE_OBJECT легко определяется драйвер устройства.

Приложение, которому необходимо произвести некоторую операцию с устройством (файлом), вызывает соответствующую WinAPI функцию (CreateFile, ReadFile, WriteFile и др.), которая, в свою очередь, обращается к функции диспетчера ввода-вывода.

Операция, которая запрашивается приложением, представляется в системе объектом типа IRP (I/O Request Packet – пакет запроса на ввод/вывод). В этом объекте хранится информация о типе операции ввода/вывода (создание, чтение, запись и т. п.), а также необходимые параметры для данной операции. Пакет IRP передается диспетчером ввода-вывода в очередь IRP потока, который запросил операцию ввода-вывода, после чего вызывается соответствующий драйвер, непосредственно выполняющий запрошенную операцию.

Структуры данных для ввода-вывода

Драйвер в системе описывается объектом типа DRIVER_OBJECT (файл base\ntos\inc\io.h, строка 1603), имеющим следующие основные поля:

  • Type – поле, определяющее тип структуры подсистемы ввода-вывода. Значения этого поля могут быть следующими – IO_TYPE_DRIVER, IO_TYPE_FILE, IO_TYPE_DEVICE, IO_TYPE_IRP и др. (см. файл base\ntos\inc\io.h, строка 25);
  • Size – размер объекта в байтах;
  • DeviceObject – ссылка на первый объект DEVICE_OBJECT в списке устройств, управляемых данным драйвером (см. рис.15.1). Следующие устройства в списке можно определять по полю NextDevice объекта DEVICE_OBJECT;
  • Flags – флаги, определяющие тип драйвера (см. файл base\ntos\inc\io.h, строка 1530);
  • DriverName – имя драйвера в системе;
  • HardwareDatabase – путь в реестре к информации о драйвере;
  • DriverStart, DriverSize, DriverSection – информация о расположении драйвера в памяти;
  • DriverInit – адрес процедуры DriverEntry (точка входа в драйвер), отвечающей за инициализацию драйвера;
  • DriverUnload – адрес процедуры выгрузки драйвера;
  • MajorFunction – массив адресов процедур, каждая из которых отвечает за определенную операцию с устройством. Максимальное количество таких процедур равно константе IRP_MJ_MAXIMUM_FUNCTION+ 1 = 2 8 (файл base\ntos\inc\io.h, строка 80), которая определяет также количество кодов IRP (см. далее).

Устройства представлены объектами типа DEVICE_OBJECT, который включает следующие главные поля (файл base\ntos\inc\io.h, строка 1397):

  • Type, Size – совпадают по назначению с полями типа DRIVER_OBJECT;
  • ReferenceCount – счетчик количества открытых дескрипторов для устройства. Позволяет отслеживать, используется кем-либо устройство или нет;
  • DriverObject – ссылка на драйвер, который управляет устройством;
  • NextDevice – указатель на следующее устройство в списке устройств для данного драйвера;
  • Flags, Characteristics – поля, уточняющие характеристики устройства;
  • DeviceType – тип устройства; возможные типы перечислены в файле public\sdk\inc\devioctl.h (строка 26);
  • SecurityDescriptor – дескриптор безопасности, сопоставленный с устройством (см. лекцию 9 "Безопасность в Windows").

Пакеты запроса на ввод-вывод описываются типом IRP (I/O Request Packet), состоящим из двух частей – заголовка фиксированной длины (тело IRP) и одного или нескольких блоков стека. В заголовке описывается информация, общая для запроса. Каждый блок стека содержит данные об одной операции ввода-вывода.

Заголовок включает следующие основные поля:

  • Type, Size – поля, по назначению аналогичные соответствующим полям типов DRIVER_OBJECT и DEVICE_OBJECT;
  • IoStatus – статус операции при завершении;
  • RequestorMode – режим, в котором работает поток, инициировавший операцию ввода-вывода, – пользовательский или режим ядра;
  • StackCount – количество блоков стека;
  • Tail.Overlay.Thread – указатель на структуру ETHREAD потока, запросившего операцию ввода-вывода;
  • Tail.Overlay.CurrentStackLocation – указатель на блок стека (IRP Stack Location), который описывается структурой IO_STACK_LOCATION.

Структура блока стека IO_STACK_LOCATION описана в файле base\ntos\inc\io.h, строка 2303) и имеет следующие главные поля:

  • MajorFunction – номер основной функции, определяющий запрошенную операцию ввода-вывода и совпадающий с номером функции драйвера в массиве MajorFunction (структура DRIVER_OBJECT, см. выше), которую нужно вызвать для выполнения запрошенной операции. Как уже отмечалось, всего кодов 28 (IRP_MJ_MAXIMUM_FUNCTION + 1), они описаны в файле base\ntos\inc\io.h (строки 51–79);
  • DeviceObject – указатель на структуру DEVICE_OBJECT, определяющую устройство для данной операции ввода-вывода;
  • FileObject – указатель на структуру FILE_OBJECT (файл base\ntos\inc\io.h, строка 1763), которая ассоциирована со структурой DEVICE_OBJECT.

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

Пример ввода-вывода

Для ввода-вывода используются следующие основные функции:

  • создание/открытие файла – IoCreateFile (файл base\ntos\io\iomgr\iosubs.c, строка 4795);
  • чтение из файла – NtReadFile (файл base\ntos\io\iomgr\read.c, строка 90);
  • запись в файл – NtWriteFile (файл base\ntos\io\iomgr\write.c, строка 87);
  • закрытие файла – IopDeleteFile файл base\ntos\io\iomgr\objsup.c, строка 465).

Рассмотрим пример чтения с устройства, используя изученные структуры данных и функцию NtReadFile (рис.15.2).

Последовательность операций и структуры данных при чтении с устройства

Рис. 15.2. Последовательность операций и структуры данных при чтении с устройства

Предположим, некоторому приложению требуется прочитать данные с устройства, например, из файла на жестком диске. Предварительно приложение должно получить дескриптор объекта FILE_OBJECT, например, при помощи WinAPI функции CreateFile.

Для чтения из файла приложение вызывает WinAPI-функцию ReadFile, которая обращается к функции диспетчера ввода-вывода NtReadFile и передает ей дескриптор объекта FILE_OBJECT.

Функция NtReadFile определена в файле base\ntos\io\iomgr\read.c (строка 90) и выполняет две основные задачи – создает объект IRP (строка 517) и вызывает функцию IopSynchronousServiceTail (строка 725). При создании объекта IRP в блок стека заносится номер основной функции (Major Function), в случае операции чтения этот код равен константе IRP_MJ_READ (строка 558) и указывает на функцию чтения в массиве MajorFunction структуры DRIVER_OBJECT.

Функция IopSynchronousServiceTail определена в файле base\ntos\io\iomgr\internal.c (строка 7458). Эта функция помещает переданный ей объект IRP в очередь потока (функция IopQueueThreadIrp, строка 7468). Указатель на очередь IRP потока хранится в поле IrpList структуры ETHREAD (файл base\ntos\inc\ps.h, строка 623). Кроме этого, функция IopQueueThreadIrp вызывает соответствующий драйвер (функция IoCallDriver, строка 7494).

Драйвер выполняет определенную кодом IRP функцию и возвращает статус операции.

Резюме

В лекции представлены компоненты подсистемы ввода вывода в Windows, рассмотрен принцип управления устройствами, а также реализация этого принципа на основе структур данных и функций Windows Research Kernel. Разобран пример ввода вывода для операции чтения из файла.

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

Контрольные вопросы

  1. Перечислите компоненты подсистемы ввода вывода в Windows.
  2. Дайте определение понятия "файл".
  3. Опишите основные структуры данных, участвующие в процессе ввода вывода.
  4. Расскажите о взаимодействии объектов FILE_OBJECT, DEVICE_OBJECT, DRIVER_OBJECT, IRP в процессе ввода вывода.
  5. Какую роль играет массив MajorFunction в структуре DRIVER_OBJECT?
  6. Приведите пример ввода вывода с описанием участвующих в нем структур данных и функций Windows Research Kernel.