§ Дискета
Так получилось, что с дискеты раньше пользовались колоссальной популярностью в 1980-х годах. Как вы догадались, сейчас идет 2022 год (11 декабря), и дискеты вообще забыли, даже не знают, как они выглядят. Это — нормально, поэтому надо сделать так, чтобы все что можно, загрузилось с дискеты.Ладно. Это лирическое отступление. А теперь код.
Компиляция кода
g++ boot.c -o boot
, запуск кода boot
. Код создает образ дискеты a.img
, беря за основу бутсектор boot.bin
и добавляет в корень файл demo.bin
.§ Код
#include <stdio.h> #include <stdlib.h> int size = 1440*1024; int clst = 3; int file_id = 0; unsigned char* disk; // Дата и время, при создании четко заданные // Точное время 18:54:30 static const int crt_time = (18 << 11) | (54 << 5) | (30 >> 1); // 10 дек 2022 года static const int crt_date = ((2022 - 1980) << 9) | (12<<5) | 10; // Запись в 2 таблицы FAT void fat_write(int n, int v) { n *= 3; int m = 0x0200 + (n >> 1); int w = disk[m] + 256*disk[m]; if (n & 1) { w = (w & 0x000F) | (v << 4); } else { w = (w & 0xF000) | v; } // FAT-1 disk[m ] = w & 255; disk[m+1] = w >> 8; // FAT-2 disk[0x1200 + m] = disk[m]; disk[0x1201 + m] = disk[m+1]; } // Запись байта void writeb(int offset, int v) { disk[offset ] = v & 255; } // Запись слова void writew(int offset, int v) { disk[offset ] = v & 255; disk[offset+1] = (v >> 8) & 255; } // Создать root запись в корне, cluster-начальный кластер; fsize-размер файла void set_root_entry(const char* name, int id, int cluster, int fsize) { // Найти имя и расширение int i = 0; int n = 0; int ptr = 0x2600 + 32*id; // Подготовка имени for (int j = 0; j < 11; j++) disk[ptr + j] = ' '; // Выстраивание имени и расширения while (name[i] && n < 11) { int ch = name[i]; if (ch >= 'a' && ch <= 'z') ch += ('A'-'a'); if (ch == '.') { n = 8; } else { disk[ptr + n] = ch; n++; } i++; } // Атрибуты файла disk[ptr + 0x0B] = 0x20; // Archived disk[ptr + 0x0C] = 0x00; // NULL // Create Time // 100 * 10ms = 1 сек, время создания файла, уточненное disk[ptr + 0x0D] = 0x64; disk[ptr + 0x0E] = crt_time & 255; disk[ptr + 0x0F] = crt_time >> 8; // Create Date disk[ptr + 0x10] = crt_date & 255; disk[ptr + 0x11] = crt_date >> 8; // Last Access Date disk[ptr + 0x12] = crt_date & 255; disk[ptr + 0x13] = crt_date >> 8; // Старший кластер для FAT32 disk[ptr + 0x14] = 0; disk[ptr + 0x15] = 0; // Last Modified Time disk[ptr + 0x16] = crt_time & 255; disk[ptr + 0x17] = crt_time >> 8; // Last Modified Date disk[ptr + 0x18] = crt_date & 255; disk[ptr + 0x19] = crt_date >> 8; // Номер кластера disk[ptr + 0x1A] = cluster & 255; disk[ptr + 0x1B] = cluster >> 8; // Номер кластера disk[ptr + 0x1C] = fsize & 255; disk[ptr + 0x1D] = (fsize >> 8) & 255; disk[ptr + 0x1E] = (fsize >> 16) & 255; disk[ptr + 0x1F] = (fsize >> 24) & 255; } // Записать весь диск void writedisk() { FILE* fp = fopen("a.img", "wb"); if (fp) { disk[510] = 0x55; disk[511] = 0xAA; fwrite(disk, 1, size, fp); fclose(fp); } } // Добавить файл с fn, имя файла name void add_file(const char* fn, const char* name = NULL) { FILE* fp = fopen(fn, "rb"); if (fp) { // Определить размер файла и прочитать его в диск целиком fseek(fp, 0, SEEK_END); int fsize = ftell(fp); fseek(fp, 0, SEEK_SET); fread(disk + (0x4200 + 512*(clst - 2)), 1, fsize, fp); fclose(fp); // Количество кластеров выделить int reserve = fsize >> 9; if (fsize % 512) reserve++; // Добавление CHAIN for (int i = 0; i < reserve; i++) { // Указатель на последний кластер будет FFFh fat_write(clst + i, reserve == i + 1 ? 0xFFF : clst + i + 1); } // Добавить описание файла set_root_entry(name ? name : fn, file_id, clst, fsize); file_id++; // К следуюшим кластерам clst += reserve; } else { printf("File not found %s\n", fn); exit(1); } } // Запись бут-сектора void update_boot() { FILE* fp = fopen("boot.bin", "rb"); if (fp) { fread(disk, 1, 512, fp); fclose(fp); } else { printf("Can't file file boot.bin\n"); exit(1); } } int main(int argc, char* argv[]) { // Создать диск в памяти и очистить его в 0 disk = (unsigned char*) malloc(size); for (int i = 0; i < size; i++) disk[i] = 0; // Обновление первого сектора update_bpb(); update_boot(); // Записать маркеры fat_write(0, 0xFF0); fat_write(1, 0xFFF); // Пока что только единственный файл add_file("demo.bin"); writedisk(); free(disk); return 0; }
§ Необязательные процедуры
Записать структуру BPB:void update_bpb() { int i; char sig1[] = "mkfs.fat"; char sig2[] = "BOOT BIN"; char sig3[] = "FAT12 "; // JMP $+3C disk[0x00] = 0xEB; disk[0x01] = 0x3D; disk[0x02] = 0x00; // Сигнатура for (i = 0; i < 8; i++) disk[0x03 + i] = sig1[i]; // Лейбл диска for (i = 0; i < 11; i++) disk[0x2B + i] = sig2[i]; // Тип системы for (i = 0; i < 8; i++) disk[0x36 + i] = sig3[i]; writew(0x0B, 0x0200); // Bytes in sector writeb(0x0D, 0x01); // Sectors by cluster writew(0x0E, 0x0001); // Count reserver sectors writeb(0x10, 0x02); // Count of FAT writew(0x11, 0x00E0); // Count of Root Entries (224) writew(0x13, 0x0B40); // Total count of sectors writeb(0x15, 0xF0); // Media writew(0x16, 0x0009); // Sectors in FAT writew(0x18, 0x0012); // Sectors on track writew(0x1A, 0x0002); // Count of heads writew(0x1C, 0x0000); // Hidden Sectors (DD) writew(0x1E, 0x0000); writew(0x20, 0x0000); // Total Sectors writew(0x22, 0x0000); writeb(0x24, 0x00); // Number of Phys. writeb(0x25, 0x01); // Flags writeb(0x26, 0x29); // Ext Sig writew(0x27, 0x0000); // Serial Numbers ES:BX writew(0x29, 0x07E0); }Чтение из FAT
// Чтение значения из FAT int fat_read(int n) { n *= 3; int m = 0x0200 + (n >> 1); int w = disk[m] + 256*disk[m]; return (n & 1 ? (w >> 4) : w) & 0xFFF; }