Разработка и исследование драйвера консоли
Понятие и назначение драйверов, схема взаимодействия прикладной программы и устройства. Разработка драйвера консоли и назначения компонентов, создание программы отладки драйвера и исследования его работы выполнении функций ввода-вывода в открытом режиме.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 20.11.2010 |
Размер файла | 1,8 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
119
1. НАЗНАЧЕНИЕ ДРАЙВЕРОВ И ПОРЯДОК РАБОТЫ С ДРАЙВЕРАМИ В MS-DOS
Обычно в состав компьютера входят клавиатура, экран, принтер, диски и другие устройства. Представьте, сколько времени необходимо, чтобы написать программу непосредственного ввода и вывода одной строки. А если для 10 разнообразных принтеров или дисковых контролеров?
Некоторые задачи решаются благодаря BIOS, но лишь со стандартными устройствами. Например, распечатать текст на так называемом Windows-принтере в DOS невозможно. Но эта проблема решается достаточно просто. Соединительным звеном между программой и принтером является драйвер.
Работа со всеми устройствами в компьютере идет через драйверы. Такая структура DOS позволяет расширить стандартные функции и организовать обмен информацией практически с любым цифровым устройством.
Устройства разделяются на 2 группы: символьные и блочные.
Символьные передают по одному символу, например клавиатура модем и другие.
Блочные устройства передают данные блоками по несколько байт, например 512 или 1024 байт. Это диски, дисководы. Разделение на такие группы дает большие преимущества, потому что операционная система работает с устройством, несмотря на его аппаратные особенности.
Обмен между драйверами и операционной системой происходит с помощью запросов. Запрос содержит всю необходимую информацию для работы устройства: какую команду нужно выполнить, в каком виде вернуть данные и т.д. Также запрос является унифицированной структурой, что очень упрощает работу прикладных программ с устройством.
Ниже на Рис. 1.1 приведена схема взаимодействия прикладной программы и устройства. Непосредственное управление устройством из программы целесообразно применить для организации обмена информацией с нестандартным устройством. Работа через BIOS менее сложная задача, но использование этого метода ограничивает возможности программы, так как можно реализовать обмен информацией лишь со стандартными устройствами. Наиболее распространенный способ работы с устройствами, причем не только в MS-DOS, - работа через драйверы. Все языки высокого уровня для ввода-вывода используют функции int21h или функции драйвера.
Для сохранения адреса запроса во внутренних переменных драйверу или организация очереди запросов обслуживания вызывается процедура стратегии. Дальше управление передается процедуре прерывания, которая анализирует поля запроса и выполняет необходимые действия.
Рис. 1.1 Схема взаимодействия программы и устройства
2. РАЗРАБОТКА СИМВОЛЬНОГО ДРАЙВЕРА КОНСОЛИ
Структура драйвера консоли и назначения компонентов
Драйвер - это программа, структура которой отличается от com- и exe-программ. Драйвер должен начинаться с так называемого заголовка драйвера, который содержит разнообразную служебную информацию, далее идет блок описания данных, блок процедур Стратегии и Прерывания. Структура драйвера приведена на Рис.2.1. Структура заголовка драйвера приведена в Табл.2.1.
Табл. 2.1 Структура заголовка драйвера
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
0 |
4 |
next |
Указатель на заголовок следующего драйвера. Если смещение адреса следующего драйвера равняется FFFFh, это последний драйвер в цепочке |
|
4 |
2 |
attrib |
Атрибуты драйвера |
|
6 |
2 |
strateg |
Смещение программы стратегии драйвера |
|
8 |
2 |
interrupt |
Смещение программы обработки прерывания для драйвера |
|
10 |
8 |
dev_name |
Имя устройства для символьных или количество устройств, которые обслуживаются, для блочных устройств |
Все драйверы связаны в цепочку. Поле next заголовка драйвера указывает на следующий драйвер (на его заголовок). Это поле имеет формат дальнего указателя и состоит из адреса сегмента и смещения. Признаком того, что данный драйвер является последним в цепочке, служит значение 0FFFFh в компоненте смещения поля next. При загрузке драйверов в память операционная система изменит содержимое поля next в заголовках драйверов для того, чтобы это поле указывало на заголовок следующего драйвера в цепочке.
Рис. 2.1 Структура драйвера
Поле attrib - это поле описывает устройство, которое обслуживает драйвер. Каждый бит слова характеризует ту или иную особенность устройства. Его структуру мы рассмотрим ниже.
Поле strateg и interrupt - это смещение процедуры стратегии драйвера и смещение процедуры обработки прерывания. Для обращения к драйверу MS-DOS формирует в своей области данных запрос, который состоит из заголовка стандартного формата и дополнительной структуры данных (переменной части запроса), длина и формат которой зависят от типа запроса. Дальше MS-DOS считывает из заголовка драйвера смещения процедуры стратегии и передает ей управление, записав в регистры ES:BX адрес заголовка запроса.
Процедура стратегии запоминает этот адрес во внутренних переменных драйвера для последующего использования
Процедура обработки прерывания считывает адрес заголовка запроса и выполняет функцию, номер которой записан в заголовке запроса. Результаты выполнения функции программа прерывания записывает в специально отведенные поля заголовка запроса, после чего процедура прерывания передает управление MS-DOS. Формат заголовка запроса приведен в Табл.2.2. Каждой команде драйвера соответствует своя структура запроса, заголовок запросов для всех команд общий. Структура запроса команды инициализации приведена в Табл.2.3, Неразрушающий ввод - Табл. 2.4 ,ввода - Табл. 2.5, структура запроса очистки ввода состоит только из заголовка запроса.
dev_name - поле для символьных устройств, в котором должно располагаться имя устройства, выровненное по левому краю. Это имя будет использоваться для обращения к драйверу.
На размер драйвера налагается такое же ограничение, как и на размер com-программ - 64 Кбайт, то есть один сегмент.
Табл. 2.2 Формат заголовка запроса
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
0 |
1 |
Size |
Общий размер блока запроса в байтах (длина заголовка запроса плюс длина переменной части запроса) |
|
1 |
1 |
Unit |
Номер устройства. Используется для блочных устройств; указывает, с каким именно устройством будет работает операционная система |
|
2 |
1 |
Cmd |
Код команды, которую требуется выполнить. Может иметь значение от 00h до 18h |
|
3 |
2 |
status |
Слово состояния устройства. Заполняется драйвером перед возвращением управления операционной системе |
|
5 |
8 |
reserved |
Зарезервировано |
Табл. 2.3 Структура запроса команды Инициализации
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
0 |
13 |
header |
Заголовок запроса |
|
13 |
1 |
n_units |
Количество устройств, обслуживаемых драйвером. Это поле заполняется только блочным драйвером. Для символьного драйвера в это поле нужно записать значение 0 |
|
14 |
4 |
end_addr |
Дальний адрес нижней границы резидентной части кода драйвера. В это поле драйвер записывает адрес байта памяти, следующего за областью драйвера, которая должна стать резидентной |
|
18 |
4 |
parm |
Дальний адрес строки параметров инициализации драйвера из файла config.sys . Эта строка содержит все, что находится в строке файла после команды 'DEVICE='. Она заканчивается символами перевода строки и возврата каретки 0Ah, 0Dh. При возврате драйвер блочного устройства должен записать в поле parm адрес массива указателей на блоки параметров BIOS (BPB ), по одному указателю на каждое устройство, обслуживаемое драйвером |
|
22 |
1 |
drive |
Номер устройства. В это поле при загрузке драйвера операционная система заносит номер, назначенный устройству, обслуживаемому драйвером. Например, для устройства А: это 0, для B: - 1 и т. д. |
|
23 |
1 |
msg_flag |
1 - отображение сообщения об ошибке, если в поле status заголовка запроса установлены соответствующие биты;0 - сообщение об ошибке не отображается |
Табл. 2.4 Структура запроса команды Ввод
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
0 |
13 |
header |
Заголовок запроса |
|
13 |
1 |
media |
В этом поле драйверу передается байт-описатель среды носителя данных |
|
14 |
4 |
buf_adr |
Адрес буфера для передачи данных |
|
18 |
2 |
count |
Количество передаваемых байтов для символьных устройств или секторов для блочных устройств |
|
20 |
2 |
sector |
Номер начального логического сектора, если драйвер использует 16-битовую адресацию секторов, или 0FFFFh для 32-битовой адресации. Это поле не используется символьными драйверами |
|
22 |
4 |
vol_id |
Указатель на метку тома в формате ASCIIZ . Возвращается блочным драйвером, если он возвращает код ошибки 15 (неправильная смена диска). Это поле должно содержать ссылку на метку требуемого диска |
|
26 |
4 |
sect32 |
Номер начального сектора, если содержимое поля sector равно 0FFFFh. Первым идет старшее слово номера сектора. Если обнаружена ошибка с кодом 15, в это поле записывается указатель на метку тома |
Табл. 2.5 Структура команды неразрушающий ввод
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
0 |
13 |
header |
Заголовок запроса |
|
13 |
1 |
byte |
В это поле драйвер записывает извлеченный из буфера байт, который будет считан следующей командой ввода |
Формирование слова атрибута драйвера
Рассмотрим слово атрибута драйвера. Назначение битов слова атрибута драйвера приведено в Табл. 2.6.
0-й и 1-й бит слова атрибута - по этому битам MS-DOS определяет драйвер консоли, который будет использоваться в системе для вывода и ввода. Биты необходимы для того, чтобы MS-DOS сформировала внутренние переменные согласно с текущим драйвером консоли, например, адрес драйвера в Списке Списков, таблица SFT и другие.
15-й бит слова атрибута - этот бит обозначает тип устройства: блочное или символьное. Консоль является символьным устройством, поэтому необходимо взводить этот бит. Назначение других битов понято из Табл.2.6.
Табл.2.6 Назначение битов слова атрибута драйвера
Бит |
Назначение |
|
0 |
1 - драйвер обслуживает стандартное устройство ввода; 0 - этот драйвер не обслуживает стандартное устройство ввода |
|
1 |
1 - драйвер обслуживает стандартное устройство вывода; 0 - драйвер не обслуживает стандартное устройство вывода |
|
2 |
1 - драйвер стандартного устройства NUL; 0 - драйвер не обслуживает устройство NUL |
|
3 |
1 - драйвер обслуживает часы |
|
4 |
Для работы с устройством можно использовать средство быстрого символьного вывода - прерывание INT 29h. Это прерывание предназначено для быстрого вывода символа на консоль, код символа необходимо записать в регистр AL |
|
5 |
Зарезервировано, бит должен быть равен 0 |
|
6 |
1 - разрешено использование драйвером функций IOCTL ; 0 - функции IOCTL не поддерживаются |
|
7 |
1 - устройство может принимать запросы IOCTL (интерфейс IOCTL будет описан позже) |
|
8-10 |
Эти биты зарезервированы и должны быть равны 0 |
|
11 |
1 - поддерживаются функции открытия/закрытия устройства (OPEN/CLOSE); 0 - функции OPEN/CLOSE для символьных устройств не поддерживаются |
|
12 |
Зарезервировано, бит должен быть равен 0 |
|
13 |
1 - для символьных устройств поддерживается функция вывода до получения состояния занятости устройства; 0 - функция вывода до состояния занятости не поддерживается |
|
14 |
1 - поддерживаются функции чтения и записи через интерфейс IOCTL 0 - функции чтения/записи через интерфейс IOCTL не поддерживаются |
|
15 |
1 - символьное устройство; 0 - блочное устройство |
Для правильной работы консольного драйвера поле attrib должно иметь значение 1000 0000 0000 0011b или 8003h.
Разработка схемы алгоритма драйвера
Структура драйвера приведена на Рис.2.2.
Рис. 2.2 Структура драйвера
Процедура СТРАТЕГИЯ является очень простой, ее работа описана ранее.
Блок-схема алгоритма процедуры Стратегия изображена на Рис.2.3
Рис. 2.3 Блок-схема алгоритма процедуры Стратегия
На Рис. 2.4. приведена блок-схема алгоритма процедуры прерывания. Ее алгоритм практически не отличается от аналогичных процедур других символьных устройств за исключением реализации команд драйвера.
Рис. 2.4 Блок-схема алгоритма процедуры прерывания
На Рис.2.5. приведен алгоритм команды INIT. Данная процедура выводит сообщение на экран и в случае необходимости инициализирует данные драйвера, а так же возвращает в соответствующих полях запроса адрес конца драйвера.
Рис. 2.5 . Алгоритм команды INIT
В процедуре INPUT есть переменная sav, в которой хранится считанный скан-код расширенной клавиши, и при следующем чтении возвращается содержание sav, то есть обращения к функциям BIOS не происходит. Блок-схема алгоритма команды INPUT приведена на Рис.2.6.
Рис. 2.6 Блок-схема алгоритма команды INPUT
Очистка буфера клавиатуры нужна для того, чтобы предотвратить считывание ранее введенных клавиш. Используется функция BIOS 01h int 16h для проверки статуса буферу клавиатуры, если буфер не пустой то считывается символ. Это происходит в цикле.
Блок-схема алгоритма команды INPUT_FLUSH изображена на Рис.2.7.
Рис.2.7 Блок-схема алгоритма команды INPUT_FLUSH
3. РАЗРАБОТКА ПРОГРАММЫ ОТЛАДКИ ДРАЙВЕРА (TEST1)
Структура программы и назначения компонентов
Программа отладки драйвера состоит из двух модулей.
Модуль test1.pas является главным модулем. В нем реализованы диалог с пользователем, формирование запроса драйвера, а также процедуры тестирования процедур Стратегия и Прерывание и команд INIT, INPUT и INPUT_FLUSH.
Вторым модулем является сам драйвер, который принимает адрес заголовка запроса от первого модуля и обслуживает этот запрос.
Таким образом, эта программа дает возможность отладки драйвера без его загрузки в систему, что уменьшает трудоемкость и общую сложность тестирования и отладки драйвера.
Разработка схемы алгоритма программы
На Рис. 3.1 изображен алгоритм тестовой программы №1.
Рис. 3.1 Схема алгоритма тестовой программы №1
На Рис. 3.2 изображен общий алгоритм тестовых процедур.
Алгоритмы процедур testinit, testread и testflush мало чем отличаются друг от друга. Но в процедуре testflush выводится буфер клавиатуры до вызова драйвера и после вызова.
Рис. 3.2 Общий алгоритм тестовых процедур
Анализ результатов отладки драйвера
Так как обмен программы и драйвера проходит через запросы, то достаточно проконтролировать поля запроса до и после обращения к драйверу.
Процедура отладки команды INIT. Как видим на Рис. 3.3 команда INIT вывела строку о своей инициализации, причем драйвер вернул конец драйвера в запросе. Мусор в счетчиках появляется вследствие слияния сегментов кода объектного файла драйвера и тестирующей программы.
Процедура отладки команды INPUT. На Рис. 3.4 Было введена 5 символов, команда взвела флаг СДЕЛАНО в слове статуса (0-й бит).
Рис. 3.3Отладка команды INIT
Рис. 3.4 Отладка команды INPUT
Процедура отладки команды FLUSH_INPUT. Как видно на Рис. 3.5 процедура выводит буфер клавиатуры и позволяет ввести пользователю символы, далее буфер клавиатуры выводится перед вызовом команды драйвера и после вызова для отображения правильности работы команды.
Рис. 3.5 Отладка команды FLUSH_INPUT
4. РАЗРАБОТКА ПРОГРАММЫ ИССЛЕДОВАНИЯ РАБОТЫ УСТАНОВЛЕННОГО ДРАЙВЕРА КОНСОЛИ (TEST2)
Назначение программы
Программа исследования работы установленного драйвера консоли предназначена для проверки и исследования связей DOS через установленный драйвер с BIOS. Эта программа с помощью функций DOS 06h int 21h, 3fh int 21h и 0сh int 21h, проверяет работу команд INPUT и INPUT_FLUSH драйвера, исследуются различия между ASCII и Бинарным режимами работы драйвера, а также работа в режиме закрытого/открытого драйвера.
Разработка схемы алгоритма программы
Схема алгоритма программы приведена на Рис. 4.1.
Рис. 4.1Схема алгоритма Test 2
Анализ результатов исследования работы драйвера консоли при выполнении функций ввода-вывода int 21h в режиме открытого драйвера
Драйвер считается открытым, когда стандартные файлы ввода-вывода открыты (0-й и 1-й дескрипторы).
Протестируем функции в ASCII режиме драйвера.
Тестирование функции 06h. Как известно функция DOS 06h int21h - функция консольного посимвольного ввода-вывода. Ввод осуществляется без эха на экране и без ожидания, управляющим символом является FFh, который переводит функцию в режим ввода. При отсутствии символа в буфере клавиатуры взводится процессорный флаг CF.
Сначала считывается 5 символов из буфера клавиатуры, затем эти символы выводятся на экран этой же функцией. Так как функция без ожидания, то непосредственно перед вызовом 06h пользователю предоставляется возможность заполнить буфер клавиатуры. Выход из этого режима осуществляется по нажатию клавиши Left Shift. Так же на экран выводится буфер клавиатуры, выход из этого режима также реализован по нажатию клавиши Left Shift,так как использование функций BIOS изменяет содержимое буфера клавиатуры. При тестировании функции в режиме открытого драйвера функция работает без каких-либо особенностей. На Рис. 4.2 изображен экран непосредственно перед вызовом функции 06h.
Рис. 4.2 Экран до вызова функции 06h int 21h
На Рис. 4.3 изображен экран после вызова функции 06h, справа счетчик ввода изменился на 5 (5 вызовов 06h).
Рис. 4.3 Экран после вызова функции 06h
Тестирование функции 0сh int 21h. Функция 0сh - очистка ввода (буфера клавиатуры) с последующим вызовом функции, номер которой загружен в al. Функция очищает буфер клавиатуры, что предотвращает считывание ранее введенных символов. Фактически функция вызывает команду драйвера Очистка Ввода. В процедуре тестирования функция 0сh после очистки вызывает 01h, что демонстрирует работу очистки ввода. Тестовая процедура дает возможность пользователю заполнить буфер клавиатуры и при нажатии клавиши Left Shift продолжает работу. На Рис. 4.44.4 можно увидеть, что драйвер клавиатуры заполнен некоторыми символами.
Рис. 4.4 Экран до вызова функции 0ch
На Рис. 4.5 видно, что функция 0сh вызвала команду драйвера Очистка Ввода. Далее управление передалось функции 01h, которая считала символ “w”.
Рис. 4.5 Экран после вызова функции 0ch
Тестирование функции 3fh. Функция 3fh предназначена для чтения блока байт из файла с использованием описателей файлов (так называемый handle-ориентированный ввод). Также с помощью этой функции можно осуществить ввод c консоли. Для этого используются стандартные описатели консоли (0-й - клавиатура , 1-й - экран). В регистре cx - количество байт для чтения. Процедура тестирования вызывает функцию 3fh для чтения 5 байт. Но фактически при работе этой функции можно ввести до 127 символов, которые помещаются в Системный буфер, а из системного буфера переписываются в пользовательский 5 байт. Чтение осуществляется до нажатия клавиши Enter. При последующих обращениях в пользовательский буфер будут записываться данные из системного буфера до тех пор, пока он не окажется пустой.
Опишем механизм работы Системного буфера. Системный буфер - буфер в сегменте данных DOS, который функция 3fh при работе с консолью использует как промежуточный. Для доступа к системному буферу используется функция DOS 52h. Функция MS-DOS с номером 52h (прерывание int 21h) является недокументированной функцией, которая возвращает указатель на список внутренних переменных MS-DOS Список Списков(List of Lists). Указатель возвращается в паре ES:BX, где ES - сегмент данных DOS. Как раз перед этим списком в слове ES:[BX-4], находится смещение системного буфера относительно сегмента данных MS-DOS (далее поле смещение системного буфера). Предположим, изначально буфер пуст. При чтении из стандартного файла ввода функцией # 3fh int 21h DOS проверяет значение смещения системного буфера, если он равен 0, то в буфер заносятся данные, введенные с клавиатуры. При этом поле смещение системного буфера указывает на символ, который будет считан при следующем обращении к буферу. При считывании символа с кодом 0Dh DOS автоматически дописывает в буфер символ с кодом 0Ah. При следующем обращении считывается символ с кодом 0Ah, далее DOS обнуляет поле смещения системного буфера, тем самым указывает на то, что буфер пуст. Фактически с момента считывания из буфера символа 0Dh DOS считает, что достигла конца буфера и дальнейшие операции с буфером (запись символа 0Ah и обнуление смещения буфера) являются подготовительными к приему новых данных. В функции 3fh это реализовано для полной эмуляции чтения из файла.
Вывод результатов ввода реализован через внутреннюю процедуру вывода строк.
На Рис. 4.6 функция 3fh ожидает ввода символов с клавиатуры.
Рис. 4.6 Ожидание ввода при выполнении функции 3fh
На Рис. 4.7 видно, что функция считывает символы до нажатия клавиши Enter, при этом в пользовательский буфер попали только первые 5 байт.
Рис. 4.7 Экран после вызова функции 3fh
Протестируем функции в бинарном режиме. Функции 06h и 0ch работают также как и ASCII режиме, исключение составляет функция 3fh. В бинарном режиме 3fh за одно обращение к драйверу считывает все затребованное количество байт без эха на экран. На Рис. 4.8 и Рис. 4.9 видно, что 3fh обращается к драйверу 1 раз, так как счетчики команд в замещающем драйвере выводятся после выполнения команды. Так же необходимо отметить то, что в бинарном режиме функция 3fh работает как при чтении из обычного дискового файла, т.е. работа ведется не через системный буфер, а напрямую; функция не реагирует на нажатие клавиши Enter.
Рис. 4.8 Вызов функции 3fh в бинарном режиме
Рис. 4.9 Экран после вызова функции 3fh в бинарном режиме
Анализ результатов исследования работы драйвера консоли при выполнении функций ввода-вывода int 21h в режиме закрытого драйвера
Особый интерес вызывает возможность закрытия и открытия драйвера.
Для исследования этого режима в тестовой программе №2 предусмотрены режимы “Закрыть драйвер на ввод”, “Закрыть драйвер на вывод”, ”Открыть драйвер”. Рассмотрим все эти режимы по порядку на примерах функций DOS.
Режим закрытия драйвера на вывод. В этом режиме вызывается функция 3Eh int 21h - закрытие файла, в качестве дескриптора файла используем описатели стандартного вывода (1-й описатель).
Исследование функции 0сh в режиме драйвера закрытого на вывод и на ввод не имеет смысла, так как данная функция ничего не выводит и не вводит.
Исследуем функцию 06h в режиме драйвера закрытого на вывод. Как видим на Рис. 4.10 буфер клавиатуры не пустой. На Рис. 4.11 видно, что функция 06h считала символы, но не вывела их на экран, следовательно, закрытие вывода для функции 06h работает. Более детально работу функции 06h мы рассмотрим в п.4.5.
Рис. 4.10 Буфер клавиатуры до вызова 06h
Рис. 4.11 Экран после вызова функции 06h в режиме закрытого драйвера
Исследуем функцию 3fh. На Рис. 4.12 изображен рабочий экран при выполнении функции 3fh. Как видим, закрытие драйвера на вывод для нее не работает, значит у 06h и у 3fh разные методы вывода на экран (далее рассмотрим этот вопрос более подробно).
Рис. 4.12 Экран при выполнении функции 3fh при закрытии на вывод
Теперь рассмотрим режим закрытия драйвера на ввод на примере функций 06h и 3fh. На Рис. 4.13 видно, что к драйверу не было обращений, значит, функция 3fh реагирует на закрытие дескриптора файла стандартного ввода.
Рис. 4.13 Работа функции 3fh в режиме драйвера закрытого на ввод
Функция 06h в режиме драйвера закрытого на ввод также теряет работоспособность, что видно на Рис. 4.14. Вместо введенного символа возвращается символ с кодом 06h, а также из буфера клавиатуры не считался ни один символ.
Рис. 4.14 Результаты работы функции 06h в режиме драйвера закрытого на ввод
Механизм взаимодействия MS-DOS и драйвера
Чтобы более четко представлять механизм работы DOS с консолью необходимо рассмотреть, как DOS взаимодействует с драйвером.
В операционной системе MS-DOS все драйверы скреплены в цепочку, каждый драйвер указывает на следующий. Чтобы получить адрес первого драйвера используется функция DOS 52h int 21h, она возвращает адрес Списка Списков - структуру внутренних переменных DOS. Эта структура описана в Списке Списков по смещению +12 находится указатель на консольный драйвер. Так же по смещению +4 находится указатель на таблицу файлов MS-DOS (System File Table, SFT). Именно эта таблица представляет наибольший интерес. Введение в DOS handle-ориентированной работы с файлами позволило значительно упростить написание программ, в том числе и работу со стандартными устройствами, такими как клавиатура, экран, экран ошибок, принтер. С точки зрения MS-DOS все вышеперечисленные устройства мало чем отличаются от обычных файлов, одни открыты только для чтения, другие только для записи и т.д. В таблице SFT хранится информация обо всех открытых файлах в системе. Структура таблицы SFT приведена в Табл.4.2.
Табл. 4.1 Структура Списка списков
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
-2 |
2 |
mcb_seg |
Сегмент первого блока памяти MCB |
|
0 |
4 |
dev_cb |
Указатель на первый блок управления устройствами MS-DOS (MS-DOS Device Control Block) |
|
4 |
4 |
file_tab |
Указатель на таблицу файлов MS-DOS |
|
8 |
4 |
clock_dr |
Указатель на драйвер CLOCK$ , установленный в файле config.sys или резидентный |
|
12 |
4 |
con_dr |
Указатель на драйвер CON , установленный в файле config.sys или резидентный |
|
16 |
2 |
max_btbl |
Максимальный размер блока (в байтах) для устройства, выполняющего передачу данных отдельными блоками |
|
18 |
4 |
disk_buf |
Указатель на структуру, описывающую дисковые буферы |
|
22 |
4 |
drv_info |
Указатель на массив информации об устройствах |
|
26 |
4 |
fcb_tabl |
Указатель на таблицу FCB |
|
30 |
2 |
fcb_size |
Размер таблицы FCB |
|
32 |
1 |
num_bdev |
Число устройств, выполняющих передачу данных отдельными блоками |
|
33 |
1 |
lastdriv |
Значение LASTDRIVE в файле config.sys (по умолчанию равно 5) |
|
34 |
? |
null_dr |
Начало драйвера NUL. Этот драйвер всегда первый в списке драйверов MS-DOS |
Табл. 4.2 Структура SFT
Смещение, байт |
Размер, байт |
Имя поля |
Описание поля |
|
0 |
4 |
next |
Указатель на следующую таблицу файлов SFT |
|
4 |
2 |
file_count |
Количество файлов, описанных в этой таблице с помощью блоков DFCB |
Таблица SFT состоит из DFCB блоков. Каждый такой блок описывает один файл. Структура DFCB блока приведена в Табл. 4.3. В DFCB блоке файла консоли записан адрес драйвера консоли. Изменяя этот адрес можно передавать управление другим драйверам консоли. На Рис. 4.14 приведен пример DFCB блока файла консоли.
Рис. 4.14 Пример DFCB блока файла консоли
Для исследования работы DOS с драйвером в тестовую программу №2 включен режим переключения драйвера. Этот режим разбит на подрежимы:
- удаление заменяющего драйвера из цепочки
- удаление заменяющего драйвера из цепочки и изменение адреса драйвера в Списке Списков
- удаление заменяющего драйвера из цепочки и изменение адреса драйвера в таблице SFT.
Табл. 4.3 Структура DFCB
Смещение, байт |
Размер, байт |
Имя поля |
Описание |
|
0 |
2 |
handl_num |
Количество идентификаторов, связанных с данным файлом |
|
2 |
1 |
access_mode |
Режим доступа к файлу, заданный при открытии файла |
|
3 |
2 |
reserv1 |
Зарезервировано |
|
5 |
2 |
Dev_info |
Информация IOCTL , полученная для устройства, на котором расположен этот файл |
|
7 |
4 |
driver |
Указатель на драйвер, обслуживающий устройство, содержащее файл |
|
11 |
2 |
first_clu |
Номер первого кластера, распределенного файла |
|
13 |
2 |
time |
Время последнего изменения файла в упакованном формате |
|
15 |
2 |
date |
Дата последнего изменения файла в упакованном формате |
|
17 |
4 |
fl_size |
Размер файла в байтах |
|
21 |
4 |
offset |
Текущее смещение внутри файла в байтах |
|
25 |
2 |
reserv2 |
Зарезервировано |
|
27 |
2 |
reserv7 |
Зарезервировано |
|
29 |
3 |
Reserv3 |
Зарезервировано |
|
32 |
1 |
reserv4 |
Зарезервировано |
|
33 |
11 |
filename |
Имя файла в формате FCB |
|
44 |
2 |
reserv5 |
Зарезервировано |
|
46 |
2 |
ownr_psp |
Адрес блока PSP программы, открывшей файл |
|
48 |
2 |
Reserv6 |
Зарезервировано |
|
50 |
2 |
last_clu |
Номер только что прочитанного кластера |
|
52 |
4 |
reserv8 |
Зарезервировано |
Исследуем, каким образом обеспечена работа функций 06h, 0сh, 3fh.
При удалении драйвера из цепочки работоспособность функций не нарушилась, следовательно, DOS не использует метод поиска драйвера консоли в цепочке. На следующем шаге изменим адрес драйвера в Списке Списков.
Как мы видим на Рис. 4.15 изменений в работе функции 06h нет (вывод по-прежнему ведется через заменяющий драйвер), значит, эта функция не использует данное поле.
Рис. 4.15 Исследование работы 06h при изменении адреса драйвера в Списке Списков
Изменений в работе функции 3fh также не возникает (см. Рис. 4.16).
Рис. 4.16 Исследование работы 3fh при изменении адреса драйвера в Списке Списков.
Попробуем теперь удалить драйвер из цепочки и изменить адрес драйвера в таблице SFT. Функция 06h теперь работает через драйвер консоли MS-DOS, что и видно на Рис. 4.17. Теперь посмотрим, как реагирует на изменения функция 3fh. Как видно на Рис. 4.18 функция 3fh продолжает работать через заменяющий драйвер консоли, однако следует отметить, что ввод осуществляется через драйвер консоли MS-DOS, так как на счетчик ввода остался в нуле, в то время как уже введено 5 символов.
Рис. 4.17 Исследование работы 06h при изменении адреса драйвера в SFT
Рис. 4.18 Исследование работы 3fh при изменении адреса драйвера в SFT
Теперь изменим указатели на драйвер в Списке Списков и таблице SFT.
Как видим на Рис. 4.19 теперь и функция 3fh работает через драйвер консоли MS-DOS. Значит, для полного переключения драйвера консоли необходимо менять указатели и в Списке Списков, и в таблице SFT.
Рис. 4.19 Исследование работы 3fh при изменении адреса драйвера в SFT и в Списке Списков
Проанализируем полученные результаты. Как известно, работать с файлами через дескрипторы намного удобнее, поэтому многие функции в DOS переписывались от версии к версии с целью увеличения быстродействия, изменения алгоритмов, унификации и т.д. Это привело к тому, что простейшие функции ввода-вывода DOS стали работать через дескриптор консоли. Отдельно стоит отметить работу функции 3fh int 21h. На основании вышеприведенных исследований данная функция осуществляет ввод через дескриптор файла консоли, а вывод через указатель на драйвер в Списке Списков (счетчик ввода справа равен 0). Этим объясняется поведение функции при закрытии драйвера на вывод, когда функция продолжала выводить символы (более подробно организацию закрытия/открытия драйвера рассмотрим ниже). Получается, что данная функция обращается только к дескриптору файла консоли (0-й), так же надо помнить о том, что функция 3fh ведет себя так, только в случае работы с консолью.
Рассмотрим механизм закрытия/открытия драйвера. Драйвер можно закрыть только функцией 3Eh int 21h, при этом в bx загружается номер дескриптора (0 и 1). На Рис. 4.20 изображен дамп DFCB блока файла консоли, черным цветом выделено поле счетчика дескрипторов связанных с файлом консоли.
Рис. 4.20 Дамп DFCB блока файла консоли
Теперь закроем драйвер на вывод. На Рис. 4.21видно, что количество связанных дескрипторов уменьшилось на 1. Это говорит о том, что дескриптор 0 - ничем не отличается от обычного дескриптора файла. При любой попытке обратится к 0 дескриптору, например, функцией дублирования дескрипторов, возвращается взведенный флаг CF и номер ошибки ax= 0006h - неверный дескриптор.
Рис. 4.21 Дамп DFCB блока файла консоли после закрытия драйвера на вывод
Закроем драйвер на ввод. На Рис. 4.22 видно, что количество связанных дескрипторов уменьшилось на 1. При попытке обращения к файлу консоли через 0-й или 1-й дескриптор базовые функции ввода-вывода DOS в большинстве случаев зависают. Например, функция 06h на Рис. 4.14 возвратила символ, код которого 06 - код ошибки при обращении к дескриптору “неверный дескриптор”.
Рис. 4.22 Дамп DFCB блока файла консоли после закрытия драйвера на ввод
При выходе из программы command.com восстанавливает закрытые дескрипторы, как это делается при переназначении ввода (с точки зрения command.com изменение стандартных дескрипторов - переназначение ввода).
Так же при переключении в бинарный режим в DFCB-блоке изменяется слово статуса IOCTL . На Рис. 4.23 дамп DFCB-блока файла драйвера в символьном режиме.
Рис. 4.23 Дамп DFCB-блока файла консоли в символьном режиме
После перевода драйвера в бинарный режим изменился 6-й бит слова атрибутов IOCTL. Рис. 4.24 дамп памяти DFCB-блока файла консоли в бинарном режиме.
Рис. 4.24 Дамп DFCB-блока файла консоли в бинарном режиме
Замена функций 06h, 0ch и 3fh прерывания int 21h
В тестовой программе №2 промоделированы функции 06h, 0ch и 3fh прерывания 21h. В режиме подмены 21 прерывания вызовы к этому прерыванию обрабатываются программой, если номер функции отличается от промоделированных, то управление передается оригинальному прерыванию DOS. Процедура моделирования функций состоит из трех частей: моделирование функции 06h, функции 0ch и функции 3fh.
Как известно прерывание это процедура, которая вызывается при выполнении команды int <номер прерывания>, а также при возникновении аппаратного прерывания. Адреса вызова этих процедур записаны в таблице векторов прерываний, которая расположена в сегменте 0000h. Подмена прерывания сводится к замене адреса прерывания DOS в векторной таблице прерываний на адрес обработчика прерывания в программе. Подменить прерывание можно двумя способами:
- используя функции DOS 25h - изменить адрес обработчика прерывания, 35h - получить адрес обработчика прерывания;
- методом прямой замены адреса обработчика прерывания в таблице векторов.
В тесте №2 реализован второй способ, как наиболее наглядный.
Алгоритм работы функции 06h приведен на Рис. 4.25. При вызове функции 06h int 21h формируется запрос на неразрушающий ввод, если символ не готов взводится флаг ZF и прерывание завершает свою работу.
Функция 0сh работает очень просто. Ее алгоритм приведен на Рис. 4.26. Фактически это процедура вызова команды драйвера FLUSH_INPUT.
Рис. 4.25 Алгоритм функции 06h
Рис. 4.26 Алгоритм функции 0ch
На Рис. 4.27 изображен алгоритм работы функции 3fh. В заменяющем прерывании, аналогично оригинальному, запись ведется в системный буфер. По нажатию клавиши Enter данные из системного буфера переписываются в пользовательский. В системный буфер нельзя ввести более 127 символов, при превышении этого числа звучит звуковой сигнал. Так же расширенные клавиши игнорируются. В бинарном режиме функция игнорирует системный буфер, чтение происходит за одно обращение к драйверу и без эха на экран. Определить режим ASCII/BIN режима драйвера можно по слову статуса IOCTL в DFCB-блоке консоли.
Рис. 4.27 Алгоритм функции 3fh
5. Разработка программы формирования списка драйверов (test3)
Назначение программы
Программа формирования списка драйверов предоставляет возможность проверить установку замещающего драйвера, а также исследовать последовательность загрузки драйверов в системе. Также эта программа дает возможность переключить драйвер консоли с замещающего на драйвер MS-DOS и отключить драйвер консоли.
Разработка схемы алгоритма программы
Алгоритм процедуры вывода списка драйверов изображен на Рис. 5.1
Рис. 5.1 Алгоритм процедуры вывода списка драйверов
Драйверы в системе скреплены в цепочку, поэтому чтобы найти драйвер в системе нужно просматривать драйвера по цепочке, пока не встретится необходимый драйвер.
Анализ результатов работы программы
Работа программы состоит из 3 этапов:
- Переключение вывода на консоль через драйвер MS-DOS
- удаление драйвера консоли MS-DOS из цепочки драйверов
- Изменение внутренних переменных MS-DOS, которые обеспечивают работу функций консоли DOS.
Сначала программа выводит список драйверов установленных в системе. На Рис. 5.2 изображен список драйверов в системе. В правой части экрана видно счетчики обращения к заменяющему драйверу.
Рис. 5.2 Список драйверов установленных в системе (перед первым этапом)
На первом этапе ввод-вывод переключается на резидентный драйвер консоли MS-DOS. Как видим на Рис. 5.3 заменяющего драйвера нет в списке, а также вывод ведется через резидентный драйвер MS-DOS (справа нет счетчиков).
Рис. 5.3 Экран тестовой программы № 3. Этап 1.
На этапе 2 резидентный драйвер MS-DOS удаляется из цепочки драйверов, но это не влияет на ввод-вывод. MS-DOS использует вышеприведенную таблицу SFT для доступа к драйверу. На рис. 5.4 в цепочке нет драйвера консоли, но вывод продолжается (вывод таблицы реализован с помощью функции DOS 09h int 21h).
Рис. 5.4 Экран тестовой программы № 3. Этап 2.
На этапе 3 будет испорчен адрес драйвера консоли в Списке Списков, что приведет к зависанию компьютера. Этот этап иллюстрирует, что при вводе-выводе DOS не пользуется цепочкой драйверов для поиска драйвера консоли, а берет его из Списка Списков.
Список литературы
1.Фролов А.,Фролов Г.Библиотека системного программиста, том 18, MS-DOS для програмиста, М.: Диалог-МИФИ, 1995, 254 с.
2. Зубков С.В. Ассемблер для DOS, Windows и UNIX, ДМК Пресс, 1999
Приложение 1.
Листинг программы драйвера
public interr,strateg
;
cseg segment para 'code'
console proc far
ASSUME cs:cseg,es:cseg,ds:cseg
rh struc ;Фиксированная структура заголовка
rh_len db ? ;Длина пакета
rh_unit db ? ;Номер устройства (блоковые)
rh_cmd db ? ;Команда драйвера устройства
rh_status dw ? ;возвращается драйвером
rh_res1 dd ? ;Зарезервировано
rh_res2 dd ? ;Зарезервировано
rh ends
;
rh0 struc ;Заголовок запроса для команды 0
rh0_rh db size rh dup (?) ;фиксированная часть
rh0_nunits db ? ;Число устройств в группе (блоковые)
rh0_brk_ofs dw ? ;Смещение для конца
rh0_brk_seg dw ? ;Сегмент для конца
rh0_bpb_tbo dw ? ;Смещение указателя массива ВРВ
rh0_bpb_tbs dw ? ;Сегмент указателя массива ВРВ
rh0_dn_itr db ? ;Первый доступный накопитель (DOS 3+)
rh0 ends
;
rh4 struc ;3аголовок запроса для команды 4
rh4_rh db size rh dup (?) ;фиксированная часть
rh4_nedla db ? ;Дескриптор носителя из DPB
rh4_buf_ofs dw ? ;Смещение DTA
rh4_buf_seg dw ? ;Сегмент DTA
rh4_count dw ? ;Счетчик передачи (секторов для
;блоковых, байтов для символьных)
rh4_start dw ? ;Начальный сектор (блоковые)
rh4 ends
;
rh5 struc ;Заголовок запроса для команды 5
rh5_rh db size rh dup (?) ;Фиксированная часть
rh5_return db ? ;Возвращаемый символ
rh5 ends
;
rh7 struc ;Заголовок запроса для команды 7
rh7_len db ? ;Длина пакета
rh7_unlt db ? ;Номер устройства (блоковые)
rh7_cmd db ? ;Команда драйвера устройства
rh7_status dw ? ;Возвращается драйвером
rh7_res1 dd ? ;Зарезервировано
rh7_res2 dd ? ;3арезервировано
rh7 ends
;
rh8 struc ;3аголовок запроса для команды 8
rh8_rh db size rh dup (?) ;Фиксированная часть
rh8_media db ? ;Дескриптор носителя из DPB
rh8_buf_ofs dw ? ;Смещение DTA
rh8_buf_seg dw ? ;Сегмент DTA
rh8_count dw ? ;Счетчик передачи (секторов для
;блоковых, байтов для символьных)
rh8_start dw ? ;Начальный сектор (блоковые)
rh8 ends
;
rh9 struc ;Заголовок-запроса для команды 9
rh9_rh db size rh dup (?) ;Фиксированная часть
rh9_medla db ? ;Дескриптор носителя из DPB
rh9_buf_of dw ? ;Смещение DTA
rh9_buf_seg dw ? ;Сегмент DTA
rh9_count dw ? ;Счетчик передачи (секторов для
;блоковых, байтов для симгольных)
rh9_start dw ? ;Начальный сектор (блоковые)
rh9 ends
;
begin:
;
next_dev dd -1
attribute dw 8003h
strategy dw dev_strategy
interrupt dw dev_interrupt
dev_name db 'CON '
;
rh_ofs dw ?
rh_seg dw ?
sav db 0
counter label word
initc dw 0
checkmc dw 0
make_BPBc dw 0
ioctl_inc dw 0
input_datac dw 0
nondest_inc dw 0
inpstatuc dw 0
flushinc dw 0
output_datac dw 0
outverifyc dw 0
outstatc dw 0
flushoutc dw 0
ioctl_outc dw 0
outstrings label byte
inits db 'inits: '
checkms db 'checkms: '
make_BPBs db 'make_BPBs: '
ioctl_ins db 'ioctl_ins: '
input_datas db 'input_datas: '
nondest_ins db 'nondest_ins: '
inpstatus db 'inpstatus: '
flushins db 'flushins: '
output_datas db 'output_datas:'
outverifys db 'outverifys: '
outstat db 'outstat: '
flushouts db 'flushouts: '
ioctl_outs db 'ioctl_outs: '
countstr db 4 dup(?) ;для числа
;
;***************************************************
;* ПРОЦЕДУРА СТРАТЕГИЯ
;***************************************************
strateg proc far
;
dev_strategy:
mov cs:rh_seg,es
mov cs:rh_ofs,bx
ret
endp
;
interr proc far
dev_interrupt:
cld
push ds
push es
push ax
push bx
push cx
push dx
push di
push si
mov ax,cs:rh_seg
mov es,ax
mov bx,cs:rh_ofs
mov al,es:[bx].rh_cmd
rol al,1
lea di,cmdtab
mov ah,0
add di,ax
jmp cs:word ptr [di]
cmdtab label byte
dw INITIALIZATION ;Инициализация
dw MEDIA_CHECK ;Контроль носителя (блоковые)
dw GET_BPB ;Получение ВРВ
dw IOCTL_INPUT ;IOCTL-BBOД
dw INPUT ;Ввод
dw ND_INPUT ;Неразрушающий ввод
dw INPUT_STATUS ;Состояние ввода
dw INPUT_FLUSH ;Очистка ввода
dw OUTPUT ;Вывод
dw OUTPUT_VERIFY ;Вывод с контролем
dw OUTPUT_STATUS ;Состояние вывода
dw OUTPUT_FLUSH ;Очистка вывода
dw IOCTL_OUTPUT ;IOCTL-вывод
dw OPEN ;Открытие устройства
dw CLOSE ;3акрытие устройства
dw REMOVABLE ;Сменный носитель
outwtohex proc
push bp
mov bp,sp
push cx bx dx
word2hex EQU [bp+4]
mov cx,4
mov bx,word2hex
c2: mov dx,bx
and dx,0F000h
shr dx,4
cmp dx,0a00h
jae add_37h
add dh,30h
cont:
mov cs:[si],dh
inc si
shl bx,4
loop c2
sub si,4
pop dx bx cx bp
ret 2
add_37h:add dh,37h
jmp cont
outwtohex endp
;------------------------------------------------------
WriteStr proc near
mov ax,0B800h
mov es,ax
mov ah,07h
c:
mov al,cs:[si]
mov es:[di],ax
inc si
add di,2
loop c
ret
WriteStr endp
;------------------------------------------------------
getDRV proc near
push bx si di cx ax
lea bx,counter
lea si,outstrings
mov di,0
mov cx,13
loopcounters:
push cx
mov cx,13
add di,126
call writeStr
push si
lea si,countstr
mov ax,[bx]
push ax
call outwtohex
mov cx,4
call writeStr
pop si
add bx,2
pop cx
loop loopcounters
pop ax cx di si bx
ret
getDRV endp
;
; Команда 0 - Инициализация
initialization:
; call initial ;Вывести сообщение
lea ax,initial ;Остановить адрес конца
mov es:[bx].rh0_brk_ofs,ax ;Сохранить смещение
mov es:[bx].rh0_brk_seg,cs ;Сохранить сегмент
mov ax,initc
inc ax
mov initc,ax
jmp done ;Остановить СДЕЛАНО и выйти
;
;Команда 1 - Контроль носителя
media_check:
mov ax,checkmc
inc ax
mov checkmc,ax
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 2 - Получение ВРВ
get_bpb:
mov ax,make_BPBc
inc ax
mov make_BPBc,ax
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда З - Ввод IOCTL
IOCTL_input:
mov ax,ioctl_inc
inc ax
mov ioctl_inc,ax
jmp unk ;Установить бит ОШИБКА и выйти
;Команда 4 - Ввод
input:
mov ax,input_datac
inc ax
mov input_datac,ax
mov cx,es:[bx].rh4_count ;3агрузить счетчик ввода
mov di,es:[bx].rh4_buf_ofs ;3агрузить смещение
mov ax,es:[bx].rh4_buf_seg ;Загрузить сегмент
mov es,ax ;Передать сегмент в ES
read1:
mov ax,0 ;Сбросить АХ
xchg al,sav ;Взять сохраненный символ
cmp al,0 ;0н равен 0 ?
jne read3 ;Нет - возвратить его
read2:
mov ah,0 ;0бслуживание считывания
int 16h ;Вызов клавиатуры BIOS
cmp ax,0 ;Клавиша равна 0 ?
jz read2 ;Да, взять другой символ
cmp al,0 ;Это расширенная клавиша ?
jne read3 ;Нет-возвратить ее
mov sav,ah ;Сохраноть скэн-код
read3:
mov es:[di],al ;Сохранить значение в буфере
inc di ;Продвинуть указатель
push cx ;Сохранить СХ
pop cx ;Восстановить СХ
loop read1 ;Продолжать до счетчика = 0
mov ax,cs:rh_seg ;восстановить регистр ES
mov es,ax ;из rh_seg
mov bx,cs:rh_ofs ;Восстановить регистр ВХ
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 5 - Неразрушающий ввод
nd_input:
mov ax,nondest_inc
inc ax
mov nondest_inc,ax
mov al,sav ;Взять сохраненный символ
cmp al,0 ;0н равен 0?
jne nd1 ;Нет - возвратить его в DOS
mov ah,1 ;Обслуживание - контроль состояния
int 16h ;Вызов клавиатуры BIOS
jz GObusy ;При ZF = 1 символа в буфере нет
cmp ax,0 ;Клавиша - 0?
jne nd1 ;Нет - возвратить ее в DOS
mov ah,0 ;Обслуживание - считывание
int 16h ;Выэов клавиатуры BIOS
jmp nd_input ;Проверять вновь
gobusy: jmp busy
nd1:
mov es:[bx].rh5_return,al ;возвратить клавишу в DOS
jmp done ;Остановить бит СДЕЛАНО и выйти
;команда 6 - Состояние ввода
input_status:
mov ax,inpstatuc
inc ax
mov inpstatuc,ax
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 7 - Очистка ввода
input_flush:
mov ax,flushinc
inc ax
mov flushinc,ax
mov sav,0 ;Сбросить сохраненный символ
if11:
mov ah,1 ;Обслуживание - контроль состояния
int 16h ;Вызов клавиатуры BIOS
jz done ;При ZF = 1 буфер пустой
mov ah,0 ;Обслуживание - считывание
int 16h ;Вызов клавиатуры BIOS
jmp if11 ;Повторять до опустошения
;Команда 8 - Вывод
output:
mov ax,output_datac
inc ax
mov output_datac,ax
mov cx,es:[bx].rh8_count ;Взять счетчик вывода
mov di,es:[bx].rh8_buf_ofs ;Загрузить смещение
mov ax,es:[bx].rh8_buf_seg ;Загрузить сегмент
mov es,ax ;в регистр ES
mov bx,0 ;Сбросить ВХ
out1:
mov al,es:[di] ;Взять выводимый символ
inc di ;Продвинуть указатель
mov ah,0eh ;Обслуживание - запись как TTY
int 10h ;Вызов экрана BIOS
loop out1 ;Повторять до исчерпания счетчика
mov ax,cs:rh_seg ;Восстановить в регистре ES
mov es,ax ;сегмент заголовка запроса
mov bx,cs:rh_ofs ;восстановить регистр ВХ
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 9 - Вывод с контролем
output_verify:
mov ax,outverifyc
inc ax
mov outverifyc,ax
jmp output ;Аналогично команде вывода
;Команда 10 - Состояние вывода
output_status:
mov ax,outstatc
inc ax
mov outstatc,ax
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 11 - Очистка вывода
output_flush:
mov ax,flushoutc
inc ax
mov flushoutc,ax
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 12 - IOCTL-вывод
ioctl_output:
mov ax,ioctl_outc
inc ax
mov ioctl_outc,ax
jmp unk ;Установить бит ОШИБКА и выйти
;Команда 13 - Открытие
open:
jmp done ;Установить бит СДЕЛАНО и выйти
;Команда 14 - Закрытие
close:
jmp done ;Остановить бит СДЕЛАНО и выйти
;Команда 15 - Сменный носитель
removable:
jmp unk ;Остановить бит ОШИБКА и выйти
;Команда 16 - Вывод до занятости
output_busy:
jmp unk ;Установить бит ОШИБКА и выйти
;
unk:
or es:[bx].rh_status,8003h ;Остановить бит и код ошибки
jmp done ;Установить бит СДЕЛАНО и выйти
busy:
or es:[bx].rh_status,0200h ;Установить бит ЗАНЯТ
done:
or es:[bx].rh_status,0100h ;Установить бит СДЕЛАНО
call getDRV
pop si di dx cx bx ax es ds ;восстановить все регистры
ret ;Возврат в DOS
endp
;******************************************************
;* КОНЕЦ ПРОГРАММЫ
;******************************************************
;
initial proc near ;Вывод сообщения на консоль
lea dx,msg ;Адрес выводимого сообщения
mov ah,09h ;Вывод на экран
int 21h ;Вызов вывода строки
ret ;Возврат
initial endp
;
msg db 'Driver module initialization called',13,10,'$'
;
console endp ;Конец процедуры CONSOLE
cseg ends ;Конец сегмента CSEG
end begin ;Конец программы
Приложение 2
Листинг программы отладки драйвера
{$D+}
{$L+}
program test1;
uses crt;
type
res = array [1..8] of byte;
theader = record
size : byte;
unitN: byte;
cmd : byte;
status:word;
reserv: res;
end;
tzapros = record
header : theader;
n_dev : byte;
end_addr_off: word;
end_addr_seg: word;
parm_off : word;
parm_seg : word;
drive : byte;
msg_flag:byte;
end;
var
zapros : tzapros;
buf : array [1..64] of char;
bufferkbd : string [82];
i : byte;
buff:word;
choice: char;
{$L drv1.obj}
{$F+}
procedure strateg; external;
procedure interr; external;
{$F-}
procedure w2h(hexword:integer);
var
work,i,shift : word;
begin
for i:=1 to 2 do
begin
work:=hexword;
work:=work and 240;
work:=work shr 4;
if work>9 then work:=work+ord('A')- 10
else work:=work+ord('0');
write(char(work));
work:=hexword;
work:=work and 15;
if work>9 then work:=work+ord('A')- 10
else work:=work+ord('0');
write(char(work));
hexword:=hexword shr 8;
end;
write (' ');
end;
procedure outheader;
begin
writeln ('Header structure:');
writeln (' size: ',zapros.header.size);
writeln (' UnitN: ',zapros.header.unitn);
writeln (' command: ',zapros.header.cmd);
write (' Status: ');
w2h(zapros.header.status);
writeln;
end;
procedure delayproc;
begin
asm
push ax
push dx
push cx
push bx
mov ah,00h
int 1ah
mov bx,dx
add bx,91d
@c:
mov ah,0h
int 1ah
cmp dx,bx
jl @c
pop bx
pop cx
pop dx
pop ax
end;
end;
procedure outreq_4;
begin
zapros.header.status:=0;
writeln ('DPB:',zapros.n_dev);
write ('Offset DTA:');
w2h(zapros.end_addr_off);
writeln;
write ('Segment DTA:');
w2h(zapros.end_addr_seg);
writeln;
writeln ('counter:',zapros.parm_off);
end;
procedure testinit;
begin
zapros.header.status:=0;
zapros.header.size:=24;
zapros.header.cmd:=0;
outheader;
writeln ('Initialization called ');
asm
push ds;
pop es;
lea bx,zapros;
end;
strateg;
interr;
outheader;
write ('Segment of end:');
w2h(zapros.end_addr_seg);
writeln;
write ('Offset of end:');
w2h(zapros.end_addr_off);
writeln;
readln;
end;
procedure testread;
begin
writeln ('Testing function 4: READ');
write('Forming header: ');
zapros.header.size:=30;
zapros.header.cmd:=4;
zapros.parm_off:=5;
zapros.end_addr_off:=ofs(buf);
zapros.end_addr_seg:=seg(buf);
writeln('done');
outheader;
outreq_4;
readln;
writeln ('Enter 5 characters! ');
asm
push ds;
pop es;
lea bx,zapros;
end;
strateg;
interr;
writeln;
writeln('Was entered: ');
for i:=1 to 5 do
write(buf[i]);
readln;
end;
procedure dispkeyb;
var
i,head_b,tail_b,work:word;
begin
asm
push ax
push bx
push es
mov bx,40h
mov es,bx
mov bx,1ah
mov ax,es:[bx]
mov head_b,ax
mov ax,es:[bx+2]
mov tail_b,ax
pop es
pop bx
pop ax
end;
i:=0;
while i<=32 do
begin
asm
push bx
push es
push ax
mov bx,40h
mov es,bx
mov bx,1eh
add bx,i
mov ax,es:[bx]
mov work,ax
pop ax
pop es
pop bx
end;
if (head_b - 30)=i then write (' H ');
if (tail_b - 30)=i then write (' T ');
w2h(work);
i:=i+2;
end;
end;
procedure testflush;
begin
writeln('Testing command 7: FLUSH');
write ('Forming request for command: ');
zapros.header.size:=13;
zapros.header.cmd:=7;
writeln ('done');
outheader;
readln;
dispkeyb;
delayproc;
writeln;
dispkeyb;
delayproc;
writeln;
writeln ('Calling driver.');
asm
push ds;
pop es;
lea bx,zapros;
end;
strateg;
interr;
dispkeyb;
writeln;
writeln ('Keyboard buffer is empty!');
readln;
end;
begin
while true do
begin
clrscr;
writeln ('Выберите режим: ');
writeln ('1. Тестирование команды инициализации');
writeln ('2. Тестирование команды чтения');
writeln ('3. Тестирование очистки ввода');
readln(choice);
clrscr;
case choice of
'1' : testinit;
'2' : testread;
'3' : testflush;
else halt(0);
end;
clrscr;
end;
end.
Приложение 3.
Листинг программы исследования драйвера
; Вывод 0ah int 10h
stacks segment 'stack' stack
db 128 dup (?)
stacks ends
datseg segment
intishooked db 13,10,'Interrupt is hooked!!!','$'
Подобные документы
Архитектура ввода/вывода Windows NT. Внутренняя организация шины USB. Сущностная характеристика драйверной модели WDM. Точки входа разрабатываемого драйвера, размещение кода в памяти, установка драйвера в системе. Реализация кода драйвера на языке C.
курсовая работа [1,2 M], добавлен 27.09.2014Повышение быстродействия операционной системы. Разработка драйверов для средств хранения данных, управление работой устройства командами PnP. Создание, настройка параметров и установка классового драйвера виртуального диска, его структура и свойства.
курсовая работа [163,2 K], добавлен 18.06.2009Анализ задания и разработка алгоритма. Основные принципы создания программы. Схема взаимодействия процессов Process 1 и Process 4, в режиме задачи и в режиме ядра. Листинг программы и ее тестирование. Результат работы и выполнения программы в консоли.
контрольная работа [395,9 K], добавлен 18.09.2010Разработка драйвера под Linux, отслеживающего выделение и освобождение процессами виртуальной памяти и выделение физических страниц при страничных отказах. Компиляция драйвера и работа с ним. Экспериментальная проверка работоспособности драйвера.
курсовая работа [43,5 K], добавлен 18.06.2009Механизмы взаимодействия драйвера режима ядра и пользовательского приложения: многослойная драйверная архитектура, алгоритм сокрытия данных, взаимодействие драйвера и приложения, пользовательский интерфейс программы фильтрации доступа к файлам.
курсовая работа [1023,3 K], добавлен 23.06.2009Описание принципа работы драйвера. Установка и регистрация драйвера. Назначение и возможности утилиты TestTerminals.exe. Использование редактора форм. Создание форм с помощью редактора задач. Последовательность выполнения операций и обработок данных.
курсовая работа [843,6 K], добавлен 09.11.2011Введение в API-программирование. Структура API-программ. Организация ввода-вывода в консольном приложении Windows. Организация низкоуровнего консольного ввода-вывода. Расширенная поддержка клавиатуры в консоли. Поддержка работы с мышью в консоли.
курсовая работа [91,0 K], добавлен 10.02.2015Использование драйвера режима ядра и управляющего приложения для создания системных потоков. Имитация обработки данных и организация задержек. Разработка драйвера на языке C++. Конфигурация тестового стенда. Точность изменения задержек и работы таймера.
курсовая работа [182,4 K], добавлен 24.06.2009Аналитический обзор существующих параллельных интерфейсов. Разработка лабораторного стенда и алгоритмов подпрограмм обмена информацией. Создание программ драйвера ИРПР. Команды микропроцессора, алгоритмы подпрограмм инициализации, ввода и вывода символа.
курсовая работа [255,2 K], добавлен 10.07.2017Разработка программного обеспечения для упрощения буквенно-цифрового ввода при невозможности использовать функционал стандартной буквенной клавиатуры. Классификация и установка драйверов. Выбор языка и среды программирования. Пользовательский интерфейс.
курсовая работа [183,0 K], добавлен 12.03.2013