diff --git a/docs/fs-spec.txt b/docs/fs-spec.txt index dc6f88b..1ec9d4c 100644 --- a/docs/fs-spec.txt +++ b/docs/fs-spec.txt @@ -4,28 +4,29 @@ Sector = 512 Bytes Block = 4096 Bytes Reserved sectors: - Sector 0 - Bootsector, will be loaded by the Bios into memory and executed (512B) - Sector 1..4 - Superblock, contains metadata about the filesystem itself (4KiB) + Sector 0..3 - Bootblock, will be loaded by the Bios into memory and executed (512B) + Sector 4..7 - Superblock, contains metadata about the filesystem itself (4KiB) Superblock structure: (4096B) - FS Name - FS Size (Sector) - FS Size (Block) + Device ID + Max File Size INode Count - INodes per sector INode Bitmap Block - Data Bitmap Block INodes Start + INode Block Count + INodes per sector + Data Bitmap Block Data Start - Root INode Number - Extents per indirect + Data Block Count + Root INode Pointer + First Unreserved INode INode structure: (64B) Type Size (bytes) - Block Count (size in blocks) + Sector Count (size in sectors) Mode - Extents[] + Extent[4] Single Indirect Double Indirect? @@ -37,3 +38,11 @@ Directory Entry: (64B) INode Number Name (max length 60 Bytes) +Filetypes: + File + Directory + #TODO + Link + Device + Stream? + diff --git a/include/fs/fs.h b/include/fs/fs.h index 9cca27d..dbb4e5e 100644 --- a/include/fs/fs.h +++ b/include/fs/fs.h @@ -1,90 +1,83 @@ #ifndef FS_H #define FS_H +/* + * For info, read the fs-spec.txt document inside of docs/ + */ + #include -#define FS_BLOCK_SIZE 4096 +// FS Definitions #define FS_SECTOR_SIZE 512 +#define FS_BLOCK_SIZE 4096 -#define FILETYPE_FILE 0 -#define FILETYPE_DIR 1 +// Conversion Macros (beatiful) +#define BYTES2BLOCKS(_n) ( (_n) == 0 ? 0 : \ + (_n) <= (FS_BLOCK_SIZE) ? 1 : \ + ((_n) / FS_BLOCK_SIZE) + (((_n) % FS_BLOCK_SIZE) > 0 ? 1 : 0) ) -// 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; +#define BYTES2SECTORS(_n) ( (_n) == 0 ? 0 : \ + (_n) <= (FS_SECTOR_SIZE) ? 1 : \ + ((_n) / FS_SECTOR_SIZE) + (((_n) % FS_SECTOR_SIZE) > 0 ? 1 : 0) ) + +// Filetypes +#define FT_FILE 0 +#define FT_DIR 1 + +// FS Structures +// TODO: datetime_t? typedef struct { uint8_t sectors[FS_BLOCK_SIZE / FS_SECTOR_SIZE][FS_SECTOR_SIZE]; -} __attribute__ ((packed)) bootBlock_t; +} __attribute__ ((packed)) bootblock_t; +// Superblock - Padded to 4096 Bytes typedef struct { + // Constant data + uint16_t deviceId; + uint16_t extentsPerIndirect; + uint32_t maxFileSize; + uint16_t inodesPerSector; + + // INode data uint32_t inodeCount; + uint32_t inodeBitmapBlock; + uint32_t inodesStart; + uint32_t inodeBlockCount; - uint16_t firstINodeBitmapBlock; - uint16_t firstDataBitmapBlock; - uint16_t inodeBitmapBlockCount; - uint16_t dataBitmapBlockCount; - uint32_t firstINodeBlock; - uint32_t firstDataBlock; - uint16_t inodeBlockCount; - uint16_t dataBlockCount; + // Data data :) + uint32_t dataBitmapBlock; + uint32_t dataStart; + uint32_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; + // Other + uint32_t rootInodePtr; + uint32_t firstUnreservedInode; +} __attribute__ ((packed)) superblock_t; +// Extent - 8 Bytes typedef struct { - uint32_t firstBlock; + uint32_t block; uint32_t length; } __attribute__ ((packed)) extent_t; +// INode - 64 Bytes typedef struct { - uint32_t id; // Idetifier - uint8_t filetype; - uint32_t sizeBytes; - uint32_t sizeSectors; - fsDatetime_t timestamp; + uint32_t id; + uint8_t type; + uint32_t sizeBytes; // Size in bytes + uint32_t sizeSectors; // Size in sectors + uint8_t mode; // Access permisions extent_t extent[4]; - uint32_t singleIndirectBlock; - uint32_t doubleIndirectBlock; - uint8_t refCount; - uint8_t reserved[2]; + uint32_t singleIndirect; + uint32_t doubleIndirect; + + uint8_t reserved[10]; } __attribute__ ((packed)) inode_t; typedef struct { - uint32_t id; // Matching ID with INode char name[60]; + uint32_t id; } __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/impl.h b/include/fs/impl.h index 8af4cd6..f8c55cc 100644 --- a/include/fs/impl.h +++ b/include/fs/impl.h @@ -1,44 +1,36 @@ #ifndef IMPL_H #define IMPL_H -#include #include #include +#include #include -#include char* currentDir; -inode_t currentDirINode; -char tempSector[FS_SECTOR_SIZE]; -char tempBlock[FS_BLOCK_SIZE]; +inode_t* getInode(char* path) { + dirEntry_t* dentry = (dirEntry_t*)SCRATCH_BLOCK_LOC; -inode_t rootINode; - -inode_t* getINode(char* path) { - dirEntry_t* dirEntry = (dirEntry_t*)SCRATCH_BLOCK_LOC; - while (dirEntry->name[0] != '\0') { - if (strcmp(dirEntry->name, path) == 0) break; - dirEntry++; + while (dentry->name[0] != '\0') { + if (strcmp(dentry->name, path)) break; + dentry++; } - if (dirEntry->name[0] == '\0') return NULL; + if (dentry->name[0] == '\0') return NULL; inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC; - while (inode->id != dirEntry->id) { - inode++; - } + while (inode->id != dentry->id) { inode++; } return inode; } uint8_t loadFile(inode_t* inode, void* dest) { - uint32_t totalBlocks = bytesToBlocks(inode->sizeBytes); - uint32_t addressOffset = 0; + uint32_t totalBlocks = BYTES2BLOCKS(inode->sizeBytes); + uint32_t offset = 0; for (uint8_t i = 0; i < 4 && totalBlocks > 0; i++) { - diskRead(inode->extent[i].firstBlock * 8, inode->extent[i].length * 8, dest + addressOffset); - addressOffset += inode->extent[i].length * FS_BLOCK_SIZE; + diskRead(inode->extent[i].block * 8, inode->extent[i].length * 8, dest + offset); + offset += inode->extent[i].length * FS_BLOCK_SIZE; totalBlocks -= inode->extent[i].length; } diff --git a/include/memory/addresses.h b/include/memory/addresses.h index 950e2ee..18cb972 100644 --- a/include/memory/addresses.h +++ b/include/memory/addresses.h @@ -12,9 +12,10 @@ * 0x6000-0x6fff - VBE info area * 0x7000-0x7bff - SMAP Area * 0x7c00-0x8bff - Bootblock - * 0x8c00-0x9bff - Superblock (i think) + * 0x8c00-0x9bff - Superblock * 0x9c00-0xafff - Free * 0xb000-0xbfff - Bootloader first INode + * 0xc000-0xcfff - Scratch INode block */ // Global Variables 0x1800-0x1fff diff --git a/makedisk.c b/makedisk.c index e84780e..ba842ac 100644 --- a/makedisk.c +++ b/makedisk.c @@ -31,7 +31,7 @@ fileInfo_t files[] = { // TODO: Not have to list all of the files, loop through { BIN_DIR"editor.bin" }, }; -superBlock_t superblock = { 0 }; +superblock_t superblock = { 0 }; FILE* imagePtr; uint32_t diskSize = DISK_SIZE; @@ -63,11 +63,11 @@ int main(int argc, char** argv) { fseek(files[i].fp, 0, SEEK_END); files[i].size = ftell(files[i].fp); rewind(files[i].fp); - fileBlocks += bytesToBlocks(files[i].size); + fileBlocks += BYTES2BLOCKS(files[i].size); } printf("Building disk image %s...\n", IMAGE_NAME); - printf("Block size: %d Bytes, Total disk blocks: %d (%d Bytes)\n\n", FS_BLOCK_SIZE, bytesToBlocks(diskSize), diskSize); + printf("Block size: %d Bytes, Total disk blocks: %d (%d Bytes)\n\n", FS_BLOCK_SIZE, BYTES2BLOCKS(diskSize), diskSize); printf("%d files (2 hidden)\n", fileCount); // Stage 1 and 2 is hidden @@ -79,12 +79,12 @@ int main(int argc, char** argv) { writeINodeBlocks(); writeDataBlocks(); - uint32_t writtenBlocks = 2 + superblock.inodeBitmapBlockCount + superblock.dataBitmapBlockCount + superblock.inodeBlockCount + superblock.dataBlockCount; + uint32_t writtenBlocks = 4 + superblock.inodeBlockCount + superblock.dataBlockCount; printf("\nWritten blocks: %d (%d Bytes)\n", writtenBlocks, writtenBlocks * FS_BLOCK_SIZE); - printf("Free blocks: %d (%d Bytes)\n", bytesToBlocks(diskSize) - writtenBlocks, diskSize - writtenBlocks * FS_BLOCK_SIZE); + printf("Free blocks: %d (%d Bytes)\n", BYTES2BLOCKS(diskSize) - writtenBlocks, diskSize - writtenBlocks * FS_BLOCK_SIZE); // Pad out to the whole disk size - for (uint32_t i = 0; i < bytesToBlocks(diskSize) - writtenBlocks; i++) { + for (uint32_t i = 0; i < BYTES2BLOCKS(diskSize) - writtenBlocks; i++) { assert(fwrite(nullBlock, FS_BLOCK_SIZE, 1, imagePtr) == 1); } @@ -98,10 +98,10 @@ int main(int argc, char** argv) { } void writeBootblock() { - bootBlock_t bootBlock = { 0 }; + 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++) { + for (uint8_t i = 1; i < BYTES2SECTORS(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); @@ -117,33 +117,39 @@ void writeBootblock() { } void writeSuperblock() { - superblock.inodeCount = fileCount; // 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.firstINodeBitmapBlock + superblock.inodeBitmapBlockCount; - superblock.inodeBlockCount = bytesToBlocks(superblock.inodeCount * sizeof(inode_t)); + /* Block Layout + * 0 - Boot + * 1 - Super + * 2 - INode Bitmap + * 3 - Data Bitmap + * 4 - First INode Block + */ - dataBlocks = bytesToBlocks(diskSize); - dataBitCount = (dataBlocks - superblock.firstDataBitmapBlock - superblock.inodeBlockCount); + // Constant + superblock.deviceId = 0x01; + superblock.extentsPerIndirect = FS_BLOCK_SIZE / sizeof(extent_t); + superblock.maxFileSize = 0xffffffff; + superblock.inodesPerSector = (FS_SECTOR_SIZE / sizeof(inode_t)); - superblock.dataBitmapBlockCount = dataBitCount / (FS_BLOCK_SIZE * 8) + ((dataBitCount % (FS_BLOCK_SIZE * 8) > 0) ? 1 : 0); - superblock.firstINodeBlock = superblock.firstDataBitmapBlock + superblock.dataBitmapBlockCount; - 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 + // INode + superblock.inodeCount = fileCount + 2; // 2 reserved INodes (0 - Invalid, 1 - Root) + superblock.inodeBitmapBlock = 2; + superblock.inodesStart = 4; + superblock.inodeBlockCount = BYTES2BLOCKS(superblock.inodeCount * sizeof(inode_t)); + + // Data + dataBlocks = BYTES2BLOCKS(diskSize); + + superblock.dataBitmapBlock = 3; + superblock.dataStart = superblock.inodesStart + superblock.inodeBlockCount; + superblock.dataBlockCount = fileBlocks; // +1 for Root, -1 for Boot + + // Other + superblock.rootInodePtr = 0; // Will be filled at runtime + superblock.firstUnreservedInode = 3; // 0 - Invalid, 1 - Root, 2 - Bootloader + + 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() { @@ -178,50 +184,33 @@ void writeDataBitmapBlocks() { 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), Set below - .timestamp = defaultTimestamp, - .extent[0] = (extent_t) { - .firstBlock = superblock.firstDataBlock, - // .length = bytesToBlocks(inode.sizeBytes), Set below - }, - }; + inode.id = 1; + inode.type = FT_DIR; + inode.sizeBytes = sizeof(dirEntry_t) * fileCount; + inode.sizeSectors = BYTES2SECTORS(inode.sizeBytes); + // TODO: Mode - inode.sizeSectors = bytesToSectors(inode.sizeBytes); - inode.extent[0].length = bytesToBlocks(inode.sizeBytes); + inode.extent[0].block = superblock.dataStart; + inode.extent[0].length = BYTES2BLOCKS(inode.sizeBytes); assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1); // INode 2 - Bootloader (stage 3) followed by other INodes - uint32_t block = superblock.firstDataBlock + inode.extent[0].length; + uint32_t block = superblock.dataStart + inode.extent[0].length; for (uint32_t i = 2; i < fileCount; i++) { memset(&inode, 0, sizeof(inode)); inode.id = i; - inode.filetype = FILETYPE_FILE; + inode.type = FT_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), - }; - inode.extent[0].length = bytesToBlocks(inode.sizeBytes); + inode.sizeSectors = BYTES2SECTORS(inode.sizeBytes); + + inode.extent[0].block = block, + inode.extent[0].length = BYTES2BLOCKS(inode.sizeBytes); assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1); @@ -248,12 +237,12 @@ void writeDataBlocks() { assert(fwrite(&dirEntry, sizeof(dirEntry), 1, imagePtr) == 1); } - // Padd out + // Pad out assert(fwrite(nullBlock, paddingBytes(fileCount * sizeof(dirEntry_t), FS_BLOCK_SIZE), 1, imagePtr) == 1); // Write actual file data for (uint32_t i = 2; i < fileCount; i++) { - uint32_t blockCount = bytesToBlocks(files[i].size); + uint32_t blockCount = BYTES2BLOCKS(files[i].size); uint32_t bytesWritten = 0; printf("%s, %d Bytes -> %d Blocks\n", files[i].name, files[i].size, blockCount); diff --git a/src/stage1.asm b/src/stage1.asm index af8abb9..dbcfb77 100644 --- a/src/stage1.asm +++ b/src/stage1.asm @@ -2,9 +2,9 @@ [org 0x7c00] %define SUPERBLOCK 0x8c00 -%define FIRST_INODE_BLOCK (SUPERBLOCK) + 12 -%define STAGE3_INODE 0xb000 + 128 -%define EXTENT0 (STAGE3_INODE) + 21 ; Offset of extent[0] in inode_t +%define FIRST_INODE_BLOCK (SUPERBLOCK) + 18 +%define STAGE3_INODE 0xb000 + (2 * 64) +%define EXTENT0 (STAGE3_INODE) + 14 ; Offset of extent[0] in inode_t start: xor ax, ax diff --git a/src/stage3.c b/src/stage3.c index 644a13f..bedd81d 100644 --- a/src/stage3.c +++ b/src/stage3.c @@ -27,16 +27,16 @@ void main() { deinitMemoryRegion(MEMMAP_AREA, maxBlocks / BLOCKS_PER_BYTE); // Load root dir, find kernel INode and parse it - superBlock_t* superblock = (superBlock_t*)SUPERBLOCK_LOC; - superblock->rootINodePtr = BOOT_FIRST_INODE_LOC + sizeof(inode_t); - diskRead(superblock->firstDataBlock * 8, 8, (void*)SCRATCH_BLOCK_LOC); + superblock_t* superblock = (superblock_t*)SUPERBLOCK_LOC; + superblock->rootInodePtr = BOOT_FIRST_INODE_LOC + sizeof(inode_t); + diskRead(superblock->dataStart * 8, 8, (void*)SCRATCH_BLOCK_LOC); inode_t* inode; - if ((inode = getINode("kernel.bin")) == NULL) { + if ((inode = getInode("kernel.bin")) == NULL) { __asm__ volatile ("cli; hlt" : : "a"(0xDeadBeef)); } else { loadFile(inode, (void*)KERNEL_LOC); } - if ((inode = getINode("term16n.fnt")) == NULL) { + if ((inode = getInode("term16n.fnt")) == NULL) { __asm__ volatile ("cli; hlt" : : "a"(0xDeadBeef)); } else { loadFile(inode, (void*)FONT_LOC); }