commit some source

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
2019-06-03 09:57:25 +08:00
parent 2afca97177
commit 5fb4ea8474
7 changed files with 297 additions and 0 deletions

45
src/defrag.c Normal file
View File

@ -0,0 +1,45 @@
#include "io.h"
#define try(x) do { int i = (x); if (i == -1) { return -1 } } while (0)
int fat12_defrag(int fd) {
uint8_t buf[512];
// Read in MBR and figure out where the FAT begins and ends
try(pang_seek(fd, 0, SEEK_SET));
// Actually read in the MBR
try(pang_read(fd, buf, sizeof(buf)));
// We only operate on 512-byte sector sizes
if (fat12_read_u16(buf + 0x0b) != 512) {
return -2;
}
// We require the cluster size to be 4096 (8 * 512)
if (buf[0x0d] != 8) {
return -2;
}
// To ensure the erase block is correct, require 4096-bytes
// of reserved data
if (fat12_read_u16(buf + 0x0e) != 4096) {
return -2;
}
// Also, we only support 1 FAT
if (buf[0x10] != 1) {
return -2;
}
// 32 root entries keeps it padded correctly.
if (fat12_read_u16(mbr + 0x11, 32) != 32) {
return -2;
}
// Total number of 512-byte sectors
fat12_write_u16(mbr + 0x13, bytes / sector_size);
return 0;
}

41
src/fat12.c Normal file
View File

@ -0,0 +1,41 @@
#include "fat12.h"
void fat12_write_u16(void *ptr, uint16_t val) {
((uint8_t *)ptr)[0] = (val >> 0) & 0xff;
((uint8_t *)ptr)[1] = (val >> 8) & 0xff;
}
uint16_t fat12_read_u16(void *ptr) {
uint16_t val = 0;
val |= (((uint8_t *)ptr)[0] << 0) & 0x00ff;
val |= (((uint8_t *)ptr)[1] << 8) & 0xff00;
return val;
}
void fat12_set_cluster(void *fat, uint32_t cluster, uint32_t value) {
uint32_t offset = (cluster * 3) / 2;
if (cluster&1) {
((uint8_t *)fat)[offset] = (((uint8_t *)fat)[offset] & 0x0f) | ((value << 4) & 0xf0);
((uint8_t *)fat)[offset + 1] = value >> 4;
}
else {
((uint8_t *)fat)[offset] = value;
((uint8_t *)fat)[offset + 1] = (((uint8_t *)fat)[offset] & 0xf0) | ((value >> 8) & 0x0f);
}
}
uint32_t fat12_get_cluster(void *fat, uint32_t cluster) {
uint32_t offset = (cluster * 3) / 2;
uint32_t value = 0;
if (cluster&1) {
value |= (((uint8_t *)fat)[offset] >> 4) & 0x00f;
value |= (((uint8_t *)fat)[offset + 1] << 4) & 0xff0;
}
else {
value |= ((uint8_t *)fat)[offset];
value |= (((uint8_t *)fat)[offset + 1] << 8) & 0xf00;
}
return value;
}

15
src/io.c Normal file
View File

@ -0,0 +1,15 @@
#include "io.h"
#ifdef unix
ssize_t pang_write(int fd, const void *buf, size_t count) {
return write(fd, buf, count);
}
ssize_t pang_read(int fd, void *buf, size_t count) {
return read(fd, buf, count);
}
off_t pang_seek(int fd, off_t offset, int whence) {
return lseek(fd, offset, whence);
}
#endif

127
src/mkfat.c Normal file
View File

@ -0,0 +1,127 @@
#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;
}