127 lines
2.9 KiB
C
127 lines
2.9 KiB
C
|
#include <stdint.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.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];
|
||
|
};
|
||
|
|
||
|
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
|
||
|
|
||
|
// XXX What happens if this is an even multiple of sectors?
|
||
|
uint32_t fat_size = 1 + ((((bytes * 3) / sector_size) / cluster_size) / 2);
|
||
|
|
||
|
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
|
||
|
mbr[0x0d] = cluster_size;
|
||
|
|
||
|
// Reserved sector count (8 sectors, to pad things to 4096-byte boundaries)
|
||
|
fat12_write_u16(mbr + 0x0e, cluster_size);
|
||
|
|
||
|
// Number of FATs (1)
|
||
|
mbr[0x10] = 1;
|
||
|
|
||
|
// Maximum number of root directory entries (16)
|
||
|
fat12_write_u16(mbr + 0x11, 32);
|
||
|
|
||
|
// Total number of 512-byte sectors
|
||
|
fat12_write_u16(mbr + 0x13, bytes / sector_size);
|
||
|
|
||
|
// Type of media (0xf8 == fixed disk)
|
||
|
mbr[0x15] = 0xf8;
|
||
|
|
||
|
// Sectors per FAT
|
||
|
fat12_write_u16(mbr + 0x16, fat_size);
|
||
|
|
||
|
// 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
|
||
|
mbr[0x24] = 0x80;
|
||
|
|
||
|
// Unused
|
||
|
mbr[0x25] = 0;
|
||
|
|
||
|
// Boot signature
|
||
|
mbr[0x26] = 0x29;
|
||
|
|
||
|
// Serial number
|
||
|
mbr[0x27] = 0xf0;
|
||
|
mbr[0x28] = 0xb0;
|
||
|
mbr[0x29] = 0x00;
|
||
|
mbr[0x2a] = 0x07;
|
||
|
|
||
|
// Volume Name
|
||
|
memcpy(mbr + 0x2b, "Fomu ", 11);
|
||
|
|
||
|
// Filesystem
|
||
|
memcpy(mbr + 0x36, "FAT12 ", 8);
|
||
|
|
||
|
// Signature
|
||
|
mbr[0xfe] = 0x55;
|
||
|
mbr[0xff] = 0xaa;
|
||
|
|
||
|
// Write MBR to disk
|
||
|
if (pang_write(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
memset(mbr, 0, sizeof(mbr));
|
||
|
|
||
|
// The first two clusters in the FAT are reserved, and must be 0xff
|
||
|
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(fd, mbr, sizeof(mbr)) != sizeof(mbr)) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|