boredos_mirror/src/fs/mkfs_fat32.c
zeyad ed5f10eb7d
Some checks are pending
Nightly Build / build-and-release (push) Waiting to run
pr: Add lslbk disk listing command (#24)
* add lsblk disk listing command

* fix lsblk placeholder labels

* fix fat32 volume labels

* doc lsblk command

* add lsblk to help

* doc lsblk usage
2026-05-11 18:59:31 +02:00

297 lines
10 KiB
C

// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "mkfs_fat32.h"
#include "../dev/disk.h"
#include <stddef.h>
#include "memory_manager.h"
extern void serial_write(const char *str);
extern void serial_write_num(uint64_t num);
// Internal helpers
static void mf_memset(void *dst, int val, int len) {
unsigned char *p = (unsigned char *)dst;
while (len-- > 0) *p++ = (unsigned char)val;
}
static void mf_memcpy(void *dst, const void *src, int len) {
unsigned char *d = (unsigned char *)dst;
const unsigned char *s = (const unsigned char *)src;
while (len-- > 0) *d++ = *s++;
}
static void mf_strncpy(char *dst, const char *src, int n) {
int i = 0;
while (i < n && src[i]) { dst[i] = src[i]; i++; }
while (i < n) { dst[i++] = ' '; } /* FAT labels are space-padded */
}
static void mf_set_disk_label(Disk *disk, const char *label) {
int end = 11;
while (end > 0 && label[end - 1] == ' ') end--;
for (int i = 0; i < end && i < 31; i++) disk->label[i] = label[i];
disk->label[end < 31 ? end : 31] = 0;
}
// On-disk BPB structures
typedef struct __attribute__((packed)) {
/* DOS 2.0 BPB */
uint8_t jump_boot[3]; /* EB 58 90 */
char oem_name[8]; /* "MSDOS5.0" */
uint16_t bytes_per_sector; /* 512 */
uint8_t sectors_per_cluster;
uint16_t reserved_sector_count;
uint8_t num_fats; /* 2 */
uint16_t root_entry_count; /* 0 for FAT32 */
uint16_t total_sectors_16; /* 0 for FAT32 */
uint8_t media; /* 0xF8 for fixed disk */
uint16_t fat_size_16; /* 0 for FAT32 */
uint16_t sectors_per_track;
uint16_t num_heads;
uint32_t hidden_sectors;
uint32_t total_sectors_32;
/* FAT32 extended BPB */
uint32_t fat_size_32;
uint16_t ext_flags;
uint16_t fs_version; /* 0x0000 */
uint32_t root_cluster; /* 2 */
uint16_t fs_info; /* sector 1 */
uint16_t backup_boot_sector; /* sector 6 */
uint8_t reserved[12];
uint8_t drive_number; /* 0x80 for fixed disk */
uint8_t reserved1;
uint8_t boot_sig; /* 0x29 */
uint32_t volume_id;
char volume_label[11]; /* space-padded */
char fs_type[8]; /* "FAT32 " */
uint8_t boot_code[420];
uint16_t boot_signature; /* 0xAA55 */
} FAT32_BPB;
typedef struct __attribute__((packed)) {
uint32_t lead_sig; /* 0x41615252 */
uint8_t reserved1[480];
uint32_t struct_sig; /* 0x61417272 */
uint32_t free_count; /* 0xFFFFFFFF = unknown */
uint32_t next_free; /* 0xFFFFFFFF = unknown */
uint8_t reserved2[12];
uint32_t trail_sig; /* 0xAA550000 */
} FAT32_FSInfo;
// Public API
int mkfs_fat32_format(Disk *disk, uint32_t sector_count, const char *label) {
if (sector_count < MIN_FAT32_SECTORS) {
serial_write("[MKFS] Error: partition too small for FAT32 (< 32 MB)\n");
return -1;
}
if (!disk || !disk->write_sector) {
serial_write("[MKFS] Error: null disk or no write function\n");
return -1;
}
uint8_t spc; /* sectors per cluster */
if (sector_count < 532480) spc = 1; /* < 260 MB -> 512 B clusters */
else if (sector_count < 1064960) spc = 2; /* < 520 MB -> 1 KB */
else if (sector_count < 2097152) spc = 4; /* < 1 GB -> 2 KB */
else if (sector_count < 16777216) spc = 8; /* < 8 GB -> 4 KB */
else if (sector_count < 33554432) spc = 16; /* < 16 GB -> 8 KB */
else if (sector_count < 67108864) spc = 32; /* < 32 GB -> 16 KB */
else spc = 64; /* >= 32 GB -> 32 KB */
const uint32_t reserved_sectors = 32;
const uint8_t num_fats = 2;
const uint32_t root_cluster = 2;
uint32_t data_sectors = sector_count - reserved_sectors;
uint32_t cluster_count = data_sectors / spc;
uint32_t fat_bytes = (cluster_count + 2) * 4;
uint32_t sectors_per_fat = (fat_bytes + 511) / 512;
uint8_t *buf = (uint8_t *)kmalloc(512);
if (!buf) {
serial_write("[MKFS] Error: out of memory\n");
return -1;
}
FAT32_BPB *bpb = (FAT32_BPB *)buf;
mf_memset(bpb, 0, 512);
bpb->jump_boot[0] = 0xEB;
bpb->jump_boot[1] = 0x58;
bpb->jump_boot[2] = 0x90;
mf_memcpy(bpb->oem_name, "MSDOS5.0", 8);
bpb->bytes_per_sector = 512;
bpb->sectors_per_cluster = spc;
bpb->reserved_sector_count = (uint16_t)reserved_sectors;
bpb->num_fats = num_fats;
bpb->root_entry_count = 0;
bpb->total_sectors_16 = 0;
bpb->media = 0xF8;
bpb->fat_size_16 = 0;
bpb->sectors_per_track = 63;
bpb->num_heads = 255;
bpb->hidden_sectors = disk->partition_lba_offset;
bpb->total_sectors_32 = sector_count;
bpb->fat_size_32 = sectors_per_fat;
bpb->ext_flags = 0;
bpb->fs_version = 0;
bpb->root_cluster = root_cluster;
bpb->fs_info = 1;
bpb->backup_boot_sector = 6;
bpb->drive_number = 0x80;
bpb->boot_sig = 0x29;
bpb->volume_id = 0x12345678; /* arbitrary non-zero volume ID */
/* Volume label */
const char *vol_label = (label && label[0]) ? label : "NO NAME ";
char upper_label[11];
for (int i = 0; i < 11; i++) {
if (vol_label[i] == 0) {
for (int j = i; j < 11; j++) upper_label[j] = ' ';
break;
}
char c = vol_label[i];
if (c >= 'a' && c <= 'z') c -= 32;
upper_label[i] = c;
}
mf_memcpy(bpb->volume_label, upper_label, 11);
mf_memcpy(bpb->fs_type, "FAT32 ", 8);
/* Boot sector signature */
bpb->boot_signature = 0xAA55;
/* Write sector 0 (BPB) */
if (disk->write_sector(disk, 0, buf) != 0) {
serial_write("[MKFS] Error: failed to write BPB (sector 0)\n");
kfree(buf);
return -1;
}
FAT32_FSInfo *fsinfo = (FAT32_FSInfo *)buf;
mf_memset(fsinfo, 0, 512);
fsinfo->lead_sig = 0x41615252;
fsinfo->struct_sig = 0x61417272;
fsinfo->free_count = 0xFFFFFFFF;
fsinfo->next_free = 0xFFFFFFFF;
fsinfo->trail_sig = 0xAA550000;
if (disk->write_sector(disk, 1, buf) != 0) {
serial_write("[MKFS] Error: failed to write FSInfo (sector 1)\n");
kfree(buf);
return -1;
}
FAT32_BPB *bpb2 = (FAT32_BPB *)buf;
mf_memset(bpb2, 0, 512);
mf_memcpy(bpb2->jump_boot, "\xEB\x58\x90", 3);
mf_memcpy(bpb2->oem_name, "MSDOS5.0", 8);
bpb2->bytes_per_sector = 512;
bpb2->sectors_per_cluster = spc;
bpb2->reserved_sector_count = (uint16_t)reserved_sectors;
bpb2->num_fats = num_fats;
bpb2->root_entry_count = 0;
bpb2->total_sectors_16 = 0;
bpb2->media = 0xF8;
bpb2->fat_size_16 = 0;
bpb2->sectors_per_track = 63;
bpb2->num_heads = 255;
bpb2->hidden_sectors = disk->partition_lba_offset;
bpb2->total_sectors_32 = sector_count;
bpb2->fat_size_32 = sectors_per_fat;
bpb2->ext_flags = 0;
bpb2->fs_version = 0;
bpb2->root_cluster = root_cluster;
bpb2->fs_info = 1;
bpb2->backup_boot_sector = 6;
bpb2->drive_number = 0x80;
bpb2->boot_sig = 0x29;
bpb2->volume_id = 0x12345678;
mf_memcpy(bpb2->volume_label, upper_label, 11);
mf_memcpy(bpb2->fs_type, "FAT32 ", 8);
bpb2->boot_signature = 0xAA55;
if (disk->write_sector(disk, 6, buf) != 0) {
serial_write("[MKFS] Error: failed to write backup BPB (sector 6)\n");
kfree(buf);
return -1;
}
FAT32_FSInfo *fsinfo2 = (FAT32_FSInfo *)buf;
mf_memset(fsinfo2, 0, 512);
fsinfo2->lead_sig = 0x41615252;
fsinfo2->struct_sig = 0x61417272;
fsinfo2->free_count = 0xFFFFFFFF;
fsinfo2->next_free = 0xFFFFFFFF;
fsinfo2->trail_sig = 0xAA550000;
if (disk->write_sector(disk, 7, buf) != 0) {
serial_write("[MKFS] Error: failed to write backup FSInfo (sector 7)\n");
kfree(buf);
return -1;
}
/* Zero both FATs */
mf_memset(buf, 0, 512);
for (uint32_t f = 0; f < num_fats; f++) {
uint32_t fat_start = reserved_sectors + (f * sectors_per_fat);
for (uint32_t s = 0; s < sectors_per_fat; s++) {
if (disk->write_sector(disk, fat_start + s, buf) != 0) {
serial_write("[MKFS] Error: failed to zero FAT\n");
kfree(buf);
return -1;
}
}
}
/* Write markers to both FATs */
mf_memset(buf, 0, 512);
uint32_t *fat_buf = (uint32_t *)buf;
fat_buf[0] = 0x0FFFFFF8; // Media type
fat_buf[1] = 0x0FFFFFFF; // Reserved
fat_buf[2] = 0x0FFFFFFF; // Root directory (Cluster 2)
for (uint32_t f = 0; f < num_fats; f++) {
uint32_t fat_start = reserved_sectors + (f * sectors_per_fat);
if (disk->write_sector(disk, fat_start, buf) != 0) {
serial_write("[MKFS] Error: failed to write FAT markers\n");
kfree(buf);
return -1;
}
}
/* Zero root cluster */
mf_memset(buf, 0, 512);
uint32_t root_start = reserved_sectors + num_fats * sectors_per_fat;
for (uint32_t s = 0; s < (uint32_t)spc; s++) {
if (disk->write_sector(disk, root_start + s, buf) != 0) {
serial_write("[MKFS] Error: failed to zero root cluster\n");
kfree(buf);
return -1;
}
}
kfree(buf);
disk->is_fat32 = true;
mf_set_disk_label(disk, upper_label);
serial_write("[MKFS] FAT32 formatted: ");
serial_write(disk->devname);
serial_write(" label=");
char lb[12];
mf_memcpy(lb, upper_label, 11);
lb[11] = 0;
for (int i = 10; i >= 0 && lb[i] == ' '; i--) lb[i] = 0;
serial_write(lb);
serial_write(" spc=");
serial_write_num(spc);
serial_write(" fat_sectors=");
serial_write_num(sectors_per_fat);
serial_write("\n");
return 0;
}