Dos7book
.pdfПриложение А.06: |
Коды ошибок |
Примечание 1: если в спецификации указано, что код ошибки возвращается в регистре AX, то его старший байт – нулевой (AH = 00h).
Примечание 2: при коде ошибки 22h в регистрах ES:DI возвращается указатель на идентификатор носителя, в котором:
со смещения 00h – 12 байтов: метка тома диска с 00h в конце, со смещения 0Ch – 4 байта: серийный номер диска (двоичный).
Примечание 3: драйвер Himem.sys возвращает код ошибки в регистре BL. Примечание 4: коды завершения функций DOS хранятся в области SDA (A.01-3,
смещение 04h). Коды завершения функций BIOS записываются в области данных BIOS (A.01-1, обычно смещение 74h).
A.06-2 Значения класса ошибки, возвращаемые MS-DOS
Приведенная ниже таблица интерпретирует значения класса ошибки, возвращаемые обработчиком прерывания INT 21\AH=59h (8.02-65) в регистре BH, а также записываемые в области текущих данных (SDA, A.01-3) в ячейку со смещением 07h.
Код |
Значение |
01h |
Не хватает ресурсов компьютера |
02h |
Временная ситуация |
03h |
Проблемы прав доступа |
04h |
Внутренние проблемы программного обеспечения |
05h |
Сбои и отказы оборудования |
06h |
Системные ошибки конфигурирования |
07h |
Ошибки прикладных программ |
08h |
Неудачи поиска объектов |
09h |
Несовместимость форматов |
0Ah |
Отказы, вызванные закрытием объектов |
0Bh |
Ошибки, вызванные носителями записи |
0Ch |
Дублирование существующих имен |
0Dh |
Ошибки из-за невыясненных причин. |
A.06-3 Коды предлагаемых действий
Приведенная ниже таблица интерпретирует коды предлагаемых действий, возвращаемые обработчиком прерывания INT 21\AH=59h (8.02-65) в регистре BL, а также записываемые в области текущих данных (SDA, A.01-3) в ячейку со смещением 06h.
– 629 –
Приложение А.06: |
Коды ошибок |
|
Код |
|
Рекомендация |
|
01h |
|
Повторить попытку |
|
02h |
|
Повторить попытку через некоторое время |
|
03h |
|
Предложить пользователю ввести данные повторно |
|
04h |
|
Закрыть файлы, удалить временные файлы, выйти из программы |
|
05h |
|
Выйти из программы немедленно |
|
06h |
|
Игнорировать ошибку |
|
07h |
|
Повторить попытку после вмешательства пользователя |
A.06-4 |
Коды вероятного места возникновения ошибки |
||
Приведенная ниже таблица интерпретирует коды вероятного места возникновения ошибки, возвращаемые обработчиком прерывания INT 21\AH=59h (8.02-65) в регистре CH, а также записываемые в области текущих данных (SDA, A.01-3) в ячейку со смещением 03h.
|
Код |
|
Вероятная локализация |
|
01h |
|
Источник ошибки не определен |
|
02h |
|
Дисковые или ленточные накопители |
|
03h |
|
Локальные сети |
|
04h |
|
Устройства, подключенные к последовательному порту |
|
05h |
|
Память компьютера |
A.06-5 |
Коды статуса ошибок ввода-вывода |
||
Данная таблица интерпретирует коды статуса ошибок, возвращаемые в регистре AH обработчиками прерываний INT 25 и INT 26 (8.02-85).
Код |
Значение |
01h |
Неверная команда |
02h |
Ошибочная адресная метка |
03h |
Диск защищен от записи (только после INT 26) |
04h |
Запрошенный сектор не найден |
08h |
Ошибка DMA (прямого доступа к памяти) |
10h |
Ошибка в данных, выявляемая с помощью кода CRC |
20h |
Отказ контроллера |
40h |
Ошибка при исполнении поиска |
80h |
Устройство не отвечает, время ожидания истекло |
– 630 –
Приложение А.07: Структуры данных для исполнения программ
A.07 Структуры данных для исполнения программ
A.07-1 Префикс сегмента программы
Когда программа загружается для исполнения в выделенный сегмент памяти, ее исполняемый код размещается начиная со смещения 100h и дальше. Предшествующая часть сегмента (смещения 00h – FFh) известна как область PSP (Program Segment Prefix), или префикс сегмента программы. Область PSP заполняется важными служебными данными, которые используются функциями DOS и могут быть использованы самой исполняемой программой.
С помощью отладчика DEBUG.EXE проще всего "подглядеть" ту область PSP, которую для него формирует командный интерпретатор COMMAND.COM. Процедура вывода части этой области PSP на экран показана на рис. 11. Оставшаяся не показанной часть этой области PSP заполнена нулями.
Рис. 11
Роль отлаживаемой программы на рис. 11 играет файл CJPEG.EXE. Параметры "-baseline" и "VC01.BMP" передаются отлаживаемой программе, чтобы показать пример заполнения первого и второго блоков FCB, начинающихся со смещений 5Ch и 6Ch соответственно. Расположение упомянутых и некоторых других полей данных в области PSP пояснено в приведенной ниже таблице.
– 631 –
Приложение А.07: Структуры данных для исполнения программ
Смещение |
Длина |
Содержание |
00h |
2 |
Команда INT 20 (для совместимости с CP/M) |
02h |
2 |
1-й занятый сегмент после сегмента данного PSP |
06h |
2 |
Размер кода в сегменте (для .COM-файлов) |
0Ah |
4 |
Запомненный адрес возврата для INT 22 |
0Eh |
4 |
Запомненный адрес обработчика INT 23 |
12h |
4 |
Запомненный адрес обработчика INT 24 |
16h |
2 |
Сегмент родительского PSP (примечания 1 и 2) |
18h |
20 |
Таблица Job File Table (JFT, примечание 3) |
2Ch |
2 |
Сегмент области окружения данной программы |
2Eh |
4 |
SS:SP перед последним вызовом INT 21 |
32h |
2 |
Число ссылок в таблице JFT (по умолчанию 20) |
34h |
4 |
Указатель на таблицу JFT (обычно PSP:0018h) |
3Ch |
1 |
= 00h (= 01h – для иероглифических клавиатур) |
40h |
2 |
Номер версии DOS для INT 21\AH=30h |
50h |
2 |
Вызова обработчика прерывания INT 21 |
5Ch |
16 |
Первый блок FCB (примечание 4) |
6Ch |
16 |
Второй блок FCB (примечание 4) |
80h |
1 |
Длина командной строки (примечания 5 и 6) |
81h |
127 |
Копия командной строки и область DTA |
Примечание 1: если вместо сегментного адреса родительского PSP в слове со смещением 16h записан собственный сегментный адрес PSP данной программы, то эта программа считается не имеющей "прародителя". Так отмечаются постоянно загруженные программы, например, командный интерпретатор. Эти программы невозможно закрыть вызовом прерывания INT 20 или INT 21\AH=4Ch.
Примечание 2: при защищенном режиме работы компьютера в PSP могут быть внесены дополнительные данные, перезаписывающие некоторые поля PSP, в том числе сегментный адрес родительского PSP в слове со смещением 16h. Поэтому при прослеживании цепи ссылок на родительские PSP необходимо убедиться в том, что адрес действительно указывает на PSP, например, посредством проверки характерных сигнатур: CD20h (INT 20) начиная со смещения 00h или CD21h (INT 21) начиная со смещения 50h.
Примечание 3: в момент запуска программы на исполнение таблица JFT (смещение 18h в PSP) содержит однобайтовые номера блоков описания, входящих в таблицу SFT (A.01-4). Эти номера соответствуют блокам описания тех "открытых" объектов, которые унаследованы от родительского процесса. Номерами 80h – FEh отмечаются блоки описания файлов, доступ к которым осуществляется через сеть.
– 632 –
Приложение А.07: Структуры данных для исполнения программ
Оставшееся свободное пространство JFT заполняется байтами FFh. Начальный размер JFT – 20 байтов – ограничивает число объектов, которые можно держать открытыми одновременно. Это ограничение можно преодолеть путем формирования таблицы JFT большего размера за пределами PSP (8.02-76) и помещения указателя на нее в PSP начиная со смещения 34h. Но надо иметь ввиду, что дочерние процессы все равно не смогут наследовать более 20 открытых объектов.
Примечание 4: поля, начинающиеся со смещений 5Ch и 6Ch, предназначены для неоткрытых блоков FCB (A.09-5). Туда записываются первый и второй параметры командной строки, предварительно подвергнутые
"разбору" с помощью INT 21\AX=2901h (8.02-19), при этом счет параметров включает те, которые "разбору" не подлежат.
Примечание 5: область 81h – FFh заполняется копией командной строки запуска текущей программы. Заполненная часть заканчивается байтом 0Dh. Длина заполненной части записывается в байт со смещением 80h. Если длина равна 7Fh, и в байт со смещением FFh занесено значение 0Dh, то, значит, реальная длина командной строки превосходит 126 байтов, и тогда неурезанную версию командной строки следует искать в переменной окружения CMDLINE.
Примечание 6: область 80h – FFh также по умолчанию используется в качестве DTA (Data Transfer Area) при операциях поиска обработчиками прерываний INT 21\AH=11h,12h,4Eh,4Fh. Если записанная там же копия командной строки должна быть сохранена, то надо сменить адрес DTA с помощью INT 21\AH=1Ah (8.02-16).
A.07-2 Блок параметров загрузки программы
В приведенной ниже таблице показана структура блока параметров, используемого обработчиками прерываний INT 21\AX=4B00h и INT 21\AX=4B01h (8.02-53) при загрузке программы в память с целью ее последующего исполнения.
Смещение |
Длина |
Содержание |
00h |
2 |
Сегмент окружения дочернего процесса |
02h |
4 |
Указатель на командную строку (примечание 2) |
06h |
4 |
Адрес данных для FCB 5Ch (примечание 3) |
0Ah |
4 |
Адрес данных для FCB 6Ch (примечание 3) |
0Eh |
4 |
При возврате: адрес вершины стека SS:SP |
12h |
4 |
При возврате: адрес вызова CS:IP (примечание 4) |
Примечание 1: в сегмент окружения дочернего процесса будет скопировано окружение вызывающего (родительского) процесса. Если дочернему
– 633 –
Приложение А.07: Структуры данных для исполнения программ
процессу должна быть предоставлена не копия, а доступ к окружению вызывающей программы, то в слове со смещением 00h вместо сегментного адреса следует указать значение 0000h.
Примечание 2: здесь следует указать все, что должно быть записано в PSP дочернего процесса, начиная с адреса 80h (примечание 5 к A.07-1). Строка должна начинаться с байта, указывающего ее длину, и кончаться байтом 0Dh.
Примечание 3: эта строка данных будет скопирована в соответствующий блок FCB (примечание 4 к A.07-1) в PSP дочернего процесса. Структура строки показана в колонке "N" таблицы A.09-5, заполнению подлежат первые 12 байт, потом следуют 4 байта 00h. Если данный блок FCB не должен быть заполнен, то за первым байтом 00h должны следовать 11 байтов 20h.
Примечание 4: указатели в ячейках со смещениями 0Eh и 12h относятся только к функции INT 21\AX=4B01h, которая загружает программу, но не инициирует ее исполнение. Чтобы инициировать ее исполнение позже, функция INT 21\AX=4B01h возвращает адрес вызова загруженной программы и указатель на вершину ее стека.
A.07-3 Дескриптор состояния исполнения
Приведенная ниже таблица показывает структуру данных в дескрипторе, используемом при вызове прерывания INT 21\AX=4B05h (8.02-54).
Смещение |
Длина |
Содержание |
00h |
2 |
= 0000h (резервировано) |
02h |
2 |
Флаги: бит 0: исполнять как программу *.EXE |
|
|
бит 1: загружаемый код – это оверлей |
04h |
4 |
Указатель на имя программы с байтом 00h в конце |
08h |
2 |
Сегментный адрес PSP загружаемой программы |
0Ah |
4 |
Адрес вызова загружаемой программы (CS:IP) |
0Eh |
4 |
Размер загружаемой программы, включая ее PSP |
A.07-4 Блок параметров для вызова серверной функции
Поскольку серверная функция INT 21\AX=5D00h (8.02-68) исполняет каждый вызов прерывания INT 21 как отдельный процесс, постольку блок параметров, структура которого показана ниже, задает все исходные состояния регистров для исполнения той функции прерывания INT 21, которую предстоит вызвать. Перед
вызовом этой функции значения из блока параметров будут скопированы в регистры автоматически.
– 634 –
Приложение А.07: Структуры данных для исполнения программ
Смещение |
Длина |
Содержание |
00h |
2 |
Содержимое регистра AX |
02h |
2 |
Содержимое регистра BX |
04h |
2 |
Содержимое регистра CX |
06h |
2 |
Содержимое регистра DX |
08h |
2 |
Содержимое регистра SI |
0Ah |
2 |
Содержимое регистра DI |
0Ch |
2 |
Содержимое регистра DS |
0Eh |
2 |
Содержимое регистра ES |
10h |
2 |
= 0000h (резервировано) |
12h |
2 |
Идентификатор виртуальной машины |
14h |
2 |
Идентификатор процесса, т.е. сегмент его PSP |
Примечание 1: если предполагается исполнять вызываемый процесс в рамках той же действующей системы DOS, то в качестве идентификатора виртуальной машины следует указывать значение 0000h.
Примечание 2: когда показанный здесь блок параметров используется для закрывания процесса с помощью INT 21\AX=5D01h (8.02-69), тогда во внимание принимаются только слова со смещениями 12h и 14h, а все остальное содержание блока игнорируется.
A.07-5 Совместное пользование номером прерывания.
Многие драйверы и резидентные программы при загрузке должны вписывать адрес своего обработчика прерывания в определенную ячейку таблицы прерываний. Однако эта ячейка может быть уже занята адресом загруженного ранее резидентного модуля. Если прежний модуль надо заместить, то встает вопрос о том, как освободить занимаемую им память. Если новый модуль дополняет функции прежнего, то возникает проблема организации их взаимодействия. В обоих случаях необходимо, чтобы резидентный модуль предоставлял данные для организации взаимодействия в "понятной" всем другим модулям форме.
Первым шагом к организации взаимодействия резидентных модулей явился предложенный фирмой IBM протокол ISP (= Interrupt Sharing Protocol),
регламентирующий наличие 16-байтового блока данных с фиксированным расположением относительно адреса вызова каждого резидентного модуля. Протокол ISP обеспечивает формирование прослеживаемой цепи ссылок на все обработчики, использующие один и тот же номер прерывания. Это дает возможность изменять порядок ссылок в цепи и удалять отдельные ссылки, что необходимо для выгрузки резидентных модулей.
– 635 –
Приложение А.07: Структуры данных для исполнения программ
Согласно протоколу ISP адрес вызова, вписываемый в таблицу прерываний, должен указывать на команду ближнего перехода на 16 байт вперед – туда, где начинается исполняемый код резидентного модуля. "Перепрыгиваемый" 16-байтный участок – это место для размещения блока данных. Состав размещаемых там данных показан в приведенной ниже таблице. Все смещения в таблице рассчитаны относительно адреса вызова обработчика прерывания.
Смещение |
Длина |
Содержание |
|
00h |
2 |
Команда перехода (EB 10) к исполняемому коду |
|
02h |
4 |
Адрес следующего обработчика в цепи |
|
06h |
2 |
Сигнатура 4Bh 42h (= "KB") |
|
08h |
1 |
= 00h |
– очередной обработчик в цепи ссылок |
|
|
= 80h |
– первоначальный обработчик прерывания |
09h |
2 |
Адрес подпрограммы выгружения модуля, |
|
|
|
|
оканчивающейся командой возврата RETF |
0Bh |
7 |
Резервировано (должны быть нули) |
|
Примечание 1: далеко не все резидентные модули соответствуют протоколу ISP. Нередко его намеренно игнорируют, чтобы предотвратить прослеживание цепи ссылок или выгружение резидентного модуля.
A.07-6 Команды альтернативного мультиплексного прерывания.
При пользовании мультиплексным прерыванием INT 2F, рассматриваемым в разделе 8.03, несогласованные действия разработчиков могут приводить к назначению одинаковых идентификаторов разным резидентным модулям. Во
избежание вызванных этим конфликтов Ральф Браун предложил назначать идентификаторы не заранее по усмотрению разработчиков, а автоматически в процессе загрузки модулей. Идея Ральфа Брауна реализована альтернативным мультиплексным прерыванием INT 2D и регламентирована спецификацией AMIS (Alternate Multiplex Interrupt Specification). Материал данного раздела основан на спецификации AMIS версии 3.6. Помимо того, каждый резидентный модуль, пользующийся прерыванием INT 2D, должен поддерживать формирование прослеживаемой цепи ссылок согласно протоколу ISP (A.07-5).
Идентификатор для загружаемого модуля предложено искать посредством цикла вызовов мультиплексного прерывания INT 2D с кодом операции AL=00h и с последовательным перебором идентификаторов в регистре AH, начиная с AH=00h. Если какой-либо из загруженных ранее модулей уже считает идентификатор в регистре AH "своим", то он должен установить AL=FFh, возвратить в регистрах CH:CL номер версии, а в регистрах DX:DI – указатель на сигнатуру длиной до 80 байт, оканчивающуюся кодом 00h. Выход из цикла – по условию возврата
– 636 –
Приложение А.07: Структуры данных для исполнения программ
неизмененного значения AL = 00h: значит, на заявленный идентификатор никто не претендует, и загружаемый модуль вправе присвоить его себе.
Аналогичный цикл, только с другим условием окончания, организуют чтобы определить, загружен ли какой-либо конкретный модуль. При таких проверках центральную роль играет сигнатура, указатель на которую возвращается в регистрах DX:DI. Для идентификации модуля должно быть достаточно 16 байт сигнатуры, причем первые 8 байт выделяются названию фирмы или имени разработчика, а последующие 8 байт – названию программы или драйвера, загрузивших данный резидентный модуль. Допускаются сокращенные названия. Если название короче 8 байт, его следует дополнить до 8 байт пробелами (байтами 20h). Часть сигнатуры сверх 16 байт не обязательна, но может содержать полезные сведения. Проверка по сигнатуре помогает предотвратить повторную загрузку резидентных программ. Вместе с выяснением факта загрузки интересующего модуля становится известен присвоенный ему идентификатор, по которому можно запросить другие функции того же модуля.
Поскольку вызовы мультиплексного прерывания предполагают прослеживание цепи ссылок и выполняются медленно, постольку обращаться к специфичным функциям резидентных модулей через прерывание INT 2D нецелесообразно (хотя для этого допускается использовать коды операций свыше 10h). Предпочтителен иной путь – прямое обращение к функциям модулей командой CALL FAR (7.03-08). Чтобы получить адрес прямого обращения, нужно вызвать прерывание INT 2D с идентификатором конкретного загруженного модуля в регистре AH и с кодом операции 01h в регистре AL. Искомый адрес, возвращаемый в регистрах DX:BX, надо запомнить, и тогда им можно будет пользоваться многократно.
Помимо упомянутых операций с кодами AL=00h и AL=01h, спецификация AMIS предусматривает унификацию кодов еще нескольких операций, перечисленных в первом столбце приведенной ниже таблицы. Операции с ненулевыми кодами не обязательны для исполнения. Если в ответ на вызов модуль возвращает в регистре AL код статуса 00h, значит он не поддерживает данную операцию. Напротив, возврат статуса FFh означает, что запрошенная операция поддерживается и успешно выполнена. Отдельные операции допускают возврат иных значений кода статуса, позволяющих судить о состоянии резидентного модуля. Эти и некоторые другие особенности исполнения операций пояснены в примечаниях к таблице.
Код |
Значение |
Примечания |
00h |
Проверка наличия резидентного модуля в памяти |
|
01h |
Запрос адреса обращения к резидентному модулю |
*1 |
02h |
Деинсталляция резидентного модуля |
*2 |
03h |
Вызов резидентной программы на исполнение |
*3 |
– 637 –
Приложение А.07: Структуры данных для исполнения программ
Продолжение таблицы А.07-6 |
|
||
|
04h |
Запрос задействованных прерываний |
*4 |
|
05h |
Запрос списка "горячих" клавишей |
*5 |
|
06h |
Запрос об установленных программой драйверах |
*6 |
Примечание 1: возврат статуса AL = 00h означает, что данный модуль не принимает обращения командой CALL FAR. Адрес в регистрах DX:BX действителен только при возврате статуса AL = FFh.
Примечание 2: при запросе деинсталляции в регистрах DX:BX должен быть указан адрес перехода после деинсталляции, хотя резидентный модуль может игнорировать этот адрес. Возвращаемые в регистре AL коды статуса (помимо 00h и FFh) означают следующее:
01h – неудача попытки деинсталляции;
02h – деинсталляция будет завершена позже;
03h – модуль не имеет деинсталлятора и остался активным; 04h – то же, что 03h, но модуль дезактивирован;
05h – попытку деинсталляции надо повторить позже;
06h – модуль дезактивирован, деинсталляция невозможна; 07h – то же, что 03h, но требуется удаление драйверов.
Возврат кодов статуса 03h, 04h или 07h означает необходимость пользования отдельной программой деинсталляции, причем для нее подлежащий удалению модуль должен возвратить в регистре BX сегментный адрес размещения своего исполняемого кода.
Примечание 3: возвращаемые в регистре AL коды статуса (помимо 00h и FFh) означают следующее:
01h – попытку активизации надо повторить позже;
02h – программа будет активизирована позже;
03h – программа уже активизирована;
04h – сбой при попытке активизации программы.
При коде статуса FFh активизируемая программа возвращает в регистре BX дополнительные сведения о своем состоянии (или просто обнуляет регистр BX). При коде статуса 04h дополнительные сведения возвращаются в регистрах BX и CX; в случае неизвестной причины сбоя эти регистры должны быть обнулены.
Примечание 4: при вызове операции 04h в регистре BL должен быть указан номер прерывания (кроме INT 2D), факт перехвата которого надлежит установить. Возвращаемые в регистре AL коды статуса (помимо 00h) означают следующее:
01h – результат проверки не определен;
02h – указанное прерывание перехвачено;
03h – то же, что 02h, плюс адрес обработчика – в DX:BX; 04h – в DX:BX – адрес списка перехваченных прерываний; FFh – указанное прерывание не перехвачено.
– 638 –
