- •1. Основы программирования для dos 9
- •1.1.7. Средства bios 21
- •2. Приемы системного программирования 57
- •Введение
- •1.Основы программирования для dos
- •1.1. Структура и выполнение программ в dos
- •Программа типа сом
- •Программа типа ехе
- •1.2.Использование служебных функций dos и bios
- •1.3.Вывод на экран в текстовом режиме
- •Средства dos
- •Средства bios
- •Выбор видеорежима
- •Управление положением курсора
- •Вывод символов на экран
- •Прямая работа с видеопамятью
- •1.4.Ввод с клавиатуры
- •Средства dos
- •Средства bios
- •1.5.Графические видеорежимы
- •Работа со стандартными графическими режимами
- •Работа с svga-режимами
- •(Продолжение таблицы 4)
- •(Окончание таблицы 4)
- •1.6.Работа с мышью
- •1.7.Другие устройства
- •Системный таймер
- •Последовательный порт
- •Параллельный порт
- •1.8.Работа с файлами
- •Создание и открытие файлов
- •Чтение из файла и запись в файл
- •Закрытие и удаление файла
- •Поиск файлов
- •Управление файловой системой
- •1.9.Управление памятью
- •Обычная память
- •Область памяти umв
- •Область памяти нма
- •Интерфейс ems
- •Интерфейс xms
- •1.10.Организация процессов
- •Запуск программ на выполнение
- •Переменные окружения
- •Командные параметры
- •2.Приемы системного программирования
- •2.1.Управляющие структуры
- •Структуры if... Then... Else
- •Структуры case
- •Конечные автоматы
- •2.2.Процедуры и функции
- •Передача параметров
- •Передача параметров по значению
- •Передача параметров по ссылке
- •Передача параметров по возвращаемому значению
- •Передача параметров по результату
- •Передача параметров по имени
- •Передача параметров отложенным вычислением
- •Передача параметров в регистрах
- •Передача параметров в глобальных переменных
- •Передача параметров в стеке
- •Передача параметров в потоке кода
- •Передача параметров в блоке параметров
- •Локальные переменные
- •2.3.Обработка прерываний
- •Обработчики прерываний
- •Прерывания от внешних устройств
- •Взаимодействие прикладных и системных обработчиков прерываний
- •2.4.Резидентные программы
- •Системные средства организации резидентных программ
- •Взаимодействие с резидентной программой
- •2.5.Драйверы устройств в dos
- •Литература
Взаимодействие прикладных и системных обработчиков прерываний
Самыми полезными для программ аппаратными прерываниями являются, пожалуй, прерывания системного таймера и клавиатуры. Так как их стандартные обработчики выполняют множество функций, от которых зависит работа системы, их нельзя заменять полностью. Следует обязательно вызвать предыдущий обработчик, передав ему управление либо до, либо после выполнения необходимых действий. Эта методика называется сцеплением прикладного и системного обработчиков прерывания.
Если прикладной обработчик выполняет свои основные действия после системного обработчика, то вначале он должен вызвать системный обработчик следующим образом (если его адрес сохранен в переменной old_handler, как в предыдущих примерах):
pushf
call old_handler
Эти две команды выполняют действие, аналогичное команде INT (сохранить флаги в стеке и передать управление подобно команде call), так что, когда обработчик завершится командой IRET, управление вернется в прерванную программу.
Другой способ — простая команда JMP — применяется, если прикладной обработчик вызывает системный после выполнения своих действий:
jmp cs:old_handler
Когда старый обработчик выполнит команду IRET, управление сразу же перейдет к прерванной программе.
Механизм аппаратных прерываний позволяет процессору выполнять одну программу, в то время как отдельные программы следят за временем, считывают символы из клавиатуры и помещают их в буфер, получают и передают данные через последовательные и параллельные порты и даже обеспечивают многозадачность, переключая процессор между разными задачами по прерыванию системного таймера.
Разумеется, обработка прерываний не должна занимать много времени: если прерывание происходит достаточно часто (например, прерывание последовательного порта может происходить 28 800 раз в секунду), его обработчик обязательно должен выполняться за более короткое время. Если, например, обработчик прерывания таймера будет выполняться 1/32,4 секунды, то есть половину времени между прерываниями, вся система будет работать в два раза медленнее. А если еще одна программа с таким же долгим обработчиком перехватит это прерывание, система остановится совсем. Именно поэтому обработчики прерываний обычно пишут на ассемблере.
Обработчики прерываний могут разрабатываться с учетом того, что возможно возникновение обрабатываемого им прерывания в то время, пока не закончилась обработка предыдущего, то есть прерывание обработчика и повторный вход в него же. Если такая ситуация правильно обрабатывается и не приводит к сбою, обработчик называется повторно входимым (реентерабельным). Некоторые критические участки кода может понадобиться защитить от прерываний, временно их запретив командой CLI (сброс флага прерываний). Следует, однако, помнить, что пока прерывания запрещены, система не отслеживает изменения часов, не получает данных с клавиатуры. Поэтому прерывания надо обязательно, при первой возможности, разрешать (командой STI).
К сожалению, в MS-DOS самый важный обработчик прерываний в системе — обработчик INT 21h — не является повторно входимым. В отличие от прерываний BIOS, обработчики которых используют стек прерванной программы, обработчик системных функций DOS записывает в SS:SP адрес дна одного из трех внутренних стеков DOS. Если функция была прервана аппаратным прерыванием, обработчик которого вызвал другую функцию DOS, она будет пользоваться тем же стеком, затирая все, что туда поместила прерванная функция. Когда управление вернется в прерванную функцию, в стеке окажется мусор и произойдет ошибка. Лучший выход — вообще не использовать прерывания DOS из обработчиков аппаратных прерываний, но если это действительно нужно, то принять необходимые меры предосторожности. Если прерывание произошло в тот момент, когда не выполнялось никаких системных функций DOS, ими можно безбоязненно пользоваться. Чтобы определить, занята DOS или нет, надо сначала, до установки собственных обработчиков, определить адрес флага занятости DOS:
Функция DOS 34h — Определить адрес флага занятости DOS
Ввод: АН = 34h
Вывод: ES:BX = адрес однобайтного флага занятости DOS
ES:BX – 1 = адрес однобайтного флага критической ошибки DOS
Теперь обработчик прерывания может проверять состояние этих флагов и, если оба флага равны нулю, разрешается свободно пользоваться функциями DOS.
Если флаг критической ошибки не ноль, никакими функциями DOS пользоваться нельзя. Если не равен нулю только флаг занятости DOS, можно пользоваться только функциями 01h — 0Ch, а чтобы воспользоваться какой-нибудь другой функцией, придется отложить действия до тех пор, пока DOS не освободится. Чтобы это сделать, надо сохранить номер функции и параметры в каких-нибудь переменных в памяти и установить обработчик прерывания 8h или 1Ch. Этот обработчик должен будет при каждом вызове проверять флаги занятости и, если DOS освободилась, вызовет функцию с номером и параметрами, оставленными в переменных в памяти. Кроме того, участок программы после проверки флага занятости — критический, и прерывания должны быть запрещены.
Не все функции DOS, однако, быстро возвращают управление — функция чтения символа с клавиатуры может оставаться в таком состоянии довольно длительное время, пока пользователь не нажмет на какую-нибудь клавишу, и все это время флаг занятости DOS будет установлен в 1. В DOS предусмотрена и такая ситуация. Все функции ввода символов с ожиданием вызывают INT 28h в том же цикле, в котором они опрашивают клавиатуру, так что, если установить обработчик прерывания 28h, из него можно вызывать все функции DOS, кроме 01 — 0Ch.