MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 18, М.: Диалог-МИФИ, 1995, 254 стр. 6.1. Структура загружаемого драйвераДрайвер - это еще одна разновидность программ (в дополнение к com- и exe-программам). Иногда говорят, что драйвер - это com-программа, но это не так. Скорее способ получения загрузочного модуля драйвера похож на способ получения com-программы. Есть еще одно сходство драйверов и com-программ (которое как раз и появляется из-за одинакового способа их получения): загрузочные модули этих программ являются точным отображением исходного текста на языке ассемблера без добавления каких-либо заголовков в начало файла на этапе редактирования. Но, оказывается, управляющий блок в самом начале модуля драйвера имеется. Это так называемый заголовок драйвера. Только в отличие от заголовка exe-программ, заголовок драйвера создается не редактором связи, а самим программистом и должен быть помещен в самое начало исходного текста программы-драйвера. При загрузке драйвера в память заголовок драйвера тоже помещается в оперативную память, и в нем операционная система делает некоторые изменения, о которых мы еще будем говорить. Таким образом, можно говорить и о сходстве драйвера с exe-программами, так как в начале загрузочного модуля драйвера имеется заголовок. Только этот заголовок, в отличие от заголовка exe-файла, является принадлежностью самой программы и загружается вместе с ней в память. Заголовок exe-программы используется только при загрузке программы; после загрузки операционная система убирает его из памяти. Не стоит пытаться запускать драйвер как com-программу, так как управление будет передано в область памяти, содержащую заголовок драйвера, а там нет правильных машинных команд. Поэтому обычно файлы драйверов имеют расширения имени, отличные от com или exe. Чаще всего используются расширения sys, drv, иногда bin. На самом деле можно использовать любое расширение имени, так как при описании драйвера в файле config.sys указывается его полное имя. Для загруженного в память драйвера никогда не создается префикс программного сегмента PSP . В начале исходного текста программы-драйвера не ставится директива ORG 100h (как это делается для com-программы), так как не надо резервировать место для PSP. Что же представляет из себя загрузочный модуль драйвера? В начале модуля находится заголовок драйвера . Мы уже немного говорили о нем при описании векторной таблицы связи операционной системы. Приведем формат заголовка:
Все драйверы связаны в цепочку. Самый первый драйвер находится сразу за векторной таблицей связи. Поле next заголовка драйвера указывает на следующий драйвер (на его заголовок). Это поле имеет формат дальнего указателя и состоит из адреса сегмента и смещения. Признаком того, что данный драйвер является последним в цепочке, служит значение 0FFFFh в компоненте смещения поля next. Программист, когда он составляет программу-драйвер, заносит в это поле либо 0FFFFh:0FFFFh, если исходный текст содержит только один драйвер, либо адрес следующего драйвера (в виде дальней ссылки на метку заголовка следующего драйвера). Если исходный текст содержит несколько драйверов, то в заголовке последнего драйвера в поле next должно находиться значение 0FFFFh:0FFFFh. При загрузке драйверов в память операционная система изменит содержимое поля next в заголовках драйверов для того, чтобы это поле указывало на заголовок следующего драйвера в цепочке (в памяти, а не в файле драйвера). Обычно исходный текст программы содержит один драйвер, и поле next задается следующим образом: next DD 0FFFFFFFFh Следующее поле в заголовке драйвера - поле атрибутов драйвера atrib. Это поле описывает устройство, которое обслуживает драйвер. Каждый бит слова отвечает за ту или иную особенность устройства. Прежде чем мы детально рассмотрим назначение всех бит этого слова, заметим, что бит 15 (самый старший бит) указывает, является ли это устройство символьным или блочным. Следует специально отметить, что все драйверы можно разделить на две группы - драйверы символьных устройств и драйверы блочных устройств. Первые обслуживают устройства символьного ввода/вывода, такие как принтеры, клавиатура, последовательные адаптеры и т. д., вторые ориентированы на обмен данных блоками - это драйверы дисковых устройств. Как правило, все нестандартные устройства от цифрового вольтметра до роботов и систем автоматизации производственных процессов обслуживаются символьными драйверами. Хотя этот тип драйверов ориентирован на символьную передачу данных, для быстродействующих периферийных устройств можно организовать буферизацию (средствами операционной системы). Блочные драйверы могут вам потребоваться в основном для обслуживания своих нестандартных дисковых устройств. Например, можно использовать более плотную запись информации для повышения эффективной емкости дисков. С помощью блочных драйверов можно организовать защиту информации, расположенной в файлах, от несанкционированного доступа. Для этого ваш драйвер может шифровать данные, которые записываются на диск, и предоставлять их по предъявлению пароля. Мы рассмотрим драйверы обоих типов, при этом мы каждый раз будем отмечать особенности символьных и блочных устройств. Приведем назначение отдельных битов слова атрибутов символьного драйвера :
Для драйверов блочных устройств формат слова атрибутов другой:
Более подробно назначение отдельных бит слова атрибутов драйвера мы рассмотрим позже при описании функций, выполняемых драйвером. Приведем пример определения слова атрибутов для символьного драйвера нестандартного устройства с минимальными функциональными возможностями: attrib DW 8000h После слова атрибутов драйвера находятся два очень важных поля: смещение программы стратегии драйвера strateg и смещение программы обработки прерывания interrupt. Эти две программы используются MS-DOS для организации вызова драйвера. Для обращения к драйверу MS-DOS формирует в своей области данных запрос, состоящий из заголовка стандартного формата и дополнительной структуры данных (переменной части запроса), длина и формат которой зависят от типа запроса. После этого MS-DOS считывает из заголовка драйвера смещение программы стратегии и передает ей управление, записав в регистры ES:BX адрес заголовка запроса. Задача программы стратегии - запомнить этот адрес внутри тела драйвера для дальнейшего использования или организовать очередь запросов обслуживания. Сразу после вызова программы стратегии MS-DOS вызывает программу обработки прерываний, определив ее адрес из поля interrupt заголовка драйвера. Программа обработки прерывания извлекает только что записанный программой стратегии адрес заголовка запроса и выполняет ту функцию, номер которой записан в запросе. Номер функции находится в заголовке запроса. Результаты выполнения функции программа прерывания записывает в специально отведенные поля заголовка запроса, после чего процедура обращения MS-DOS к драйверу завершается. Формат заголовка запроса будет приведен ниже, а сейчас покажем, как в заголовке драйвера задаются смещения программ стратегии и прерывания: strateg DW strateg_proc interrupt DW interrupt_proc Последнее поле заголовка драйвера dev_name имеет различную интерпретацию для символьных и блочных устройств. Для символьных устройств в этом поле должно располагаться имя устройства, выровненное по левому краю. Если длина имени меньше 8 байт, его нужно дополнить пробелами. Это имя будет использоваться для обращения к драйверу. Если вы собираетесь заменить драйвер стандартного символьного устройства MS-DOS на свой, нужно записать имя устройства прописными буквами: dev_name DB 'AUX ' Для блочных устройств первый байт поля dev_name содержит количество устройств, обслуживаемых данным драйвером, остальные семь байт не используются: dev_name DB 1 DB 7 dup(?) Таким образом, мы выяснили, что драйвер содержит в самом начале заголовок, и где-то дальше должны располагаться программы стратегии и прерывания. Не следует путать программу прерывания драйвера с программой обслуживания аппаратных или программных прерываний. Хотя программа прерывания драйвера немного похожа на обработчик программных прерываний, назначение этой программы и механизм ее использования совершенно другой. Что еще может находиться в драйвере? Это могут быть области данных, используемые драйвером, и функции, вызываемые программами стратегии и прерывания. Иногда стандартные драйверы переключают на себя некоторые векторы прерываний, и тогда они содержат в себе обработчики этих прерываний. В области памяти, отведенной операционной системой драйверу, может располагаться стек драйвера, если размер системного стека недостаточен. На длину драйвера накладывается такое же ограничение, как и на длину com-программ - 64 Кбайт, то есть один сегмент. |