ЛАБОРАТОРНАЯ РАБОТА №6
«Исследование главной загрузочной записи жесткого диска»
1.ЦЕЛЬ РАБОТЫ
Изучение структуры главной загрузочной записи жесткого диска. Получение практических навыков работы с главной загрузочной записью жесткого диска с использованием программного интерфейса приложений(API) ОС MS DOS и Windows.
2. ОСНОВНЫЕ ПОЛОЖЕНИЯ
2.1. Структуры для хранения информации о диске
Первый сектор жесткого диска содержит главную загрузочную запись – Master Boot Record (MBR) которая, в свою очередь, содержит загрузочную запись (Boot Record), выполняющуюся в процессе загрузки ОС. За загрузочной записью расположена таблица разделов (Partition Table), содержащая 4 записи – элементы логических разделов (Partitions). Завершается MBR специальной сигнатурой – последовательностью из 2-х байт с шестнадцатеричными значениями 55h и ААh, указывающая на то, что раздел, после которого расположена сигнатура, является последним разделом в таблице. Структура MBR приведена в таблице 1.
Таблица 1 – Структура MBR
Название записи в MBR |
Длина, байт |
Загрузочная запись |
446 |
Элемент таблицы разделов 1 |
16 |
Элемент таблицы разделов 2 |
16 |
Элемент таблицы разделов 3 |
16 |
Элемент таблицы разделов 4 |
16 |
Сигнатура окончания таблицы разделов |
2 |
Каждый элемент таблицы разделов содержит информацию о логическом разделе. Формат элемента таблицы разделов представлен в таблице 2.
Таблица 2 – Формат элемента таблицы разделов
Название записи элемента |
Длина, байт |
Флаг активности раздела |
1 |
Номер головки начала раздела |
1 |
Номер сектора и номер цилиндра загрузочного сектора раздела |
2 |
Кодовый идентификатор операционной системы |
1 |
Номер головки конца раздела |
1 |
Номер сектора и цилиндра последнего сектора раздела |
2 |
Младшее и старшее двухбайтовое слово относительного номера начального сектора |
4 |
Младшее и старшее двухбайтовое слово размера раздела в секторах |
4 |
Первым байтом в элементе раздела идет флаг активности раздела (0 – не активен, 128 (80h) – активен). Он служит для определения, является ли раздел системным загрузочным и указывает необходимость производить загрузку операционной системы с него при запуске компьютера. Активным может быть только один раздел. За флагом активности раздела следует байт номера головки, с которой начинается раздел. За ним следуют два байта, означающие соответственно номер сектора и номер цилиндра загрузочного сектора, где располагается первый сектор загрузчика операционной системы (номер сектора и номер цилиндра занимают 6 и 10 бит соответственно, т.е. биты 0-5 – номер сектора, биты 6-15 – номер цилиндра). Затем следует байт – кодовый идентификатор операционной системы, расположенной в разделе. Некоторые значения кодовых идентификаторов приведены в таблице 3.
Таблица 3 - Коды и типы разделов жесткого диска
Код |
Раздел |
ОС, с которой введен |
Файловая система |
Объем |
01 |
DOS FAT12 |
MS-DOS 2.0 |
FAT12 |
до 16 Мбайт |
04 |
DOS FAT16 |
MS-DOS 3.0 |
FAT16 |
до 32 Мбайт |
05 |
DOS Extended |
MS-DOS 3.3 |
FAT16 |
до 2 Гбайт |
06 |
DOS FAT16 (Big DOS) |
MS-DOS 4.0 |
FAT16 |
до 2 Гбайт |
07 |
OS/2 HPFS, Advanced Unix, Windows NT NTFS |
Windows NT NTFS |
HPFS, NTFS |
512 Мбайт - 2 Тбайт |
0B |
Win95 FAT32 |
Windows 95 OSR2 |
FAT32 |
512 Мбайт - 2 Тбайт |
0С |
Win95 FAT32 (LBA) |
Windows 95 OSR2 |
FAT32 |
512 Мбайт - 2 Тбайт |
0Е |
Win95 FAT16 (LBA) |
Windows 95 OSR2 |
FAT16 |
32 Мбайт - 2 Гбайт |
0F |
Win95 Extended (LBA) |
Windows 95 OSR2 |
FAT32 |
512 Мбайт - 2 Тбайт |
Далее расположен байт номера головки конца раздела, за которым идут два байта – номер сектора и номер цилиндра последнего сектора раздела. Завершают элемент раздела младшее и старшее двухбайтовое слово относительного номера первого сектора раздела и размер раздела в секторах соответственно.
Элемент таблицы разделов может быть описан структурой следующего вида:
struct PART {
byte Boot, // признак активного
// физический адрес начала раздела
Begin_Hd; // # головки
word Begin_SecTrk; // # сектора и дорожки
byte SysCode, // код системы
// физический адрес конца раздела
End_Hd; // # головки
word End_SecTrk; // # сектора и дорожки
dword RelSec, // # начального сектора
Size; // количество секторов в разделе
};
Тогда MBR можно описать структурой вида:
struct MBR
{
char LoadCode[0x1be]; //Загрузочная запись
struct PART rt[4]; // 4 элемента разделов
word EndFlag; // подпись MBR
};
Структуру загрузочной записи логического диска опишем следующим образом:
struct BootRec {
byte jmp[3], ident[8];
word SectSize;//Размер сектора в байтах
byte ClustSize;//Количество секторов в кластере
word ResSect;//Количество секторов в резервной области
byte FatCnt;//Количество копий ФАТ
word RootSize;//Количество элементов корневого каталога
word TotSecs;//Общее количество секторов диска. Если 0,
// то общее количество секторов хранится в LongTotSecs
byte Media;//Тип носителя
word FatSize;//Размер одной копии FAT в секторах
word TrkSecs;//Количество секторов на дорожке
word HeadCnt;//Количество головок
word HidnSecL, HidnSecH;/*Количество скрытых секторов, предшествующих данному разделу*/
dword LongTotSecs;//Общее количество секторов диска. Если 0,
// то общее количество секторов хранится в TotSecs
byte Drive;//Номер диска(0x00 – гибкий диск, 0x80 – жесткий диск)
byte reserved1;//Зарезервировано
byte DOS4_flag;//Флаг (0x29). Показывает, что есть следующие 3 поля
dword VolNum;//Серийный номер диска
char VolLabel[11];//Метка диска
char FatForm[8];//Строка “FAT12 ”, “FAT16 ”, or “FAT ”
};
2.2. Доступ к дискам с использованием функций BIOS
В MS-DOS и Windows 3.1-98 для низкоуровнего доступа к дискам может быть использовано прерывание INT 13h. Это прерывание выполняет множество функций. Для вызова определенной функции необходимо перед вызовом прерывания занести ее код в регистр AH. При этом в другие регистры могут заноситься прочие параметры.
Функций прерывания INT 13h приведены в таблице 4.
Таблица 4 – Функции прерывания 13h
Номер функции |
Описание |
00h |
Сброс дисковой системы |
01h |
Определение состояния дисковой системы |
02h |
Чтение сектора |
03h |
Запись сектора |
04h |
Проверка сектора |
05h |
Форматирование дорожки |
06h |
Форматирование дорожки НМД |
07h |
Форматирование НМД |
08h |
Получить текущие параметры НГМД или НМД |
09h |
Инициализация таблиц параметров НМД |
0Ah |
Чтение длинное (только для НМД) |
0Bh |
Запись длинная (только для НМД) |
0Ch |
Поиск цилиндра (только для НМД) |
0Dh |
Альтернативный сброс НМД |
0Eh |
Чтение буфера сектора (только для НМД) |
0Fh |
Запись буфера сектора (только для НМД) |
10h |
Проверка готовности НМД |
11h |
Рекалибровка НМД |
12h |
Проверка памяти контроллера НМД |
13h |
Проверка НМД |
14h |
Проверка контроллера НМД |
15h |
Получить тип НМД или НГМД |
16h |
Проверка замены диска |
17h |
Установка типа дискеты |
18h |
Установка среды носителя данных для форматирования |
19h |
Парковка головок (только для НМД) |
1Ah |
Форматирование НМД с интерфейсом ESDI |
Чтение сектора
На входе: |
AH |
02h |
|
AL |
Количество секторов, которые нужно прочитать |
|
CH |
Номер дорожки |
|
CL |
Номер сектора |
|
DH |
Номер головки |
|
DL |
Адрес устройства НГМД или НМД (0, 1, …, 80h, 81h, …) |
|
ES:BX |
Адрес буфера для данных |
На выходе: |
AH |
Состояние дисковода после завершения последней операции |
|
CF |
1, если произошла ошибка, 0, если ошибки нет |
Эта функция прерывания 13h позволяет прочитать один или несколько секторов диска в буфер, находящийся в оперативной памяти.
Для НМД номер дорожки и номер сектора задаются следующим образом: биты 5…0 регистра CX задают номер сектора, а биты 15…6 – номер дорожки. Для получения номера дорожки и номера сектора из упакованного формата можно использовать следующие макросы:
#define SECT(x) x&0x3f // Получение из упакованного SecTrk номера сектора
#define TRK(x) (x>>8)|((x<<2)&0x300) /* Получение из упакованного SecTrk номера дорожки*/
Чтение главной загрузочной записи (MBR)
Используя описанные выше структуры для хранения информации о главной загрузочной записи и элементов таблицы разделов, с использованием функции 02h прерывания INT 13h возможно реализовать чтение MBR. Так как MBR занимает 512 байт, т.е. один сектор, и расположена на первом секторе нулевой дорожки нулевой поверхности диска, функция чтения MBR будет иметь следующий вид:
byte head=0; /* номеp головки (0) */
word Sect_Trk=1; /* номеp доpожки и сектоpа (0,1) */
union REGS rr;
struct SREGS sr;
void read_MBR(struct MBR *_mbr)
{ //Чтение MBR с помощью прерывания 13
//Заполняет структуру _mbr данными главной загрузочной записи
rr.h.ah=2; // Чтение
rr.h.al=1; // Секторов 1
rr.h.dl=0x80; // Жесткий диск
rr.h.dh=head; // Головка
rr.x.cx=Sect_Trk; // Дорожка, сектор
sr.es=FP_SEG(_mbr); // Адрес буфера
rr.x.bx=FP_OFF(_mbr);
int86x(0x13,&rr,&rr,&sr);//Вызываем прерывание 13
// Проверка ошибок чтения
if (rr.x.cflag)
{
printf(“Ошибка чтения: %x.”,rr.h.ah);
printf(“Нажмите любую клавишу…\n\7”);
getch();
exit(1);
}
}
В результате выполнения фрагмента кода:
struct MBR mbr;
read_MBR(&mbr);
переменная mbr будет содержать главную загрузочную запись. Для вывода на экран информации о разделах диска необходимо в цикле перебрать элементы таблицы разделов:
word EndList;
int ndrive=0;
for (EndList=(word *)&mbr.rt[(i=0)];/*Указатель на текущий элемент таблицы разделов*/
(*EndList!=0xaa55) //Пока не дошли до сигнатуры АА55
&&(mbr.rt[i].Size>0L);//Или раздела с нулевым размером
EndList=(word *)&mbr.rt[++i])//Переходим к очередному элементу таблицы
{
cout<<”Размер раздела ”<<'C'+ndrive++<<” равен ”<<mbr.rt[i].Size;/*Выводим размер раздела*/
}
Если диск содержит расширенный раздел (т.е. раздел с системным кодом 0fh для FAT32), то необходимо прочитать таблицу его подразделов, расположенную в первом секторе расширенного раздела:
if (mbr.rt[i].SysCode==0xf)
{
/* если код системы 0fh, pаздел содержит свою таблицу
pазделов; определяется ее дисковый адpес,
и новая таблица считывается в память */
head=mbr.rt[i].Begin_Hd;
Sect_Trk=mbr.rt[i].Begin_SecTrk;
goto NEXT; /* Т.е. снова вызов read_MBR() и перебор его элементов, как показано выше*/
}
Такую проверку необходимо выполнять для каждого элемента корневого каталога.