diff --git a/Makefile b/Makefile index 429b6bb..2ba9a15 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ CFLAGS ?= -Iinclude -all: build build/test-get-set-cluster +all: build build/test-get-set-cluster build/test-mkfs-simple build: mkdir build -build/test-get-set-cluster: - $(CC) $(CFLAGS) tests/get-set-cluster.c src/fat12.c -o build/test-get-set-cluster \ No newline at end of file +build/test-get-set-cluster: tests/get-set-cluster.c src/fat12.c include/fat12.h + $(CC) $(CFLAGS) tests/get-set-cluster.c src/fat12.c -o build/test-get-set-cluster + +build/test-mkfs-simple: tests/mkfs-simple.c src/fat12.c include/fat12.h src/mkfat.c src/io.c + $(CC) $(CFLAGS) tests/mkfs-simple.c src/mkfat.c src/fat12.c src/io.c -o $@ \ No newline at end of file diff --git a/include/fat12.h b/include/fat12.h index 76c1548..4ca9527 100644 --- a/include/fat12.h +++ b/include/fat12.h @@ -3,6 +3,8 @@ #include +void fat12_write_u8(void *ptr, uint8_t val); +uint8_t fat12_read_u8(void *ptr); void fat12_write_u16(void *ptr, uint16_t val); uint16_t fat12_read_u16(void *ptr); void fat12_set_cluster(void *fat, uint32_t cluster, uint32_t value); @@ -11,4 +13,20 @@ uint32_t fat12_get_cluster(void *fat, uint32_t cluster); int fat12_defrag(int fd); int fat12_mkfs(int fd, uint32_t bytes); +struct fat_directory_entry { + uint8_t file_name[8]; + uint8_t extension[3]; + uint8_t file_attributes; + uint8_t reserved1; + uint8_t ctime_ms; + uint8_t ctime_hms[2]; + uint8_t ctime_date[2]; + uint8_t atime_date[2]; + uint8_t ea_index[2]; + uint8_t mtime_hms[2]; + uint8_t mtime_date[2]; + uint8_t first_cluster[2]; + uint8_t file_size[4]; +}; + #endif /* PANG_O_LIN_FAT12_H__ */ \ No newline at end of file diff --git a/src/fat12.c b/src/fat12.c index 98b0de8..6ee9bcb 100644 --- a/src/fat12.c +++ b/src/fat12.c @@ -1,5 +1,16 @@ #include "fat12.h" + +void fat12_write_u8(void *ptr, uint8_t val) { + ((uint8_t *)ptr)[0] = (val >> 0) & 0xff; +} + +uint8_t fat12_read_u8(void *ptr) { + uint16_t val = 0; + val |= (((uint8_t *)ptr)[0] << 0) & 0xff; + return val; +} + void fat12_write_u16(void *ptr, uint16_t val) { ((uint8_t *)ptr)[0] = (val >> 0) & 0xff; ((uint8_t *)ptr)[1] = (val >> 8) & 0xff; diff --git a/src/mkfat.c b/src/mkfat.c index 1c07a33..3605620 100644 --- a/src/mkfat.c +++ b/src/mkfat.c @@ -2,31 +2,40 @@ #include #include +#include "fat12.h" #include "io.h" -struct directory_entry { - uint8_t file_name[8]; - uint8_t extension[3]; - uint8_t file_attributes; - uint8_t reserved1; - uint8_t ctime_ms; - uint8_t ctime_hms[2]; - uint8_t ctime_date[2]; - uint8_t atime_date[2]; - uint8_t ea_index[2]; - uint8_t mtime_hms[2]; - uint8_t mtime_date[2]; - uint8_t first_cluster[2]; - uint8_t file_size[4]; -}; - +// 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(int fd, uint32_t bytes) { uint8_t mbr[512]; - const uint16_t sector_size = 512; - const uint8_t cluster_size = 8; // 4 kiB cluster sizes match flash erase block size + const uint32_t sector_size = 512; + uint32_t cluster_size = 4096 / sector_size; // 4 kiB cluster sizes match flash erase block size + if (bytes > 16000) { + // 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); + 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)); @@ -42,25 +51,25 @@ int fat12_mkfs(int fd, uint32_t bytes) { fat12_write_u16(mbr + 0x0b, sector_size); // Sectors per cluster (8), so cluster is 512 * 8 - mbr[0x0d] = cluster_size; + fat12_write_u8(mbr + 0x0d, cluster_size); // Reserved sector count (8 sectors, to pad things to 4096-byte boundaries) - fat12_write_u16(mbr + 0x0e, cluster_size); + fat12_write_u16(mbr + 0x0e, reserved_sectors); // Number of FATs (1) - mbr[0x10] = 1; + fat12_write_u8(mbr + 0x10, 1); // Maximum number of root directory entries (16) - fat12_write_u16(mbr + 0x11, 32); + 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) - mbr[0x15] = 0xf8; + fat12_write_u8(mbr + 0x15, 0xf8); // Sectors per FAT - fat12_write_u16(mbr + 0x16, fat_size); + fat12_write_u16(mbr + 0x16, fat_size_sectors); // Sectors per track fat12_write_u16(mbr + 0x18, 32); @@ -69,31 +78,31 @@ int fat12_mkfs(int fd, uint32_t bytes) { fat12_write_u16(mbr + 0x1a, 64); // Hidden sectors - mbr[0x1c] = 0x00; - mbr[0x1d] = 0x00; - mbr[0x1e] = 0x00; - mbr[0x1f] = 0x00; + // 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; + // mbr[0x20] = 0; + // mbr[0x21] = 0; + // mbr[0x22] = 0; + // mbr[0x23] = 0; // BIOS drive - mbr[0x24] = 0x80; + fat12_write_u8(mbr + 0x24, 0x80); // Unused - mbr[0x25] = 0; + fat12_write_u8(mbr + 0x25, 0); // Boot signature - mbr[0x26] = 0x29; + fat12_write_u8(mbr + 0x26, 0x29); // Serial number - mbr[0x27] = 0xf0; - mbr[0x28] = 0xb0; - mbr[0x29] = 0x00; - mbr[0x2a] = 0x07; + 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); @@ -102,8 +111,8 @@ int fat12_mkfs(int fd, uint32_t bytes) { memcpy(mbr + 0x36, "FAT12 ", 8); // Signature - mbr[0xfe] = 0x55; - mbr[0xff] = 0xaa; + fat12_write_u8(mbr + 0xfe, 0x55); + fat12_write_u8(mbr + 0xff, 0xaa); // Write MBR to disk if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) { @@ -112,16 +121,33 @@ int fat12_mkfs(int fd, uint32_t bytes) { memset(mbr, 0, sizeof(mbr)); - // The first two clusters in the FAT are reserved, and must be 0xff + // 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); + // fat12_set_cluster(mbr, 2, 0xfff); if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) { return -1; } + // 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(fd, mbr, sizeof(mbr)) != sizeof(mbr)) { + return -1; + } + } + + // 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(fd, mbr, sizeof(mbr)) != sizeof(mbr)) { + return -1; + } + } + return 0; } \ No newline at end of file diff --git a/tests/mkfs-simple.c b/tests/mkfs-simple.c new file mode 100644 index 0000000..76584d4 --- /dev/null +++ b/tests/mkfs-simple.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "fat12.h" + +static int make_image(const char *name, uint32_t size) { + + int fd = open(name, O_WRONLY | O_CREAT, 0777); + if (-1 == fd) { + fprintf(stderr, "couldn't open %s: %s\n", name, strerror(errno)); + return 1; + } + + if (-1 == fat12_mkfs(fd, size)) { + fprintf(stderr, "couldn't make fat12 on %s: %s\n", name, strerror(errno)); + close(fd); + return 1; + } + close(fd); + return 0; +} + +int main(int argc, char **argv) { + int ret = 0; + + ret += make_image("fat12-1300k.img", 1300 * 1024); + // ret += make_image("fat12-1800k.img", 1800 * 1024); + // ret += make_image("fat12-128k.img", 128 * 1024); + ret += make_image("fat12-16M.img", 16 * 1024 * 1024); + + return ret; +} \ No newline at end of file