pang-o-lin/src/mkfat.c

171 lines
5.1 KiB
C

#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include "fat12.h"
#include "fat12-internals.h"
#include "io.h"
#include <stdio.h>
// Create a FAT12 filesystem using the given file descriptor,
// with length _bytes_.
// It will define a root directory size and padding size so that the file sectors
// end up on 4096-byte boundaries.
int fat12_mkfs(struct pang_io *io, uint32_t bytes) {
uint8_t mbr[512];
off_t offset = 0;
const uint32_t sector_size = 512;
uint32_t cluster_size = 4096 / sector_size; // 4 kiB cluster sizes match flash erase block size
if (bytes > 16000000) {
// We run out of clusters just below 16 megabytes. Use bigger cluseters.
cluster_size = 8192 / sector_size;
}
const uint32_t reserved_sectors = 1; // The MBR is the only reserved sector
// XXX What happens if this is an even multiple of sectors?
// Size of FAT (in bytes)
uint32_t fat_size = 1 + ((((bytes * 3) / sector_size) / cluster_size) / 2);
uint32_t fat_size_sectors = ((fat_size - 1) / sector_size) + 1;
uint32_t root_directory_sector_count = cluster_size - (fat_size_sectors + reserved_sectors);
if (!root_directory_sector_count)
root_directory_sector_count = cluster_size;
uint32_t root_directory_entry_count = (sector_size / sizeof(struct fat_directory_entry)) * root_directory_sector_count;
fprintf(stderr, "bytes: %d\n", bytes);
fprintf(stderr, "sector_size: %d\n", sector_size);
fprintf(stderr, "cluster_size: %d\n", cluster_size);
fprintf(stderr, "reserved_sectors: %d\n", reserved_sectors);
fprintf(stderr, "fat_size: %d\n", fat_size);
fprintf(stderr, "fat_size_sectors: %d\n", fat_size_sectors);
fprintf(stderr, "root_directory_sector_count: %d\n", root_directory_sector_count);
fprintf(stderr, "root_directory_entry_count: %d\n", root_directory_entry_count);
fprintf(stderr, "\n");
memset(mbr, 0, sizeof(mbr));
// jmp instruction
mbr[0] = 0xeb;
mbr[1] = 0x3c;
mbr[2] = 0x90;
// OEM name
memcpy(mbr+3, "Fomu MBR", 8);
// Bytes per sector (512)
fat12_write_u16(mbr + 0x0b, sector_size);
// Sectors per cluster (8), so cluster is 512 * 8
fat12_write_u8(mbr + 0x0d, cluster_size);
// Reserved sector count (8 sectors, to pad things to 4096-byte boundaries)
fat12_write_u16(mbr + 0x0e, reserved_sectors);
// Number of FATs (1)
fat12_write_u8(mbr + 0x10, 1);
// Maximum number of root directory entries (16)
fat12_write_u16(mbr + 0x11, root_directory_entry_count);
// Total number of 512-byte sectors
fat12_write_u16(mbr + 0x13, bytes / sector_size);
// Type of media (0xf8 == fixed disk)
fat12_write_u8(mbr + 0x15, 0xf8);
// Sectors per FAT
fat12_write_u16(mbr + 0x16, fat_size_sectors);
// Sectors per track
fat12_write_u16(mbr + 0x18, 32);
// Number of heads
fat12_write_u16(mbr + 0x1a, 64);
// Hidden sectors
// mbr[0x1c] = 0x00;
// mbr[0x1d] = 0x00;
// mbr[0x1e] = 0x00;
// mbr[0x1f] = 0x00;
// Total number of sectors (unused, since we put it in 0x13)
// mbr[0x20] = 0;
// mbr[0x21] = 0;
// mbr[0x22] = 0;
// mbr[0x23] = 0;
// BIOS drive
fat12_write_u8(mbr + 0x24, 0x80);
// Unused
fat12_write_u8(mbr + 0x25, 0);
// Boot signature
fat12_write_u8(mbr + 0x26, 0x29);
// Serial number
fat12_write_u8(mbr + 0x27, 0xf0);
fat12_write_u8(mbr + 0x28, 0xb0);
fat12_write_u8(mbr + 0x29, 0x00);
fat12_write_u8(mbr + 0x2a, 0x07);
// Volume Name
memcpy(mbr + 0x2b, "Fomu ", 11);
// Filesystem
memcpy(mbr + 0x36, "FAT12 ", 8);
// Signature
fat12_write_u8(mbr + 0xfe, 0x55);
fat12_write_u8(mbr + 0xff, 0xaa);
// Write MBR to disk
if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) {
return -1;
}
offset += sector_size;
memset(mbr, 0, sizeof(mbr));
// The first two clusters in the FAT are reserved
fat12_set_cluster(mbr, 0, 0xff8); // 0xff8 instead of 0xfff indicates "Hard Disk"
fat12_set_cluster(mbr, 1, 0xfff); // 0xfff is reserved value
// Root directory is only one cluster
// fat12_set_cluster(mbr, 2, 0xfff);
if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) {
return -1;
}
offset += sector_size;
// Fill in the rest of the FAT
uint32_t fat_sector;
memset(mbr, 0, sizeof(mbr));
for (fat_sector = 1; fat_sector < fat_size_sectors; fat_sector++) {
if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) {
return -1;
}
offset += sector_size;
}
// Fill in the root directory
uint32_t root_directory_sector;
for (root_directory_sector = 0; root_directory_sector < cluster_size; root_directory_sector++) {
if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) {
return -1;
}
offset += sector_size;
}
// Fill in the rest of the disk
while (offset < bytes) {
if (pang_write(io, offset, mbr, sizeof(mbr)) != sizeof(mbr)) {
return -1;
}
offset += sector_size;
}
return 0;
}