Implemented custom filesystem and got it to compile. It seems that it isn't loading the 3rd stage bootloader though

This commit is contained in:
2024-08-12 16:30:45 +02:00
parent 044b1eceac
commit be6b65863f
7 changed files with 149 additions and 165 deletions
+20 -11
View File
@@ -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?
+53 -60
View File
@@ -1,90 +1,83 @@
#ifndef FS_H
#define FS_H
/*
* For info, read the fs-spec.txt document inside of docs/
*/
#include <stdint.h>
#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
+12 -20
View File
@@ -1,44 +1,36 @@
#ifndef IMPL_H
#define IMPL_H
#include <disk/disk.h>
#include <fs/fs.h>
#include <memory/addresses.h>
#include <disk/disk.h>
#include <stdint.h>
#include <string.h>
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;
}
+2 -1
View File
@@ -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
+53 -64
View File
@@ -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);
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)
// Constant
superblock.deviceId = 0x01;
superblock.extentsPerIndirect = FS_BLOCK_SIZE / sizeof(extent_t);
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
superblock.inodesPerSector = (FS_SECTOR_SIZE / sizeof(inode_t));
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);
+3 -3
View File
@@ -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
+5 -5
View File
@@ -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); }