From 1e5b4a765b83058171299fededcb46c3a65abe78 Mon Sep 17 00:00:00 2001 From: David Goeke Date: Fri, 13 Jun 2025 18:03:39 -0500 Subject: [PATCH] Espresso 0.0.0e --- Makefile | 6 +- drivers/fs/fat32.c | 1 - drivers/gdt.c | 52 ++++-- drivers/gdt_ec.c | 0 drivers/idt.c | 228 ++++++++++++----------- drivers/irq.c | 9 + drivers/isr.c | 42 ----- drivers/pit.c | 32 ++++ drivers/ps2_keyboard.c | 90 +-------- drivers/timer.c | 21 +++ drivers/tty.c | 5 +- gdt.asm | 7 +- idt.asm | 40 ---- include/drivers/gdt_ec.c | 8 + include/drivers/gdt_ec.h | 50 +++++ include/drivers/idt.h | 13 ++ include/drivers/irq.h | 8 + include/drivers/pit.h | 2 + include/drivers/ps2_keyboard.h | 2 - include/drivers/timer.h | 11 ++ include/fs/fat32.h | 3 +- include/gdt.h | 18 +- include/idt.h | 25 --- include/io.h | 3 +- include/isr.h | 23 --- include/kernel/{intro_anim.h => intro.h} | 0 include/kernel/syscalls.h | 8 - include/printf.h | 1 + isr.asm | 167 +++++++++++++++++ isr.old.asm | 97 ++++++++++ isr128.asm | 34 ---- isr_stub_table.asm | 87 --------- kernel/boot.c | 3 +- kernel/{intro_anim.c => intro.c} | 2 +- kernel/kernel.c | 46 +++-- kernel/syscalls.c | 10 - lib/mm/paging.c | 47 +++-- lib/printf.c | 120 +++++++----- misc_asm.s | 12 ++ pit.asm | 127 ------------- 40 files changed, 742 insertions(+), 718 deletions(-) create mode 100644 drivers/gdt_ec.c create mode 100644 drivers/irq.c delete mode 100644 drivers/isr.c create mode 100644 drivers/timer.c delete mode 100644 idt.asm create mode 100644 include/drivers/gdt_ec.c create mode 100644 include/drivers/gdt_ec.h create mode 100644 include/drivers/idt.h create mode 100644 include/drivers/irq.h create mode 100644 include/drivers/timer.h delete mode 100644 include/idt.h delete mode 100644 include/isr.h rename include/kernel/{intro_anim.h => intro.h} (100%) delete mode 100644 include/kernel/syscalls.h create mode 100644 isr.asm create mode 100644 isr.old.asm delete mode 100644 isr128.asm delete mode 100644 isr_stub_table.asm rename kernel/{intro_anim.c => intro.c} (97%) delete mode 100644 kernel/syscalls.c diff --git a/Makefile b/Makefile index d7955e0..8fd1d52 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,8 @@ CC := i686-elf-gcc AS := i686-elf-as NASM := nasm QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M +MKFS_VFAT := sudo mkfs.vfat +MKFS_FLAGS := -F 32 --mbr -S 512 NASMFLAGS := -f elf32 WNOFLAGS := -Wno-discarded-qualifiers CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) @@ -21,7 +23,7 @@ GRUB_CFG := grub.cfg # === File collection === C_SRCS := $(foreach dir, $(SRC_DIRS), $(shell find $(dir) -name '*.c')) S_SRCS := boot.s crti.s crtn.s misc_asm.s -NASM_SRCS := idt.asm isr128.asm gdt.asm isr_stub_table.asm pit.asm +NASM_SRCS := gdt.asm pit.asm isr.asm CRTI_OBJ := crti.o CRTBEGIN_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o) CRTEND_OBJ := $(shell $(CC) $(CFLAGS) -print-file-name=crtend.o) @@ -64,6 +66,8 @@ iso: $(TARGET) # === Run in QEMU === run: iso $(QEMU_MKE_IMG) + echo "\n" + $(MKFS_VFAT) $(MKFS_FLAGS) espresso.img qemu-system-i386 $(QEMUFLAGS) # === Clean all build artifacts === diff --git a/drivers/fs/fat32.c b/drivers/fs/fat32.c index ffa17aa..859c5eb 100644 --- a/drivers/fs/fat32.c +++ b/drivers/fs/fat32.c @@ -44,7 +44,6 @@ int32_t fat32_init(int32_t drive) memcpy(&bpb, sector, sizeof(bpb)); - fat_start_lba = bpb.reserved_sector_count; cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32; current_directory_cluster = bpb.root_cluster; diff --git a/drivers/gdt.c b/drivers/gdt.c index 99e06ec..ad27348 100644 --- a/drivers/gdt.c +++ b/drivers/gdt.c @@ -1,34 +1,52 @@ +#include + #include +#include +#define GDT_ENTRIES 5 +uint64_t gdt[GDT_ENTRIES]; -#define GDT_ENTRIES 3 +struct { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) gp; -struct gdt_entry gdt[GDT_ENTRIES]; -struct gdt_ptr gp; extern void gdt_flush(uint32_t); -void gdt_install() +void gdt_install(bool prnt_gdt) { - gp.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1; - gp.base = (uint32_t)&gdt; + create_descriptor(0, 0, 0, 0, prnt_gdt); // Null + create_descriptor(1, 0, 0x000FFFFF, GDT_CODE_PL0, prnt_gdt); // Kernel code + create_descriptor(2, 0, 0x000FFFFF, GDT_DATA_PL0, prnt_gdt); // Kernel data + create_descriptor(3, 0, 0x000FFFFF, GDT_CODE_PL3, prnt_gdt); // User code + create_descriptor(4, 0, 0x000FFFFF, GDT_DATA_PL3, prnt_gdt); // User data - gdt_set_entry(0, 0, 0, 0, 0); /* Null segment */ - gdt_set_entry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */ - gdt_set_entry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */ + gp.limit = sizeof(gdt) - 1; + gp.base = (uint32_t)&gdt; gdt_flush((uint32_t)&gp); } -void gdt_set_entry(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) +void create_descriptor(int index, uint32_t base, uint32_t limit, uint16_t flag, bool prnt_gdt) { - gdt[num].base_low = (base & 0xFFFF); - gdt[num].base_middle = (base >> 16) & 0xFF; - gdt[num].base_high = (base >> 24) & 0xFF; + uint64_t descriptor; - gdt[num].limit_low = (limit & 0xFFFF); - gdt[num].granularity = (limit >> 16) & 0x0F; + descriptor = limit & 0x000F0000; // limit bits 19:16 + descriptor |= (flag << 8) & 0x00F0FF00; // flags and access + descriptor |= (base >> 16) & 0x000000FF; // base bits 23:16 + descriptor |= base & 0xFF000000; // base bits 31:24 - gdt[num].granularity |= (gran & 0xF0); - gdt[num].access = access; + descriptor <<= 32; + + descriptor |= ((uint64_t)base << 16); // base bits 15:0 + descriptor |= (limit & 0x0000FFFF); // limit bits 15:0 + + gdt[index] = descriptor; + + if (prnt_gdt) + { + printf("GDT[%d] = 0x%llX\n", index, descriptor); + } } + diff --git a/drivers/gdt_ec.c b/drivers/gdt_ec.c new file mode 100644 index 0000000..e69de29 diff --git a/drivers/idt.c b/drivers/idt.c index b5810de..04003ea 100644 --- a/drivers/idt.c +++ b/drivers/idt.c @@ -1,131 +1,141 @@ -#include +#include #include -#include +#include -#define IDT_ENTRIES 256 -struct idt_entry idt[IDT_ENTRIES]; -struct idt_ptr idtp; +#define IDT_MAX_DESCRIPTORS 256 -extern void idt_load(uint32_t); +#define PIC1_COMMAND 0x20 +#define PIC1_DATA 0x21 +#define PIC2_COMMAND 0xA0 +#define PIC2_DATA 0xA1 -void idt_install(void) +/* + Most of the code is this file (and idt.h) are taken from the osdev wiki: https://wiki.osdev.org/Interrupts_Tutorial, though not all of it. +*/ + +typedef struct { + uint16_t isr_low; // The lower 16 bits of the ISR's address + uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR + uint8_t reserved; // Set to zero + uint8_t attributes; // Type and attributes; see the IDT page + uint16_t isr_high; // The higher 16 bits of the ISR's address +} __attribute__((packed)) idt_entry_t; + +typedef struct { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) idtr_t; + +__attribute__((aligned(0x10))) + +static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance + +static idtr_t idtr; + +static bool vectors[IDT_MAX_DESCRIPTORS]; + +extern void* isr_stub_table[]; + + +__attribute__((noreturn)) +void exception_dispatcher(uint32_t int_no, uint32_t err_code) { - idtp.limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1; - idtp.base = (uint32_t)&idt; + switch (int_no) + { + case 0: + printf("Divide by zero exception\n"); + break; + case 13: + printf("General Protection Fault: err=0x%x\n", err_code); + break; + case 14: + { + uint32_t cr2; + __asm__ volatile ("mov %%cr2, %0" : "=r"(cr2)); + printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code); + break; + } + default: + printf("Unhandled exception #%u, err=0x%x\n", int_no, err_code); + break; + } - memset(&idt, 0, sizeof(struct idt_entry) * IDT_ENTRIES); + uint16_t cs, ds, es, ss; + asm volatile ("mov %%cs, %0" : "=r"(cs)); + asm volatile ("mov %%ds, %0" : "=r"(ds)); + asm volatile ("mov %%es, %0" : "=r"(es)); + asm volatile ("mov %%ss, %0" : "=r"(ss)); - /* Set entries for IRQs/ISRs here using `idt_set_entry(...)` */ - /* Example: idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E); */ + printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss); - idt_load((uint32_t)&idtp); + __asm__ volatile ("cli; hlt"); +} + + + +void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) { + idt_entry_t* descriptor = &idt[vector]; + + descriptor->isr_low = (uint32_t)isr & 0xFFFF; + descriptor->kernel_cs = 0x08; + descriptor->attributes = flags; + descriptor->isr_high = (uint32_t)isr >> 16; + descriptor->reserved = 0; } void pic_remap(void) { - outb(0x20, 0x11); /* Start init for master PIC */ - outb(0xA0, 0x11); /* Start init for slave PIC */ - outb(0x21, 0x20); /* Master PIC vector offset */ - outb(0xA1, 0x28); /* Slave PIC vector offset */ - outb(0x21, 0x04); /* Tell Master PIC about Slave PIC at IRQ2 */ - outb(0xA1, 0x02); /* Tell Slave PIC its cascade identity */ - outb(0x21, 0x01); /* 8086/88 mode */ - outb(0xA1, 0x01); - outb(0x21, 0x0); /* Unmask master */ - outb(0xA1, 0x0); /* Unmask slave */ + uint8_t a1, a2; + + // Save masks + a1 = inb(PIC1_DATA); + a2 = inb(PIC2_DATA); + + // Start initialization sequence (in cascade mode) + outb(PIC1_COMMAND, 0x11); + outb(PIC2_COMMAND, 0x11); + + // Set vector offset + outb(PIC1_DATA, 0x20); // IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) + outb(PIC2_DATA, 0x28); // IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) + + // Tell Master PIC about Slave PIC at IRQ2 (0000 0100) + outb(PIC1_DATA, 0x04); + + // Tell Slave PIC its cascade identity (0000 0010) + outb(PIC2_DATA, 0x02); + + // Set 8086/88 mode + outb(PIC1_DATA, 0x01); + outb(PIC2_DATA, 0x01); + + // Restore saved masks + outb(PIC1_DATA, a1); + outb(PIC2_DATA, a2); } -void idt_set_entry(int num, uint32_t base, uint16_t sel, uint8_t flags) +void idt_init(void) { - idt[num].base_low = base & 0xFFFF; - idt[num].base_high = (base >> 16) & 0xFFFF; + idtr.base = (uintptr_t)&idt[0]; + idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1; - idt[num].sel = sel; - idt[num].always0 = 0; - idt[num].flags = flags; -} - -extern void IRQ0_handler(void); -extern void isr0(void); -extern void isr1(void); -extern void isr2(void); -extern void isr3(void); -extern void isr4(void); -extern void isr5(void); -extern void isr6(void); -extern void isr7(void); -extern void isr8(void); -extern void isr9(void); -extern void isr10(void); -extern void isr11(void); -extern void isr12(void); -extern void isr13(void); -extern void isr14(void); -extern void isr15(void); -extern void isr16(void); -extern void isr17(void); -extern void isr18(void); -extern void isr19(void); -extern void isr20(void); -extern void isr21(void); -extern void isr22(void); -extern void isr23(void); -extern void isr24(void); -extern void isr25(void); -extern void isr26(void); -extern void isr27(void); -extern void isr28(void); -extern void isr29(void); -extern void isr30(void); -extern void isr31(void); - -extern void isr33(void); - -extern void isr128(void); - - -void idt_install_isrs(void) -{ - idt_set_entry(0, (uint32_t)isr0, 0x08, 0x8E); - idt_set_entry(1, (uint32_t)isr1, 0x08, 0x8E); - idt_set_entry(2, (uint32_t)isr2, 0x08, 0x8E); - idt_set_entry(3, (uint32_t)isr3, 0x08, 0x8E); - idt_set_entry(4, (uint32_t)isr4, 0x08, 0x8E); - idt_set_entry(5, (uint32_t)isr5, 0x08, 0x8E); - idt_set_entry(6, (uint32_t)isr6, 0x08, 0x8E); - idt_set_entry(7, (uint32_t)isr7, 0x08, 0x8E); - idt_set_entry(8, (uint32_t)isr8, 0x08, 0x8E); - idt_set_entry(9, (uint32_t)isr9, 0x08, 0x8E); - idt_set_entry(10, (uint32_t)isr10, 0x08, 0x8E); - idt_set_entry(11, (uint32_t)isr11, 0x08, 0x8E); - idt_set_entry(12, (uint32_t)isr12, 0x08, 0x8E); - idt_set_entry(13, (uint32_t)isr13, 0x08, 0x8E); - idt_set_entry(14, (uint32_t)isr14, 0x08, 0x8E); - idt_set_entry(15, (uint32_t)isr15, 0x08, 0x8E); - idt_set_entry(16, (uint32_t)isr16, 0x08, 0x8E); - idt_set_entry(17, (uint32_t)isr17, 0x08, 0x8E); - idt_set_entry(18, (uint32_t)isr18, 0x08, 0x8E); - idt_set_entry(19, (uint32_t)isr19, 0x08, 0x8E); - idt_set_entry(20, (uint32_t)isr20, 0x08, 0x8E); - idt_set_entry(21, (uint32_t)isr21, 0x08, 0x8E); - idt_set_entry(22, (uint32_t)isr22, 0x08, 0x8E); - idt_set_entry(23, (uint32_t)isr23, 0x08, 0x8E); - idt_set_entry(24, (uint32_t)isr24, 0x08, 0x8E); - idt_set_entry(25, (uint32_t)isr25, 0x08, 0x8E); - idt_set_entry(26, (uint32_t)isr26, 0x08, 0x8E); - idt_set_entry(27, (uint32_t)isr27, 0x08, 0x8E); - idt_set_entry(28, (uint32_t)isr28, 0x08, 0x8E); - idt_set_entry(29, (uint32_t)isr29, 0x08, 0x8E); - idt_set_entry(30, (uint32_t)isr30, 0x08, 0x8E); - idt_set_entry(31, (uint32_t)isr31, 0x08, 0x8E); + for (uint8_t vector = 0; vector < 32; vector++) + { + idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); + vectors[vector] = true; + } - idt_set_entry(33, (uint32_t)isr33, 0x08, 0x8E); + extern void* irq_stub_table[]; + for (uint8_t i = 0; i < 16; i++) + { + idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E); + } + + + __asm__ volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */ + __asm__ volatile ("sti"); /* set the interrupt flag */ } -void idt_install_syscall(void) -{ - idt_set_entry(128, (uint32_t)isr128, 0x08, 0xEE); -} diff --git a/drivers/irq.c b/drivers/irq.c new file mode 100644 index 0000000..baa9442 --- /dev/null +++ b/drivers/irq.c @@ -0,0 +1,9 @@ + + +#include + + +void irq_handler(uint8_t irq_number) +{ + +} diff --git a/drivers/isr.c b/drivers/isr.c deleted file mode 100644 index 2b95b16..0000000 --- a/drivers/isr.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -#include - - -void (*irq_handlers[256])(isr_stack_t *r) = { 0 }; - -void register_interrupt_handler(uint8_t n, void (*handler)(isr_stack_t *)) -{ - irq_handlers[n] = handler; -} - -void isr_handler(isr_stack_t *r) -{ - if (irq_handlers[r->int_no]) { - irq_handlers[r->int_no](r); - } else { - printf("Unhandled interrupt: %d\n", r->int_no); - } - - - /* Send EOI to PIC */ - if (r->int_no >= 40) - { - outb(0xA0, 0x20); - } - if (r->int_no >= 32) - { - outb(0x20, 0x20); - } -} - -void syscall_handler(regs_t *r) -{ - switch (r->eax) { - case 0: printf("Syscall: Hello world\n"); break; - case 1: printf("Syscall: value = %d\n", r->ebx); break; - default: printf("Unknown syscall %d\n", r->eax); - } -} - diff --git a/drivers/pit.c b/drivers/pit.c index e69de29..b6c89bc 100644 --- a/drivers/pit.c +++ b/drivers/pit.c @@ -0,0 +1,32 @@ +/*#include +#include +#include + +#define PIT_CHANNEL0 0x40 +#define PIT_COMMAND 0x43 +#define PIT_FREQUENCY 1193182 + +static uint32_t tick = 0; + +void pit_callback(struct regs* r) +{ + (void)r; + tick++; +} + +void pit_init(uint32_t frequency) +{ + uint32_t divisor = PIT_FREQUENCY / frequency; + + outb(PIT_COMMAND, 0x36); + outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF)); + outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); + + register_interrupt_handler(32, pit_callback); +} + +void sleep(uint32_t milliseconds) +{ + uint32_t target = tick + milliseconds; + while (tick < target); +}*/ diff --git a/drivers/ps2_keyboard.c b/drivers/ps2_keyboard.c index 794fc44..87a0396 100644 --- a/drivers/ps2_keyboard.c +++ b/drivers/ps2_keyboard.c @@ -5,94 +5,18 @@ /* -PS/2 Controller IO Ports + PS/2 Controller IO Ports -The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers. + The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers. -Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles. -IO Port Access Type Purpose -0x60 Read/Write Data Port -0x64 Read Status Register -0x64 Write Command Register + Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles. + IO Port Access Type Purpose + 0x60 Read/Write Data Port + 0x64 Read Status Register + 0x64 Write Command Register */ -#define PS2_DATA_PORT 0x60 -#define PS2_STATUS_PORT 0x64 - -#define KEYBOARD_IRQ 33 - -/*extern void register_interrupt_handler(int irq, void (*handler)(void));*/ - -static const char scancode_map[128] = { - 0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */ - '\t', /* Tab */ - 'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */ - 0, /* Control */ - 'a','s','d','f','g','h','j','k','l',';','\'','`', - 0, /* Left shift */ - '\\','z','x','c','v','b','n','m',',','.','/', - 0, /* Right shift */ - '*', - 0, /* Alt */ - ' ', /* Spacebar */ - 0, /* Caps lock */ - /* The rest are function and control keys */ -}; - -static bool shift_pressed = false; - -void keyboard_handler(isr_stack_t* regs) -{ - (void)regs; /* Only here to dismiss the "Unused parameter" warnings */ - printd("PS/2 Keyboard handler fired!\n"); - - uint8_t scancode = inb(PS2_DATA_PORT); - - /* Handle shift press/release */ - if (scancode == 0x2A || scancode == 0x36) - { - shift_pressed = true; - return; - } - else if (scancode == 0xAA || scancode == 0xB6) - { - shift_pressed = false; - return; - } - - if (scancode & 0x80) - { - /* Key release event, ignore for now */ - } - else - { - char c = scancode_map[scancode]; - if (shift_pressed && c >= 'a' && c <= 'z') - { - c -= 32; /* Convert to uppercase */ - } - - if (c) - { - /* Do something with the keypress (e.g., print or buffer) */ - printf("Char: %c", c); - } - } - - outb(0x20, 0x20); /* Acknowledge PIC */ -} - -void test_handler(isr_stack_t* r) { - printf("IRQ1 fired!\n"); -} - - void keyboard_init(void) { - outb(0x21, inb(0x21) & ~0x02); - register_interrupt_handler(KEYBOARD_IRQ, test_handler); - - /* Enable keyboard (controller-specific, often optional if already working) */ - //outb(0x64, 0xAE); } diff --git a/drivers/timer.c b/drivers/timer.c new file mode 100644 index 0000000..552659f --- /dev/null +++ b/drivers/timer.c @@ -0,0 +1,21 @@ +/*#include +#include + +#include + +volatile uint32_t tick_count = 0; + +void irq0_handler(regs_t* regs) +{ + tick_count++; +} + +void timer_sleep(uint32_t ms) +{ + uint32_t target = tick_count + ms; + while (tick_count < target) + { + asm volatile("hlt"); + } +} +*/ diff --git a/drivers/tty.c b/drivers/tty.c index c61e467..4d46a38 100644 --- a/drivers/tty.c +++ b/drivers/tty.c @@ -151,7 +151,10 @@ void terminal_clearl(size_t num_lines) while (terminal_row < num_lines) { - terminal_writechar_r(' '); + for (int32_t k = 0; k < (int32_t)VGA_WIDTH; k++) + { + terminal_putentryat((unsigned char)' ', terminal_getcolor(), (size_t)terminal_row, (size_t)k); + } terminal_row -= 1; } } diff --git a/gdt.asm b/gdt.asm index 9b9fa94..d3be992 100644 --- a/gdt.asm +++ b/gdt.asm @@ -3,13 +3,12 @@ global gdt_flush gdt_flush: mov eax, [esp + 4] lgdt [eax] - ; Reload segment registers - mov ax, 0x10 ; Kernel data segment + jmp 0x08:.flush_label ; long jump to reload CS with new segment +.flush_label: + mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax - jmp 0x08:.flush ; Kernel code segment -.flush: ret diff --git a/idt.asm b/idt.asm deleted file mode 100644 index 4bdeb86..0000000 --- a/idt.asm +++ /dev/null @@ -1,40 +0,0 @@ -[bits 32] -global idt_load -global common_isr_stub - -extern isr_handler -extern _push_regs -extern _pop_regs - -idt_load: - mov eax, [esp + 4] - lidt [eax] - ret - -common_isr_stub: - call _push_regs ; Push all general-purpose registers - push ds - push es - push fs - push gs - - mov ax, 0x10 ; Load kernel data segment - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - push esp ; Pass pointer to the register state - call isr_handler ; Call your C ISR handler - - add esp, 4 ; Clean up stack from push esp - pop gs - pop fs - pop es - pop ds - - call _pop_regs ; restore all general-purpose registers - - add esp, 8 ; Remove int_no and err_code - sti - iret diff --git a/include/drivers/gdt_ec.c b/include/drivers/gdt_ec.c new file mode 100644 index 0000000..aa6b3a3 --- /dev/null +++ b/include/drivers/gdt_ec.c @@ -0,0 +1,8 @@ +#ifndef _GDT_EC_H +#define _GDT_EC_H + +#include + +void create_descriptor(uint32_t base, uint32_t limit, uint16_t flag); + +#endif diff --git a/include/drivers/gdt_ec.h b/include/drivers/gdt_ec.h new file mode 100644 index 0000000..fe151ca --- /dev/null +++ b/include/drivers/gdt_ec.h @@ -0,0 +1,50 @@ +#ifndef _GDT_EC_H +#define _GDT_EC_H + +#include + +// Each define here is for a specific flag in the descriptor. +// Refer to the intel documentation for a description of what each one does. +#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data) +#define SEG_PRES(x) ((x) << 0x07) // Present +#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use +#define SEG_LONG(x) ((x) << 0x0D) // Long mode +#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32) +#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) +#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3) + +#define SEG_DATA_RD 0x00 // Read-Only +#define SEG_DATA_RDA 0x01 // Read-Only, accessed +#define SEG_DATA_RDWR 0x02 // Read/Write +#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed +#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down +#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed +#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down +#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed +#define SEG_CODE_EX 0x08 // Execute-Only +#define SEG_CODE_EXA 0x09 // Execute-Only, accessed +#define SEG_CODE_EXRD 0x0A // Execute/Read +#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed +#define SEG_CODE_EXC 0x0C // Execute-Only, conforming +#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed +#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming +#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed + +#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_EXRD + +#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_DATA_RDWR + +#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_CODE_EXRD + +#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_DATA_RDWR + + +#endif diff --git a/include/drivers/idt.h b/include/drivers/idt.h new file mode 100644 index 0000000..8921162 --- /dev/null +++ b/include/drivers/idt.h @@ -0,0 +1,13 @@ +#ifndef _IDT_H +#define _IDT_H + +#include + + +void idt_init(void); +void pic_remap(void); +void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags); +void exception_dispatcher(uint32_t int_no, uint32_t err_code); + + +#endif diff --git a/include/drivers/irq.h b/include/drivers/irq.h new file mode 100644 index 0000000..d5b53cc --- /dev/null +++ b/include/drivers/irq.h @@ -0,0 +1,8 @@ +#ifndef _IRQ_H +#define _IRQ_H + +#include + +void irq_handler(uint8_t irq_number); + +#endif diff --git a/include/drivers/pit.h b/include/drivers/pit.h index f8fd0d0..291e3db 100644 --- a/include/drivers/pit.h +++ b/include/drivers/pit.h @@ -3,5 +3,7 @@ #include +void pit_init(uint32_t freq); +void sleep(uint32_t millis); #endif diff --git a/include/drivers/ps2_keyboard.h b/include/drivers/ps2_keyboard.h index 76c5184..e6c349b 100644 --- a/include/drivers/ps2_keyboard.h +++ b/include/drivers/ps2_keyboard.h @@ -2,9 +2,7 @@ #define _PS2_KEYBOARD_H #include -#include void keyboard_init(void); -void keyboard_handler(isr_stack_t* regs); #endif diff --git a/include/drivers/timer.h b/include/drivers/timer.h new file mode 100644 index 0000000..b7a8d67 --- /dev/null +++ b/include/drivers/timer.h @@ -0,0 +1,11 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#include + +extern volatile uint32_t tick_count; + +void timer_sleep(uint32_t ms); +void pit_init(uint32_t frequency); + +#endif diff --git a/include/fs/fat32.h b/include/fs/fat32.h index 4c498be..bc40795 100644 --- a/include/fs/fat32.h +++ b/include/fs/fat32.h @@ -1,6 +1,7 @@ #ifndef _FAT32_H #define _FAT32_H -#include + +#include #define FAT32_MAX_FILENAME 11 #define FAT32_ATTR_DIRECTORY 0x10 diff --git a/include/gdt.h b/include/gdt.h index f66d62d..4362736 100644 --- a/include/gdt.h +++ b/include/gdt.h @@ -3,21 +3,7 @@ #include -struct gdt_entry { - uint16_t limit_low; /* Lower 16 bits of limit */ - uint16_t base_low; /* Lower 16 bits of base */ - uint8_t base_middle; /* Next 8 bits of base */ - uint8_t access; /* Access flags */ - uint8_t granularity; /* Granularity + high 4 bits of limit */ - uint8_t base_high; /* Last 8 bits of base */ -} __attribute__((packed)); - -struct gdt_ptr { - uint16_t limit; /* Size of GDT - 1 */ - uint32_t base; /* Base address of GDT */ -} __attribute__((packed)); - -void gdt_install(); -void gdt_set_entry(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran); +void gdt_install(bool prnt_gdt); +void create_descriptor(int index, uint32_t base, uint32_t limit, uint16_t flag, bool prnt_gdt); #endif diff --git a/include/idt.h b/include/idt.h deleted file mode 100644 index 7fecd1c..0000000 --- a/include/idt.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _IDT_H -#define _IDT_H - -#include - -struct idt_entry { - uint16_t base_low; - uint16_t sel; /* Kernel segment selector */ - uint8_t always0; /* Always 0 */ - uint8_t flags; /* Type and attributes */ - uint16_t base_high; -} __attribute__((packed)); - -struct idt_ptr { - uint16_t limit; - uint32_t base; -} __attribute__((packed)); - -void idt_install(void); -void idt_install_isrs(void); -void idt_install_syscall(void); -void pic_remap(void); -void idt_set_entry(int num, uint32_t base, uint16_t sel, uint8_t flags); - -#endif diff --git a/include/io.h b/include/io.h index 2cfa726..a469d70 100644 --- a/include/io.h +++ b/include/io.h @@ -4,7 +4,6 @@ #define ESPRESSO_IO_H #include -#include void print(const char* str); @@ -13,4 +12,4 @@ char* input(uint8_t dev=0); void writefile(uint8_t mode, char* file, char* data); char* readfile(char* file); -#endif \ No newline at end of file +#endif diff --git a/include/isr.h b/include/isr.h deleted file mode 100644 index d82fea5..0000000 --- a/include/isr.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _ISR_H -#define _ISR_H - -#include - -typedef struct { - uint32_t ds, edi, esi, ebp, esp, ebx, edx, ecx, eax; - uint32_t int_no, err_code; - uint32_t eip, cs, eflags, useresp, ss; -} regs_t; - -typedef struct { - uint32_t ds; - uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; - uint32_t int_no, err_code; - uint32_t eip, cs, eflags, useresp, ss; -} isr_stack_t; - -void isr_handler(isr_stack_t *r); -void syscall_handler(regs_t *r); -void register_interrupt_handler(uint8_t n, void (*handler)(isr_stack_t *)); - -#endif diff --git a/include/kernel/intro_anim.h b/include/kernel/intro.h similarity index 100% rename from include/kernel/intro_anim.h rename to include/kernel/intro.h diff --git a/include/kernel/syscalls.h b/include/kernel/syscalls.h deleted file mode 100644 index c29a68e..0000000 --- a/include/kernel/syscalls.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _SYSCALLS_H -#define _SYSCALLS_H - -#include - -int16_t syscall_write(int32_t fd, const void* buffer, int32_t length); - -#endif diff --git a/include/printf.h b/include/printf.h index 5f5928f..06bc1a6 100644 --- a/include/printf.h +++ b/include/printf.h @@ -14,6 +14,7 @@ void printf(const char*, ...); void print_int(int32_t value); void print_uint(uint32_t value); void print_hex(uint32_t value, int width, bool uppercase); +void print_hex64(uint64_t value, int width, bool uppercase); void print_double(double value, int precision); #endif diff --git a/isr.asm b/isr.asm new file mode 100644 index 0000000..6513859 --- /dev/null +++ b/isr.asm @@ -0,0 +1,167 @@ +[BITS 32] +[GLOBAL isr_stub_table] +[GLOBAL irq_stub_table] +extern irq_handler ; C function + +section .text + +; -------------------------------------------- +; ------------------- IRQs ------------------- +; -------------------------------------------- + +%macro irq_stub 1 +irq_stub_%+%1: + pusha + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push dword %1 ; Push IRQ number + call irq_handler + add esp, 4 ; Clean up stack + + ; Send EOI + mov al, 0x20 + mov bl, %1 + cmp bl, 8 + jb .skip_slave_eoi + out 0xA0, al +.skip_slave_eoi: + out 0x20, al + + pop gs + pop fs + pop es + pop ds + popa + iret +%endmacro + + +; Define 16 IRQ stubs +irq_stub 0 +irq_stub 1 +irq_stub 2 +irq_stub 3 +irq_stub 4 +irq_stub 5 +irq_stub 6 +irq_stub 7 +irq_stub 8 +irq_stub 9 +irq_stub 10 +irq_stub 11 +irq_stub 12 +irq_stub 13 +irq_stub 14 +irq_stub 15 + +irq_stub_table: +%assign i 0 +%rep 16 + dd irq_stub_%+i +%assign i i+1 +%endrep + +; -------------------------------------------- +; ------------------- ISRs ------------------- +; -------------------------------------------- + +; Common exception handler entry point +isr_common_handler: + pusha ; Push general-purpose registers + push ds + push es + push fs + push gs + + ; Load known-good segment selectors + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Print exception number and error code + ; You can insert direct port writes or call kernel logging function here + ; For now, just hang +.halt: + cli + hlt + jmp .halt + + ; If you want to later restore: + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 ; clean up int_no + err_code + iret + +; Macro: for exceptions with error code +%macro isr_err_stub 1 +isr_stub_%+%1: + cli + push dword %1 ; interrupt number + jmp isr_common_handler +%endmacro + +; Macro: for exceptions without error code +%macro isr_no_err_stub 1 +isr_stub_%+%1: + cli + push dword 0 ; fake error code + push dword %1 ; interrupt number + jmp isr_common_handler +%endmacro + +; Define all 32 exception stubs +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_no_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_no_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 + +; Create jump table +isr_stub_table: +%assign i 0 +%rep 32 + dd isr_stub_%+i +%assign i i+1 +%endrep + diff --git a/isr.old.asm b/isr.old.asm new file mode 100644 index 0000000..3739336 --- /dev/null +++ b/isr.old.asm @@ -0,0 +1,97 @@ + +[BITS 32] +[GLOBAL isr_stub_table] + +section .text + +; Common exception handler entry point +isr_common_handler: + pusha ; Push general-purpose registers + push ds + push es + push fs + push gs + + ; Load known-good segment selectors + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Print exception number and error code + ; You can insert direct port writes or call kernel logging function here + ; For now, just hang +.halt: + cli + hlt + jmp .halt + + ; If you want to later restore: + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 ; clean up int_no + err_code + iret + +; Macro: for exceptions with error code +%macro isr_err_stub 1 +isr_stub_%+%1: + cli + push dword %1 ; interrupt number + jmp isr_common_handler +%endmacro + +; Macro: for exceptions without error code +%macro isr_no_err_stub 1 +isr_stub_%+%1: + cli + push dword 0 ; fake error code + push dword %1 ; interrupt number + jmp isr_common_handler +%endmacro + +; Define all 32 exception stubs +isr_no_err_stub 0 +isr_no_err_stub 1 +isr_no_err_stub 2 +isr_no_err_stub 3 +isr_no_err_stub 4 +isr_no_err_stub 5 +isr_no_err_stub 6 +isr_no_err_stub 7 +isr_err_stub 8 +isr_no_err_stub 9 +isr_err_stub 10 +isr_err_stub 11 +isr_err_stub 12 +isr_err_stub 13 +isr_err_stub 14 +isr_no_err_stub 15 +isr_no_err_stub 16 +isr_err_stub 17 +isr_no_err_stub 18 +isr_no_err_stub 19 +isr_no_err_stub 20 +isr_no_err_stub 21 +isr_no_err_stub 22 +isr_no_err_stub 23 +isr_no_err_stub 24 +isr_no_err_stub 25 +isr_no_err_stub 26 +isr_no_err_stub 27 +isr_no_err_stub 28 +isr_no_err_stub 29 +isr_err_stub 30 +isr_no_err_stub 31 + +; Create jump table +isr_stub_table: +%assign i 0 +%rep 32 + dd isr_stub_%+i +%assign i i+1 +%endrep + diff --git a/isr128.asm b/isr128.asm deleted file mode 100644 index 8aa2976..0000000 --- a/isr128.asm +++ /dev/null @@ -1,34 +0,0 @@ -[bits 32] -global isr128 -extern isr_handler -extern _push_regs -extern _pop_regs - -isr128: - cli - call _push_regs - - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - ; Pass register state to C handler - push esp - call isr_handler - add esp, 4 - - pop gs - pop fs - pop es - pop ds - call _pop_regs - - sti - iret diff --git a/isr_stub_table.asm b/isr_stub_table.asm deleted file mode 100644 index 620970e..0000000 --- a/isr_stub_table.asm +++ /dev/null @@ -1,87 +0,0 @@ -[bits 32] -global isr_stub_table -global isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7 -global isr8, isr9, isr10, isr11, isr12, isr13, isr14, isr15 -global isr16, isr17, isr18, isr19, isr20, isr21, isr22, isr23 -global isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31 -global isr33 - -extern isr_handler -extern _push_regs -extern _pop_regs - -%macro ISR_NOERR 1 -isr%1: - cli - push dword 0 ; Fake error code - push dword %1 ; Interrupt number - jmp isr_common_stub -%endmacro - -%macro ISR_ERR 1 -isr%1: - cli - push dword %1 ; Interrupt number - jmp isr_common_stub -%endmacro - -; ISRs 0-31 (exceptions) -ISR_NOERR 0 -ISR_NOERR 1 -ISR_NOERR 2 -ISR_NOERR 3 -ISR_NOERR 4 -ISR_NOERR 5 -ISR_NOERR 6 -ISR_NOERR 7 -ISR_ERR 8 ; Double fault -ISR_NOERR 9 -ISR_ERR 10 ; Invalid TSS -ISR_ERR 11 ; Segment not present -ISR_ERR 12 ; Stack segment fault -ISR_ERR 13 ; General protection fault -ISR_ERR 14 ; Page fault -ISR_NOERR 15 -ISR_NOERR 16 -ISR_NOERR 17 -ISR_NOERR 18 -ISR_NOERR 19 -ISR_NOERR 20 -ISR_NOERR 21 -ISR_NOERR 22 -ISR_NOERR 23 -ISR_NOERR 24 -ISR_NOERR 25 -ISR_NOERR 26 -ISR_NOERR 27 -ISR_NOERR 28 -ISR_NOERR 29 -ISR_ERR 30 ; Security exception -ISR_NOERR 31 -ISR_NOERR 33 - -isr_common_stub: - pusha - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - push esp - call isr_handler - add esp, 4 - - pop gs - pop fs - pop es - pop ds - popa - add esp, 8 - ;sti - iret diff --git a/kernel/boot.c b/kernel/boot.c index 2536dde..ad3dab3 100644 --- a/kernel/boot.c +++ b/kernel/boot.c @@ -3,7 +3,8 @@ #include #include - + + uint8_t parse_boot_data(const char* data) { if (strlen(data) == 0) diff --git a/kernel/intro_anim.c b/kernel/intro.c similarity index 97% rename from kernel/intro_anim.c rename to kernel/intro.c index 93d2b20..be46eb1 100644 --- a/kernel/intro_anim.c +++ b/kernel/intro.c @@ -3,7 +3,7 @@ #include #include -#include +#include void delay_us(uint32_t microseconds, uint32_t cpu_mhz) { uint32_t count = cpu_mhz * microseconds; diff --git a/kernel/kernel.c b/kernel/kernel.c index 897f753..4303bed 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -18,14 +18,14 @@ #include #include -#include +#include #include #include #include #include -//#include +/*#include */ #include #include #include @@ -34,7 +34,7 @@ #include -#include +#include #define DEBUG @@ -42,6 +42,7 @@ extern HBA_PORT *ahci_port;*/ extern void _hang_asm(void); +extern void _sti_asm(void); void kernel_main(multiboot_info_t* mbd, unsigned int magic) @@ -49,9 +50,13 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic) /* --- BEGIN INITIALIZATION SECTION --- */ + const char* espresso_kernel_version = "0.0.0e"; + /* We need to initialize the terminal so that any error/debuging messages show. */ terminal_initialize(); + printf("Loading Espresso %s...\n", espresso_kernel_version); + terminal_setcolor(VGA_COLOR_RED); /* Make sure the magic number matches for memory mapping*/ @@ -69,17 +74,17 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic) _hang_asm(); } - gdt_install(); + gdt_install(false); + pic_remap(); - idt_install_isrs(); - idt_install(); + idt_init(); + /*pit_init(1000); 1000 Hz = 1ms tick */ + _sti_asm(); terminal_setcolor(VGA_COLOR_GREEN); printd("Initializing physical memory manager...\n"); - pmm_init(mbd); - printd("Physical memory manager initialized\n"); printd("Initializing paging...\n"); @@ -115,23 +120,30 @@ void kernel_main(multiboot_info_t* mbd, unsigned int magic) ide_initialize(); printd("IDE initialized\n"); - printd("Initializing DuckFS...\n"); + /*printd("Initializing DuckFS...\n"); int32_t duckfs_init_rv = duckfs_init(0); - printf("[ DEBUG ] DuckFS initialized with RV %d\n", duckfs_init_rv); + printf("[ DEBUG ] DuckFS initialized with RV %d\n", duckfs_init_rv);*/ + /*printd("Initializing FAT32...\n"); + fat32_init(0); + printd("FAT32 initialized\n");*/ + + /*printd("Initializing the PIT...\n"); + pit_init(1000); + printd("PIT initialized\n");*/ /* --- END INITIALIZATION SECTION --- */ terminal_setcolor(VGA_COLOR_LIGHT_GREEN); - const char* espresso_kernel_version = "0.0.0b"; + /*sleep(1000);*/ - printf("Loading Espresso %s...\n", espresso_kernel_version); + begin_anim(espresso_kernel_version); - /*begin_anim(espresso_kernel_version);*/ + printf("Guten tag and welcome to Espresso\n"); - printf("Hello and welcome to Espresso\n"); - - - _hang_asm(); + while (true) + { + + } } diff --git a/kernel/syscalls.c b/kernel/syscalls.c deleted file mode 100644 index 8c734bf..0000000 --- a/kernel/syscalls.c +++ /dev/null @@ -1,10 +0,0 @@ - -#include - -#include - - -int16_t syscall_write(int32_t fd, const void* buffer, int32_t length) -{ - return -1; -} diff --git a/lib/mm/paging.c b/lib/mm/paging.c index 6b06e5b..fd84c58 100644 --- a/lib/mm/paging.c +++ b/lib/mm/paging.c @@ -3,6 +3,7 @@ #include #include +#include #define PAGE_DIRECTORY_ENTRIES 1024 #define PAGE_TABLE_ENTRIES 1024 @@ -11,7 +12,7 @@ typedef uint32_t page_directory_entry_t; typedef uint32_t page_table_entry_t; -static page_directory_entry_t* page_directory = (page_directory_entry_t*)0x9C000; /* Must be page-aligned */ +static page_directory_entry_t* page_directory = NULL; /* Will be allocated */ static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES]; extern void _enable_paging_asm(void); @@ -19,37 +20,37 @@ extern void _enable_paging_asm(void); void paging_init(void) { /* Allocate and clear the page directory */ - page_directory = (uint32_t*)alloc_page(); - memset(page_directory, 0, 4096); + page_directory = (page_directory_entry_t*)alloc_page(); + memset(page_directory, 0, PAGE_SIZE); /* Allocate and set up the first identity-mapped page table (0–4MB) */ - uint32_t* first_table = (uint32_t*)alloc_page(); - memset(first_table, 0, 4096); - for (uint32_t i = 0; i < 1024; i++) + page_tables[0] = (page_table_entry_t*)alloc_page(); + memset(page_tables[0], 0, PAGE_SIZE); + for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) { - first_table[i] = (i * 0x1000) | 3; /* Present | RW */ + page_tables[0][i] = (i * PAGE_SIZE) | 3; /* Present | RW */ } - page_directory[0] = ((uint32_t)first_table) | 3; + page_directory[0] = ((uint32_t)page_tables[0]) | 3; - /* --- Map 4MB heap at 0xC0000000 --- */ - uint32_t* heap_table = (uint32_t*)alloc_page(); - memset(heap_table, 0, 4096); - - for (uint32_t i = 0; i < 1024; i++) /* 256 pages = 1MB */ + /* Allocate and clear the heap page table */ + uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */ + page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page(); + memset(page_tables[heap_pd_index], 0, PAGE_SIZE); + + /* Map 4MB heap pages */ + for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) /* 1024 pages = 4MB */ { - uint32_t phys = (uint32_t)alloc_page(); + void* phys = alloc_page(); if (phys == 0) { printf("Out of physical memory during heap mapping!\n"); while (1); } - heap_table[i] = phys | 3; /* Present | RW */ + page_tables[heap_pd_index][i] = ((uint32_t)phys & 0xFFFFF000) | 3; /* Present | RW */ } + page_directory[heap_pd_index] = ((uint32_t)page_tables[heap_pd_index]) | 3; - /* 0xC0000000 >> 22 == 768 */ - page_directory[768] = ((uint32_t)heap_table) | 3; - - // Load page directory + /* Load page directory */ asm volatile ("mov %0, %%cr3" : : "r"(page_directory)); /* Enable paging */ @@ -67,16 +68,14 @@ void map_page(void* phys_addr, void* virt_addr) void* pt_phys = alloc_page(); page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */ - for (int i = 0; i < PAGE_TABLE_ENTRIES; i++) - { - page_tables[pd_index][i] = 0x00000002; /* Not present */ - } + memset(page_tables[pd_index], 0, PAGE_SIZE); page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */ } - page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) | 0xC0000000); + page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) + 0xC0000000); page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */ asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory"); } + diff --git a/lib/printf.c b/lib/printf.c index 4a0efcb..01e9b53 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -34,7 +34,7 @@ void printf(const char* format, ...) { if (format[i] == '%' && format[i + 1] != '\0') { ++i; - // Parse width (only supports zero-padding like %04x) + // Check for width (like %016llx) int width = 0; if (format[i] == '0') { ++i; @@ -44,6 +44,13 @@ void printf(const char* format, ...) { } } + // Check for 'll' prefix + bool is_ll = false; + if (format[i] == 'l' && format[i + 1] == 'l') { + is_ll = true; + i += 2; + } + switch (format[i]) { case 's': { const char* str = va_arg(args, const char*); @@ -67,13 +74,23 @@ void printf(const char* format, ...) { break; } case 'x': { - uint32_t val = va_arg(args, uint32_t); - print_hex(val, width, false); + if (is_ll) { + uint64_t val = va_arg(args, uint64_t); + print_hex64(val, width ? width : 16, false); + } else { + uint32_t val = va_arg(args, uint32_t); + print_hex(val, width ? width : 8, false); + } break; } case 'X': { - uint32_t val = va_arg(args, uint32_t); - print_hex(val, width, true); + if (is_ll) { + uint64_t val = va_arg(args, uint64_t); + print_hex64(val, width ? width : 16, true); + } else { + uint32_t val = va_arg(args, uint32_t); + print_hex(val, width ? width : 8, true); + } break; } case 'p': { @@ -84,8 +101,8 @@ void printf(const char* format, ...) { } case 'f': case 'F': { - double val = va_arg(args, double); // double is promoted from float - print_double(val, 2); // 2 decimal places + double val = va_arg(args, double); + print_double(val, 2); break; } case '%': { @@ -106,41 +123,6 @@ void printf(const char* format, ...) { va_end(args); } -void print_double(double value, int precision) -{ - // Handle the integer part - int32_t integer_part = (int32_t)value; - double fractional_part = value - integer_part; - - // Print the integer part - print_int(integer_part); - - // Print the decimal point - terminal_putchar('.'); - - // Print the fractional part (scaled up) - fractional_part *= 1; - for (int i = 0; i < precision; i++) { - fractional_part *= 10; - } - - int32_t frac_int = (int32_t)fractional_part; - print_int(frac_int); -} - -void print_uint(uint32_t value) { - char buffer[11]; // Enough for 32-bit unsigned int - int i = 0; - - do { - buffer[i++] = '0' + (value % 10); - value /= 10; - } while (value > 0); - - while (i--) { - terminal_putchar(buffer[i]); - } -} void print_int(int32_t value) { char buffer[12]; // Enough for 32-bit signed int (-2147483648) @@ -181,3 +163,57 @@ void print_hex(uint32_t value, int width, bool uppercase) terminal_putchar(buffer[i]); } } + +void print_double(double value, int precision) +{ + // Handle the integer part + int32_t integer_part = (int32_t)value; + double fractional_part = value - integer_part; + + // Print the integer part + print_int(integer_part); + + // Print the decimal point + terminal_putchar('.'); + + // Print the fractional part (scaled up) + fractional_part *= 1; + for (int i = 0; i < precision; i++) { + fractional_part *= 10; + } + + int32_t frac_int = (int32_t)fractional_part; + print_int(frac_int); +} + +void print_uint(uint32_t value) { + char buffer[11]; // Enough for 32-bit unsigned int + int i = 0; + + do { + buffer[i++] = '0' + (value % 10); + value /= 10; + } while (value > 0); + + while (i--) { + terminal_putchar(buffer[i]); + } +} + +void print_hex64(uint64_t value, int width, bool uppercase) { + char buffer[17] = {0}; + const char* digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; + int i = 0; + + do { + buffer[i++] = digits[value % 16]; + value /= 16; + } while (value > 0); + + while (i < width) + buffer[i++] = '0'; + + while (i--) + terminal_putchar(buffer[i]); +} + diff --git a/misc_asm.s b/misc_asm.s index 408b5b6..6004cc4 100644 --- a/misc_asm.s +++ b/misc_asm.s @@ -19,6 +19,10 @@ .global _pop_regs .global _hang_asm +.global _halt_asm + +.global _sti_asm + _enable_paging_asm: push %eax @@ -59,4 +63,12 @@ _hang_asm: hlt jmp _hang_asm +_halt_asm: + nop + ret + +_sti_asm: + sti + ret + .section .data diff --git a/pit.asm b/pit.asm index 6db5ed6..b61693d 100644 --- a/pit.asm +++ b/pit.asm @@ -3,130 +3,3 @@ -section .bss -system_timer_fractions: resd 1 ; Fractions of 1 ms since timer initialized -system_timer_ms: resd 1 ; Number of whole ms since timer initialized -IRQ0_fractions: resd 1 ; Fractions of 1 ms between IRQs -IRQ0_ms: resd 1 ; Number of whole ms between IRQs -IRQ0_frequency: resd 1 ; Actual frequency of PIT -PIT_reload_value: resw 1 ; Current PIT reload value - -section .text - -global IRQ0_handler -global init_PIT - -IRQ0_handler: - push eax - push ebx - - mov eax, [IRQ0_fractions] - mov ebx, [IRQ0_ms] ; eax.ebx = amount of time between IRQs - add [system_timer_fractions], eax ; Update system timer tick fractions - adc [system_timer_ms], ebx ; Update system timer tick milli-seconds - - mov al, 0x20 - out 0x20, al ; Send the EOI to the PIC - - pop ebx - pop eax - iretd - - -;Input - ; ebx Desired PIT frequency in Hz - - init_PIT: - pushad - - ; Do some checking - - mov eax,0x10000 ;eax = reload value for slowest possible frequency (65536) - cmp ebx,18 ;Is the requested frequency too low? - jbe .gotReloadValue ; yes, use slowest possible frequency - - mov eax,1 ;ax = reload value for fastest possible frequency (1) - cmp ebx,1193181 ;Is the requested frequency too high? - jae .gotReloadValue ; yes, use fastest possible frequency - - ; Calculate the reload value - - mov eax,3579545 - mov edx,0 ;edx:eax = 3579545 - div ebx ;eax = 3579545 / frequency, edx = remainder - cmp edx,3579545 / 2 ;Is the remainder more than half? - jb .l1 ; no, round down - inc eax ; yes, round up - .l1: - mov ebx,3 - mov edx,0 ;edx:eax = 3579545 * 256 / frequency - div ebx ;eax = (3579545 * 256 / 3 * 256) / frequency - cmp edx,3 / 2 ;Is the remainder more than half? - jb .l2 ; no, round down - inc eax ; yes, round up - .l2: - - - ; Store the reload value and calculate the actual frequency - - .gotReloadValue: - push eax ;Store reload_value for later - mov [PIT_reload_value],ax ;Store the reload value for later - mov ebx,eax ;ebx = reload value - - mov eax,3579545 - mov edx,0 ;edx:eax = 3579545 - div ebx ;eax = 3579545 / reload_value, edx = remainder - cmp edx,3579545 / 2 ;Is the remainder more than half? - jb .l3 ; no, round down - inc eax ; yes, round up - .l3: - mov ebx,3 - mov edx,0 ;edx:eax = 3579545 / reload_value - div ebx ;eax = (3579545 / 3) / frequency - cmp edx,3 / 2 ;Is the remainder more than half? - jb .l4 ; no, round down - inc eax ; yes, round up - .l4: - mov [IRQ0_frequency],eax ;Store the actual frequency for displaying later - - - ; Calculate the amount of time between IRQs in 32.32 fixed point - ; - ; Note: The basic formula is: - ; time in ms = reload_value / (3579545 / 3) * 1000 - ; This can be rearranged in the following way: - ; time in ms = reload_value * 3000 / 3579545 - ; time in ms = reload_value * 3000 / 3579545 * (2^42)/(2^42) - ; time in ms = reload_value * 3000 * (2^42) / 3579545 / (2^42) - ; time in ms * 2^32 = reload_value * 3000 * (2^42) / 3579545 / (2^42) * (2^32) - ; time in ms * 2^32 = reload_value * 3000 * (2^42) / 3579545 / (2^10) - - pop ebx ;ebx = reload_value - mov eax,0xDBB3A062 ;eax = 3000 * (2^42) / 3579545 - mul ebx ;edx:eax = reload_value * 3000 * (2^42) / 3579545 - shrd eax,edx,10 - shr edx,10 ;edx:eax = reload_value * 3000 * (2^42) / 3579545 / (2^10) - - mov [IRQ0_ms],edx ;Set whole ms between IRQs - mov [IRQ0_fractions],eax ;Set fractions of 1 ms between IRQs - - - ; Program the PIT channel - - pushfd - cli ;Disabled interrupts (just in case) - - mov al,00110100b ;channel 0, lobyte/hibyte, rate generator - out 0x43, al - - mov ax,[PIT_reload_value] ;ax = 16 bit reload value - out 0x40,al ;Set low byte of PIT reload value - mov al,ah ;ax = high 8 bits of reload value - out 0x40,al ;Set high byte of PIT reload value - - popfd - - popad - ret -