From d8fd8c0a2901b60baefc80fe1b9b034af0800336 Mon Sep 17 00:00:00 2001 From: Tom-on64 Date: Sat, 1 Jun 2024 12:25:32 +0200 Subject: [PATCH] Added fs/fs.h header for new filesystem and added a utility that builds it. The filesystem is not in use though --- Makefile | 6 +- include/fs/fs.h | 91 +++++++++++++++ include/fs/fs_h.swo | Bin 0 -> 12288 bytes include/fs/fs_h.swp | Bin 0 -> 12288 bytes makeDisk.c | 266 ++++++++++++++++++++++++++++++++++++++++++++ src/calc.c | 5 +- src/kernel.c | 1 + 7 files changed, 363 insertions(+), 6 deletions(-) create mode 100644 include/fs/fs.h create mode 100644 include/fs/fs_h.swo create mode 100644 include/fs/fs_h.swp create mode 100644 makeDisk.c diff --git a/Makefile b/Makefile index 3784aeb..83998c2 100644 --- a/Makefile +++ b/Makefile @@ -26,8 +26,8 @@ filesystem: bootloader kernel $(C_FILES) $(FONTS) @dd if=$(BUILD)/boot.bin of=kern.iso bs=512 seek=0 conv=notrunc status=none @dd if=$(BUILD)/filetable.bin of=kern.iso bs=512 seek=15 conv=notrunc status=none @dd if=$(BUILD)/kernel.bin of=kern.iso bs=512 seek=16 conv=notrunc status=none - @dd if=$(BUILD)/term16n.bin of=kern.iso bs=512 seek=56 conv=notrunc status=none - @dd if=$(BUILD)/testfont.bin of=kern.iso bs=512 seek=60 conv=notrunc status=none + @dd if=$(BUILD)/term16n.fnt of=kern.iso bs=512 seek=56 conv=notrunc status=none + @dd if=$(BUILD)/testfont.fnt of=kern.iso bs=512 seek=60 conv=notrunc status=none @dd if=$(SRC)/fs/test.txt of=kern.iso bs=512 seek=64 conv=notrunc status=none @dd if=$(BUILD)/calc.bin of=kern.iso bs=512 seek=65 conv=notrunc status=none @dd if=$(BUILD)/editor.bin of=kern.iso bs=512 seek=71 conv=notrunc status=none @@ -63,7 +63,7 @@ $(C_FILES): $(FONTS): @echo "Assembling $(SRC)/fonts/$@.asm..." - @$(AS) -fbin -o $(BUILD)/$@.bin $(SRC)/fonts/$@.asm + @$(AS) -fbin -o $(BUILD)/$@.fnt $(SRC)/fonts/$@.asm # Run QEMU run: diff --git a/include/fs/fs.h b/include/fs/fs.h new file mode 100644 index 0000000..cee2641 --- /dev/null +++ b/include/fs/fs.h @@ -0,0 +1,91 @@ +#ifndef FS_H +#define FS_H + +#include + +#define FS_BLOCK_SIZE 4096 +#define FS_SECTOR_SIZE 512 + +#define FILETYPE_FILE 0 +#define FILETYPE_DIR 1 + +// Filesystem structures +typedef struct { + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t day; + uint8_t month; + uint16_t year; + uint8_t reserved; +} __attribute__ ((packed)) fsDatetime_t; + +typedef struct { + uint8_t sectors[FS_BLOCK_SIZE / FS_SECTOR_SIZE][FS_SECTOR_SIZE]; +} __attribute__ ((packed)) bootBlock_t; + +typedef struct { + uint32_t inodeCount; + + uint16_t firstInodeBitmapBlock; + uint16_t firstDataBitmapBlock; + uint16_t inodeBitmapBlockCount; + uint16_t dataBitmapBlockCount; + uint32_t firstInodeBlock; + uint32_t firstDataBlock; + uint16_t inodeBlockCount; + uint16_t dataBlockCount; + + uint32_t maxFileSize; // in bytes + uint16_t blockSize; // in bytes + uint8_t inodeSize; // in bytes + + uint32_t rootInodePtr; + uint8_t inodesPerBlock; + uint8_t directExtentsPerInode; + uint16_t extentsPerIndirectBlock; + uint32_t firstFreeInodeBit; + uint32_t firstFreeDataBit; + uint16_t deviceNumber; + uint8_t firstUnreservedInode; + + uint8_t reserved[14]; +} __attribute__ ((packed)) superBlock_t; + +typedef struct { + uint32_t firstBlock; + uint32_t length; +} __attribute__ ((packed)) extent_t; + +typedef struct { + uint32_t id; // Idetifier + uint8_t filetype; + uint32_t sizeBytes; + uint32_t sizeSectors; + fsDatetime_t timestamp; + extent_t extent[4]; + uint32_t singleIndirectBlock; + uint32_t doubleIndirectBlock; + uint8_t refCount; + uint8_t reserved[2]; +} __attribute__ ((packed)) inode_t; + +typedef struct { + uint32_t id; // Matching ID with INode + char name[60]; +} __attribute__ ((packed)) dirEntry_t; + +// Utility functions +uint32_t bytesToBlocks(uint32_t bytes) { + if (bytes == 0) return 0; + if (bytes <= FS_BLOCK_SIZE) return 1; + return (bytes / FS_BLOCK_SIZE) + ((bytes % FS_BLOCK_SIZE) > 0 ? 1 : 0); +} + +uint32_t bytesToSectors(uint32_t bytes) { + if (bytes == 0) return 0; + if (bytes <= FS_SECTOR_SIZE) return 1; + return (bytes / FS_SECTOR_SIZE) + ((bytes % FS_SECTOR_SIZE) > 0 ? 1 : 0); +} + +#endif diff --git a/include/fs/fs_h.swo b/include/fs/fs_h.swo new file mode 100644 index 0000000000000000000000000000000000000000..9e95f281fdc06c3b303a9060a38124bd7a07f056 GIT binary patch literal 12288 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 MBh+1lgq$V+1HUm5BLDyZ literal 0 HcmV?d00001 diff --git a/makeDisk.c b/makeDisk.c new file mode 100644 index 0000000..1136470 --- /dev/null +++ b/makeDisk.c @@ -0,0 +1,266 @@ +// A utility to build the disk +#include +#include +#include +#include +#include + +#include "include/fs/fs.h" + +#define IMAGE_NAME "kern.iso" +#define DISK_SIZE (2880 * 512) // 1.44MB + +uint8_t nullBlock[FS_BLOCK_SIZE] = { 0 }; + +typedef struct { + char name[60]; + uint32_t size; + FILE* fp; +} fileInfo_t; + +fileInfo_t files[] = { // TODO: Not have to list all of the files, loop through a directory or smth + { "./build/stage1.bin" }, + { "./build/stage2.bin" }, + { "./build/stage3.bin" }, + { "./build/kernel.bin" }, + { "./build/term16n.fnt" }, + { "./build/testfont.fnt" }, + { "./src/fs/test.txt" }, + { "./build/calc.bin" }, + { "./build/editor.bin" }, +}; + +superBlock_t superblock = { 0 }; + +FILE* imagePtr; +uint32_t diskSize = DISK_SIZE; +uint32_t fileCount; +uint32_t fileBlocks = 0; +uint32_t dataBlocks; +uint32_t dataBitCount; + +void writeBootblock(); +void writeSuperblock(); +void writeINodeBitmapBlocks(); +void writeDataBitmapBlocks(); +void writeINodeBlocks(); +void writeDataBlocks(); + +uint32_t paddingBytes(uint32_t bytes, uint32_t bound) { + if (bytes % bound == 0) return 0; + return (bytes - (bytes % bound) + bound) - bytes; +} + +int main(int argc, char** argv) { + imagePtr = fopen(IMAGE_NAME, "wb"); + + fileCount = sizeof(files) / sizeof(files[0]); + + // Open files and get file info + for (int i = 0; i < fileCount; i++) { + files[i].fp = fopen(files[i].name, "rb"); + fseek(files[i].fp, 0, SEEK_END); + files[i].size = ftell(files[i].fp); + rewind(files[i].fp); + fileBlocks += bytesToBlocks(files[i].size); + } + + printf("Building disk image %s...\n", IMAGE_NAME); + printf("Block size: %d Bytes, Total disk blocks: %d\n", FS_BLOCK_SIZE, bytesToBlocks(diskSize)); + printf("Used blocks: %d, Free blocks %d\n\n", fileBlocks, bytesToBlocks(diskSize) - fileBlocks); + printf("%d files (2 hidden)\n", fileCount); // Stage 1 and 2 is hidden + + // Build disk image + writeBootblock(); + writeSuperblock(); + writeINodeBitmapBlocks(); + writeDataBitmapBlocks(); + writeINodeBlocks(); + writeDataBlocks(); + + // Pad out to the whole disk size + uint32_t writtenBlocks = 2 + superblock.inodeBitmapBlockCount + superblock.dataBitmapBlockCount + superblock.inodeBlockCount + superblock.dataBlockCount; + for (uint32_t i = 0; i < bytesToBlocks(diskSize) - writtenBlocks; i++) { + assert(fwrite(nullBlock, FS_BLOCK_SIZE, 1, imagePtr) == 1); + } + + // Cleanup + for (uint32_t i = 0; i < fileCount; i++) { + fclose(files[i].fp); + } + fclose(imagePtr); + + return 0; +} + +void writeBootblock() { + bootBlock_t bootBlock = { 0 }; + assert(fread(bootBlock.sectors[0], FS_SECTOR_SIZE, 1, files[0].fp) == 1); // File 0 - Stage 1 + + for (uint8_t i = 1; i < bytesToSectors(files[i].size); i++) { + if (i > 7) { + fprintf(stderr, "%s is too large, maximum size of bootblock is 7 sectors (%d Bytes)\n", files[1].name, 7 * FS_SECTOR_SIZE); + exit(1); + } + + assert(fread(bootBlock.sectors[i], FS_SECTOR_SIZE, 1, files[1].fp) == 1); // File 1 - Stage 2 + } + + // Write bootblock to disk + for (uint8_t i = 0; i < FS_BLOCK_SIZE / FS_SECTOR_SIZE; i++) { + assert(fwrite(bootBlock.sectors[i], FS_SECTOR_SIZE, 1, imagePtr) == 1); + } +} + +void writeSuperblock() { + superblock.inodeCount = fileCount + 2; // 2 reserved INodes (0 - Invalid, 1 - Root) + superblock.firstInodeBitmapBlock = 2; // Block 0 - Boot, Block 1 - Superblock + superblock.inodeBitmapBlockCount = superblock.inodeCount / (FS_BLOCK_SIZE * 8) + ((superblock.inodeCount % (FS_BLOCK_SIZE * 8) > 0) ? 1 : 0); + superblock.firstDataBitmapBlock = superblock.firstInodeBlock + superblock.inodeBitmapBlockCount; + + dataBlocks = bytesToBlocks(diskSize); + dataBitCount = (dataBlocks - superblock.firstDataBitmapBlock); + + superblock.dataBitmapBlockCount = dataBitCount / (FS_BLOCK_SIZE * 8) + ((dataBitCount % (FS_BLOCK_SIZE * 8) > 0) ? 1 : 0); + superblock.firstInodeBlock = superblock.firstDataBitmapBlock + superblock.dataBitmapBlockCount; + superblock.inodeBlockCount = bytesToBlocks(superblock.inodeCount * sizeof(inode_t)); + superblock.firstDataBlock = superblock.firstInodeBlock + superblock.inodeBlockCount; + superblock.dataBlockCount = (fileBlocks - 2) + 1; // 1 Block for root dir (-1 for boot block) + superblock.maxFileSize = 0xffffffff; + superblock.blockSize = FS_BLOCK_SIZE; + superblock.inodeSize = sizeof(inode_t); + superblock.rootInodePtr = 0; // Gets setup at runtime + superblock.inodesPerBlock = FS_BLOCK_SIZE / sizeof(inode_t); + superblock.directExtentsPerInode = 4; + superblock.extentsPerIndirectBlock = FS_BLOCK_SIZE / sizeof(extent_t); + superblock.firstFreeInodeBit = superblock.inodeCount; + superblock.firstFreeDataBit = (fileBlocks - 2) + 1; // +1 for root dir + superblock.deviceNumber = 0x01; + superblock.firstUnreservedInode = 3; // 0 - Invalid; 1 - Root dir; 2 - Bootloader INode + + assert(fwrite(&superblock, sizeof(superBlock_t), 1, imagePtr) == 1); + assert(fwrite(&nullBlock, paddingBytes(sizeof(superBlock_t), FS_BLOCK_SIZE), 1, imagePtr) == 1); // Padding +} + +void writeINodeBitmapBlocks() { + uint8_t temp[FS_SECTOR_SIZE] = { 0 }; + + // Set number of bits = number of inodes + *(uint32_t*)temp |= (2 << (superblock.inodeCount - 1)) - 1; + assert(fwrite(temp, FS_SECTOR_SIZE, 1, imagePtr) == 1); + + // Padd out + assert(fwrite(nullBlock, paddingBytes(FS_SECTOR_SIZE, FS_BLOCK_SIZE), 1, imagePtr) == 1); +} + +void writeDataBitmapBlocks() { + uint64_t bitChunk = 0; + uint32_t totalBlocks = superblock.dataBlockCount / 32; + uint32_t bytesWritten = 0; + + while (totalBlocks > 0) { + bitChunk = 0xffffffff; + totalBlocks--; + assert(fwrite(&bitChunk, 4, 1, imagePtr) == 1); + bytesWritten += 4; + } + + bitChunk = (2 << ((superblock.dataBlockCount % 32) - 1)) - 1; + assert(fwrite(&bitChunk, 4, 1, imagePtr) == 1); + bytesWritten += 4; + + assert(fwrite(nullBlock, paddingBytes(bytesWritten, FS_BLOCK_SIZE), 1, imagePtr) == 1); +} + +void writeINodeBlocks() { + inode_t inode = { 0 }; + fsDatetime_t defaultTimestamp = { + .second = 12, + .minute = 12, + .hour = 12, + .day = 20, + .month = 4, + .year = 2024, + }; + + // INode 0 - Invalid + assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1); + + // INode 1 - Root directory + inode = (inode_t) { // OOP In C??? + .id = 1, + .filetype = FILETYPE_DIR, + .sizeBytes = sizeof(dirEntry_t) * fileCount, + .sizeSectors = bytesToSectors(inode.sizeBytes), + .timestamp = defaultTimestamp, + .extent[0] = (extent_t) { + .firstBlock = superblock.firstDataBlock, + .length = bytesToBlocks(inode.sizeBytes), + }, + }; + + // INode 2 - Bootloader (stage 3) followed by other INodes + uint32_t id = 2; + uint32_t block = superblock.firstDataBlock + inode.extent[0].length; + for (uint32_t i = 2; i < fileCount; i++) { + memset(&inode, 0, sizeof(inode)); + inode.id = id++; + inode.filetype = FILETYPE_FILE; + inode.sizeBytes = files[i].size; + inode.sizeSectors = bytesToSectors(inode.sizeBytes); + inode.timestamp = defaultTimestamp; + inode.extent[0] = (extent_t) { + .firstBlock = block, + .length = bytesToBlocks(inode.sizeBytes), + }; + + assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1); + + block += inode.extent[0].length; + } + + assert(fwrite(nullBlock, paddingBytes(fileCount * sizeof(inode_t), FS_BLOCK_SIZE), 1, imagePtr) == 1); +} + +void writeDataBlocks() { + uint8_t sector[FS_SECTOR_SIZE] = { 0 }; + dirEntry_t dirEntry = { + .id = 1, + .name = ".", + }; + + assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1); + strcpy(dirEntry.name, ".."); + assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1); + + for (uint32_t i = 2; i < fileCount; i++) { + dirEntry.id = i; + strcpy(dirEntry.name, strrchr(files[i].name, '/') + 1); // We skip the './build/' + assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1); + } + + // Padd out + assert(fwrite(nullBlock, paddingBytes(fileCount * sizeof(dirEntry_t), FS_BLOCK_SIZE), 1, imagePtr) == 1); + + // Write actual file data + uint32_t bytesWritten = 0; + for (uint32_t i = 2; i < fileCount; i++) { + uint32_t blockCount = bytesToBlocks(files[i].size); + printf("%s, %d Bytes -> %d Blocks\n", files[i].name, files[i].size, blockCount); + bytesWritten = 0; + + for (uint32_t j = 0; j < blockCount * (FS_BLOCK_SIZE / FS_SECTOR_SIZE); j++) { + uint32_t byteCount = fread(sector, 1, sizeof(sector), files[i].fp); + fwrite(sector, 1, sizeof(sector), imagePtr); + bytesWritten += byteCount; + + if (byteCount < sizeof(sector)) break; // EOF + } + + memset(sector, 0, sizeof(sector)); + + // Padd out block + fwrite(nullBlock, paddingBytes(bytesWritten, FS_BLOCK_SIZE), 1, imagePtr); + } +} + diff --git a/src/calc.c b/src/calc.c index 425bc97..0951cf9 100644 --- a/src/calc.c +++ b/src/calc.c @@ -9,14 +9,13 @@ int parseNumber(char** ptr); // TODO: Parsing doesn't account for addition/subtraction inside brackets, fix that __attribute__ ((section("entry"))) -void main() { +int main(int argc, char** argv) { printf("Welcome to calc.\n"); char input[256]; while (1) { printf("> "); read(input); - *strchr(input, '\n') = '\0'; // Remove whitespace char* old = input; @@ -39,7 +38,7 @@ void main() { } } - return; + return 0; } int evalExpr(char* expr, int* res) { diff --git a/src/kernel.c b/src/kernel.c index 4ada2a9..665fb51 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -23,6 +23,7 @@ #include #include #include +#include #define PROMPT "#> "