[Previous] [Next]

Постановка эксперимента

Как известно, аппаратные прерывания — это сигналы, поступающие по специальным линиям в процессор, ради которых процессор приостанавливает работу, сохраняет состояние отложенной работы (контекст) и приступает к обработке возникшей ситуации. Разумеется, при условии, что поступивший сигнал должным образом зарегистрирован, как требующий обработки специально на то предназначенным фрагментом кода, имеющим заранее оговоренный приоритет.

Тестовое приспособление CheckIt Loopback Device

Читатель вправе задать вопрос: для повторения эксперимента, с каким бы то ни было драйвером и аппаратными прерываниями на его персональном компьютере, обязательно понадобится устройство, которое эти прерывания генерирует. Где его взять?

Идея простых тестовых устройств, позволяющих тестировать параллельный порт (до сих пор все еще существующий в персональных компьютерах на пока еще существующей внутренней шине ISA) и получать в нем прерывания, возникла практически в момент появления параллельного порта. Одно из таких устройств называется "заглушка CheckIt" (CheckIt Loopback Device), которую по настоящее время производит фирма Smith Micro Software (см. Интернет сайт smithmicro.com). Данная конструкция неоднократно использовалась авторами книг по драйверам, например, Артом Бейкером и Джерри Лозано, и идеально подходит для практического ознакомления с процедурами обслуживания прерываний. Внутреннее устройство этого приспособления давно является всеобщим достоянием, и его несложно найти в Интернете. Самостоятельное "приготовление" доступно каждому и состоит в том, что следует взять стандартный 25-выводной male-разъем и замкнуть в нем 5 пар контактов. Схему для выполнения этой манипуляции можно взять, например, в книге Михаила Гука "Аппаратные средства IMM PC, Энциклопедия", 2-е издание, СПб, Питер, 2002, в разделе "Неисправности и тестирование параллельных портов". Однако чтобы не отвлекать читателя поисками столь простой схемы, приведем ее еще раз, см. рис. 11.1.

Если сопоставить схему с информацией, приведенной ранее в таблице 5.1, Регистры интерфейса стандартного параллельного порта (SPP), то становится вполне понятной идея этого приспособления. Стандартный параллельный порт имеет регистр данных DR (для ввода/вывода), регистр управления CR (для вывода) и регистр состояния SR (для ввода). Согласно схеме 11.1, выполняя вывод в регистр данных и управления, можно получать выведенные данные в регистре состояния. Поскольку один из разрядов (один из пяти используемых для вывода) поступает на вывод ACK# (бит 6 регистра состояния, SR.6), предназначенный для получения сигнала о прерывании, то получается, что передать можно 4 бита информации и сигнал о прерывании. При выводе данных в регистры DR и CR, они поступят снова в параллельный порт в регистр SR. Включив определенное воображение, можно считать, что к параллельному порту компьютера подключено "сложное" внешнее устройство, которое способно генерировать сигналы прерываний.

Рис. 11.1
Разводка тестовой заглушки CheckIt, вид со стороны пайки

В соответствии со схемой рис. 11.1 и свойствами параллельного порта (режим SPP), получаем следующие переносы данных.

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

В упомянутом тесте, описанном Артом Бейкером и Джерри Лозано, распознавание поступившего прерывания в ISR процедуре производится по значению бита SR.2 (PIRQ, внутренний бит 2 регистра состояния SR). В некоторых реализация параллельного порта этот бит действительно хранит флаг прерывания. Он имеет нулевое значение, если прерывание имело место (напряжение на выводе Ack#, SR.6, контакт 10, выполнило отрицательный перепад — переход из высокого в низкое значения при условии CR.4=1). Единичное значение бита SR.2 устанавливается по аппаратному с6росу или при чтении регистра состояния. Однако на всех компьютерах, доступных автору, параллельный порт в конфигурации SPP вел себя, точно следуя первоисточникам (например, ]an Axelson, Parallel Port Complete), где указывается, что бит SR.2 не используется. Соответственно, тест Арта Бейкера и Джерри Лозано не работает без отключения строки кода, выполняющего эту проверку. Строго говоря, такому обстоятельству может быть и несколько иное объяснение. В Windows XP, где разрабатывались приведенные ниже примеры, тяжело отказаться от услуг всех системных компонентов, потенциально касающихся параллельного порта. Поэтому при тестах представляемых драйверов сам стандартный системный драйвер параллельного порта было решено не отключать, а именно он (его процедура обслуживания прерывания) и считывает регистр состояния SR перед тем как получит управление Isr процедура собственно испытываемых драйверов. Даже если сам порт и позволил бы использовать бит SR, то все равно Isr процедура собственно испытываемых драйверов могла бы считать только единичное значение бита SR.2 (что говорило бы об отсутствии прерывания).

Настройка операционной системы

При работе с приводимыми тестовыми драйверами и заглушкой CheckIt использовалась операционная система Windows XP. Несмотря на ее способности к автоконфигурированию, для проведения тестов потребовались некоторые изменения в ее настройках и настройках BIOS.

Прежде всего, чтобы избежать разночтений и странных ошибок, следует выставить в BIOS компьютера настройки SPP параллельного порта по адресу 378 с использованием прерывания 7. Эти фиксированные настройки как раз и будет использовать драйвер.

Во-вторых, после загрузки операционной системы следует обратиться к настройкам системного драйвера параллельного порта, который будет выполнять начальное инициирование параллельного порта без участия испытываемых драйверов. Для этого следует выполнить Пуск — Настройка — Панель управления — Система — Свойства системы — Диспетчер устройств — Оборудование — Порты (СОМ и LPT) — Порт принтера (LPT). Запустив системный апплет "Свойства: Порт принтера (LPT1)" следует проверить, что порту выделены ресурсы портов ввода-вывода (0378) и прерывания 7. Затем в закладке "Параметры порта" указать, что стандартный системный драйвер должен использовать прерывание, см. рисунок 11.2.

Рис. 11.2
Настройки системного драйвера для использования прерываний

Использование системного драйвера обусловлено тем, что в противном случае пришлось бы самостоятельно заниматься регистрацией ресурсов LPT порта как устройства шины ISA. Теоретически это не является большим затруднением, однако на практике регистрация этих ресурсов всегда завершается неудачей, поскольку ресурсы оказываются выделенными другим системным компонентам. В данном случае испытываемые драйверы объявляют совместное использование прерывания, что не вызывает затруднений при их запуске и работе "рядом" с системным драйвером.

Используемые инструментальные программы

Запуск драйверов выполнялся при помощи программы Monitor (из пакета Numega Driver Studio) после полной загрузки операционной системы. Этот простой способ запуск драйверов позволяет проследить все диагностические сообщения всех рабочих процедур испытываемых драйверов, начиная от DriverEntry и заканчивая процедурой DriverUnload.

Сборка драйвера выполнялась в отладочной среде Win 2K Checked Build Environment, что уже стало традицией для примеров данной книги. Драйвер собирался как Legacy Driver при помощи определений ntddk.h и простейшего файла Sources:

TARGETNAME=LPTPort
TARGETTYPE=DRIVER TARGETPATH=.
INCLUDES= $(BASEDIR)\inc;. SOURCES=driver.cpp

Компиляция драйверов как Legacy Driver обеспечила отсутствие проблем при старте и остановке драйверов программой Monitor. Программный код драйверов размещен в двух файлах Driver.cpp (собственно исполняемые процедуры) и Driver.h (заголовочный файл). Для двух вариантов драйверов, работающих с прерываниями, которые описываются в данной главе, исходные тексты приводятся ниже полностью по причине необходимости большого количества дополнительных комментариев.

Поскольку драйверы компилировались в отладочной среде DDK, это позволило выводить отладочную диагностику при помощи условно компилируемых фрагментов вида:

#if DBG==1
	DbgPrint( "LPTPORT: Interrupt %d converted to kIrql = %d, "
	          "kAffinity = %d, kVector = %X(hex)\n",
	          pDevExt->Irq, kIrql, kAffinity, kVector);
#endif  

Сбор диагностики выполнялся программой DebugView, которая всегда запускалась до старта драйвера из программы Monitor. Это позволило собирать отладочные сообщения всех драйверных процедур, включая диагностику из DriverEntry.

При работе с объектом события во втором варианте драйвера привлекалась программа WinObj, которая подтвердила создание именованного объекта события "BaseNamedObjects\LPTPORT_EVENT" в соответствующей ситуации.

Кроме того, при отсутствии документированного описания должного уровня детализации на функцию IoCreateSynchronizationEvent во всех версиях DDK (включая примеры) было предпринято дизассемблирование некоторых системных драйверов при помощи дизассемблера IDA. Это позволило установить причину отказа данной функции от нормального завершения при вызовах с целью создания именованного объекта события в драйвере и правильно выполнить ее вызов.

Для интерпретации ошибок по их коду использовалась программа ErrLook, описанная ранее.