КАТЕГОРИИ:
АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника
|
Запрос ввода-вывода (IRP). Схема выполнения ввода-вывода в стеке драйверов.
При осуществлении операции ввода/вывода диспетчер ввода/вывода создает специальный пакет, описывающий эту операцию - пакет запроса ввода/вывода (I/O Request Packet, IRP). Обработка такого пакета может происходить поэтапно несколькими объектами-устройствами. IRP содержит всю необходимую информацию для полного описания запроса Ввода - вывода Диспетчеру Ввода/вывода и драйверам устройств. IRP описывается стандартной структурой типа "IRP", показанной на рис. 10. Структура IRP специально разработана для поддержки многоуровневой модели ввода/вывода, при которой запрос ввода/вывода последовательно обрабатывается стеком из нескольких драйверов. Для обеспечения этого каждый пакет запроса ввода/вывода состоит из двух частей: "фиксированной" части и Стека Ввода/вывода. Фиксированная часть IRP содержит информацию относительно той части запроса, которая или не изменяется от драйвера к драйверу, или которую не надо сохранять при передаче IRP от одного драйвера к другому. Стек Ввода/вывода содержит набор Стеков Размещения Ввода/вывода, каждый из которых содержит информацию, специфическую для каждого драйвера, который может обрабатывать запрос. В стеке размещения ввода/вывода для каждого устройства, которое должно принимать участие в обработке пакета, содержатся указатели на объект-устройство, которое будет обрабатывать запрос, и на объект-файл, для которого была инициирована операция ввода/вывода. Пакеты IRP всегда выделяются из невыгружаемой системной памяти (nonpaged pool), поэтому к ним может осуществляться обращение из функций, работающих на любом уровне IRQL. Как уже говорилось, драйверы подразделяются на три класса по их положению в стеке драйверов: драйверы высшего уровня, драйверы промежуточного уровня и драйверы низшего уровня. Драйвер высшего уровня - это верхний драйвер в стеке драйверов, получающий запросы через Диспетчер ввода/вывода от компонентов прикладного уровня. Драйвер высшего уровня (или, что более правильно, устройство высшего уровня) имеет один или несколько стеков размещения ввода/вывода. Число стеков размещения ввода/вывода устанавливается Диспетчером ввода/вывода в поле StackSize объекта-устройства. По умолчанию это значение равно 1. Присваивание происходит при создании устройства функцией IoCreateDevice(). Если вы создаёте многоуровневый драйвер, вы должны установить StackSize на 1 больше, чем StackSize объекта-устройства, над которым будете размещать свое устройство. В случае, если ваше устройство будет использовать больше одного устройства уровнем ниже, поле StackSize этого устройства должно быть на 1 больше максимального значения StackSize из всех устройств уровнем ниже.
40. Структура API ядра ОС Windows: Kernel API, Windowing API, Messaging API. Функции ZwXXX/NtXXX в пользовательском режиме и в режиме ядра.
Ядро состоит из следующих компонентов: · Исполнительная система ( Executive ) - управление памятью, процессами и потоками; · Ядро ( Kernel ) - планирование потоков, диспетчеризация прерываний и исключений и др. (реализовано в Ntoskrnl . exe); · Драйверы устройств ( Device Drivers ) - драйверы аппаратных устройств, сетевые драйверы, драйверы файловых систем; · Уровень абстрагирования от оборудования ( Hardware Abstraction Layer , HAL) - изолирует три вышеперечисленных компонента от различий между аппаратными архитектурами (реализован в Hal.dll); · Подсистема поддержки окон и графики ( Windowing And Graphics System ) - функции графического пользовательского интерфейса ( Graphic User Interface , GUI) (реализована в Win32k.sys). Ядро ( Kernel ) работает в тесном контакте с уровнем аппаратных абстракций. Этот модуль занимается планированием действий компьютерного процессора. В случае если компьютер содержит несколько процессоров, ядро синхронизирует их работу с целью достижения максимальной производительности системы. Ядро осуществляет диспетчеризацию нитей управления ( threads ) таким образом, чтобы максимально загрузить процессоры системы и обеспечить первоочередную обработку нитей с более высоким приоритетом. Исполняющая система ( Executive ), в состав которой входит ядро и уровень аппаратных абстракций HAL, обеспечивает общий сервис системы, который могут использовать все подсистемы среды. Каждая группа сервиса находится под управлением одной из отдельных составляющих исполняющей системы: диспетчера объектов ( Object Manager ) диспетчера виртуальной памяти ( Virtual Memory Manager ); диспетчера процессов ( Process Manager ) средства вызова локальных процедур ( Local Procedure Call Facility ); диспетчера ввода - вывода (E/O Maneger ); мониторы безопасности ( Security Reference Monitor ). Монитор безопасности совместно с процессором входа в сиситему ( Logon ) и защищёнными подсистемами реализует модель безопасности Windows NT. Верхний уровень исполняющей системы называется системным сервисом ( System Services ). Native API для Windows NT является средством, которое реализует контролируемый вызов системных сервисов, исполняемых в режиме ядра. Этот интерфейс API является интерфейсом системных вызовов и не предназначается для непосредственного использования пользовательскими программами, кроме того, его документация ограничена. Native API предоставляется коду пользовательского режима библиотекой ntdll.dll. Библиотека ntdll.dll, имеющая точки входа в Native API для кода пользовательского режима, содержит также код загрузки модуля и запуска потока процесса. Однако большинство входов в Native API являются заглушками, которые просто передают управление режиму ядра. Все функции прикладного уровня, вызывающие это прерывание, сосредоточены в модуле ntdll.dll и имеют в своем названии префикс Nt либо Zw , например, NtCreateFile ()/ ZwCreateFile (). Точка входа для двух таких имен одна. Вызов многих функций различных подсистем рано или поздно приведет к вызову соответствующей функции из ntdll.dll. При этом не все, что есть в ntdll.dll вызывается из подсистемы Win32. Вызов системных сервисов возможен не только из прикладной программы, но и из ядра ОС, то есть из драйверов. Имена соответствующих функций ядра имеют префикс либо Zw , либо Nt ( ZwCreateFile (), NtCreateFile ()). Функции с префиксом Zw обращаются к сервисам посредством прерывания 2Е, тогда как функции с префиксом Nt являются собственно точками входа стандартных системных сервисов. Из этого следует, что число функций с префиксом Nt неизменно, а множество этих функций является подмножеством функций с префиксом Zw .
41. Переход из пользовательского режима в режим ядра. Таблицы описателей функций ОС Windows. Диспетчеризация вызова Kernel API и Windowing+ Messaging API. Понятие UI-потока.
Прикладные программы могут переключаться из пользовательского режима в режим ядра, обращаясь к системному сервису. Например, Windows-функции ReadFile в ходе своего выполнения приходится вызывать внутреннюю подпрограмму Windows — она то и считывает данные из файла. Так как эта подпрограмма обращается к внутрисистемным структурам данных, она должна выполняться в режиме ядра. Переключение из пользовательского режима в режим ядра осуществляется специальной командой процессора. Операционная система перехватывает эту команду, обнаруживает запрос системного сервиса, проверяет аргументы, которые поток передал системной функции, и выполняет внутреннюю подпрограмму. Перед возвратом управления пользовательскому потоку процессор переключается обратно в пользовательский режим. Благодаря этому операционная система защищает себя и свои данные от возможной модификации пользовательскими процессами. Так что ситуация, когда пользовательский поток часть своего времени работает в пользовательском режиме, а часть — в режиме ядра, совершенно нормальна. Все функции, создающие объекты ядра, возвращают описатели, которые привязаны к конкретному процессу и могут быть использованы в любом потоке данного процесса Значение описателя представляет собой индекс в таблице описателей, принадлежащей процессу, и таким образом идентифицирует место, где хранится информация, связанная с объектом ядра. Всякий раз, когда Вы вызываете функцию, принимающую описатель объекта ядра как аргумент, Вы передаете ей значение, возвращенное одной из Create-функций. При этом функция смотрит в таблицу описателей, принадлежащую Вашему процессу, и считывает адрес нужного объекта ядра. Если Вы передаете неверный индекс (описатель), функция завершается с ошибкой и GetLastError возвращает 6 (ERROR_INVALID_HANDLE). Это связано с тем, что на самом деле описатели представляют собой индексы в таблице, их значения привязаны к конкретному процессу и недейовительны в других процессах. Потоки пользовательского режима классифицируются в ядре как потоки, имеющие пользовательский интерфейс(UI-потоки) и не имеющие его (non UI-потоки). Non UI-поток становится UI автоматически, как только делает вызов функции Windowing или Messaging API. UI-потоки: · Имеют стек > 12 кбайт (увеличение переменной, хранящей максимальный размер стека) · Драйвер Win32K.sys отслеживает все такие потоки (это драйвер виртуального устройства, видеосистемы) · Содержат указатели на переменную KeServiceDescripterTableShadow, эта переменная содержит указатель на массив из четырех таблиц указателей на функции обработки сервисов, 2-ой элемент этого массива – таблица дескрипторов, указывающих на функции в библиотеке драйвера Win32k.sys.
|