Характеристики дисководов
Прежде чем начать работу с дисками на физическом уровне, необходимо выяснить конфигурацию дисковой подсистемы - сколько дисководов и какого типа подключено к компьютеру, сколько дорожек и головок имеется на каждом из дисководов и т.п. Способ, которым определяется конфигурация дисковой подсистемы, зависит от модели компьютера (PC, XT, AT), поэтому вначале займемся определением типа персонального компьютера.
ПЗУ BIOS BIOSсодержит по адресу FFFF:FFFE
байт, значение которого можно использовать для идентификации типа компьютера:
FF | оригинальный IBM PC |
FE | XT, Portable PC |
FD | PCjr |
FC | AT |
FB | XT с памятью 640 К на материнской плате |
F9 | Convertible PC |
Для компьютеров IBM PC и IBM XT конфигурация дисковой подсистемы определяется установкой переключателей на материнской плате, в частности, переключателями устанавливается количество подключенных к системе НГМД.
Машины IBM AT (и машины более высокого класса) имеют на материнской плате КМОП-память с малым энергопотреблением и питающуюся от аккумулятора (КМОП - это технология изготовления микросхем - КОМПЛЕМЕНТАРНАЯ пара МЕТАЛЛ-ОКИСЕЛ-ПОЛУПРОВОДНИК). В КМОП-памяти хранится информация о конфигурации дисковой подсистемы, при инициализации BIOS считывает эту информацию и записывает ее в свою внутреннюю область данных.
Для определения модели компьютера мы предлагаем следующую функцию:
/** *.Name pc_model * *.Title Определить модель компьютера * *.Descr Функция возвращает байт, идентифицирующий * модель персонального компьютера * *.Params Нет * *.Return Код модели персонального компьютера: * * 0xff - оригинальный PC; * 0xfe - XT, Portable PC; * 0xfd - PCjr; * 0xfc - AT; * 0xfb - XT с памятью 640К; * 0xf9 - Convertible PC. **/
#include <stdio.h> #include <dos.h> #include "sysp.h"
char unsigned pc_model(void) {
char unsigned _far *modptr;
modptr = FP_MAKE(0xf000,0xfffe);
return *modptr; }
Проанализировав значение, возвращаемое этой функцией, можно сделать предварительное заключение о конфигурации дисковой подсистемы компьютера. Если мы получили значения 0xff, 0xfd, 0xf9,
то наш компьютер не имеет НМД - это одна из разновидностей IBM PC. Значения 0xfe, 0xfb могут соответствовать IBM XT и совместимым с ним машинам. Такие машины могут быть оборудованы НМД. И, наконец, значение 0xfc соответствует IBM AT. Для этой машины конфигурация дисковой подсистемы должна определяться исходя из содержимого КМОП-памяти.
Следует заметить, что новые модели компьютеров могут иметь другие, не перечисленные выше, коды идентификации.
Прерывание BIOS INT11h возвращает в регистре AX
байт конфигурации системы, который можно использовать для определения количества НГМД и наличия НМД. Самый младший бит байта конфигурации - бит 0 - содержит признак наличия в системе НМД. Если этот бит установлен в 1, то НМД присутствует в системе, иначе дисковая подсистема состоит только из накопителей на гибких магнитных дисках.
Биты 7 и 6 содержат информацию о количестве флоппи-дисков:
Содержимое битов 7 и 6 | Количество установленных флоппи-дисков |
00 | 1 |
01 | 2 |
10 | 3 |
11 | 4 |
КМОП-память не адресуема непосредственно из программы, как обычная оперативная память. Для работы с ней необходимо использовать команды ввода/вывода в порты с адресами 70h и 71h. Перед началом операции чтения/записи в порт 70h
надо записать адрес для КМОП-памяти (0...3Fh). Затем из порта 71h можно прочитать содержимое требуемой ячейки КМОП-памяти или записать в этот порт байт, который будет записан в КМОП-память.
Приведем фрагмент программы, составленной на языке ассемблера, который считывает байт из КМОП-памяти с адресом 12h:
mov al,12h out 70h,al ; задаем адрес в КМОП-памяти jmp $+2 ; небольшая задержка in al,71h ; записываем в AL считанное значение
Запись в КМОП-память выполняется аналогично.
При анализе конфигурации дисковой подсистемы для нас представляют наибольший интерес ячейки КМОП-памяти со следующими адресами:
14h - байт конфигурации
Биты 7, 6 этого байта имеют такое же значение, что и в младшем байте слова конфигурации, возвращаемого прерыванием BIOS INT 11h - они содержат информацию о количестве установленных дисководов для флоппи-дисков.
Значение бита 0, равное нулю, говорит о том, что система не содержит НГМД.
10h - тип используемых флоппи-дисков
Младшая и старшая тетрады этого байта описывают соответственно второй и первый НГМД:
0000 | дисковод не установлен; |
0001 | дисковод на 360К; |
0010 | дисковод на 1,2М. |
0011 | дисковод на 720К. |
0100 | дисковод на 1.44М. |
Этот байт разделен на две тетрады аналогично байту, описывающему НГМД. Однако в тетраде можно закодировать только 16 различных значений, а типов НМД значительно больше. Поэтому тип 15
используется специальным образом - если тип НМД в младшей тетраде (диск C:) равен 15, то правильное значение типа находится в КМОП-памяти по адресу 19h. Аналогично для диска D: этот тип можно взять из байта по адресу 1Ah (если старшая тетрада байта с адресом 12h равна 15).
Если в вашем компьютере установлены диски с интерфейсом ESDI или SCSI или другим специализированным интерфейсом, то как правило, для работы с ними используется специальный "дисковый" BIOS. При этом в КМОП-памяти в ячейке 12h для типа диска может быть указано нулевое значение, несмотря на то, что диск установлен. Прерывание BIOS INT 11h скажет вам, что в системе имеется НМД.
Если используется "дисковый" BIOS, то он сам инициализирует таблицу параметров диска и выполняет обработку дискового прерывания INT 13h. Так как MS-DOS для работы использует именно это прерывание, то не возникает никаких проблем, связанных с отсутствием типа диска в КМОП-памяти. Другие операционные системы, такие как XENIX и OS/2, могут использовать для работы с диском собственные драйверы. При установке они могут запрашивать информацию о типе установленного диска.
Если ваша машина содержит дисковый BIOS, то не исключено, что у вас будут проблемы при установке операционных систем XENIX и OS/2. В этом случае необходимо убедиться в том, что устанавливаемая операционная система содержит драйверы для работы с вашим типом диска.
Теперь мы готовы к тому, чтобы определить конфигурацию дисковой подсистемы - количество и типы используемых дисководов.
Приведем функцию, которая заполнит структуру типа DISK_CONFIG, описанную в файле sysp.h,
информацией о конфигурации дисковой подсистемы.
Структура DISK_CONFIG содержит поля:
n_floppy | количество установленных в системе НГМД. |
n_hard | количество установленных жестких НМД. |
t_floppy1 | тип первого НГМД. |
t_floppy2 | тип второго НГМД. |
t_hard1 | тип первого НМД. |
t_hard2 | тип второго НМД. |
#include <stdio.h> #include <dos.h> #include "sysp.h"
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 = FP_MAKE(0xf000,0xfffe); pc_type = *modptr;
// В зависимости от типа компьютера выбираем // способ определения конфигурации дисковой // подсистемы
switch (pc_type) {
case 0xfc:
// Для IBM AT считываем конфигурацию дисковой // подсистемы из КМОП-памяти
// Считываем байт конфигурации
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 машин невозможно // определить тип диска, так как в КМОП-памяти для // типа диска установлено значение 0, несмотря на то, // что диск установлен (например машина Bondwell, // модель В-300). В таких случаях можно определить // наличие жесткого диска, используя слово // конфигурации, возвращаемое прерыванием 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;
}
}
Пользуясь приведенной выше функцией мы всегда сможем определить количество дисководов для флоппи-дисков и жестких дисков, но не всегда сможем определить их тип. Это само по себе не страшно, так как для работы с дисками на физическом уровне нам надо знать не столько тип диска, сколько другие его характеристики, такие как количество головок, секторов и др. Эти характеристики можно определить из таблиц параметров для дискет и жестких дисков, заполняемых модулями BIOS процессе инициализации системы.
Приведем сокращенную таблицу параметров для стандартных типов жестких дисков, возвращаемых функцией disk_cfg. Информация, которая содержится в этой таблице, используется BIOS процессе инициализации, когда модули BIOS анализируют содержимое КМОП-памяти.
Тип | Количество цилиндров | Количество головок | Емкость диска в байтах |
1 | 306 | 4 | 10.653.696 |
2 | 615 | 4 | 21.411.840 |
3 | 615 | 6 | 32.117.760 |
4 | 940 | 8 | 65.454.080 |
5 | 940 | 6 | 49.090.560 |
6 | 615 | 4 | 21.411.840 |
7 | 462 | 8 | 32.169.984 |
8 | 733 | 5 | 31.900.160 |
9 | 900 | 15 | 117.504.000 |
10 | 820 | 3 | 21.411.840 |
11 | 855 | 5 | 37.209.600 |
12 | 855 | 7 | 52.093.440 |
13 | 306 | 8 | 21.307.392 |
14 | 733 | 7 | 44.660.224 |
15 | 0 | 0 | 0 |
16 | 612 | 4 | 21.307.392 |
17 | 977 | 5 | 42.519.040 |
18 | 977 | 7 | 59.526.656 |
19 | 1024 | 7 | 62.390.272 |
20 | 733 | 5 | 31.900.160 |
21 | 733 | 7 | 44.660.224 |
22 | 733 | 5 | 31.900.160 |
23 | 306 | 4 | 10.653.696 |
24 | 977 | 5 | 42.519.040 |
25 | 1024 | 9 | 80.216.064 |
26 | 1224 | 7 | 74.575.872 |
27 | 1224 | 11 | 117.190.656 |
28 | 1224 | 15 | 159.805.440 |
29 | 1024 | 8 | 71.303.168 |
30 | 1024 | 11 | 98.041.856 |
31 | 918 | 11 | 87.892.992 |
32 | 925 | 9 | 72.460.800 |
33 | 1024 | 10 | 89.128.960 |
34 | 1024 | 12 | 106.954.752 |
35 | 1024 | 13 | 115.867.648 |
36 | 1024 | 14 | 124.780.544 |
37 | 1024 | 2 | 17.825.792 |
38 | 1024 | 16 | 142.606.336 |
39 | 918 | 15 | 119.854.080 |
40 | 820 | 6 | 42.823.680 |
секторов.
Стандартная машина IBM XT комплектуется обычно НМД с типом 1, тип 2 используется стандартной IBM AT. Остальные типы НМД поддерживаются не всеми версиями BIOS, например, типы 16...23 поддерживаются BIOS только тех версий, которые были изготовлены не позднее 15/11/85.
Наиболее широко распространены флоппи-диски емкостью 360К, 1.2М, 720К, 1.44М. Их параметры приведены в следующей таблице:
Тип | Емкость, Кбайтов | Диаметр, дюймы | Количество секторов на одну дорожку | Количество цилиндров |
1 | 360 | 5 | 9 | 40 |
2 | 1200 | 5 | 15 | 80 |
3 | 720 | 3 | 9 | 40 |
4 | 1440 | 3 | 18 | 80 |
Анализируя содержимое КМОП-памяти в машинах AT или установку переключателей конфигурации на материнской плате в машинах PC и XT, BIOS процессе инициализации создает таблицу параметров дискеты DPT (Diskette Parameter Table), а также одну или две таблицы параметров жесткого диска HDPT (Hard Disk Parameter Table). Если имеется специальный дисковый BIOS, то он сам создает таблицы HDPT.
Таблица параметров дискеты DPT имеет длину 10 байт, ее адрес располагается в области данных BIOS по адресу 0000:0078, что соответствует вектору прерывания INT 1Eh. Таблица содержит параметры, важные для работы дисковода:
(0) 1 | srt_hut | Биты 0...3 - SRT (Step Rate Time) - задержка для переключения головок, лежит в пределах 1-16 мс и задается с интервалом 1 мс (0Fh - 1mc, 0Eh - 2 mc, 0Dh - 3 mc, ...); биты 4...7 - задержка разгрузки головки, лежит в пределах 16-240 мс и задается с интервалом 16 мс (1 - 16 mc, 2 - 32 mc, ..., 0Fh - 240 mc). |
(+1) 1 | dma_hlt | Бит 0 - значение этого бита, равное 1, говорит о том, что используется прямой доступ к памяти (DMA); биты 2...7 - время загрузки головок HLT - интервал между сигналом загрузки головок и началом операции чтение/запись, лежит в пределах 2-254 мс и задается с интервалом 2 мс (1 - 2 mc, 2 - 4 mc, ..., 0FFh - 254 mc). |
(+2) 1 | motor_w | Задержка перед выключением двигателя. |
(+3) 1 | sec_size | Код размера сектора в байтах (0 - 128 байтов, 1 - 256, 2 - 512, 3 - 1024). |
(+4) 1 | eot | Номер последнего сектора на дорожке |
(+5) 1 | gap_rw | Длина межсекторного промежутка для чтения/записи. |
(+6) 1 | dtl | Максимальная длина передаваемых данных, используется когда не задана длина сектора. |
(+7) 1 | gap_f | Длина межсекторного промежутка для операции форматирования. |
(+8) 1 | fill_char | Байт-заполнитель для форматирования (обычно используется F6h). |
(+9) 1 | hst | Время установки головки в миллисекундах. |
(+10) 1 | mot_start | Время запуска двигателя в 1/8 долях секунды. |
Все времена в таблице зависят от частоты тактового генератора контроллера НГМД, приведенные значения соответствуют частоте 8 МГц.
Для удобства работы с таблицей параметров дискеты файл sysp.h содержит определение типа DPT:
#pragma pack(1)
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;
#pragma pack()
Адреса таблиц параметров жестких дисков HDPT
расположены по адресам, соответствующим векторам прерываний INT 41h (для первого физического диска) и INT 46h (для второго физического диска). Эти таблицы имеют следующий формат:
(0) 2 | max_cyl | Максимальное количество цилиндров на диске. |
(+2) 1 | max_head | Максимальное количество магнитных головок. |
(+3) 2 | srwcc | Начальный цилиндр для предварительной записи (Starting reduced-write current cylinder). |
(+5) 2 | swpc | Начальный цилиндр для предварительной компенсации при записи (Starting write precompensation cylinder). |
(+7) 1 | max_ecc | Максимальная длина блока коррекции ошибок ECC (Maximum ECC data burst length). |
(+8) 1 | dstopt | Опции устройства: бит 7 - запрет восстановления; бит 6 - запрет восстановления по блоку коррекции ошибок ECC (Error Correction Code); биты 2-0 - опции устройства. |
(+9) 1 | st_del | Стандартная величина задержки. |
(+10) 1 | fm_del | Величина задержки для форматирования диска. |
(+11) 1 | chk_del | Величина задержки для проверки диска. |
(+12) 4 | reserve | Зарезервировано. |
#pragma pack(1)
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;
#pragma pack()
Наиболее полезная информация, которую можно извлечь из таблицы параметров дискеты - это код размера сектора. Если вам когда-либо понадобится работать с нестандартным размером сектора (512 байтов), вам не обойтись без этой таблицы.
Таблица параметров жесткого диска содержит такие важнейшие значения, как максимальное количество цилиндров и максимальное количество головок. Если вам не удалось определить тип диска, то таблица HDPT - единственное надежное место, откуда можно получить информацию о цилиндрах и головках.
Для удобства использования таблиц параметров дискет и дисков мы подготовили следующие функции:
/** *.Name get_dpt * *.Title Вычислить адрес таблицы параметров дискеты * *.Descr Функция возвращает указатель на таблицу * параметров дискеты * *.Params Нет * *.Return Указатель на таблицу параметров дискеты DPT **/
#include <stdio.h> #include <dos.h> #include "sysp.h"
DPT _far *get_dpt(void) { void _far * _far *ptr;
ptr = (void _far * _far *)FP_MAKE(0x0,0x78); return(*ptr); } /** *.Name get_hdp1 * *.Title Вычислить адрес таблицы параметров диска 1 * *.Descr Функция возвращает указатель на таблицу * параметров диска 1 * *.Params Нет * *.Return Указатель на таблицу параметров диска 1 HDPT **/
#include <stdio.h> #include <dos.h> #include "sysp.h"
HDPT _far *get_hdp1(void) { void _far * _far *ptr;
ptr = (void _far * _far *)FP_MAKE(0x0,0x104); return(*ptr);
} /** *.Name get_hdp2 * *.Title Вычислить адрес таблицы параметров диска 2 * *.Descr Функция возвращает указатель на таблицу * параметров диска 2 * *.Params Нет * *.Return Указатель на таблицу параметров диска 2 HDPT **/
#include <stdio.h> #include <dos.h> #include "sysp.h"
HDPT _far *get_hdp2(void) { void _far * _far *ptr;
ptr = (void _far * _far *)FP_MAKE(0x0,0x118); return(*ptr);
}
В качестве примера приведем программу, которая определяет конфигурацию дисковой подсистемы и отображает основные характеристики используемых дисководов. Программа обращается к таблицам параметров НГМД и НМД:
#include <stdio.h> #include <dos.h> #include "sysp.h"
void main(void); void main(void) {
DISK_CONFIG cfg; DPT _far *dpt_ptr; HDPT _far *hdpt1_ptr; HDPT _far *hdpt2_ptr;
printf("\n" "\nКонфигурация дисковой подсистемы" "\n (C)Фролов А., 1991" "\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);
}