Got the OS to boot from new disk image

- Pretty much rewrote stage1.asm
- Changed some addresses in stage2.asm and in memory/adresses.h
- Changed stage3.c to read root INode and it's dirEntries to find kernel.bin and term16n.fnt
- Made a fake ls command in kernel.c, just so it prints something
- Fixed makedisk.c to make the disk image properly
- Changed Makefile to compile makedisk.c and then run makedisk
- Added makedisk executable to .gitignore
This commit is contained in:
2024-06-02 19:09:33 +02:00
parent 2a9d33d733
commit 9c96636436
8 changed files with 258 additions and 174 deletions
+1
View File
@@ -1,2 +1,3 @@
build
kern.iso
makedisk
+5 -16
View File
@@ -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
+25 -12
View File
@@ -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
+9 -6
View File
@@ -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,7 +119,7 @@ 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);
@@ -195,14 +194,17 @@ 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);
// INode 2 - Bootloader (stage 3) followed by other INodes
@@ -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);
+16 -43
View File
@@ -25,10 +25,10 @@
#include <color.h>
#include <fs/fs.h>
#define PROMPT "#> "
#define PROMPT "/ #> "
// Function declarations
void printFiletable(char* ft);
void listFiles();
void printPhysicalMemmap();
__attribute__ ((section("entry")))
@@ -72,12 +72,10 @@ void main() {
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() {
+134 -64
View File
@@ -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 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
; 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]
mov dx, 0x1F2 ; Sector count port
mov al, 15 ; number of sectors to read
out dx, al
mov ah, 2 ; Read from disk
int 0x13 ; Read interrupt
inc dx ; 0x1F3 - LBA low
mov al, 1 ; LBA 1 = 2nd disk sector (0-based), bits 0-7 of LBA
out dx, al
jnc loadPrekernel
inc dx ; 0x1F4 - LBA mid
xor ax, ax ; bits 8-15 of LBA
out dx, al
dec byte [counter]
jnz .read
inc dx ; 0x1F5 - LBA high
; xor ax, ax ; bits 16-23 of LBA
out dx, al
diskErr:
mov si, diskErrMsg
mov bl, 0x04
mov ax, VIDMEM
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
.printLoop:
movsb
mov [es:di], bl
inc di
cmp byte [si], 0
jne .printLoop
cli
hlt
call loadSectorLoop
loadPrekernel:
mov byte [counter], 3
xor ax, ax
mov es, ax ; ES = 0x0000
.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
;; Jump to 2nd stage bootloader here, does not return
mov dl, [driveNum]
jmp 0x0000:0x7E00
mov ah, 2 ; Read from disk
int 0x13 ; Read interrupt
;; 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
jnc nextStage
dec byte [counter]
jnz .read
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
;; Far jump to second stage bootloader
nextStage:
mov dl, [driveNum]
jmp 0x0000:0x7e00
;; 400ns delay - Read alternate status register
mov dx, 0x3F6
in al, dx
in al, dx
in al, dx
in al, dx
;; Data
cmp bl, 0 ; Sector # to still read
je .return
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
+6 -7
View File
@@ -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
+47 -11
View File
@@ -2,34 +2,40 @@
#include <memory/virtual.h>
#include <memory/addresses.h>
#include <disk/disk.h>
#include <disk/filesys.h>
//#include <disk/filesys.h>
#include <screen/gfxmode.h>
#include <fs/fs.h>
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;
}