diff --git a/.gitignore b/.gitignore index b401568..8ba6358 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build kern.iso +makedisk diff --git a/Makefile b/Makefile index 83998c2..4a5e45d 100644 --- a/Makefile +++ b/Makefile @@ -14,24 +14,11 @@ FONTS = testfont term16n .PHONY: os clean run # Main compilation target -os: $(BUILD) filesystem +os: $(BUILD) bootloader kernel $(C_FILES) $(FONTS) + @cc ./makedisk.c -o ./makedisk + @./makedisk # TODO: List of files @echo "\nDone!\n" -# Filesystem -filesystem: bootloader kernel $(C_FILES) $(FONTS) - @echo "Building filesystem..." - @$(AS) -fbin -o $(BUILD)/filetable.bin $(SRC)/filetable.asm - @dd if=/dev/zero of=kern.iso bs=512 count=2880 status=none -# TODO: Make this not so manual - @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.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 - $(BUILD): @[ -d $(BUILD) ] || mkdir $(BUILD) @rm -rf $(BUILD)/* @@ -55,12 +42,14 @@ kernel: $(SRC)/kernel.c @$(LD) -T$(SRC)/kernel.ld -z notext --oformat binary -o $(BUILD)/kernel.bin $(BUILD)/kernel.o @rm $(BUILD)/kernel.o +# This target compiles *.c (except kernel.c) $(C_FILES): @echo "Compiling $(SRC)/$@.c..." @$(CC) $(CFLAGS) -o $(BUILD)/$@.o -c $(SRC)/$@.c @$(LD) -T$(SRC)/$@.ld -z notext --oformat binary -o $(BUILD)/$@.bin $(BUILD)/$@.o @rm $(BUILD)/$@.o +# This target builds all fonts inside src/fonts $(FONTS): @echo "Assembling $(SRC)/fonts/$@.asm..." @$(AS) -fbin -o $(BUILD)/$@.fnt $(SRC)/fonts/$@.asm diff --git a/include/memory/addresses.h b/include/memory/addresses.h index 379f73c..950e2ee 100644 --- a/include/memory/addresses.h +++ b/include/memory/addresses.h @@ -2,25 +2,28 @@ #define ADDRESSES_H /* - * Memory layout of addresses 0x0000 - 0xA000 + * Memory layout of addresses 0x0000 - 0x12000 * 0x0000-0x0fff - Probably shouldn't mess with this? idk it feels wrong * 0x1000-0x17ff - Free * 0x1800-0x1fff - Global Variables * 0x2000-0x2fff - Larger structs - * 0x3000-0x3fff - Filesystem area + * 0x3000-0x3fff - Free * 0x4000-0x4fff - Font area - * 0x6000-0x84ff - Free - * 0x8500-0x8fff - SMAP Area - * 0x9000-0x9fff - VBE info area + * 0x6000-0x6fff - VBE info area + * 0x7000-0x7bff - SMAP Area + * 0x7c00-0x8bff - Bootblock + * 0x8c00-0x9bff - Superblock (i think) + * 0x9c00-0xafff - Free + * 0xb000-0xbfff - Bootloader first INode */ -// Global Variables +// Global Variables 0x1800-0x1fff #define SLEEP_TIMER 0x1800 #define CURRENT_PAGE_DIR_ADDR 0x1804 #define PHYS_MEM_MAX_BLOCKS 0x1808 #define PHYS_MEM_USED_BLOCKS 0x180C -// Some structs +// Some structs 0x2000-0x2fff #define TERMINAL_INFO_LOC 0x2000 #define KEYBOARD_STATE_LOC 0x2100 #define DATETIME_LOC 0x2200 @@ -33,12 +36,22 @@ #define FONT_WIDTH (FONT_LOC) #define FONT_HEIGHT (FONT_LOC + 1) -// Smap Area 0x8500 - 0x8fff -#define SMAP_ENTRY_COUNT 0x8500 -#define SMAP_ENTRIES 0x8504 +// VBE Info Area 0x6000 - 0x6fff +#define MODE_INFO_BLOCK_LOC 0x6000 // 512 Bytes -// VBE Info Area 0x9000 - 0x9fff -#define MODE_INFO_BLOCK_LOC 0x9000 // 512 Bytes +// Smap Area 0x7000 - 0x7bff +#define SMAP_ENTRY_COUNT 0x7000 +#define SMAP_ENTRIES 0x7004 + +// Bootblock 0x7c00-0x9bff +#define BOOTBLOCK_LOC 0x7c00 + +// Superblock 0x9c00-0xabff +#define SUPERBLOCK_LOC 0x8c00 + +// First INode from bootloader +#define BOOT_FIRST_INODE_LOC 0xb000 +#define SCRATCH_BLOCK_LOC 0xc000 // Other addresses #define KERNEL_LOC 0x100000 diff --git a/makedisk.c b/makedisk.c index 73b3411..70bfede 100644 --- a/makedisk.c +++ b/makedisk.c @@ -83,10 +83,9 @@ int main(int argc, char** argv) { printf("Free blocks: %d (%d Bytes)\n", bytesToBlocks(diskSize) - writtenBlocks, diskSize - writtenBlocks * FS_BLOCK_SIZE); // Pad out to the whole disk size - /* 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++) { @@ -120,9 +119,9 @@ 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.firstInodeBlock + superblock.inodeBitmapBlockCount; + superblock.firstDataBitmapBlock = superblock.firstInodeBitmapBlock + superblock.inodeBitmapBlockCount; superblock.inodeBlockCount = bytesToBlocks(superblock.inodeCount * sizeof(inode_t)); - + dataBlocks = bytesToBlocks(diskSize); dataBitCount = (dataBlocks - superblock.firstDataBitmapBlock - superblock.inodeBlockCount); @@ -195,13 +194,16 @@ void writeINodeBlocks() { .id = 1, .filetype = FILETYPE_DIR, .sizeBytes = sizeof(dirEntry_t) * fileCount, - .sizeSectors = bytesToSectors(inode.sizeBytes), + // .sizeSectors = bytesToSectors(inode.sizeBytes), Set below .timestamp = defaultTimestamp, .extent[0] = (extent_t) { .firstBlock = superblock.firstDataBlock, - .length = bytesToBlocks(inode.sizeBytes), + // .length = bytesToBlocks(inode.sizeBytes), Set below }, }; + + inode.sizeSectors = bytesToSectors(inode.sizeBytes); + inode.extent[0].length = bytesToBlocks(inode.sizeBytes); assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1); @@ -216,8 +218,9 @@ void writeINodeBlocks() { inode.timestamp = defaultTimestamp; inode.extent[0] = (extent_t) { .firstBlock = block, - .length = bytesToBlocks(inode.sizeBytes), + // .length = bytesToBlocks(inode.sizeBytes), }; + inode.extent[0].length = bytesToBlocks(inode.sizeBytes); assert(fwrite(&inode, sizeof(inode), 1, imagePtr) == 1); diff --git a/src/kernel.c b/src/kernel.c index 665fb51..048ad45 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -25,10 +25,10 @@ #include #include -#define PROMPT "#> " +#define PROMPT "/ #> " // Function declarations -void printFiletable(char* ft); +void listFiles(); void printPhysicalMemmap(); __attribute__ ((section("entry"))) @@ -71,13 +71,11 @@ void main() { mallocVirtualAddr = kernelMallocVirtualAddr; mallocPhysicalAddr = kernelMallocPhysicalAddr; mallocPages = kernelMallocPages; - - // Screen setup - loadFont("term16n.fnt"); + terminal->fg = FG_COLOR; terminal->bg = BG_COLOR; clear(); - printf("kern.\n\n"); + print("kern.\n\n"); // Run Interactive Shell Program // TODO: Make it in another file @@ -174,14 +172,14 @@ void main() { printf(" exit | Exits shell\n"); printf(" gfx | Does a graphics test\n"); printf(" help | Prints this message\n"); - printf(" ls | Lists all available files\n"); + printf(" ls | Lists files in current directory\n"); printf(" memmap | Prints the memory map and info\n"); printf(" reboot | Reboots the system\n"); printf(" sleep | Sleeps for input number of seconds\n"); printf(" soundtest | Plays a tune :)\n"); printf(" test | Performs tests\n"); } else if (strcmp(argv[0], "ls") == 0) { - printFiletable(filetable); + listFiles(); } else if (strcmp(argv[0], "memmap") == 0) { printPhysicalMemmap(); } else if (strcmp(argv[0], "reboot") == 0) { @@ -269,8 +267,6 @@ void main() { mallocVirtualAddr = kernelMallocVirtualAddr; mallocPhysicalAddr = kernelMallocPhysicalAddr; mallocPages = kernelMallocPages; - } else if (strcmp(file->filetype, "tab") == 0) { - printFiletable(entryPoint); } else if (strcmp(file->filetype, "fnt") == 0) { printf("Loading %s...\n", file->filename); memcpy(entryPoint, (char*)FONT_LOC, file->length * 512); @@ -299,40 +295,17 @@ void main() { while (1); // Just hang } -void printFiletable(char* ft) { - while (*ft != '\0') { - char filename[15] = { 0 }; - uint8_t offset = 0; - for (uint8_t i = 0; i < 14; i++) { - if (i == 9) { - filename[offset++] = '.'; - continue; - } - if (*ft != '\0') { filename[offset++] = *ft; } - ft++; - } - ft++; // RESERVED - - uint8_t sector = *ft++; - uint8_t size = *ft++; - - // TODO: Use printf() here for padding - if (sector < 10) putc('0'); - if (sector == 0) putc('0'); - else printf("%d", sector); - printf(": %s", filename); - - for (uint8_t i = 14 - strlen(filename); i > 0; i--) { - printf(" "); - } - - printf(" | "); - if (size >> 1) { - printf("%d%skB\n", size >> 1, (size & 0x01) ? ".5" : ""); - } else { - printf("%dB\n", size * 512); - } - } +void listFiles() { + // TODO: Make this real + printf("Total 8\n"); + printf(". [dir]\n"); + printf(".. [dir]\n"); + printf("stage3.bin 2868B\n"); + printf("kernel.bin 13536B\n"); + printf("testfont.fnt 2048B\n"); + printf("term16n.fnt 2048B\n"); + printf("calc.bin 1724B\n"); + printf("editor.bin 1280B\n"); } void printPhysicalMemmap() { diff --git a/src/stage1.asm b/src/stage1.asm index 611d9c9..af8abb9 100644 --- a/src/stage1.asm +++ b/src/stage1.asm @@ -1,97 +1,167 @@ [bits 16] [org 0x7c00] -[global start] -%define VIDMEM 0xb800 -%define FILETAB_LOC 0x7000 +%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 start: - mov [driveNum], dl ; Store the drive number xor ax, ax mov es, ax - mov ds, ax + mov ds, ax + + mov byte [driveNum], dl ; Clear screen mov ax, 0x03 int 0x10 - ; Reset disk - mov ah, 0x0 - mov dl, [driveNum] - int 0x13 + ;; Read in the boot block and the superblock to memory for 2nd stage bootloader + mov al, 15 ; 8 - 1 for boot block - bootsector & 8 for super block + mov bl, al + dec bl ; Number of sectors - 1 + mov di, 0x7E00 ; Destination 0x7c00-0x8c00 = boot block, 0x8c00-0x9c00 = superblock -.read: - ; Location - mov ax, 0 - mov es, ax - mov bx, 0x7e00 ; 2nd stage bootloader location + mov dx, 0x1F6 ; flags + mov al, 0xE0 ; 0b0111 0000, bits: 0-3 = LBA bits 24-27, 4 = drive, 5 = always set, 6 = set for LBA, 7 = always set + out dx, al + + mov dx, 0x1F2 ; Sector count port + mov al, 15 ; number of sectors to read + out dx, al + + inc dx ; 0x1F3 - LBA low + mov al, 1 ; LBA 1 = 2nd disk sector (0-based), bits 0-7 of LBA + out dx, al + + inc dx ; 0x1F4 - LBA mid + xor ax, ax ; bits 8-15 of LBA + out dx, al + + inc dx ; 0x1F5 - LBA high + ; xor ax, ax ; bits 16-23 of LBA + out dx, al + + inc dx + inc dx ; 0x1F7 - Command port + mov al, 0x20 ; Read with retry + out dx, al + + call loadSectorLoop + + ;; Parse superblock for first inode block, offset to reserved bootloader + + ;; Read first inode block to memory + ;; Each disk block is 4KB or 8 sectors of 512 bytes + imul cx, [FIRST_INODE_BLOCK], 8 ; CX = disk sector/LBA of first inode block + + mov bl, 7 ; 8 sectors for a block - 1 + mov di, 0xb000 ; Address to read into, first inode block = 0xB000-0xC000 + + mov dx, 0x1F6 ; flags + mov al, 0xE0 + out dx, al + + mov dx, 0x1F2 + mov al, 8 + out dx, al + + inc dx + mov al, cl + out dx, al + + inc dx + mov al, ch + out dx, al + + inc dx + xor ax, ax + out dx, al + + inc dx + inc dx + mov al, 0x20 + out dx, al + + call loadSectorLoop + + ;; Read boot loader inode to memory + ;; inode 2, each inode is 64 bytes in size + imul ecx, [EXTENT0], 8 ; first_block translated to disk sector/LBA + imul ebx, [EXTENT0+4], 8 ; length_blocks translated to disk sectors/LBAs + + mov dx, 0x1F2 + mov al, bl + out dx, al + + inc dx + mov al, cl + out dx, al + + inc dx + mov al, ch + out dx, al + + inc dx + shr ecx, 16 + mov al, cl + out dx, al + + inc dx + and ch, 0x0F + mov al, ch + or al, 0xE0 + out dx, al + + inc dx + mov al, 0x20 + out dx, al + + dec bl + mov ax, 0x5000 + mov es, ax + xor di, di + + call loadSectorLoop + + xor ax, ax + mov es, ax ; ES = 0x0000 + + ;; Jump to 2nd stage bootloader here, does not return + mov dl, [driveNum] + jmp 0x0000:0x7E00 + + ;; Poll status port after reading 1 sector +loadSectorLoop: + in al, dx ; Status register (reading port 1F7h) + test al, 8 ; Sector buffer requires servicing + je loadSectorLoop ; Keep trying until sector buffer is ready + + mov cx, 256 ; # of words to read for 1 sector + mov dx, 0x1F0 ; Data port, reading + rep insw ; Read bytes from DX port # into DI, CX # of times - ; CHS Location - mov al, 4 ; Number of sectors to read (4 = 2kB) - mov ch, 0 ; Cylinder - mov dh, 0 ; Head - mov cl, 2 ; Sector - mov dl, [driveNum] + ;; 400ns delay - Read alternate status register + mov dx, 0x3F6 + in al, dx + in al, dx + in al, dx + in al, dx - mov ah, 2 ; Read from disk - int 0x13 ; Read interrupt + cmp bl, 0 ; Sector # to still read + je .return - jnc loadPrekernel - - dec byte [counter] - jnz .read - -diskErr: - mov si, diskErrMsg - mov bl, 0x04 - mov ax, VIDMEM - mov es, ax - xor di, di -.printLoop: - movsb - mov [es:di], bl - inc di - cmp byte [si], 0 - jne .printLoop - - cli - hlt - -loadPrekernel: - mov byte [counter], 3 - -.read: - ; Location - mov ax, 0x5000 ; Making es 0x5000 will load the prekernel at 0x50000 - mov es, ax - xor bx, bx - - ; CHS Location - mov al, 10 ; Prekernel size - mov ch, 0 ; Cylinder - mov dh, 0 ; Head - mov cl, 6 ; Sector - mov dl, [driveNum] - - mov ah, 2 ; Read from disk - int 0x13 ; Read interrupt - - jnc nextStage - dec byte [counter] - jnz .read - -;; Far jump to second stage bootloader -nextStage: - mov dl, [driveNum] - jmp 0x0000:0x7e00 - -;; Data + dec bl + mov dx, 0x1F7 + jmp loadSectorLoop +.return: + ret + +;; VARIABLES driveNum: db 0 -counter: db 3 -; Strings -diskErrMsg: db "Failed while reading from disk!", 0 - -times 510-($-$$) db 0 +;; Boot sector magic +times 510-($-$$) db 0 ; Padding dw 0xaa55 diff --git a/src/stage2.asm b/src/stage2.asm index a91718c..8b70dc0 100644 --- a/src/stage2.asm +++ b/src/stage2.asm @@ -2,8 +2,7 @@ [org 0x7e00] %define STAGE3_LOC 0x50000 -%define VIDMEM 0xb800 -%define MODE_INFO_BLOCK_LOC 0x9000 +%define MODE_INFO_BLOCK_LOC 0x6000 start: mov [driveNum], dl @@ -12,9 +11,9 @@ start: xor ax, ax mov es, ax -memMapEntries equ 0x8500 +memMapEntries equ 0x7000 getMemoryMap: - mov di, 0x8504 ; 4 bytes after memMapEntries + mov di, memMapEntries + 4 ; 4 bytes after memMapEntries xor ebx, ebx xor bp, bp mov edx, "PAMS" ; SMAP in little endian @@ -370,9 +369,9 @@ DATA_SEG equ GDT.dataDescriptor - GDT.start ;; VBE Stuff ;; !! IF YOU WANT TO SELECT ANY VALUE IN THE SETUP, SET THESE TO ZERO !! -width: dw 1920 -height: dw 1080 -bpp: db 32 +width: dw 0 +height: dw 0 +bpp: db 0 offset: dw 0 _segment: dw 0 ; segment is a keyword diff --git a/src/stage3.c b/src/stage3.c index dff2b36..b10eabc 100644 --- a/src/stage3.c +++ b/src/stage3.c @@ -2,34 +2,40 @@ #include #include #include -#include +//#include #include +#include + +uint8_t loadFile(char* filename, void* dest); + __attribute__ ((section("entry"))) void main() { - diskRead(15, 1, filetable); // Load filetable into memory; TODO: Make a filetableUpdate() function that just keeps the stored and memory verisons in sync - // Physical memory manager setup uint32_t smapEntryCount = *(uint32_t*)SMAP_ENTRY_COUNT; - smapEntry_t* smapEntries = (smapEntry_t*)SMAP_ENTRIES; // After a unit32_t - uint32_t totalMemory = smapEntries[smapEntryCount - 1].baseAddress + smapEntries[smapEntryCount - 1].length - 1; + smapEntry_t* smapEntries = (smapEntry_t*)SMAP_ENTRIES; + smapEntries += smapEntryCount - 1; + uint32_t totalMemory = smapEntries->baseAddress + smapEntries->length - 1; setupPhysicalMemoryManager(MEMMAP_AREA, totalMemory); + smapEntries = (smapEntry_t*)SMAP_ENTRIES; for (uint32_t i = 0; i < smapEntryCount; i++) { if (smapEntries[i].type == 1) { initMemoryRegion(smapEntries[i].baseAddress, smapEntries[i].length); } } - deinitMemoryRegion(0x1000, 0x9000); // Reserve kernel memory (under 0xa000) + deinitMemoryRegion(0x1000, 0x11000); // Reserve kernel memory (under 0x12000) deinitMemoryRegion(MEMMAP_AREA, maxBlocks / BLOCKS_PER_BYTE); - // Load kernel into memory - if (readFile("kernel.bin", (void*)KERNEL_LOC) != 0) { // Check if kernel.bin was loaded - // TODO: Add error messages - while (1); - } + // 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); + + if (loadFile("kernel.bin", (void*)KERNEL_LOC) != 0) __asm__ volatile ("cli; hlt" : : "a"(0xDeadBeef)); + if (loadFile("term16n.fnt", (void*)FONT_LOC) != 0) __asm__ volatile ("cli; hlt" : : "a"(0xDeadBeef)); // Virtual memory manager setup if (setupVirtualMemoryManager() != 0) { @@ -60,3 +66,33 @@ void main() { ((void(*)(void))0xC0000000)(); } +uint8_t loadFile(char* filename, void* dest) { + dirEntry_t* dirEntry = (dirEntry_t*)SCRATCH_BLOCK_LOC; + while (dirEntry->name[0] != '\0') { + if (strcmp(dirEntry->name, filename) == 0) break; + dirEntry++; + } + + if (dirEntry->name[0] == '\0') return 1; + + inode_t* inode = (inode_t*)BOOT_FIRST_INODE_LOC; + while (inode->id != dirEntry->id) { + inode++; + } + + uint32_t totalBlocks = bytesToBlocks(inode->sizeBytes); + uint32_t addressOffset = 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; + totalBlocks -= inode->extent[i].length; + } + + if (totalBlocks > 0) { + // TODO: Indirect extents + } + + return 0; +} +