diff --git a/.gitignore b/.gitignore index 4941711..93b0c9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *~ -build/* \ No newline at end of file +build/* +*.ini \ No newline at end of file diff --git a/Makefile b/Makefile index bcbc84f..950afc5 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ ASM=nasm +CC=gcc SRC_DIR=src +TOOLS_DIR=tools BUILD_DIR=build -.PHONY: all floppy_image kernel bootloader clean always +.PHONY: all floppy_image kernel bootloader clean always tools_fat + +all: floppy_image tools_fat # # Floppy image @@ -37,6 +41,14 @@ kernel: $(BUILD_DIR)/kernel.bin $(BUILD_DIR)/kernel.bin: always $(ASM) $(SRC_DIR)/kernel/main.asm -f bin -o $(BUILD_DIR)/kernel.bin +# +# Tools +# +tools_fat: $(BUILD_DIR)/tools/fat +$(BUILD_DIR)/tools/fat: always $(TOOLS_DIR)/fat/fat.c + mkdir -p $(BUILD_DIR)/tools + $(CC) -g -o $(BUILD_DIR)/tools/fat $(TOOLS_DIR)/fat/fat.c + # # Always # diff --git a/tools/fat/fat.c b/tools/fat/fat.c new file mode 100644 index 0000000..bf2baf6 --- /dev/null +++ b/tools/fat/fat.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include + +typedef uint8_t bool; +#define true 1 +#define false 0 + +typedef struct +{ + uint8_t BootJumpInstruction[3]; + uint8_t OemIdentifier[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; + + +//global vars +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) +{ + bool ok = true; + ok = ok && (fseek(disk, lba * g_BootSector.BytesPerSector, SEEK_SET) == 0); + ok = ok && (fread(bufferOut, g_BootSector.BytesPerSector, count, disk) == count); + return ok; +} + +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!", argv[1]); + return -1; + } + + if(!readBootSector(disk)) { + fprintf(stderr, "Could not read boot sector!"); + 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 FAT!\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; +}