В первой главе мы расскажем о назначении основных файлов, входящих в состав MS-DOS, о структуре и принципах работы этой операционной системы. Мы опишем процесс начальной загрузки MS-DOS.
На дистрибутивных дискетах MS-DOS расположены файлы io.sys, msdos.sys, wina20.386, командный процессор command.com, файлы внешних команд операционной системы (такие, как format.com, fdisk.exe и т. п.), драйверы и другие файлы.
После установки MS-DOS файлы io.sys, msdos.sys, wina20.386 и command.com переписываются в корневой каталог диска C:. Остальные файлы записываются в отдельный каталог, который по умолчанию называется dos (хотя при установке вы можете указать другое имя). Дополнительно в корневом каталоге формируются два текстовых файла с именами config.sys и autoexec.bat.
Для чего предназначены файлы, расположенные в корневом каталоге диска C:?
Файлы io.sys, msdos.sys и command.com являются основными компонентами MS-DOS. Опишем назначение этих и других файлов более подробно.
Файл io.sys содержит расширение базовой системы ввода/вывода BIOS (Basic Input/Output System) и является интерфейсом между операционной системой и BIOS. Расширение используется операционной системой для взаимодействия с аппаратурой компьютера и BIOS.
Для того чтобы максимально уменьшить зависимость программ от особенностей аппаратного обеспечения компьютера используется многоступенчатая схема доступа программ к устройствам ввода/вывода. Согласно этой схеме программа никогда (в идеальном случае) не обращается непосредственно к портам аппаратуры. Вместо этого она взывает программное прерывание с нужным номером и запрашивает ту или иную функцию, загружая соответствующим образом регистры процессора.
Все программные прерывания можно разделить на две группы.
Первая группа - это прерывания базовой системы ввода/вывода BIOS. Обработчик этих прерываний записан в микросхеме постоянного запоминающего устройства (ПЗУ), расположенной на основной плате компьютера (motherboard). Обработчики прерываний BIOS работают с портами ввода/вывода стандартных устройств компьютера и обслуживают соответствующие аппаратные прерывания.
В мире выпускается очень много различных моделей основных плат для компьютеров, совместимых в той или иной степени с IBM PC. Использование BIOS позволяет до некоторой степени стандартизовать программный интерфейс с аппаратурой, так как производитель основной платы может учесть в BIOS все аппаратные особенности.
Вторая группа - прерывания MS-DOS. Обработчики этих прерываний находятся в файлах io.sys и msdos.sys.
Расширение базовой системы ввода/вывода MS-DOS, расположенное в файле io.sys, является как бы прослойкой между операционной системой MS-DOS и BIOS. Для выполнения операций ввода/вывода ядро MS-DOS обращается как к самой базовой системе ввода/вывода BIOS, так и к ее расширению, загружаемому в оперативную память из файла io.sys.
В результате применения такой многоступенчатой схемы была достигнута потрясающая совместимость операционной системы MS-DOS с аппаратурой. MS-DOS способна работать практически на любом компьютере, созданном любой фирмой. Лишь бы этот компьютер был хоть немного совместим с IBM PC.
Файл msdos.sys является в некотором смысле набором программ обработки прерываний, в частности прерывания INT 21h. Это ядро операционной системы.
Программы MS-DOS обращаются к прерыванию INT 21h в тех случаях, когда им нужно получить обслуживание от операционной системы. Например, заказать блок памяти, открыть файл или прочитать его содержимое, и т. д.
Файл command.com - это так называемый командный процессор.
Командный процессор предназначен для организации диалога с пользователем компьютера. Он анализирует введенные команды и организует их выполнение.
Так называемые внутренние команды (dir, copy и т. д.) обрабатываются именно командным процессором. Не ищите в каталоге dos файлы программ с именами dir.exe или copy.com - таких файлов там нет. Внутренние команды потому и называются внутренними, что их обработчик находится в самой операционной системе. Точнее говоря, в файле command.com, который является важнейшей компонентой операционной системы MS-DOS.
Программист может написать свой собственный командный процессор и подключить его вместо стандартного. Новый командный процессор должен выполнять все функции, которые раньше выполняла стандартная программа command.com.
Файл config.sys представляет собой текстовый файл, предназначенный для определения конфигурации MS-DOS, а также для загрузки драйверов и резидентных программ. Он создается автоматически программой установки MS-DOS и затем при необходимости редактируется пользователем. Для редактирования файла можно использовать текстовый редактор edit, который входит в состав MS-DOS.
Для автоматического выполнения часто используемых последовательностей команд MS-DOS можно создать так называемый пакетный файл. Этот текстовый файл с расширением имени .bat в каждой своей строке содержит вызов внутренней или внешней команды MS-DOS, а также специальные операторы.
На этапе установки MS-DOS в корневом каталоге диска C: создается пакетный файл с именем autoexec.bat. Этот файл запускается сразу после загрузки MS-DOS и содержит команды определения среды выполнения программ, а также вызовы инициализирующих и резидентных программ.
Файл с именем wina20.386, который записывается в корневой каталог программой установки MS-DOS, представляет собой виртуальный драйвер для операционной системы Microsoft Windows (о виртуальных драйверах Microsoft Windows вы можете прочитать в 17 томе нашей серии книг "Библиотека системного программиста").
Основное назначение виртуального драйвера wina20.386 - обеспечение совместной работы со старшей областью памяти HMA операционных систем MS-DOS и Microsoft Windows версии 3.0 в расширенном режиме. Так как в настоящее время подавляющее большинство пользователей работают с Microsoft Windows версии 3.1 или с Microsoft Windows for Workgroups, этот файл, скорее всего, не понадобится вам совсем. Вы можете удалить его с диска.
Драйверы представляют собой программы, обслуживающие различную аппаратуру. Кроме этого, в виде драйверов могут быть оформлены различные расширения MS-DOS, такие как система динамического сжатия данных на диске или система управления расширенной памятью.
Обычно драйверы находятся в файлах, имеющих расширение имени .sys, хотя есть и драйверы, встроенные в MS-DOS. Драйвер подключается к операционной системе MS-DOS с помощью оператора device, расположенного в файле config.sys.
Загрузочный файл драйвера имеет специальный формат, который будет подробно описан в нашей книге.
Драйверы легко решают проблемы использования новой аппаратуры - достаточно написать для нового устройства драйвер и подключить его к операционной системе. Прикладные программы и операционная система взаимодействуют с устройствами через драйвер, поэтому в них не нужно вносить изменения при подключении нового устройства.
Например, новое дисковое устройство может иметь другое количество дорожек и секторов, другие управляющие команды. Все это учитывается драйвером и базовой системой ввода/вывода BIOS, а прикладная программа будет работать с новым диском, как и раньше, используя прерывания BIOS и MS-DOS.
Файлы внешних команд операционной системы содержат программы, предназначенные для выполнения разнообразных операций, таких как форматирование дисков, сортировка файлов, печать текстов и других.
Подробное описание внутренних и внешних команд выходит за рамки нашей книги. Основные команды описаны в первом томе нашей серии книг "Персональный компьютер - шаг за шагом". Сведения об остальных командах вы сможете найти в руководстве пользователя MS-DOS. Кроме того, в продаже есть много книг, посвященных командам MS-DOS.
Расскажем немного о программах, предназначенных для подготовки дисков и дискет.
Файлы операционной системы выделяются своим особым расположением на диске (кроме файла command.com) - эти файлы должны находиться в специально отведенном для них месте. Если вам нужно подготовить системную дискету (т. е. такую, с которой можно загружать операционную систему), для переноса файлов операционной системы следует использовать специальные средства. Если вы просто скопируете файлы msdos.sys и io.sys на чистую дискету, она от этого не станет системной.
Самый простой способ подготовки системной дискеты - отформатировать ее при помощи внешней команды format с параметром /s, например:
c:\>format a: /s
В этом случае после форматирования на дискету будут перенесены файлы операционной системы.
Вы можете также перенести системные файлы на дискету командой sys:
c:\>sys c:
Перед тем как вводить эту команду, сделайте текущим корневой каталог диска C:, так как в противном случае программа sys.com не сможет найти файлы io.sys, msdos.sys и command.com (что довольно странно, эти файлы найти достаточно легко).
Программа fdisk предназначена для подготовки жесткого диска к работе. Она разбивает диск на участки, называемые разделами.
На одном физическом диске могут быть разделы, принадлежащие разным операционным системам. Один из разделов всегда активный, так как операционная система загружается только из активного раздела.
Программа fdisk позволяет создать для MS-DOS первичный и вторичный раздел. В первичном разделе располагается системный диск C:, с которого выполняется загрузка операционной системы, вторичный раздел может быть разделен на логические диски (D:, E:, F: и т. д.). Диски, расположенные во вторичном разделе, не могут быть системными.
Заметим, что старые версии MS-DOS (до версии 4.0) позволяли создавать логические диски размером не более 32 Мбайт. Это связано с тем, что эти версии использовали 16-разрядную адресацию секторов диска, что недостаточно для дисков больших размеров.
Иногда вместо программы fdisk для подготовки жесткого диска используются специальные программы, такие как Advanced Disk Manager, Speed Stor и т. д. Используя свои собственные форматы разделов и таблиц разделов (и свои драйверы дисковых устройств), перечисленные выше программы предоставляют такие дополнительные возможности, как защита логического диска от записи или организация парольной защиты данных на диске. При этом для доступа к нестандартному разделу используется специальный драйвер.
Однако не всегда применение специальных программ формирования разделов может привести к желаемому результату. Защита от несанкционированного доступа часто легко преодолевается, мощные системы защиты могут быть сильно привязаны к конкретной версии операционной системы.
Кроме того, драйверы, используемые для доступа к нестандартным разделам диска занимают дефицитное место в оперативной памяти и уменьшают производительность MS-DOS.
Некоторые программы, особенно защищенные от копирования, отказываются работать на диске, подготовленном нестандартными средствами. Причины этого мы объясним в следующем томе, когда будем обсуждать проблемы защиты программ от несанкционированного копирования.
Обычные программы MS-DOS удаляются из оперативной памяти сразу после своего завершения. В отличие от них резидентные программы остаются в памяти и могут быть активизированы при помощи заранее заданной комбинации клавиш, по инициативе другой программы, либо как результат возникновения аппаратного прерывания.
В некоторых случаях резидентные программы выполняют функции драйвера устройства ввода/вывода. Однако чаще они используются, для того чтобы пользователь, работая с какой-либо программой, мог запустить другую, не прерывая работу с текущей программой.
Например, пользователь работает с текстовым процессором. И тут ему потребовалось поискать что-нибудь в справочной базе данных, сделать вычисления на калькуляторе и т. п. Для этого ему достаточно активизировать нужную резидентную программу, нажав соответствующую комбинацию клавиш. После завершения работы с резидентной программой пользователь может вернуться к редактированию текста или другой прерванной работе.
К сожалению, в документации для программиста нет четкого стандарта, регламентирующего поведение резидентных программ. Поэтому неизбежны конфликты между различными резидентными программами, а также несовместимость одних резидентных программ с другими. Ситуация усугубляется необходимостью применения недокументированных прерываний.
В качестве альтернативы пользователь MS-DOS версий от 5.0 и выше может использовать переключатель задач. Однако этот способ имеет свои недостатки.
При включении питания компьютера управление передается базовой системе ввода/вывода BIOS. Она выполняет проверку аппаратуры компьютера, формирует начальную часть таблицы векторов прерываний, инициализирует устройства и начинает процесс загрузки операционной системы.
Загрузка начинается с того, что BIOS делает попытку прочитать самый первый сектор дискеты, вставленной в дисковод А: (на системной дискете этот сектор содержит загрузчик операционной системы). Если в дисковод вставлена системная дискета, с ее самого первого сектора считывается загрузчик. Затем ему передается управление. Если дискета не системная, т. е. не содержит загрузочной записи, на экран выводится сообщение с просьбой заменить дискету.
Если же дискеты в дисководе А: вообще нет, то BIOS читает основную загрузочную запись (Master Boot Record), расположенную в начале диска С:. Обычно это самый первый сектор на диске. Управление передается загрузчику, который находится в этом секторе. Загрузчик анализирует содержимое таблицы разделов (она также находится в первом секторе), выбирает активный раздел и читает загрузочную запись этого раздела. Загрузочная запись активного раздела (Boot Record) аналогична загрузочной записи, расположенной в первом секторе системной дискеты.
Загрузочная запись активного раздела считывает с диска файлы io.sys и msdos.sys (именно в этом порядке). Затем считываются и загружаются драйверы, встроенные в MS-DOS. Анализируется содержимое файла config.sys, загружаются перечисленные в этом файле драйверы. Сначала загружаются драйверы, описанные операторами device, затем - резидентные программы, указанные оператором install. После этого считывается командный процессор command.com и ему передается управление.
Командный процессор состоит из трех частей - резидентной, инициализирующей и транзитной. Первой загружается резидентная часть. Она обрабатывает прерывания INT 22h, INT 23h, INT 24h, управляет загрузкой транзитной части. Эта часть командного процессора обрабатывает ошибки и выдает запрос пользователю о действиях при обнаружении ошибок.
Инициализирующая часть используется только в процессе загрузки операционной системы. Она определяет начальный адрес, по которому будут загружаться запускаемые программы и инициализирует выполнение файла autoexec.bat.
Транзитная часть командного процессора располагается в старших адресах памяти. В этой части находятся обработчики внутренних команд MS-DOS и интерпретатор пакетных файлов (с расширением имени .bat). Транзитная часть выдает системное приглашение (например, А:\>), ожидает ввода команды оператора с клавиатуры или из пакетного файла и организует их выполнение.
После загрузки командного процессора и выполнения начальных процедур, перечисленных в файле autoexec.bat, подготовка системы к работе завершена.
Для того чтобы правильно работать с системным программным и аппаратным обеспечением, вы должны понимать механизм взаимодействия прикладной программы с операционной системой MS-DOS и аппаратурой компьютера.
Как мы уже говорили, в идеальном случае программа MS-DOS обращается к портам аппаратуры компьютера при помощи многоступенчатой схемы, в которую входит базовая система ввода/вывода BIOS, драйверы и программные прерывания MS-DOS (рис. 1.1).
Рис.1.1. Схема взаимодействия программы с MS-DOS, BIOS и аппаратурой компьютера
Из рис. 1.1 видно, что программа MS-DOS может обращаться к ядру MS-DOS (вызывая программные прерывания MS-DOS), к базовой системе ввода/вывода BIOS, а также непосредственно к портам ввода/вывода аппаратуры. Однако программа не может непосредственно вызывать драйверы MS-DOS.
Ядро MS-DOS вызывает драйверы и прерывания BIOS, а также может работать с аппаратурой. В свою очередь, драйверы могут вызывать программные прерывания BIOS и работают с портами ввода/вывода.
Как правило, ядро MS-DOS разделяют на несколько систем, каждая из которых отвечает за выполнение той или иной задачи. Обычно выделяются следующие системы:
Эти системы общаются с аппаратурой через прерывания BIOS, драйверы или напрямую. Прикладное программное обеспечение может вызывать системы MS-DOS, работать с BIOS или непосредственно с аппаратурой. Еще раз обращаем ваше внимание на то, что прикладные программы могут обращаться к драйверам только через соответствующую систему MS-DOS.
Рассмотрим системы MS-DOS отдельно.
Файловая система является одной из важнейших систем MS-DOS. Она используется как во время загрузки операционной системы, так и в процессе ее работы. Сама операционная система записана на системном диске в виде файлов (io.sys, msdos.sys, command.com, драйверы, внешние команды и т. д.). Все прикладные программы и вообще все программы, а также данные для них хранятся на дисках в виде файлов, поэтому можно сказать, что файловая система - ключевая система MS-DOS (злые языки говорят, что кроме файловой системы в MS-DOS больше ничего нет).
Для обращения к файловой системе прикладная программа должна использовать специальные функции программного прерывания MS-DOS. Такие функции выполняют все файловые операции - создание, удаление файлов и каталогов, буферизованная и не буферизованная запись или чтение, получение справочной информации о состоянии файловой системы и другие.
Файловая система работает с дисками через драйверы. Драйверы, в свою очередь, пользуются сервисом BIOS.
На уровне BIOS выполняются элементарные операции с диском, такие как чтение/запись секторов, форматирование и т. п. Этот низкий уровень доступен и прикладной программе, но обычно она пользуется функциями прерывания MS-DOS, выполняющими все необходимые действия по обслуживанию каталогов и таблицы размещения файлов (File Allocation Table - FAT). Программы защиты от несанкционированного доступа или копирования вынуждены обращаться к средствам более низкого уровня, вызывая прерывания BIOS, или даже работать с контроллером диска через порты ввода/вывода.
Используя систему MS-DOS, отвечающую за связь с драйверами, прикладные программы могут выполнять элементарные операции с диском, такие как форматирование, с помощью драйвера диска.
Эта система MS-DOS используется для распределения памяти запускаемым программам.
MS-DOS управляет памятью с помощью блоков MCB (Memory Control Block). Память разбивается на фрагменты. Каждому фрагменту памяти предшествует MCB, в котором записаны характеристики блока памяти. Для каждой вновь запускаемой программы MS-DOS создает определенное количество фрагментов памяти. При освобождении памяти или при выполнении запросов на получение дополнительной памяти MS-DOS проверяет и соответствующим образом изменяет содержимое блоков MCB.
Все блоки MCB располагаются друг за другом. Адрес первого блока хранится в векторной таблице связи CVT, доступ к которой можно получить с помощью недокументированных средств.
Прикладная программа может заказать для себя дополнительные фрагменты памяти. Для этого она обращается к системе управления памятью, используя функции прерывания INT 21h.
При запуске программы операционная система MS-DOS выполняет несколько действий. Сначала она обращается к системе управления памятью, чтобы подготовить блоки памяти для запускаемой программы. С помощью файловой системы файл, содержащий программу, загружается в память, после чего программа (это относится только к файлам типа .exe) настраивается на конкретный физический адрес. Только после этого программе передается управление.
Как известно, в MS-DOS существуют два формата выполняемых программ. Соответствующие файлы имеют расширение имени .com и .exe. Способы запуска этих программ сильно различаются. Система управления программами автоматически распознает их и загружает в память по-разному. Мы еще вернемся к описанию различий между этими типами программ.
Другая задача, решаемая системой управления программами - запуск программ из программ и загрузка оверлеев (дополнительных модулей программы, загружаемых в память с перекрытием). Если не все модули большого программного комплекса нужны одновременно, вы можете разбить комплекс на несколько модулей. Это могут быть либо несколько отдельных программ, либо несколько оверлейных модулей. Каждый из этих способов имеет свои преимущества и недостатки; оба они пригодны для экономии памяти.
И наконец, последняя функция системы управления программами - работа с резидентными программами. Если вам надо, чтобы после завершения своей работы программа осталась резидентной в памяти, вы, как и в случае завершения обычной программы, обращаетесь к системе управления программами через соответствующую функцию прерывания INT 21h.
Эта система скрыта от прикладных программ - программы не могут обращаться непосредственно к драйверам периферийных устройств. Программа вызывает прерывание MS-DOS, а MS-DOS, в свою очередь, обращается при необходимости к драйверам.
Возможно, что запрет на непосредственный вызов драйверов введен для обеспечения совместимости с будущими версиями операционной системы, в которых механизм вызова драйверов может измениться. Однако используя сведения, приведенные в этой книге, вы сможете обойти этот запрет и обратиться непосредственно к драйверу. При этом вам придется использовать некоторые недокументированные прерывания MS-DOS, что само по себе нежелательно из-за возможной потери совместимости с другими версиями операционной системы.
Для управления состоянием устройства ввода/вывода или состоянием драйвера используется специальная функция 44h прерывания INT 21h. Эта функция предназначена для обмена управляющей информацией между прикладной программой и драйвером.
Система обработки ошибок MS-DOS проста и удобна. Для обнаружения ошибок, возникающих при вызове прерываний MS-DOS, как правило, используется флаг переноса процессора. Если после обращения к прерыванию MS-DOS флаг переноса установлен в 1, произошла ошибка. Для того чтобы проанализировать ошибку и предпринять какие-то действия, можно вызвать соответствующую функцию MS-DOS, которая вернет уточняющую информацию об ошибке и предоставит соответствующие рекомендации (разумеется, лишь в виде кодов, находящихся в регистрах процессора).
Если произошла критическая ошибка ввода/вывода (например, невозможно прочитать дискету), вызывается стандартная процедура MS-DOS, которая выводит на экран запрос о дальнейших действиях. Программа может подключить вместо системной свою функцию обработки критических ошибок.
Любой компьютер оборудован системными часами. Это часы с питанием от аккумулятора. Их содержимое не сбрасывается при выключении компьютера.
Дополнительно для формирования временных интервалов используется таймер, постоянно вырабатывающий прерывания. Программа может использовать прерывания таймера для регулярного выполнения каких-либо функций.
Операционная система MS-DOS ведет подсчет времени и хранит текущие показания часов, а также текущую дату. Программа может опросить часы, обратившись к MS-DOS через одну из функций прерывания INT 21h, или установить новое состояние часов.
В составе операционной системы MS-DOS имеется драйвер устройства CLOCK$. Прикладная программа может обратиться к этому устройству для чтения показания часов или для установки часов.
Консоль оператора состоит из двух устройств - клавиатуры и дисплея. Эти два устройства обслуживаются одним драйвером - драйвером консоли CON. Вы можете рассматривать консоль как одно устройство с именем CON.
Операционная система обслуживает консоль с помощью функций прерывания INT 21h, обеспечивающих ввод и вывод символов на устройство CON. Для работы с клавиатурой и видеоконтроллером этот драйвер вызывает прерывания BIOS.
MS-DOS имеет драйверы для работы с параллельными и последовательными портами, которые обеспечивают обмен данными в символьном режиме и управление подключенными к ним устройствами (обычно это принтеры, мышь или факс-модемы).
Кроме того, для печати текста в фоновом режиме в состав MS-DOS входит программа print.com. Эта практически единственная "мультизадачная" программа MS-DOS является примером стандартной резидентной программы. Она позволяет выполнять почти любую работу (такую, например, как редактирование текста или прием файла через модем) параллельно с печатью текста.
Специально следует отметить драйверы электронного диска и кэш-памяти. Драйвер электронного диска называется ramdrive.sys. Этот драйвер организует в расширенной или в дополнительной памяти компьютера быстрый псевдодиск. Можно организовать электронный диск и в основной памяти, но основной памяти всегда мало!
Операционная система MS-DOS версии 6.22 имеет в своем составе систему управления дополнительной и расширенной памятью, которая реализуется драйверами himem.sys и emm386.exe. Эти драйверы позволяет программам, составленным специальным образом, использовать расширенную или дополнительную память для хранения данных и выполнения программ (в некоторых случаях).
С помощью программы memmaker.exe и перечисленных выше драйверов пользователь может в автоматическом режиме освободить первый мегабайт оперативной памяти, переместив драйверы и резидентные программы в расширенную память.
Если подключен драйвер himem.sys, то с помощью драйвера smartdrv.exe можно создать кэш-память (или просто кэш) для жесткого диска. Особенно эффективно применение кэша для работы с базами данных, когда вам периодически требуется одна и та же информация. Если данные были считаны с диска, то в следующий раз, когда они потребуются снова, с большой вероятностью данные будут доступны без повторного обращения к диску.
Такое широко распространенное и ставшее стандартным для любого персонального компьютера устройство, как мышь, не поддерживается операционной системой MS-DOS. Для использования мыши следует подключить драйвер, который обычно поставляется вместе с этим устройством.
Другие периферийные устройства (сканеры, плоттеры, стримеры, факс-модемы и т. п.) также не поддерживаются MS-DOS. Для этих устройств фирмы-изготовители поставляют специальные программы, а также драйверы, которые надо подключить к операционной системе.
Как правило, любая программа работает с тем или иным устройством ввода/вывода. Программы для первых ЭВМ работали непосредственно с портами и регистрами этих устройств. Модули, выполняющие такие стандартные действия, как ввод данных с перфокарт или печать результатов вычислений, входили в состав пользовательских программ.
В начале своего развития микропроцессорные системы имели в своем составе программу, называемую "монитор". Эта программа обычно находилась в постоянном запоминающем устройстве и обслуживала аппаратуру, такую как клавиатура, дисплей, кассетный накопитель на магнитной ленте и т. п. Диалоговая часть монитора позволяла выполнять некоторые операторские функции: загрузку и запуск программы, отладку программы в пошаговом режиме, печать текста, просмотр и редактирование содержимого памяти и т. д.
Но самое главное - прикладные программы, составленные для этих систем, могли пользоваться модулями монитора для работы с периферийной аппаратурой и для решения других задач.
Программа уже не содержала в своем загрузочном модуле все необходимые для работы модули, а пользовалась "стандартными" услугами программы-монитора. Такая организация программы не только уменьшила размер ее загрузочного модуля, но и позволила программистам сосредоточить свои усилия на решении прикладной задачи.
Как программа пользовалась услугами монитора?
Механизм взаимодействия программы пользователя и монитора был реализован в разных системах по-разному. В худшем случае прикладная программа пользовалась известными абсолютными адресами модулей монитора, в лучшем - специальными таблицами адресов программных модулей.
К сожалению, разные системы были несовместимы по составу модулей монитора и механизму их вызова, что сильно затрудняло, если не совершенно исключало их программную совместимость.
В первых персональных компьютерах Apple и IBM PC модули обслуживания стандартной периферии были записаны в постоянном запоминающем устройстве. Совокупность этих модулей (плюс программа начальной инициализации и тестирования) в компьютере IBM PC назвали базовой системой ввода/вывода BIOS.
Выпускаемые различными фирмами компьютеры, совместимые с IBM PC, могут немного отличаться по типу периферийного оборудования, но для достижения совместимости с IBM PC модули BIOS нивелируют эти различия, предоставляя в распоряжение программы пользователя стандартный набор модулей для работы с устройствами ввода/вывода.
Не будет преувеличением сказать, что одна из причин такого невиданного успеха IBM PC на рынке персональных компьютеров - наличие хорошо продуманного стандартного интерфейса модулей BIOS и прикладных программ. Именно благодаря этому интерфейсу достигается почти стопроцентная совместимость по программному обеспечению компьютеров этого типа, выпускаемых разными фирмами.
В этом разделе книги мы расскажем о том, как прикладные программы могут пользоваться модулями BIOS для работы со стандартной периферией, затем приведем краткий обзор основных модулей BIOS.
Напомним вам, что такое программное прерывание.
В начале оперативной памяти персонального компьютера (в пределах первого килобайта) находится так называемая векторная таблица прерываний. Она состоит из 256 ячеек, хранящих адреса программ-обработчиков прерывания. Мы будем подробно изучать эту таблицу, а сейчас вспомним машинную команду INT <n>.
По команде INT <n> содержимое ячейки векторной таблицы прерываний с номером n помещается в адресные регистры процессора, причем в стеке запоминается текущее содержимое адресных регистров. Управление передается по адресу, записанному в ячейке таблицы. Программа-обработчик прерывания должна заканчиваться командой IRET, по которой из стека извлекается старое значение адресных регистров и управление передается обратно в программу, вызвавшую прерывание командой INT <n>.
Вообще говоря, процедура вызова и обработки программного прерывания похожа на процедуру вызова подпрограммы. Отличие заключается в том, что вызывающая программа "не знает" абсолютного адреса модуля обработки прерывания в памяти. Поэтому работа программ не зависит от адресов расположения модулей обработчиков прерывания, а также от адреса загрузки вызывающей программы.
Для вызова модуля BIOS программа использует команду INT <n> с соответствующим номером n. Программа передает параметры модулям BIOS через регистры процессора, результат работы модуля возвращается также в регистрах.
BIOS использует не все возможные номера прерываний. Часть из них предназначена для аппаратных прерываний от периферийных устройств, часть зарезервирована для MS-DOS, часть - для программ пользователя.
Мы приведем краткий обзор прерываний BIOS, предназначенный в основном для иллюстрации основных возможностей BIOS. Поэтому в обзор вошли не все прерывания BIOS, а только самые важные. Остальные прерывания будут изучаться по мере необходимости при изложении соответствующего материала.
Прежде чем пытаться работать с каким-либо периферийным устройством, следует убедиться в том, что оно есть в компьютере. В процессе инициализации тестовые модули, расположенные в BIOS, определяют конфигурацию компьютера и записывают соответствующие значения в специально отведенную для этого ячейку памяти.
Для определения конфигурации компьютера программа может вызвать прерывание INT 11h. При этом она получает в регистре AX содержимое указанной выше ячейки памяти, имеющей размер в одно слово. Каждый бит в слове конфигурации отвечает за соответствующее устройство.
Анализируя слово конфигурации, программа может узнать, подключены ли к компьютеру накопители на гибких магнитных дисках (НГМД) и, если подключены, то сколько их имеется в наличии. Можно определить начальный режим видеоконтроллера, выяснить, присутствует ли арифметический сопроцессор, сколько в системе установлено параллельных и последовательных портов, подключен ли игровой адаптер (джойстик).
Обычно программа не работает сама с аппаратурой, а пользуется услугами операционной системы. При обращении к стандартной аппаратуре через операционную систему программа получит признак ошибки, если соответствующее устройство отсутствует.
Программы, составленные на языках высокого уровня, таких как С или Pascal, могут в случае отсутствия арифметического сопроцессора использовать модули эмуляции. Операции сопроцессора эмулируются центральным процессором и программа просто работает медленнее.
Но если программа обращается непосредственно к портам отсутствующего устройства, это может привести к непредсказуемым последствиям.
Сказанное выше справедливо и по отношению к оперативной памяти. Для работы некоторых программ требуется достаточное количество памяти. Прерывание INT 12h возвращает в регистре AX количество имеющихся блоков памяти размером в один килобайт. Анализируя эту величину, программы могут при недостатке памяти либо вывести на экран соответствующее сообщение и отказаться от работы, либо изменить алгоритмы работы, организовав, например, виртуальную память на диске или просто записывая в файл промежуточные результаты.
Если ваш компьютер оборудован расширенной памятью (адресное пространство расширенной памяти находится выше границы в 1 мегабайт), размер этой памяти в килобайтах можно узнать, вызвав прерывание INT 15h со значением регистра AX, равным 8800h.
Однако будьте осторожны - при использовании драйвера himem.sys операционная система MS-DOS резервирует для себя всю расширенную память. Несмотря на то что объем свободной расширенной оперативной памяти, определенный с помощью прерывания INT 15h, будет при этом равным нулю, программа все же сможет заказать себе блоки в такой памяти. Для этого следует воспользоваться программным интерфейсом драйвера himem.sys.
Прерывание INT 10h выполняет все многочисленные операции по обслуживанию видеоконтроллера.
При вызове прерывания INT 10h, как и при вызове многих других прерываний, регистр AH содержит номер функции, которую требуется выполнить. Остальные регистры содержат дополнительные параметры.
Программирование видеоконтроллера - сложная задача. Функции, выполняемые прерыванием INT 10h слишком обширны даже для простого перечисления. Поэтому мы приведем краткий обзор только некоторых из этих функций.
Эта функция обычно вызывается первой в начале работы с видеоконтроллером или в том случае, когда нужно изменить текущий режим видеоконтроллера.
Что здесь имеется в виду?
Напомним, что видеоконтроллер может работать либо в текстовом, либо в графическом режиме. На самом деле существует много различных текстовых и графических режимов, различающихся размером изображения в пикселах (для графического режима), количеством строк и столбцов (для текстового режима), способом представления цвета и т. д.
В процессе инициализации BIOS задает начальный режим видеоконтроллера исходя из типа последнего. Если программе нужен другой режим, отличный от исходного, она должна использовать функцию 00h. При этом необходимо учитывать, что видеоконтроллеры могут работать не во всех режимах.
С помощью этой функции вы можете установить размер и форму курсора, сделать курсор мигающим или убрать его совсем.
Эта функция позволяет управлять расположением курсора на экране. В частности, один из способов убрать курсор - переместить его за пределы экрана, например, на несуществующую 26 строку.
Программа может узнать в любое время, в каком месте экрана находится курсор. Это может потребоваться ей, например, для того, чтобы переместить курсор в следующую позицию (вправо, вверх, вниз, на 10 символов левее текущего положения и т. д.).
Световое перо используется исключительно редко, однако если оно есть, то функция 04h позволит вам с ним работать.
Компьютер может хранить в видеопамяти не один образ экрана, а несколько. Для этого видеопамять (память для хранения видеоизображения, находится в видеоконтроллере) разбивается на блоки, которые называются страницами. Отображается только активная страница видеопамяти.
Используя механизм страниц, программа может заранее подготовить изображение в неактивной странице, затем сделать подготовленную страницу активной. Изображение новой страницы мгновенно появится на экране.
Некоторые отладчики программ используют одну страницу видеопамяти для отлаживаемой программы, другую - для вывода своих диагностических сообщений.
С помощью этих функций вы сможете переместить вверх или вниз выбранную область экрана на заданное число строк. Освободившееся место будет заполняться пустыми строками. Одно из применений этой функции - полная очистка экрана.
С помощью этих функций можно прочитать из видеопамяти или записать в нее символ и его атрибут. При записи символа можно задать число повторений. Функцию записи с повторением удобно использовать для заполнения области экрана каким-либо символом.
Запись и чтение символа начинается с текущего положения курсора.
Эта функция предназначена для записи символа в видеопамять без определения для него индивидуального значения атрибута. Используется текущий атрибут. Можно задавать кратность записи.
Эта функция позволяет управлять цветом рамки вокруг изображения в текстовом режиме и цветом фона в графическом режиме (для видеоконтроллеров EGA, VGA и SVGA).
С помощью этих функций можно, соответственно, высветить точку нужного цвета в заданном месте экрана для выбранной страницы видеопамяти или определить цвет любой точки на экране (в графических режимах).
После записи символа на экран с помощью этой функции курсор продвигается на следующую позицию, при этом обрабатываются такие управляющие символы, как BEL (звуковой сигнал), возврат на одну позицию, перевод строки, возврат к началу строки.
Если программа изменяет видеорежим, она может предварительно сохранить старый видеорежим, определив его с помощью этой функции, и установить новый. Затем перед завершением своей работы она может восстановить старый режим.
Кроме того, функция возвращает количество столбцов на экране и номер текущей активной страницы видеопамяти.
Эти функции работают только при использовании видеоадаптеров EGA, VGA и SVGA. Они позволяют устанавливать цветовую палитру, загружать знакогенератор (например, шрифтом для русских букв) и выполнять некоторые другие функции.
Для машин класса AT и выше при наличии дисплейных адаптеров EGA, VGA или SVGA эта функция позволяет вывести на экран произвольную строку символов заданной длины, с заданным атрибутом и в заданном месте экрана. Можно также указать номер страницы видеопамяти.
Если вы не можете использовать эту функцию (программа работает на компьютере типа XT или в компьютере установлен видеоконтроллер CGA), единственный способ вывести на экран строку символов с помощью прерывания INT 10h - вызов в цикле функций 09h, 0Ah или 0Eh для вывода строки по одному символу.
Обработчик прерывания INT 16h выполняет несколько функций, связанных с обслуживанием клавиатуры. С помощью функций обслуживания клавиатуры можно выполнить ввод кода нажатой клавиши или ожидание момента, когда пользователь нажмет любую заданную клавишу либо комбинацию клавиш.
Заметим, что коды нажатых клавиш помещаются в специальный буфер клавиатуры. Одна из функций прерывания INT 16h проверяет состояние буфера - есть в нем коды нажатых клавиш или нет. Если буфер не пуст, первый помещенный в буфер код клавиши возвращается программе. Этот код затем может быть считан другой функцией ввода (ввод с ожиданием). Такая функция приостанавливает работу программы до тех пор, пока пользователь не нажмет любую клавишу. Затем она возвращает программе код нажатой клавиши.
Пару описанных выше функций можно также использовать для очистки буфера клавиатуры: сначала программа проверяет, пуст ли буфер. Если он не пуст, считывает код клавиши. Этот код никуда не помещается (теряется). После считывания кода программа опять проверяет содержимое буфера и так до тех пор, пока клавиатурный буфер не окажется пустым.
Для машин класса не ниже AT обработчик прерывания INT 16h выполняет и другие функции: установку задержки, запись символов в буфер клавиатуры, обслуживание расширенной клавиатуры.
Прерывание INT 13h предназначено для обслуживания жестких дисков и НГМД. Многочисленные функции прерывания INT 13h выполняют все операции записи и чтения данных. Мы сделаем обзор только самых важных функций.
Эта функция выполняет установку в исходное состояние всей дисковой системы или выбранного дискового устройства. Используется обычно перед началом работы с устройством.
Эта функция позволяет проверить результат выполнения предыдущей операции. Если операция завершилась неудачно, при помощи этой функции можно определить код ошибки.
С помощью этих функций выполняется чтение секторов диска в оперативную память компьютера или запись информации из памяти в секторы диска.
Перед вызовом функции следует задать номера устройства, дорожки и головки. Программа должна также указать количество читаемых или записываемых секторов.
Функция проверяет содержимое секторов диска с использованием циклической контрольной суммы CRC (Cyclic Redundancy Check).
Среди других функций прерывания INT 13h - форматирование дорожки, позиционирование головки на заданную дорожку диска, тестирование и предварительная установка диска, запуск диагностики контроллера и многое другое.
BIOS содержит простейшую систему обслуживания параллельного порта, состоящую из трех функций прерывания INT 17h. Это функции 01h (инициализация параллельного порта), 02h (опрос состояния параллельного порта) и 00h (вывод байта в параллельный порт).
Поскольку к персональному компьютеру можно подключить несколько параллельных портов, при обращении к принтеру следует указывать номер порта.
Функции прерывания INT 14h обслуживают порт последовательной передачи данных. С помощью этих функций можно задавать формат и скорость передачи данных, определять состояние портов и, конечно, выполнять передачу данных.
Функции прерывания INT 1Ah обслуживают часы, которые есть в каждом компьютере. С помощью этих функций вы можете установить время и дату, опросить текущее состояние часов. Заметим, что часы реального времени имеются на машинах класса не ниже AT.
Пользуясь часами реального времени, можно установить на заданное время "будильник". После этого в нужный момент будет вызвано прерывание "будильника" с номером 4Ah. Обработчик прерывания INT 4Ah может подать звуковой сигнал или вывести на экран предупреждающее сообщение.
Вызов прикладной программой прерывания INT 19h приведет к перезагрузке операционной системы.
Прерывание INT 15h использовалось в компьютерах IBM PC и IBM PC Jr для управления кассетным накопителем на магнитной ленте (функции 0-3). Для машин класса AT и более высокого класса прерывание INT 15h имеет и другое назначение. С его помощью обслуживается расширенная клавиатура, выполняется программная задержка, задаваемая в микросекундах, обслуживается расширенная память.
Кроме того, одна из функций прерывания INT 15h переводит процессор в защищенный режим. Заметим, что вернуть процессор обратно в реальный режим можно только сигналом начального сброса. Это же относится и к арифметическому сопроцессору.
Сигнал начального сброса появляется не только тогда, когда пользователь нажимает кнопку сброса, расположенную на корпусе компьютера. Программа может выдать такой сигнал при помощи контроллера клавиатуры. Подробности вы можете узнать из 6 тома "Библиотеки системного программиста", который называется "Защищенный режим процессоров Intel 80286/80386/80486".
Функция C0h прерывания INT 15h выдает дополнительные сведения о конфигурации аппаратных средств компьютера.
На этом мы завершим описание функций, предоставляемых BIOS, и перейдем к обзору функций MS-DOS.
Операционная система MS-DOS предоставляет программе набор системных вызовов, реализованных с использованием механизма программных прерываний. Эти вызовы открывают прикладной программе доступ к системной информации, к системе консольного ввода/вывода, файловой системе, к системе управления программами и памятью, позволяют организовать обращение к драйверам периферийных устройств компьютера и т. д.
Все основные функции MS-DOS вызываются с помощью прерывания INT 21h, однако MS-DOS использует и другие прерывания:
Прерывание |
Описание |
INT 20h |
Завершение работы программы |
INT 25h |
Чтение диска с абсолютной адресацией
секторов |
INT 26h |
Запись на диск с абсолютной адресацией
секторов |
INT 27h |
Завершение работы программы с
оставлением ее резидентной в памяти |
INT 28h |
Прерывание зарезервировано для MS-DOS,
используется резидентными программами |
INT 2Eh |
Выполнение команды MS-DOS |
INT 2Fh |
Мультиплексное прерывание,
используется для программы печати print и других
резидентных программ; открывает доступ к
внутренним функциям и структурам MS-DOS |
Функции прерывания INT 21h можно разделить на следующие группы:
В данном обзоре мы кратко рассмотрим эти группы, делая акцент в основном на составе функций. Более подробная информация об использовании функций прерывания MS-DOS INT 21h (и других прерываний MS-DOS) будет приводиться в соответствующих разделах книги.
Номер функции задается при вызове прерывания INT 21h в регистре AH.
Функция 30h возвращает в регистре AX номер версии MS-DOS. Например, для версии MS-DOS 5.00 содержимое регистра AH равно 00h, регистра AL - 05h, для версии 6.2, соответственно, 14h и 06h.
Дополнительно через регистр BH функция возвращает программе ОЕМ-код фирмы-производителя операционной системы (IBM - 00, DEC - 16h, 0FFh - Microsoft и т. п.). В регистрах BL:CX после вызова функции должен находится серийный номер дистрибутива операционной системы, однако в существующих версиях MS-DOS серийный номер всегда равен нулю.
Эта информация может применяться для анализа возможности использования таких средств операционной системы, которые поддерживаются не всеми версиями MS-DOS.
Функции 2Ah и 2Ch позволяют программе узнать системную дату и время.
Есть функции, возвращающие текущий диск и текущий каталог. Номера этих функций - 19h и 47h.
Функция 2Fh позволяет программе узнать адрес текущей области DTA (Disk Transfer Area). Эта область используется, например, при поиске файлов в каталоге.
Важная информация находится в блоке PSP (Program Segment Prefix). Этот блок располагается в памяти непосредственно перед выполняющейся программой. В нем находятся, в частности, параметры, передаваемые программе при запуске. Функция 62h возвращает адрес текущего блока PSP.
Кратко перечислим некоторые другие функции, предназначенные для получения системной информации.
Номер функции |
Описание |
35h |
Позволяет получить значение вектора
прерывания с заданным номером |
4Dh |
С помощью этой функции можно узнать код
завершения программы |
59h |
Предназначена для получения
расширенного кода ошибки |
54h |
Позволяет определить, используется ли
проверка при записи на диск |
33h |
Позволяет узнать, может ли пользователь
прервать работу программы при помощи комбинации
клавиш <Ctrl+Break> |
Эти функции применяются для работы со всеми символьными устройствами, такими как консоль, принтер, последовательный порт. Они называются функциями стандартного ввода/вывода.
Ввод и вывод программы, использующей стандартные функции, может быть переназначен, например, в текстовый файл.
Приведем обзор основных функций стандартного символьного ввода/вывод в виде таблицы.
Код |
Назначение |
Описание |
01h |
Ввод с клавиатуры |
Выполняется ввод символа с устройства
стандартного ввода, а также эхо-вывод символа на
стандартное устройство вывода. Пользователь
может прервать работу программы при помощи
комбинации клавиш <Ctrl+C> и <Ctrl+Break> |
06h |
Ввод с клавиатуры без ожидания |
Ввод символа с устройства стандартного
ввода без ожидания, а также вывод его на
устройство стандартного вывода.Комбинации
клавиш <Ctrl+C> и <Ctrl+Break> не проверяются |
07h |
Прямой ввод с клавиатуры |
Ввод символа с клавиатуры.Комбинации
клавиш <Ctrl+C> и <Ctrl+Break> не проверяются |
08h |
Ввод с клавиатуры |
Аналогично функции 07h, но проверяются
комбинации клавиш <Ctrl+C> и <Ctrl+Break> |
02h |
Отобразить символ |
Отображаемый символ посылается на
стандартное устройство вывода |
09h |
Отобразить строку |
На стандартное устройство вывода
символов посылается строка, в конце которой
находится символ "$" |
03h |
Ввод из последовательного порта |
Вводится символ из последовательного
порта |
04h |
Вывод в последовательный порт |
Выводится символ на последовательный
порт |
05h |
Вывод на принтер |
Выводится символ на принтер |
Из таблицы видно, что для ввода с клавиатуры можно использовать несколько функций. Ввод без эхо-вывода удобен для такой информации, как пароли. Если логика работы программы не допускает прерывания со стороны пользователя, нужно использовать функции, которые не проверяют комбинации клавиш <Ctrl+C> и <Ctrl+Break>.
Для вывода строки символов можно использовать функцию 09h, но отображаемая строка не может содержать символ "$", так как этот символ используется в качестве признака конца строки.
MS-DOS предоставляет программам обширный сервис для работы с файлами и дисками. Практически все файловые операции можно выполнять с помощью специально предназначенных для этого функций. Только в некоторых случаях (например, защита данных от копирования) приходится использовать прямое обращение к функциям BIOS или портам контроллера диска.
С помощью файловых функций MS-DOS можно создавать и удалять файлы и каталоги, открывать и закрывать файлы, создавать временные файлы. И ввод, и вывод может быть буферизован. Программа может получить как последовательный доступ к содержимому файла, так и произвольный.
MS-DOS предоставляет программам возможность организовать запуск других программ или загрузку и выполнение программных оверлеев. Для этого служит функция 4Bh.
Для завершения работы программа должна также использовать одну из специальных функций MS-DOS. Функция 4Ch, завершая работу программы, позволяет передать операционной системе некоторое число, называемое кодом завершения программы. Это число может быть затем проанализировано в пакетном файле командой IF ERRORLEVEL. Если одна программа запускает другую, то первая может получить код завершения второй с помощью функции 4Dh.
Для того чтобы завершающаяся программа осталась в оперативной памяти (т. е. стала резидентной), она должна вызвать прерывание INT 27h или воспользоваться функцией 31h.
В нашей книге мы приведем различные примеры запуска программ из программ и научимся составлять резидентные программы.
MS-DOS управляет распределением памяти с помощью блоков управления памятью MCB (Memory Control Block). Вся память разбивается на фрагменты различного размера, которым предшествует блок MCB, содержащий характеристики данного фрагмента (например, такие, как его размер).
Программа может динамически получать и освобождать области памяти с помощью функций 48h и 49h, соответственно. Кроме того, можно изменять размер фрагмента памяти, выделенного операционной системой программе. Это делает функция 4Ah.
Драйвер himem.sys предоставляет программе доступ к расширенной памяти, расположенной в адресном пространстве выше границы первого мегабайта. Так как в реальном или виртуальном режиме процессор не может непосредственно адресовать блоки расширенной памяти, для выполнения такой адресации необходимо пользоваться программным интерфейсом драйвера himem.sys.
Мы уже обращали ваше внимание на то, что программы не могут обращаться непосредственно к драйверам периферийных устройств. Все обращения к драйверам имеют либо неявный характер (ввод/вывод с помощью функций прерывания INT 21h), либо используют специальную функцию MS-DOS с кодом 44h. Эта функция предназначена для обмена управляющей информацией между драйвером и программой.
Существуют функции, позволяющие переопределять прерывания, работать с системными часами и календарем, функции для работы в сети и некоторые другие. Эти функции будут описаны позже в соответствующих разделах книги.
Когда программа обращается к MS-DOS для выполнения какой-либо операции, она должна вызвать соответствующее прерывание, загрузив перед этим все необходимые параметры в регистры процессора. Если выполнение операции невозможно по каким-то причинам (неправильные параметры, устройство неработоспособно, запрашиваемая операция не поддерживается текущей версией MS-DOS и т. д.), то для большинства функций MS-DOS устанавливается признак ошибки - флаг переноса. При этом регистр AX содержит код ошибки.
Перечислим коды ошибок, возвращаемые программе через регистр AX.
Код |
Описание |
01 |
Указан неправильный код функции |
02 |
Файл не найден |
03 |
Путь не найден |
04 |
Слишком много открытых файлов |
05 |
Доступ запрещен |
06 |
Неправильный идентификатор |
07 |
Разрушен блок управления памятью |
08 |
Недостаточно памяти |
09 |
Неправильный адрес блока памяти |
0Ah |
Неправильная среда |
0Bh |
Неправильный формат |
0Ch |
Неправильный доступ |
0Dh |
Неправильные данные |
0Eh |
Зарезервировано |
0Fh |
Ошибка при указании диска |
10h |
Невозможно удалить текущий
каталогтекущий каталог |
11h |
Другое устройство |
12h |
Больше нет файлов |
Для MS-DOS версии 3.0 и более поздних версий обработка ошибок значительно расширена. Введена функция 59h, предназначенная для получения дополнительной информации об ошибках.
При вызове этой функции регистр BX должен содержать индикатор уровня анализа ошибок, который должен быть равен 0. Кроме расширенного кода ошибки, возвращаемого в регистре AX, программа может получить класс ошибки (регистр BH), код предполагаемых действий (регистр BL), локализацию ошибки (регистр CH).
К сожалению, эта функция разрушает содержимое регистров CL, DX, SI, DI, BP, DS, ES. Программа, использующая функцию 59h прерывания INT 21h, должна позаботиться о сохранении содержимого этих регистров.
Расширенный код ошибки, возвращаемый в регистре AX, может принимать значения, указанные ниже. Коды от 1 до 12h эквивалентны кодам, рассмотренным ранее и второй раз не приводятся.
Код |
Описание |
13h |
Выполнена попытка записи на защищенный
от записи диск |
14h |
Указан неизвестный идентификатор
устройства |
15h |
Диск не готов |
16h |
Неизвестная команда |
17h |
Ошибка циклического кода проверки |
18h |
Неправильная длина структуры запроса |
19h |
Ошибка при поиске |
1Ah |
Неизвестен тип среды носителя данных |
1Bh |
Сектор не найден |
1Ch |
Кончилась бумага в принтере |
1Dh |
Ошибка записи |
3Eh |
Ошибка чтения |
1Fh |
Общая ошибка |
20h |
Ошибка при доступе к совместно
используемому файлу |
21h |
Нарушение блокировки файла |
22h |
Неправильный диск |
23h |
FCBFCB недоступен (слишком много блоков FCB) |
24h |
Переполнился буфер, предназначенный для
совместного доступа к файлам |
25h |
Несоответствие кодовых страниц |
26h |
Ошибка при обработке конца файла |
27h |
Переполнение диска |
28h - 31h |
Зарезервировано |
32h |
Сетевая функция не поддерживается |
33h |
Удаленный компьютер не отвечает |
34h |
Дублирование имени в сети |
35h |
Сетевое имя не найдено |
36h |
Сеть занята |
37h |
Сетевое устройство больше не существует
|
38h |
Слишком много команд |
39h |
Ошибка в аппаратуре сетевого адаптера |
3Ah |
Неправильный ответ из сети |
3Bh |
Непредусмотренная ошибка сети |
3Ch |
Несовместимый удаленный адаптер |
3Dh |
Переполнена очередь печати |
3Eh |
Мало места в очереди печати |
3Fh |
Печать отменена |
40h |
Сетевое имя было удалено |
41h |
Доступ к сетевому ресурсу запрещен |
42h |
Неправильный тип сетевого устройства |
43h |
Сетевое имя не найдено |
44h |
Слишком много сетевых имен |
45h |
Слишком много сеансов связи |
46h |
Совместное использование ресурсов в
сети временно отменено |
47h |
Сетевой запрос отвергнут |
48h |
Переадресация приостановлена |
49h - 4Fh |
Зарезервировано |
50h |
Файл уже существует |
51h |
Дублирование блока FCBFCB |
52h |
Невозможно создать дескриптор в
каталоге |
53h |
Ошибка обработчика критических ошибок
INT 24hINT 24h |
54h |
Слишком много переназначений |
55h |
Двойное переназначение |
56h |
Неправильный пароль |
57h |
Неправильный параметр |
58h |
Ошибка при записи данных в сети |
59h |
Нет такой функции в сети |
5Ah |
Не установлен необходимый компонент
системы |
Класс ошибки, передаваемый в регистре BH, содержит информацию, которая поможет вам обработать данную ошибку:
Класс ошибки |
Описание |
1 |
Недостаточно ресурсов: блоков FCBFCB,
памяти и т. д. |
2 |
Временная ситуация, попробуйте
повторить операцию позже |
3 |
Нет прав доступа |
4 |
Внутренняя ошибка MS-DOS |
5 |
Ошибка аппаратуры |
6 |
Системная ошибка MS-DOS |
7 |
Ошибка в прикладной программе |
8 |
Файл или объект не найден |
9 |
Неправильный формат файла или объекта |
10 |
Файл или объект заблокирован |
11 |
Ошибка носителя данных |
12 |
Файл или объект уже существует |
13 |
Прочие ошибки |
Код предполагаемых действий, передаваемый через регистр BL, поможет вашей программе правильно обработать ошибку. Приведем список кодов предполагаемых действий:
Код |
Рекомендуемые действия |
1 |
Повторить операцию позже. Можно
спросить пользователя, желает он повторить
операцию или завершить работу программы |
2 |
Повторить предыдущую операцию после
небольшой паузы. Если ошибка не исчезла, следует
спросить пользователя, будет он ждать и дальше,
или следует завершить работу программы |
3 |
Если пользователь вводил какие-то
данные для MS-DOS, следует попросить его ввести эти
данные еще раз (например, пользователь мог
указать неправильный идентификатор диска или
путь доступа к файлу) |
4 |
Аварийно завершить работу прикладной
программы с выполнением всех обычных
завершающих действий (закрытие файлов, сброс
буферов на диск, освобождение блоков памяти и т.
д.) |
5 |
Немедленный выход из программы без
выполнения завершающих действий. Система
находится в непредсказуемом состоянии |
6 |
Следует игнорировать ошибку |
7 |
Повторить операцию, после того как
пользователь выполнит требуемые действия
(установит дискету и т. п.) |
Сведения о локализации ошибки передаются в регистре CH. Приведем список кодов локализации:
Код |
Место, где произошла ошибка |
1 |
Система не знает, где произошла ошибка |
2 |
В устройстве, выполняющем обмен данными
отдельными блоками (диск или магнитная лента) |
3 |
Ошибка связана с сетью |
4 |
В символьном устройстве, например, в
принтере |
5 |
Ошибка связана с оперативной памятью |
Если ваша программа составлена на языке ассемблера, то после обращения к MS-DOS через прерывание следует проверить состояние флага переноса:
int 21h jc error
MS-DOS имеет еще одно средство для обработки ошибок - обработчик критических ошибок (Critical Error Handler). Этот модуль вызывается MS-DOS, когда она получает сообщение об ошибке от драйвера устройства.
Модуль выдает на экран хорошо известное вам сообщение:
Abort, Retry, Fail?
Это сообщение обычно появляется тогда, когда вы забываете вставить дискету или начинаете печатать при отключенном принтере.
Прикладные программы могут подключать свой модуль обработки критических ошибок вместо стандартного модуля.
А теперь расскажем более подробно о том, как программа может вызывать прерывания MS-DOS.
Программы, составленные на языке С, обращаются к прерываниям MS-DOS обычно с помощью таких функций, как intdos, int86, intdosx и т. д.
Для передачи параметров используются структуры REGS, WORDREGS, BYTEREGS, SREGS, описанных в файле dos.h. Программа записывает параметры в поля структуры, соответствующие регистрам процессора, а затем вызывает одну из перечисленных выше функций, передавая ей адрес структуры. После выполнения прерывания результат записывается в эту же или другую структуру. Например:
union REGS inregs, outregs; struct SREGS segregs; .... inregs.h.ah = 0x3a; segregs.ds = FP_SEG(dir_name); inregs.x.dx = FP_OFF(dir_name); intdosx(&inregs, &outregs, &segregs); ....
В этом фрагменте кода вызывается функция 3Ah прерывания INT 21h, для чего используется функция intdosx, которая входит в стандартную библиотеку системы разработки Borland C++.
Номер функции записывается в поле h.ah объединения inregs, параметры функции (передаваемые через регистры DS:DX), соответственно, в поле ds структуры segregs и в поле x.dx объединения inregs.
Функция intdosx записывает содержимое регистров процессора после выполнения программного прерывания в объединение outregs.
Объединение REGS определено в файле dos.h следующим образом:
union REGS{ struct WORDREGS x; struct BYTEREGS h; };
В нем имеется две структуры - WORDREGS и BYTEREGS.
Первая из этих структур предназначена для работы с 16-разрядными регистрами. Она определена так:
struct WORDREGS{ unsigned int ax, bx, cx, dx, si, di, cflag, flags; };
В этой структуре поля ax, bx, cx, dx, si и di соответствуют одноименным регистрам процессора.
Значение флага переноса записывается в переменную cflag, определенную в структуре WORDREGS. Поле flags предназначено для остальных флагов процессора.
С помощью структуры BYTEREGS вы можете задавать (и определять) содержимое 8-разрядных регистров процессора:
struct BYTEREGS { unsigned char al, ah, bl, bh, cl, ch, dl, dh; };
И, наконец, для работы с сегментными регистрами предназначена структура SREGS, определенная следующим образом:
struct SREGS{ unsigned int es; unsigned int cs; unsigned int ss; unsigned int ds; };
Для использования перечисленных выше структур программа должна содержать следующую строку:
include <dos.h>
После вызова программного прерывания программа должна проверить флаг переноса, который сохраняется в поле cflag. Проверка поля cflag может быть выполнена, например, таким образом:
union REGS inregs, outregs; .... intdos(&inregs, &outregs); if(outregs.x.cflaf != 0) error(); ....
Код ошибки при этом записывается в переменную outregs.x.ax.
Приведем пример программы с именем ERRCODE (листинг 1.1), которая стирает каталог с именем DIR в текущем каталоге и, в случае ошибки, выводит расширенную информацию об ошибке, класс ошибки, код предполагаемых действий и код локализации ошибки.
Листинг 1.1. Файл errcode\errcode.cpp
#include <dos.h> #include <stdio.h> #include <conio.h> union REGS inregs, outregs; struct SREGS segregs; void main(void); void main(void) { char far *dir_name = "DIR"; // Стираем каталог с именем DIR. Для этого вызываем // функцию 0x3A прерывания INT 21h inregs.h.ah = 0x3a; segregs.ds = FP_SEG(dir_name); inregs.x.dx = FP_OFF(dir_name); intdosx(&inregs, &outregs, &segregs); // Если после выполнения прерывания установлен // флаг переноса, выводим сообщение об ошибке if(outregs.x.cflag != 0) { printf("\n\nОшибка при удалении каталога:\t%d", outregs.x.ax); // Получаем расширенную информацию об ошибке // с помощью функции 0x59 прерывания INT 21h inregs.h.ah = 0x59; inregs.x.bx = 0; // Сохраняем регистры в стеке, так как их содержимое // изменится asm push ds asm push es asm push si asm push di // Вызываем прерывание intdosx(&inregs, &outregs, &segregs); // Восстанавливаем содержимое регистров asm pop di asm pop si asm pop es asm pop ds // Выводим расширенную информацию об ошибке printf("\nРасширенный код ошибки: \t%d" "\nКласс ошибки: \t%d" "\nПредполагаемые действия:\t%d" "\nЛокализация ошибки: \t%d", outregs.x.ax, outregs.h.bh, outregs.h.bl, outregs.h.ch); } printf("\n\nНажмите любую клавишу..."); getch(); }
При составлении программ обработки ошибок следует учитывать, что некоторые старые функции MS-DOS возвращают при ошибке в регистре AX значение 0FFh. Начиная с версии MS-DOS 2.0 в случае возникновения ошибки устанавливается флаг переноса. При этом код ошибки записывается в регистр AX. Однако для более полной диагностики причины ошибки следует использовать функцию 59h прерывания INT 21h.
Если ваша программа, составленная на языке С, вызывает программные прерывания MS-DOS неявным образом (через функции стандартной библиотеки транслятора, такие как fprintf, puts и т. д.), то можно воспользоваться средствами обработки ошибок, входящими в состав стандартной библиотеки.
Когда при обращении к прерываниям MS-DOS средствами стандартной библиотеки транслятора С возникает ошибка, то в глобальную переменную с именем errno записывается код ошибки.
Приведем список кодов ошибок в виде символических констант, определенных в файле errno.h.
Код ошибки |
Описание |
EZERO (0) |
Нет ошибки |
EINVFNC (1) |
Неправильный номер функции |
ENOFILE, (2) |
Файл или каталог не найден.Запрошенный
файл или каталог отсутствует, либо не может быть
найден |
ENOPATH (3) |
Путь не найден |
EMFILE (4) |
Слишком много открытых файлов |
EACCES (5) |
Доступ запрещен.Затребованный вид
доступа к файлу запрещен или несовместим с
установленными атрибутами файла (или каталога).
Этот код ошибки передается при попытке чтения из
неоткрытого файла, при попытке записи в файл,
защищенный от записи, или при попытке открыть
каталог как файл |
EBADF (6) |
Плохой идентификатор файла
(handle).Идентификатор файла, использованный при
вызове функции, имеет неверное значение или не
относится к открытому файлу. Возможно, сделана
попытка записи в файл, открытый только для
чтения, или попытка вывода данных на устройство,
открытое только для чтения |
ECONTR (7) |
Указанный блок памяти уничтожен |
ENOMEM (8) |
Слишком мало памяти.Эта ошибка
появляется, когда не хватает памяти для запуска
процесса или для удовлетворения запроса
программы на выделение блока памяти |
EINVMEM (9) |
Неправильный адрес блока памяти |
EINVENV (10) |
Неправильная среда |
EINVFMT (11) |
Неправильный формат |
EINVACC (12) |
Неправильный код доступа |
EINVDAT, (13) |
Неправильные данные |
EINVDRV, (15) |
Ошибка при указании дискового
устройства |
ECURDIR (16) |
Сделана попытка удаления текущего
каталога |
ENOTSAM (17) |
Сделана попытка переместить файл на
другое устройство при помощи функции, которая
может выполнить эту операцию только в пределах
одного устройства |
ENMFILE (18) |
Нет свободных идентификаторов
файлов.Исчерпан запас идентификаторов файлов,
поэтому больше нельзя открыть ни один файл |
EINVAL (19) |
Неправильный параметр.Для одного из
параметров функции было задано неверное
значение |
E2BIG (20) |
Слишком длинный список
параметров.Либо размер списка превышает 128
байт, либо требуемый размер памяти для среды
превышает 32 Кбайт |
ENOEXEC (21) |
Ошибка в формате исполняемого
файла.Сделана попытка выполнить файл, имеющий
неправильный формат |
EXDEV (22) |
Связь различных устройств.Сделана
попытка переслать файл на другое устройство,
используя функцию переименования |
EDOM (33) |
Ошибка в аргументе математической
функции. Аргумент математической функции вышел
за пределы области определения этой функции |
ERANGE (34) |
Слишком большой результат, который
привел к частичной или полной потере значимости |
EEXIST (35) |
Файл уже существует. Сделана попытка
создать файл с именем, которое уже используется
существующим файлом |
EDEADLOCK (36) |
Произошла блокировка ресурсов.
Выполнено 10 неудачных попыток заблокировать
файл |
Из приведенного выше списка кодов ошибок видно, что средствами стандартной библиотеки транслятора обрабатываются не только ошибки, возникающие при обращении к функциям MS-DOS, но и ошибки, появляющиеся при работе с математическим функциями.
Для диагностической выдачи сообщения об ошибке можно использовать функции perror и strerror. Первая функция записывает в поток вывода stderr соответствующее сообщение об ошибке, вторая только формирует строку сообщения.
Функции perror и strerror имеют параметр - указатель на строку. Эта строка добавляется в начало стандартного сообщения об ошибке. Если к стандартному сообщению ничего добавлять не надо, параметр должен иметь значение NULL.
Следует заметить, что значение переменной errno отражает последнюю ошибку. Успешный вызов функции не приводит к автоматическому сбросу переменной errno. Поэтому функции perror и strerror необходимо вызывать сразу после того, как вызываемая функция возвратит признак ошибки.
Приведем пример программы ERRNO (листинг 1.2), обрабатывающей ошибки с использованием переменной errno. При запуске вы должны передать этой программе параметр - имя любого существующего файла.
Листинг 1.2. Файл errno\errno.cpp
#include <stdio.h> #include <conio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #pragma argsused void main(int argc, char *argv[]) { FILE *stream; // Открываем файл только для чтения stream = fopen(argv[1], "r"); // Если произошла ошибка, выводим сообщение if((stream == NULL) || (ferror(stream))) { perror("Не могу открыть файл"); printf("\nНажмите любую клавишу..."); getch(); exit(errno); } // Пытаемся выполнить запись в файл, который // открыт только для чтения. Это приведет к ошибке. fprintf(stream, "Пишем в файл\n"); if((stream == NULL) || (ferror(stream))) { // Выводим сообщение об ошибке двумя способами - // с помощью функции perror и strerror perror("Запись в защищенный файл"); printf("Запись в защищенный файл: %s\n", strerror(errno)); exit(errno); } printf("\nНажмите любую клавишу..."); getch(); exit( 0 ); }
Программа открывает файл при помощи функции fopen, передавая ей в качестве последнего параметра строку "r". В результате файл будет открыт только для чтения.
Если файл не удалось открыть, на консоль с помощью функции perror выводится сообщение об ошибке, вслед за чем работа программы завершается.
Если файл открыт успешно, программа пытается
записать в него текстовую строку, вызывая для
этого функцию fprintf. Так как файл открыть только
для чтения, неизбежно возникнет ошибка. Описание
этой ошибки будет выведено на консоль два раза с
помощью функций perror и printf. В последнем случае
текстовое описание ошибки будет получено при
помощи функции stderror.