на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Профилировщик приложений
p align="left">Каждая ячейка IRP-стека содержит:

MajorFunction типа UCHAR - это код, описывающий назначение операции;

MinorFunction типа UCHAR - это код, описывающий суб-код операции;

DeviceObject типа PDEVICE_OBJECT - это указатель на объект устройства, которому был адресован данный запрос IRP;

FileObject типа PFILE_OBJECT - файловый объект для данного запроса;

Parameters типа union - применение зависит от значения MajorFunction.

Диспетчер ввода/вывода использует поле MajorFunction для того, чтобы извлечь из массива MajorFunction нужную для обработки запроса процедуру.

Каждая процедура обработки IRP пакетов должна в качестве параметров принимать:

Указатель на объект устройства, для которого предназначен IRP запрос;

Указатель на пакет IRP, описывающий этот запрос;

2.4.3.3 Функция обработки пакетов IRP_MJ_CREATE. Данная функция предназначена для обработки запросов на получение дескриптора драйвера от пользовательских приложений или вышестоящих драйверов. Как правило, эта функция просто помечает IRP-пакет, как завершённый.

2.4.3.4 Функция обработки пакетов IRP_MJ_CLOSE. Данная функция предназначена для обработки запросов на закрытие дескриптора драйвера от пользовательских приложений или вышестоящих драйверов. Как правило, эта функция просто помечает IRP-пакет, как завершённый.

2.4.3.5 Функция обработки пакетов IRP_MJ_DEVICE_CONTROL. Данная функция позволяет обрабатывать расширенные запросы от клиентов пользовательского режима, служат чаще всего для обмена данными между приложением и драйвером. Такой запрос может быть сформирован посредством вызова функции DeviceIoControl из пользовательского режима.

Здесь используются IOCTL-коды (I/O Control code), часть из которых предопределена операционной системой, а часть может создаваться разработчиком драйвера. Такой код задаётся в запросе Диспетчером ввода/вывода при формировании IRP-пакета.

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

Метод доступа к данным, обеспечиваемый Диспетчером ввода/вывода, определяется в IOCTL-коде. Такими методами могут быть:

METHOD_BUFFERED: входной пользовательский буфер копируется в системный, а по окончании обработки системный копируется в выходной пользовательский буфер.

METHOD_IN_DIRECT: необходимые страницы пользовательского буфера загружаются с диска в оперативную память и блокируются. Далее с помощью DMA осуществляется передача данных между устройством и пользователем.

METHOD_OUT_DIRECT: необходимые страницы пользовательского буфера загружаются с диска в оперативную память и блокируются. Далее с помощью DMA осуществляется передача данных между устройством и пользователем.

METHOD_NEITHER: при данном методе передачи не производится проверка доступности памяти, не выделяются промежуточные буфера и не создаются MDL. В IRP-пакете передаются виртуальные адреса буферов в адресном пространстве инициатора запроса ввода/вывода.

В данном случае флаги, определяющие тип буферизации в объекте устройства, не имеют значения при работе с IOCTL запросами. Механизм буферизованного обмена определяется при каждом задании значения IOCTL в специально предназначенном для этого фрагменте этой структуры данных. Данный подход обеспечивает максимальную гибкость при работе с вызовом пользовательского режима DeviceIoControl.

С точки зрения драйвера, доступ к буферным областям, содержащим данные или предназначенным для данных, осуществляется с помощью следующих полей структур [1]:

METHOD_BUFFERED

METHOD_IN_DIRECT или METHOD_OUT_DIRECT

METHOD_NEITHER

Input

Буфер с данными

Использует буферизацию (системный буфер)

Адрес буфера в системном адресном пространстве указан в pIrp->AssociatedIrp.SystemBuffer

Клиентский виртуальный адрес в Parameters. DeviceIoControl. Type3InputBuffer

Длина указана в Parameters.DeviceIoControl.InputBufferLength

Output

Буфер для данных

Использует буферизацию (системный буфер)

Адрес буфера в системном адресном пространстве указан в pIrp-> AssociatedIrp. SystemBuffer

Использует прямой доступ, клиентский буфер преобразован в MDL список, указатель на который размещен в pIrp->MdlAddress

Клиентский виртуальный адрес в pIrp->UserBuffer

Длина указана в Parameters.DeviceIoControl.OutputBufferLength

2.4.4 ISR - процедура обработки прерываний

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

2.4.5 DPC - процедура отложенного вызова

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

3. Конструкторский раздел

Так выглядит схема взаимодействия пользовательского приложения с драйвером через компоненты системы:

3.1 Legacy-драйвер

В Legacy-драйвере данного курсового проекта реализованы следующие процедуры:

DriverEntry;

DriverUnload;

DispatchCreate (обработка IRP_MJ_CREATE-пакета);

DispatchClose (обработка IRP_MJ_CLOSE-пакета);

DispatchDeviceControl (обработка IRP_MJ_DEVICE_CONTROL-пакета).

3.1.1 Процедура DriverEntry

Здесь выполняются типичные для инициализации драйвера драйвера действия.

Регистрируются точки входа в драйвер:

pDriverObject->DriverUnload = SpectatorDriverUnload;

PDRIVER_DISPATCH * majorFunction = pDriverObject->MajorFunction;

majorFunction[ IRP_MJ_CREATE ] = SpectatorDispatchCreate;

majorFunction[ IRP_MJ_CLOSE ] = SpectatorDispatchClose;

majorFunction[ IRP_MJ_DEVICE_CONTROL ] = SpectatorDispatchDeviceControl;

Создаётся объект устройства с именем DEVICE_NAME:

#define DEVICE_NAME L"\\Device\\Spectator"

RtlInitUnicodeString( &deviceName, DEVICE_NAME );

status = IoCreateDevice

(pDriverObject,

sizeof( DEVICE_EXTENSION ),

&deviceName,

FILE_DEVICE_SPECTATOR,

FILE_DEVICE_SECURE_OPEN,

FALSE,

&pDeviceObject);

Для созданного обекта устройства регистрируется символьная ссылка SYMBOLIC_LINK:

#define SYMBOLIC_LINK L"\\DosDevices\\Spectator"

RtlInitUnicodeString( &symbolicLink, SYMBOLIC_LINK );

status = IoCreateSymbolicLink( &symbolicLink, &deviceName );

Создаётся объект ядра мьютекс:

NTSTATUS CreateMutex()

{BEGIN_FUNC( CreateMutex );

NTSTATUS status = STATUS_SUCCESS;

status = _ExAllocatePool( g_pMutex, NonPagedPool, sizeof( KMUTEX ) );

if ( NT_SUCCESS( status ) )

{KeInitializeMutex( g_pMutex, 0 );

status = STATUS_SUCCESS;}

END_FUNC( CreateMutex );

return ( status );}

Впервые загружается информация о процессах и их потоках:

if ( LockInfo() == STATUS_SUCCESS )

{ReloadInfo();

UnlockInfo();}

Функции LockInfo() и UnlockInfo() являются просто напросто функциями-обёртками для функций LockMutex() и UnlockMutex() соответственно. Первая из последних двух функций ожидает на объекте ядра мьютекс.

Объекты ядра «мьютексы» гарантируют потокам взаимоисключающий доступ к един ственному ресурсу. Отсюда и произошло название этих объектов (mutual exclusion, mutex). Они содержат счетчик числа пользователей, счетчик рекурсии и переменную, в которой запоминается идентификатор потока. Мьютексы ведут себя точно так же, как и критические секции. Однако, если последние являются объектами пользователь ского режима, то мьютексы -- объектами ядра. Кроме того, единственный объект-мью текс позволяет синхронизировать доступ к ресурсу нескольких потоков из разных процессов; при этом можно задать максимальное время ожидания доступа к ресурсу.

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

Инициализируется работа таймера:

Таймер необходим для того, чтобы с определённым интервалом обновлять хранимую информацию.

Для этого создаётся объект ядра «таймер»:

status = _ExAllocatePool( g_pTimer, NonPagedPool, sizeof( KTIMER ) );

KeInitializeTimerEx( g_pTimer, SynchronizationTimer );

Замечание: память под объекты ядра должна выделяться исключительно в нестраничном пуле (ключевое слово NonPagedPool).

Таймеры могут быть двух типов:

SynchronizationTimer -- по истечении указанного временного интервала или очередного периода, он переводится в сигнальное состояние, пока один из потоков, ждущих его, не будет пробуждён. Тогда же таймер переводится в несигнальное состояние.

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

Для того, чтобы выполнять какую-то полезную работу по таймеру, необходимо зарегистрировать DPC-процедуру OnTimer(). Для неё необходимо создать собственный DPC-объект, который будет периодически ставится в общесистемную очередь:

status = _ExAllocatePool( g_pTimerDpc, NonPagedPool, sizeof( KDPC ) );

KeInitializeDpc( g_pTimerDpc, OnTime, NULL );

Далее, в силу того, что в данном драйвере по таймеру должны выполняться действия, требующие пользовательского контекста, необходимо их вынести из функции OnTimer(), которая является DPC-процедурой, а следовательно, во время её выполнения доступен лишь системный контекст. Тем не менее, необходимо обеспечить приемлемую синхронность выполнения необходимой работы с моментом извлечения DPC-объекта функции из очереди для обработки. Для этого создадим поток, который будет посвящён ожиданию некоторого события:

OBJECT_ATTRIBUTES objectAttributes;

InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE,

NULL, NULL );

status = PsCreateSystemThread( &hThread, THREAD_ALL_ACCESS, &objectAttributes,

NULL, NULL, UpdateThreadFunc, NULL );

KeInitializeEvent( g_pUpdateEvent, SynchronizationEvent, FALSE );

Замечание: объекты ядра «события» по своему типу идентичны объектам ядра «таймер».

При поступлении этого события поток будет обновлять системную информацию о процессах и их потоках. Объект этого события будем переводить в сигнальное состояние в функции OnTimer(). Данный способ синхронизации позволил обеспечить выполнение необходимых действий через заданный интервалом с точностью до милисекунды, что следует из нижеприведённых сообщений, перехваченных программой DebugView от отладочной версии драйвера:

0.00075233 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

0.00116579 [Spectator] ======== LockInfo ========

0.00118814 [Spectator] ======== ReloadInfo ========

0.99727142 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

1.00966775 [Spectator] ======== LockInfo ========

1.00968981 [Spectator] ======== ReloadInfo ========

1.99729049 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

2.05610037 [Spectator] ======== LockInfo ========

2.05632067 [Spectator] ======== ReloadInfo ========

2.99727035 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

2.99741030 [Spectator] ======== LockInfo ========

2.99743295 [Spectator] ======== ReloadInfo ========

3.99727631 [Spectator] ^^^^^^^^ OnTime ^^^^^^^^

Страницы: 1, 2, 3



© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент.