Лисья Нора

Оглавление


§ Дискета

Так получилось, что с дискеты раньше пользовались колоссальной популярностью в 1980-х годах. Как вы догадались, сейчас идет 202X год (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;
}