Выбор операционной системы и среды программирования. Рабочие процедуры обработки IRP-пакетов. DPC–процедура отложенного вызова. Структура Legacy-драйвера. Периодичность обновления информации о процессах и потоках. ISR–процедура обработки прерываний.
Аннотация к работе
Очень часто при разработке программного обеспечения возникает необходимость, проследить за его работой: сколько времени его потоки выполняются в режиме ядра, сколько - в пользовательском режиме, сколько времени они проводят в ожидании, а также количество переключений контекста из одного режима в другой. В режиме ядра код выполняется быстрее, но существует потенциальная возможность повреждения данных/кода системы. В противоположность режиму ядра, пользовательский режим ограничен в предоставляемых ему сервисах так, чтобы его код не мог привести к краху системы.Целью представленного курсового проекта является разработка простого профилировщика приложений, который в себя включает: Legacy-драйвер, который должен: Периодически обновлять информацию о процессах и их потоках; Предоставлять базовую информацию о процессах и их потоках;Код ее ядра выполняется в привилегированном режиме процессора (режим ядра), который обеспечивает доступ к системным данным и оборудованию. Код приложений выполняется в непривилегированном режиме процессора (пользовательский режим) с неполным набором интерфейсов, ограниченным доступом к системным данным и без прямого доступа к оборудованию. Когда программа пользовательского режима вызывает системный сервис, процессор перехватывает вызов и переключает вызывающий поток в режим ядра. По окончании системного сервиса операционная система переключает контекст потока обратно в пользовательский режим и продолжает его выполнение.В отличие от пользовательского приложения, драйвер не является процессом и не имеет потока исполнения. Вместо этого управление драйверу передается в результате запроса на ввод/вывод от пользовательского приложения или драйвера, либо возникает в результате прерывания. В третьем случае контекст исполнения случайный, поскольку прерывание (и, соответственно, исполнение кода драйвера) может произойти при выполнении любой прикладной программы.Legacy-драйвер имеет следующие основные точки входа: DRIVERENTRY - процедура загрузки драйвера;Legacy-драйверы выполняют в ней существенно большую работу, нежели WDM-драйвера, так как они вынуждены выполнять работу процедуры ADDDEVICE, обязательной для WDM-драйверов. Помимо решения инициализационных задач и регистрации точек входа рабочих процедур обработки поддерживаемых IRP-пакетов и процедуры выгрузки драйвера, здесь: Определяется аппаратное обеспечение, которое драйвер будет контролировать;Диспетчер ввода/вывода вызывает данну процедуру при динамической выгрузке драйвера. Эта процедура выполняет действия, «обратные» тем, что выполняются в процедуре DRIVERENTRY.Эти запросы всегда оформлены в виде специальных структур данных - IRP-пакетов, память под которые выделяется Диспетчером ввода/вывода в нестраничном системном пуле. Структура IRP-пакета такова, что он состоит из заголовка фиксированного размера и IRP-стека, размер которого зависит от количества объектов устройств в стеке. Структура заголовка IRP-пакета имеет следующие поля: Поле IOSTATUS типа IO_STATUS_BLOCK содержит два подполя: Status содержит значение, которое устанавливает драйвер после обработки пакета; Поле ASSOCIATEDIRP.SYSTEMBUFFER типа PVOID содержит указатель на системный буфер для случая, если устройство поддерживает буферизованный ввод/вывод; Для запроса, который послан драйверу верхнего уровня, Диспетчер ввода/вывода создает пакет IRP с несколькими стековыми ячейками - по одной для каждого объекта устройства.Эту функцию драйвер регистрирует, чтобы она получала управление в момент, когда аппаратура, обслуживаемая драйвером, передала сигнал прерывания.Такие процедуры выполняются при более низком уровне запроса прерывания (IRQL), чем ISR, что позволяет не блокировать другие прерывания.Так выглядит схема взаимодействия пользовательского приложения с драйвером через компоненты системы:В Legacy-драйвере данного курсового проекта реализованы следующие процедуры: DRIVERENTRY;Создается объект устройства с именем DEVICE_NAME: #define DEVICE_NAME L"\\Device\\Spectator" (PDRIVEROBJECT, sizeof( DEVICE_EXTENSION ), &DEVICENAME, FILE_DEVICE_SPECTATOR, FILE_DEVICE_SECURE_OPEN, FALSE, &PDEVICEOBJECT); Впервые загружается информация о процессах и их потоках: if (LOCKINFO() == STATUS_SUCCESS ) Таймеры могут быть двух типов: SYNCHRONIZATIONTIMER - по истечении указанного временного интервала или очередного периода, он переводится в сигнальное состояние, пока один из потоков, ждущих его, не будет пробужден. Далее, в силу того, что в данном драйвере по таймеру должны выполняться действия, требующие пользовательского контекста, необходимо их вынести из функции ONTIMER(), которая является DPC-процедурой, а следовательно, во время ее выполнения доступен лишь системный контекст.Как понятно из названий эти классы отвечают соответственно за взаимодействие с пользователем через диалоговое окно приложения и взаимодействие с драйвером преимущественно через IOCTL-запросы. При запуске экземпляр пользовательского приложения первым делом пытается установить драйвер, в том случае, если
План
Содержание
1. Введение
2. Аналитический раздел
2.1. Техническое задание
2.2. Обзор архитектуры Windows NT 5.x
2.3. Классификация драйверов
2.4. Общая структура Legacy-драйвера
2.4.1. Процедура DRIVERENTRY
2.4.2. Процедура DRIVERUNLOAD
2.4.3. Рабочие процедуры обработки IRP-пакетов
2.4.3.1. Заголовок IRP пакета
2.4.3.2. Стек IRP-пакета
2.4.3.3. Функция обработки пакетов IRP_MJ_CREATE
2.4.3.4. Функция обработки пакетов IRP_MJ_CLOSE
2.4.3.5. Функция обработки пакетов IRP_MJ_DEVICE_CONTROL
2.4.4. ISR - процедура обработки прерываний
2.4.5. DPC - процедура отложенного вызова
3. Конструкторский раздел
3.1. Legacy-драйвер
3.1.1. Процедура DRIVERENTRY
3.1.2. DRIVERUNLOAD
3.1.3. DISPATCHCREATE и DISPATCHCLOSE
3.1.4. DISPATCHDEVICECONTROL
3.1.4.1. IOCTL_LAST_CLIENT
3.1.4.2. IOCTL_LOCK_INFO и IOCTL_UNLOCK_INFO
3.1.4.3. IOCTL_PROCESS_FIRST и IOCTL_PROCESS_NEXT
3.1.4.4. IOCTL_THREAD_FIRST и IOCTL_THREAD_NEXT
3.1.4.5. IOCTL_OPEN_THREAD
3.1.4.6. IOCTL_CLOSE_THREAD
3.1.4.7. IOCTL_GET_THREAD_CONTEXT
3.2. Пользовательское приложение
4. Технический раздел
4.1. Выбор операционной системы и среды программирования.
4.2. Интерфейс
4.3. Системные требования
5. Заключение.
6. Список использованной литературы.
Введение
Очень часто при разработке программного обеспечения возникает необходимость, проследить за его работой: сколько времени его потоки выполняются в режиме ядра, сколько - в пользовательском режиме, сколько времени они проводят в ожидании, а также количество переключений контекста из одного режима в другой. Все это важно, так как каждый из режимов имеет свои особенности. В режиме ядра код выполняется быстрее, но существует потенциальная возможность повреждения данных/кода системы. В противоположность режиму ядра, пользовательский режим ограничен в предоставляемых ему сервисах так, чтобы его код не мог привести к краху системы. Для этой же цели в пользовательском режиме выполняются дополнительные проверки, позволяющие предотваратить выполнение вредоносных инструкций. Поэтому скорость выполнения кода пользовательского режима существенно ниже. Количество переключений контекста тоже влияет на скорость выполнения кода, так как это операция является довольно дорогостоящей (около 2000 тактов). Это было хорошо заметно при разработке лабораторных работ и курсового проекта по машинной графике: при рисовании изображения попиксельно с помощью функции SETPIXEL, скорость прорисовки была несоизмеримо меньше, чем при использовании буфера пользовательского режима, в который постепенно заносилась информация о цвете соответствующих элементам буффера пикселям. Это происходило засчет того, что при использовании функции SETPIXEL происходило два переключения контекста (из пользовательского режима в режим ядра и обратно) на один пиксель, а при использовании буфера, хранящего контекстно независимое представление цвета, - те же два переключения, но один раз на прорисовку целого кадра.
Таким образом, возможность узнать вышеуказанную статистическую информацию о целевом программном обеспечении, позволит своевременно заметить так называемые «узкие» места в программе, которые мешают улучшению производительности приложения в целом.