MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 19, М.: Диалог-МИФИ, 1995, 253 стр. 1.3. Характеристики дисковых накопителейПрежде чем начать работу с дисками на физическом уровне, необходимо выяснить конфигурацию дисковой системы - сколько дисководов и какого типа подключено к компьютеру, сколько дорожек и головок имеется на каждом из дисководов и т. д. Способ, которым определяется конфигурация дисковой системы, зависит от модели компьютера (PC, XT, AT), поэтому вначале займемся определением типа персонального компьютера. Определение типа компьютераПЗУ базовой системы ввода/вывода BIOS содержит по
адресу FFFFh:FFFEh байт конфигурации, значение
которого можно использовать для идентификации
типа компьютера:
Для компьютеров IBM PC и IBM PC/XT конфигурация дисковой системы определяется установкой переключателей на основной плате, в частности, переключателями устанавливается количество подключенных к системе НГМД. Компьютеры IBM PC/AT (и более высокого класса) имеют на основной плате CMOS-память с малым энергопотреблением, которая питается от аккумулятора. В CMOS-памяти хранится информация о конфигурации дисковой системы. В процессе инициализации BIOS считывает эту информацию и записывает ее в свою внутреннюю область данных. Проанализировав значение байта конфигурации, можно сделать предварительное заключение о составе дисковой системы компьютера. Если оно равно FFh, FDh, F9h, то наш компьютер не имеет НМД - это одна из разновидностей IBM PC. Значения FEh, FBh могут соответствовать IBM PC/XT и совместимым с ним компьютерам. Такие компьютеры могут быть оборудованы НМД. И, наконец, значение FCh соответствует IBM PC/AT. Для этого компьютера конфигурация дисковой системы должна определяться исходя из содержимого CMOS-памяти. Следует заметить, что новые модели компьютеров могут иметь и другие, не перечисленные выше, коды идентификации. Прерывание INT 11hПрерывание базовой системы ввода/вывода INT 11h возвращает в регистре AX байт конфигурации системы, который можно использовать для определения количества НГМД и наличия НМД. Самый младший бит байта конфигурации (бит 0) - признак наличия в системе НМД. Если этот бит установлен в 1, то компьютер оборудован НМД, иначе дисковая система состоит только из накопителей на гибких магнитных дисках. Биты 7 и 6 содержат информацию о количестве НГМД:
Это прерывание лучше всего использовать для IBM PC/XT и IBM PC. Для IBM PC/AT необходимо исследовать содержимое CMOS-памяти. Займемся этим. Анализ содержимого CMOS-памятиПрограмма не может непосредственно адресовать CMOS-память , как обычную оперативную память. Для работы с CMOS-памятью необходимо использовать порты ввода/вывода с адресами 70h и 71h, причем процедура записи или чтения состоит из двух шагов. На первом шаге операции чтения или записи программа должна записать в порт 70h номер нужной ячейки CMOS-памяти (0...3Fh). На втором шаге программа должна обратиться к порту 71h для выполнения записи в указанную ячейку памяти или чтения из нее. Приведем фрагмент программы, составленной на языке ассемблера, который считывает байт из CMOS-памяти с адресом 12h: mov al,12h out 70h,al ; задаем адрес в CMOS-памяти jmp $+2 ; небольшая задержка in al,71h ; записываем в AL считанное значение Запись в CMOS-память выполняется аналогично. При анализе конфигурации дисковой системы для нас представляют наибольший интерес ячейки CMOS-памяти со следующими адресами:
Биты 7, 6 этого байта имеют такое же значение, что и в младшем байте слова конфигурации, возвращаемого прерыванием INT 11h - они содержат информацию о количестве установленных в компьютере НГМД. Значение бита 0, равное нулю, говорит о том, что в системе нет ни одного НГМД.
Младшая и старшая тетрады этого байта
описывают, соответственно, второй и первый НГМД:
Этот байт разделен на две тетрады аналогично байту, который описывает НГМД. Однако в тетраде можно закодировать только 16 значений, а различных типов НМД значительно больше. Поэтому тип 15 используется специальным образом - если тип НМД в младшей тетраде (диск C:) равен 15, то правильное значение типа находится в CMOS-памяти по адресу 19h. Аналогично для диска D: этот тип можно взять из байта по адресу 1Ah (если содержимое старшей тетрады байта с адресом 12h равно 15). Если в вашем компьютере установлен НМД с интерфейсом ESDI , SCSI или другим специализированным интерфейсом, то, как правило, для работы с ними используется специальная "дисковая" базовая система ввода/вывода. Соответствующая микросхема ПЗУ может быть расположена непосредственно в контроллере. При этом в CMOS-памяти в ячейке 12h для типа диска может быть указано нулевое значение, несмотря на то, что диск установлен. Прерывание INT 11h , тем не менее, скажет вам, что в системе имеется НМД. Если используется "дисковая" базовая система ввода/вывода, то она сама инициализирует таблицу параметров диска (будет описана позже) и выполняет обработку прерывания INT 13h . Так как MS-DOS при обращении к дискам использует именно это прерывание, то не возникает никаких проблем, связанных с отсутствием типа диска в CMOS-памяти. Другие операционные системы, такие как Windows NT и OS/2 , используют для работы с дисками специальные драйверы. Приведем сокращенную таблицу параметров для
стандартных типов НМД (зависит от версии BIOS):
Для всех приведенных в таблице типов дисков на одной дорожке располагается 17 секторов. Стандартный компьютер IBM PC/XT комплектуется обычно НМД с типом 1, тип 2 используется в стандартном компьютере IBM PC/AT. Остальные типы НМД используются главным образом старыми версиями BIOS. Таблицы параметров НМД и НГМДДля работы с диском на физическом уровне необходимо знать такие его характеристики, как количество головок, секторов и др. Эти характеристики можно определить из таблиц параметров НГМД и НМД, заполняемых BIOS в процессе инициализации системы. Анализируя содержимое CMOS-памяти в компьютерах IBM PC/AT или установку переключателей конфигурации на основной плате в компьютерах IBM PC и IBM PC/XT, BIOS в процессе инициализации создает таблицу параметров дискеты DPT (Diskette Parameter Table ), а также одну или две таблицы параметров жесткого диска HDPT (Hard Disk Parameter Table). Если имеется специальная "дисковая" система ввода/вывода, то она сама создает таблицы HDPT. Таблица параметров дискеты DPT имеет длину 10
байт, ее адрес располагается в области данных BIOS
по адресу 0000h:0078h, что соответствует вектору
прерывания INT 1Eh . Таблица содержит следующие
параметры:
Все времена зависят от частоты тактового генератора контроллера НГМД, приведенные значения соответствуют частоте 8 МГц. Адреса таблиц параметров жестких дисков HDPT
расположены по адресам, соответствующим
векторам прерываний INT 41h (для первого
физического диска) и INT 46h (для второго
физического диска). Эти таблицы имеют следующий
формат:
Наиболее полезная информация, которую можно извлечь из таблицы параметров дискеты - это код размера сектора . Если вам когда-либо придется работать с нестандартным размером сектора (отличным от 512 байт), вам не обойтись без этой таблицы. Таблица параметров жесткого диска содержит такие важнейшие значения, как максимальное количество дорожек и максимальное количество головок. Если вам не удалось определить тип диска, то таблица HDPT - единственное надежное место, откуда можно получить информацию о количестве дорожек и головок. Программа DISKINFOДля иллюстрации описанных выше приемов определения конфигурации дисковой системы компьютера приведем исходные тексты программы DISKINFO (листинг 1.1). Она определяет конфигурацию дисковой подсистемы и отображает основные характеристики используемых дисководов. Программа DISKINFO обращается к таблицам параметров НГМД и НМД. В процессе своей работы программа вызывает
функцию disk_cfg, которая заполняет поля структуры
DISK_CONFIG сведениями о конфигурации дисковой
системы:
Листинг 1.1. Файл diskinfo\diskinfo.cpp
#include <stdio.h>
#include <dos.h>
typedef struct _DISK_CONFIG_
{
int n_floppy;
int n_hard;
int t_floppy1;
int t_floppy2;
int t_hard1;
int t_hard2;
} DISK_CONFIG;
typedef struct _DPT _
{
unsigned char srt_hut;
unsigned char dma_hlt;
unsigned char motor_w;
unsigned char sec_size;
unsigned char eot;
unsigned char gap_rw;
unsigned char dtl;
unsigned char gap_f;
unsigned char fill_char;
unsigned char hst;
unsigned char mot_start;
} DPT ;
typedef struct _HDPT _
{
unsigned max_cyl;
unsigned char max_head;
unsigned srwcc;
unsigned swpc;
unsigned char max_ecc;
unsigned char dstopt;
unsigned char st_del;
unsigned char fm_del;
unsigned char chk_del;
char reserve[4];
} HDPT ;
void disk_cfg(DISK_CONFIG* cfg);
DPT far *get_dpt(void);
HDPT far *get_hdp1(void);
HDPT far *get_hdp2(void);
void main(void)
{
DISK_CONFIG cfg;
DPT far *dpt_ptr;
HDPT far *hdpt1_ptr;
HDPT far *hdpt2_ptr;
printf("\n"
"\nКонфигурация дисковой подсистемы"
"\n (C)Фролов А., 1995\n");
// Определяем конфигурацию дисковой подсистемы
disk_cfg(&cfg);
printf("\nУстановлено:"
"\n НГМД: %d"
"\n НМД: %d",
cfg.n_floppy, cfg.n_hard);
printf("\nТип НГМД: A: - %d, B: - %d"
"\nТип НМД: C: - %d, D: - %d",
cfg.t_floppy1, cfg.t_floppy2,
cfg.t_hard1, cfg.t_hard2);
// Получаем адрес таблицы параметров дискеты
dpt_ptr = get_dpt();
printf("\n"
"\nКод размера сектора дискеты: %d"
"\nЗаполняющий символ для форматирования: %2.2X",
dpt_ptr->sec_size, dpt_ptr->fill_char);
// Получаем адреса первой и второй таблицы
// параметров жесткого диска
hdpt1_ptr = get_hdp1();
hdpt2_ptr = get_hdp2();
printf("\n"
"\nПараметры первого НМД:"
"\n Количество дорожек: %d"
"\n Количество головок: %d"
"\n"
"\nПараметры второго диска:"
"\n Количество дорожек: %d"
"\n Количество головок: %d",
hdpt1_ptr->max_cyl, hdpt1_ptr->max_head,
hdpt2_ptr->max_cyl, hdpt2_ptr->max_head);
}
/**
* disk_cfg
*
* Определить конфигурацию дисковой подсистемы
*
* Функция заполняет структуру, описывающую
* конфигурацию дисковой подсистемы:
*
* typedef struct _DISK_CONFIG_
* {
* int n_floppy;
* int n_hard;
* int t_floppy1;
* int t_floppy2;
* int t_hard1;
* int t_hard2;
* } DISK_CONFIG;
*
**/
void disk_cfg(DISK_CONFIG* cfg)
{
char unsigned far *modptr;
char unsigned pc_type;
char cfg_byte;
int cfg_word;
union REGS inregs, outregs;
// Определяем тип компьютера
modptr = (char unsigned far*)MK_FP(0xf000, 0xfffe);
pc_type = *modptr;
// В зависимости от типа компьютера выбираем
// способ определения конфигурации дисковой
// подсистемы
switch (pc_type)
{
case 0xfc:
// Для IBM AT считываем конфигурацию дисковой
// подсистемы из CMOS-памяти
// Считываем байт конфигурации
outp(0x70, 0x14);
cfg_byte = inp(0x71);
// Определяем количество установленных НГМД
if((cfg_byte & 1) == 0)
{
// Если младший бит байта конфигурации равен 0,
// НГМД отсутствуют
cfg->n_floppy = 0;
cfg->t_floppy1 = 0;
cfg->t_floppy2 = 0;
}
else
{
// Определяем количество установленных НГМД
cfg->n_floppy = ((cfg_byte >> 6) & 3) + 1;
// Определяем типы НГМД
outp(0x70, 0x10);
cfg_byte = inp(0x71);
cfg->t_floppy2 = cfg_byte & 0xf;
cfg->t_floppy1 = (cfg_byte >> 4) & 0xf;
}
// Определяем конфигурацию НМД
outp(0x70, 0x12);
cfg_byte = inp(0x71);
if(cfg_byte == 0)
{
// Если обе тетрады равны нулю, система
// не содержит НМД
cfg->n_hard = 0;
cfg->t_hard1 = 0;
cfg->t_hard2 = 0;
}
else
{
// Определяем тип первого диска - диска C:
if((cfg_byte & 0xf) != 0xf)
cfg->t_hard1 = cfg_byte & 0xf;
else
{
outp(0x70, 0x19);
cfg->t_hard1 = inp(0x71);
}
// Определяем тип второго диска - диска D:
if((cfg_byte & 0xf0) != 0xf0)
cfg->t_hard2 = (cfg_byte >> 4) & 0xf;
else
{
outp(0x70, 0x1a);
cfg->t_hard2 = inp(0x71);
}
}
// Вычисляем количество НМД, установленных
// в системе
cfg->n_hard = 0;
if(cfg->t_hard1 != 0) cfg->n_hard++;
if(cfg->t_hard2 != 0) cfg->n_hard++;
// Для некоторых совместимых с IBM AT машин невозможно
// определить тип диска, так как в CMOS-памяти для
// типа диска установлено значение 0, несмотря на то,
// что диск имеется. В таких случаях можно определить
// наличие жесткого диска, используя слово
// конфигурации, возвращаемое прерыванием INT 11h.
if(cfg->n_hard == 0)
{
int86(0x11, &inregs, &outregs);
cfg_word = outregs.x.ax;
// Проверяем, есть ли НМД
if((cfg_word & 1) != 0)
{
cfg->n_hard = 1;
// Считаем, что тип используемого жесткого
// диска неопределен
cfg->t_hard1 = 0;
cfg->t_hard2 = 0;
}
}
break;
default:
// Для остальных типов компьютеров вызываем
// прерывание INT 11h, используем возвращаемый
// этим прерыванием байт конфигурации
int86(0x11, &inregs, &outregs);
cfg_word = outregs.x.ax;
// Определяем количество установленных
// НГМД
cfg->n_floppy = ((cfg_word >> 6) & 3) + 1;
// Считаем, что тип используемого НГМД
// неопределен
cfg->t_floppy1 = 0;
cfg->t_floppy2 = 0;
// Определяем наличие НМД
if((cfg_word & 1) != 0)
{
cfg->n_hard = 1;
// Считаем, что тип используемого НМД
// неопределен
cfg->t_hard1 = 0;
cfg->t_hard2 = 0;
}
break;
}
}
/**
* get_dpt
*
* Вычислить адрес таблицы параметров дискеты
*
* Функция возвращает указатель на таблицу
* параметров дискеты
*
**/
DPT far *get_dpt(void)
{
void far * far *ptr;
ptr = (void far * far *)MK_FP(0x0, 0x78);
return(DPT far*)(*ptr);
}
/**
* get_hdp1
*
* Вычислить адрес первой таблицы параметров диска
*
* Функция возвращает указатель на первую таблицу
* параметров диска
*
**/
HDPT far *get_hdp1(void)
{
void far * far *ptr;
ptr = (void far * far *)MK_FP(0x0, 0x104);
return(HDPT far*)(*ptr);
}
/**
* get_hdp2
*
* Вычислить адрес второй таблицы параметров диска
*
* Функция возвращает указатель на вторую таблицу
* параметров диска
*
**/
HDPT far *get_hdp2(void)
{
void far * far *ptr;
ptr = (void far * far *)MK_FP(0x0, 0x118);
return(HDPT far*)(*ptr);
}
|

