From 773c99727a03b8a908d78964395ab813b2f74e5c Mon Sep 17 00:00:00 2001 From: Allen <63997543+aaw3@users.noreply.github.com> Date: Fri, 7 Jun 2024 00:34:14 -0500 Subject: [PATCH] Add bootloader, kernel, and fat-12 implementation and some additional configs --- tools/fat/fat.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 tools/fat/fat.c diff --git a/tools/fat/fat.c b/tools/fat/fat.c new file mode 100644 index 0000000..93120f9 --- /dev/null +++ b/tools/fat/fat.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +typedef uint8_t bool; +#define true 1 +#define false 0 + +typedef struct +{ + uint8_t BootJump[3]; + uint8_t OemID[8]; + uint16_t BytesPerSector; + uint8_t SectorsPerCluster; + uint16_t ReservedSectors; + uint8_t FATCount; + uint16_t DirEntryCount; + uint16_t TotalSectors; + uint8_t MediaDescriptorType; + uint16_t SectorsPerFAT; + uint16_t SectorsPerTrack; + uint16_t Heads; + uint32_t HiddenSectors; + uint32_t LargeSectorCount; + + // extended boot record + uint8_t DriveNumber; + uint8_t _Reserved; + uint8_t Signature; + uint32_t VolumeID; // serial number, value doesn't matter + uint8_t VolumeLabel[11]; // 11 bytes, padded with spaces + uint8_t SystemID[8]; + +} __attribute__((packed)) BootSector; + +typedef struct +{ + uint8_t Name[11]; + uint8_t Attributes; + uint8_t _Reserved; + uint8_t CreatedTimeTenths; + uint16_t CreatedTime; + uint16_t CreatedDate; + uint16_t AccessedDate; + uint16_t FirstClusterHigh; + uint16_t ModifiedTime; + uint16_t ModifiedDate; + uint16_t FirstClusterLow; + uint32_t Size; +} __attribute__((packed)) DirectoryEntry; + + +BootSector g_BootSector; +uint8_t* g_FAT = NULL; +DirectoryEntry* g_RootDirectory = NULL; +uint32_t g_RootDirectoryEnd; + + +bool readBootSector(FILE* disk) +{ + return fread(&g_BootSector, sizeof(g_BootSector), 1, disk) > 0; +} + +bool readSectors(FILE* disk, uint32_t lba, uint32_t count, void* bufferOut) +{ + return (fseek(disk, lba * g_BootSector.BytesPerSector, SEEK_SET) == 0) && (fread(bufferOut, g_BootSector.BytesPerSector, count, disk) == count); +} + +bool readFat(FILE* disk) +{ + g_FAT = (uint8_t*) malloc(g_BootSector.SectorsPerFAT * g_BootSector.BytesPerSector); + return readSectors(disk, g_BootSector.ReservedSectors, g_BootSector.SectorsPerFAT, g_FAT); +} + +bool readRootDirectory(FILE* disk) +{ + uint32_t lba = g_BootSector.ReservedSectors + g_BootSector.SectorsPerFAT * g_BootSector.FATCount; + uint32_t size = sizeof(DirectoryEntry) * g_BootSector.DirEntryCount; + uint32_t sectors = (size / g_BootSector.BytesPerSector); + if (size % g_BootSector.BytesPerSector > 0) + sectors++; + + g_RootDirectoryEnd = lba + sectors; + g_RootDirectory = (DirectoryEntry*) malloc(sectors * g_BootSector.BytesPerSector); + return readSectors(disk, lba, sectors, g_RootDirectory); +} + +DirectoryEntry* findFile(const char* name) +{ + for (uint32_t i = 0; i < g_BootSector.DirEntryCount; i++) + { + if (memcmp(name, g_RootDirectory[i].Name, 11) == 0) + return &g_RootDirectory[i]; + } + + return NULL; +} + +bool readFile(DirectoryEntry* fileEntry, FILE* disk, uint8_t* outputBuffer) +{ + bool ok = true; + uint16_t currentCluster = fileEntry->FirstClusterLow; + + do { + uint32_t lba = g_RootDirectoryEnd + (currentCluster - 2) * g_BootSector.SectorsPerCluster; + ok = ok && readSectors(disk, lba, g_BootSector.SectorsPerCluster, outputBuffer); + outputBuffer += g_BootSector.SectorsPerCluster * g_BootSector.BytesPerSector; + + uint32_t fatIndex = currentCluster * 3 / 2; + if (currentCluster % 2 == 0) + currentCluster = (*(uint16_t*)(g_FAT + fatIndex)) & 0x0FFF; + else + currentCluster = (*(uint16_t*)(g_FAT + fatIndex)) >> 4; + + } while (ok && currentCluster < 0x0FF8); + + return ok; +} + +int main(int argc, char** argv) +{ + if (argc < 3) { + printf("Syntax: %s \n", argv[0]); + return -1; + } + + FILE* disk = fopen(argv[1], "rb"); + if (!disk) { + fprintf(stderr, "Cannot open disk image %s!\n", argv[1]); + return -1; + } + + if (!readBootSector(disk)) { + fprintf(stderr, "Could not read boot sector!\n"); + return -2; + } + + if (!readFat(disk)) { + fprintf(stderr, "Could not read FAT!\n"); + free(g_FAT); + return -3; + } + + if (!readRootDirectory(disk)) { + fprintf(stderr, "Could not read root directory!\n"); + free(g_FAT); + free(g_RootDirectory); + return -4; + } + + DirectoryEntry* fileEntry = findFile(argv[2]); + if (!fileEntry) { + fprintf(stderr, "Could not find file \'%s\'!\n", argv[2]); + free(g_FAT); + free(g_RootDirectory); + return -5; + } + + uint8_t* buffer = (uint8_t*) malloc(fileEntry->Size + g_BootSector.BytesPerSector); + if (!readFile(fileEntry, disk, buffer)) { + fprintf(stderr, "Could not read file \'%s\'!\n", argv[2]); + free(g_FAT); + free(g_RootDirectory); + free(buffer); + return -5; + } + + for (size_t i = 0; i < fileEntry->Size; i++) + { + if (isprint(buffer[i])) fputc(buffer[i], stdout); + else printf("<%02x>", buffer[i]); + } + printf("\n"); + + free(buffer); + free(g_FAT); + free(g_RootDirectory); + return 0; +} \ No newline at end of file