§ Дискета
Так получилось, что с дискеты раньше пользовались колоссальной популярностью в 1980-х годах. Как вы догадались, сейчас идет 2022 год (11 декабря), и дискеты вообще забыли, даже не знают, как они выглядят. Это — нормально, поэтому надо сделать так, чтобы все что можно, загрузилось с дискеты.Ладно. Это лирическое отступление. А теперь код.
Компиляция кода
g++ boot.c -o boot
, запуск кода boot
. Код создает образ дискеты a.img
, беря за основу бутсектор boot.bin
и добавляет в корень файл demo.bin
.§ Код
1#include <stdio.h> 2#include <stdlib.h> 3 4int size = 1440*1024; 5int clst = 3; 6int file_id = 0; 7 8unsigned char* disk; 9 10// Дата и время, при создании четко заданные 11 12// Точное время 18:54:30 13static const int crt_time = (18 << 11) | (54 << 5) | (30 >> 1); 14 15// 10 дек 2022 года 16static const int crt_date = ((2022 - 1980) << 9) | (12<<5) | 10; 17 18// Запись в 2 таблицы FAT 19void fat_write(int n, int v) { 20 21 n *= 3; 22 23 int m = 0x0200 + (n >> 1); 24 int w = disk[m] + 256*disk[m]; 25 26 if (n & 1) { 27 w = (w & 0x000F) | (v << 4); 28 } else { 29 w = (w & 0xF000) | v; 30 } 31 32 // FAT-1 33 disk[m ] = w & 255; 34 disk[m+1] = w >> 8; 35 36 // FAT-2 37 disk[0x1200 + m] = disk[m]; 38 disk[0x1201 + m] = disk[m+1]; 39} 40 41// Запись байта 42void writeb(int offset, int v) { 43 disk[offset ] = v & 255; 44} 45 46// Запись слова 47void writew(int offset, int v) { 48 49 disk[offset ] = v & 255; 50 disk[offset+1] = (v >> 8) & 255; 51} 52 53// Создать root запись в корне, cluster-начальный кластер; fsize-размер файла 54void set_root_entry(const char* name, int id, int cluster, int fsize) { 55 56 // Найти имя и расширение 57 int i = 0; 58 int n = 0; 59 60 int ptr = 0x2600 + 32*id; 61 62 // Подготовка имени 63 for (int j = 0; j < 11; j++) disk[ptr + j] = ' '; 64 65 // Выстраивание имени и расширения 66 while (name[i] && n < 11) { 67 68 int ch = name[i]; 69 if (ch >= 'a' && ch <= 'z') ch += ('A'-'a'); 70 71 if (ch == '.') { 72 n = 8; 73 } else { 74 disk[ptr + n] = ch; 75 n++; 76 } 77 78 i++; 79 } 80 81 // Атрибуты файла 82 disk[ptr + 0x0B] = 0x20; // Archived 83 disk[ptr + 0x0C] = 0x00; // NULL 84 85 // Create Time 86 // 100 * 10ms = 1 сек, время создания файла, уточненное 87 disk[ptr + 0x0D] = 0x64; 88 disk[ptr + 0x0E] = crt_time & 255; 89 disk[ptr + 0x0F] = crt_time >> 8; 90 91 // Create Date 92 disk[ptr + 0x10] = crt_date & 255; 93 disk[ptr + 0x11] = crt_date >> 8; 94 95 // Last Access Date 96 disk[ptr + 0x12] = crt_date & 255; 97 disk[ptr + 0x13] = crt_date >> 8; 98 99 // Старший кластер для FAT32 100 disk[ptr + 0x14] = 0; 101 disk[ptr + 0x15] = 0; 102 103 // Last Modified Time 104 disk[ptr + 0x16] = crt_time & 255; 105 disk[ptr + 0x17] = crt_time >> 8; 106 107 // Last Modified Date 108 disk[ptr + 0x18] = crt_date & 255; 109 disk[ptr + 0x19] = crt_date >> 8; 110 111 // Номер кластера 112 disk[ptr + 0x1A] = cluster & 255; 113 disk[ptr + 0x1B] = cluster >> 8; 114 115 // Номер кластера 116 disk[ptr + 0x1C] = fsize & 255; 117 disk[ptr + 0x1D] = (fsize >> 8) & 255; 118 disk[ptr + 0x1E] = (fsize >> 16) & 255; 119 disk[ptr + 0x1F] = (fsize >> 24) & 255; 120} 121 122// Записать весь диск 123void writedisk() { 124 125 FILE* fp = fopen("a.img", "wb"); 126 if (fp) { 127 128 disk[510] = 0x55; 129 disk[511] = 0xAA; 130 131 fwrite(disk, 1, size, fp); 132 fclose(fp); 133 } 134} 135 136// Добавить файл с fn, имя файла name 137void add_file(const char* fn, const char* name = NULL) { 138 139 FILE* fp = fopen(fn, "rb"); 140 141 if (fp) { 142 143 // Определить размер файла и прочитать его в диск целиком 144 fseek(fp, 0, SEEK_END); 145 int fsize = ftell(fp); 146 fseek(fp, 0, SEEK_SET); 147 fread(disk + (0x4200 + 512*(clst - 2)), 1, fsize, fp); 148 fclose(fp); 149 150 // Количество кластеров выделить 151 int reserve = fsize >> 9; 152 if (fsize % 512) reserve++; 153 154 // Добавление CHAIN 155 for (int i = 0; i < reserve; i++) { 156 157 // Указатель на последний кластер будет FFFh 158 fat_write(clst + i, reserve == i + 1 ? 0xFFF : clst + i + 1); 159 } 160 161 // Добавить описание файла 162 set_root_entry(name ? name : fn, file_id, clst, fsize); 163 file_id++; 164 165 // К следуюшим кластерам 166 clst += reserve; 167 168 } else { 169 170 printf("File not found %s\n", fn); 171 exit(1); 172 } 173} 174 175// Запись бут-сектора 176void update_boot() { 177 178 FILE* fp = fopen("boot.bin", "rb"); 179 if (fp) { 180 181 fread(disk, 1, 512, fp); 182 fclose(fp); 183 184 } else { 185 printf("Can't file file boot.bin\n"); 186 exit(1); 187 } 188} 189 190int main(int argc, char* argv[]) { 191 192 // Создать диск в памяти и очистить его в 0 193 disk = (unsigned char*) malloc(size); 194 for (int i = 0; i < size; i++) disk[i] = 0; 195 196 // Обновление первого сектора update_bpb(); 197 update_boot(); 198 199 // Записать маркеры 200 fat_write(0, 0xFF0); 201 fat_write(1, 0xFFF); 202 203 // Пока что только единственный файл 204 add_file("demo.bin"); 205 206 writedisk(); 207 free(disk); 208 return 0; 209}
§ Необязательные процедуры
Записать структуру BPB:1void update_bpb() { 2 3 int i; 4 char sig1[] = "mkfs.fat"; 5 char sig2[] = "BOOT BIN"; 6 char sig3[] = "FAT12 "; 7 8 // JMP $+3C 9 disk[0x00] = 0xEB; disk[0x01] = 0x3D; disk[0x02] = 0x00; 10 11 // Сигнатура 12 for (i = 0; i < 8; i++) disk[0x03 + i] = sig1[i]; 13 14 // Лейбл диска 15 for (i = 0; i < 11; i++) disk[0x2B + i] = sig2[i]; 16 17 // Тип системы 18 for (i = 0; i < 8; i++) disk[0x36 + i] = sig3[i]; 19 20 writew(0x0B, 0x0200); // Bytes in sector 21 writeb(0x0D, 0x01); // Sectors by cluster 22 writew(0x0E, 0x0001); // Count reserver sectors 23 writeb(0x10, 0x02); // Count of FAT 24 writew(0x11, 0x00E0); // Count of Root Entries (224) 25 writew(0x13, 0x0B40); // Total count of sectors 26 writeb(0x15, 0xF0); // Media 27 writew(0x16, 0x0009); // Sectors in FAT 28 writew(0x18, 0x0012); // Sectors on track 29 writew(0x1A, 0x0002); // Count of heads 30 writew(0x1C, 0x0000); // Hidden Sectors (DD) 31 writew(0x1E, 0x0000); 32 writew(0x20, 0x0000); // Total Sectors 33 writew(0x22, 0x0000); 34 writeb(0x24, 0x00); // Number of Phys. 35 writeb(0x25, 0x01); // Flags 36 writeb(0x26, 0x29); // Ext Sig 37 writew(0x27, 0x0000); // Serial Numbers ES:BX 38 writew(0x29, 0x07E0); 39}Чтение из FAT
1 2// Чтение значения из FAT 3int fat_read(int n) { 4 5 n *= 3; 6 7 int m = 0x0200 + (n >> 1); 8 int w = disk[m] + 256*disk[m]; 9 10 return (n & 1 ? (w >> 4) : w) & 0xFFF; 11}