- •1.1. Основные компоненты операционной системы
- •1.2. Процесс загрузки операционной системы
- •1.3. Состав и общая схема работы ms-dos
- •1.4. Обзор прерываний bios
- •1.5. Обзор прерываний ms-dos
- •1.6. Обработка ошибок
- •1.7. Вызов прерываний ms-dos
- •1.8. Программа errcode
- •1.9. Переменная errno
- •1.10. Программа errno
1.7. Вызов прерываний 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.
1.8. Программа errcode
Приведем пример программы с именем 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.