From 43bc0df81a8755b46f7062263c6063319353d5f1 Mon Sep 17 00:00:00 2001 From: slinky55 Date: Fri, 26 Jun 2026 20:05:01 -0500 Subject: [PATCH] did some restructuring, got multitasking almost working --- compile_commands.json | 8 +- kernel/{common_stubs.S => common.S} | 5 + kernel/drivers/pic/{pic_stubs.S => pic.S} | 9 +- kernel/drivers/pic/pic.h | 16 ++- kernel/drivers/pit/{pit_stubs.S => pit.S} | 3 - kernel/drivers/pit/pit.h | 6 + kernel/drivers/ps2/{ps2_stubs.S => ps2.S} | 2 - kernel/drivers/ps2/ps2.c | 1 + kernel/drivers/ps2/ps2.h | 6 + .../vga/{vga_stream_writer.c => vga.c} | 21 +-- kernel/drivers/vga/vga.h | 7 + kernel/{gdt_stubs.S => gdt.S} | 1 + kernel/gdt.c | 4 +- kernel/gdt.h | 6 + kernel/globals.c | 3 +- kernel/idt.c | 61 -------- kernel/idt.h | 19 --- kernel/{idt_stubs.S => interrupts.S} | 26 ++-- kernel/interrupts.c | 86 +++++++++-- kernel/interrupts.h | 6 + kernel/kmain.c | 136 ++++-------------- kernel/lib/memory.c | 89 +++++++----- kernel/lib/memory.h | 2 +- kernel/lib/print.c | 31 ++-- kernel/lib/tasks.c | 11 ++ kernel/lib/tasks.h | 13 ++ kernel/memory/mm.c | 14 +- kernel/memory/mm.h | 2 +- kernel/process.h | 20 +++ kernel/scheduler.S | 12 ++ kernel/scheduler.c | 136 ++++++++++++++++++ kernel/scheduler.h | 13 ++ kernel/{syscall_stubs.S => syscall.S} | 0 kernel/syscall.h | 6 + makefile | 7 +- 35 files changed, 481 insertions(+), 307 deletions(-) rename kernel/{common_stubs.S => common.S} (95%) rename kernel/drivers/pic/{pic_stubs.S => pic.S} (81%) rename kernel/drivers/pit/{pit_stubs.S => pit.S} (84%) rename kernel/drivers/ps2/{ps2_stubs.S => ps2.S} (98%) rename kernel/drivers/vga/{vga_stream_writer.c => vga.c} (84%) create mode 100644 kernel/drivers/vga/vga.h rename kernel/{gdt_stubs.S => gdt.S} (97%) create mode 100644 kernel/gdt.h delete mode 100644 kernel/idt.c delete mode 100644 kernel/idt.h rename kernel/{idt_stubs.S => interrupts.S} (76%) create mode 100644 kernel/interrupts.h create mode 100644 kernel/lib/tasks.c create mode 100644 kernel/lib/tasks.h create mode 100644 kernel/process.h create mode 100644 kernel/scheduler.S create mode 100644 kernel/scheduler.c create mode 100644 kernel/scheduler.h rename kernel/{syscall_stubs.S => syscall.S} (100%) create mode 100644 kernel/syscall.h diff --git a/compile_commands.json b/compile_commands.json index e999a0e..c07e8d7 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -9,11 +9,11 @@ "-Wextra", "-Ikernel", "-o", - "obj/kernel/boot/boot.o", - "kernel/boot/boot.S" + "obj/kernel/drivers/pit/pit.S.o", + "kernel/drivers/pit/pit.S" ], "directory": "/home/slinky/source/RockOS", - "file": "/home/slinky/source/RockOS/kernel/boot/boot.S", - "output": "/home/slinky/source/RockOS/obj/kernel/boot/boot.o" + "file": "/home/slinky/source/RockOS/kernel/drivers/pit/pit.S", + "output": "/home/slinky/source/RockOS/obj/kernel/drivers/pit/pit.S.o" } ] diff --git a/kernel/common_stubs.S b/kernel/common.S similarity index 95% rename from kernel/common_stubs.S rename to kernel/common.S index 3402d5f..5a8dc6c 100644 --- a/kernel/common_stubs.S +++ b/kernel/common.S @@ -115,4 +115,9 @@ outsw: pop %ecx pop %esi leave + ret + +.global fetch_cr3 +fetch_cr3: + mov %cr3, %eax ret \ No newline at end of file diff --git a/kernel/drivers/pic/pic_stubs.S b/kernel/drivers/pic/pic.S similarity index 81% rename from kernel/drivers/pic/pic_stubs.S rename to kernel/drivers/pic/pic.S index 312ac43..0719097 100644 --- a/kernel/drivers/pic/pic_stubs.S +++ b/kernel/drivers/pic/pic.S @@ -1,7 +1,12 @@ -#include "drivers/pic/pic.h" +#define PIC1_ADDR 0x20 + 0xC0000000 +#define PIC2_ADDR 0xA0 + 0xC0000000 +#define PIC1_COMMAND PIC1_ADDR +#define PIC1_DATA (PIC1_ADDR+1) +#define PIC2_COMMAND PIC2_ADDR +#define PIC2_DATA (PIC2_ADDR+1) +#define PIC_EOI 0x20 .code32 -.extern io_wait .global init_pic init_pic: diff --git a/kernel/drivers/pic/pic.h b/kernel/drivers/pic/pic.h index 5d3e795..07d008f 100644 --- a/kernel/drivers/pic/pic.h +++ b/kernel/drivers/pic/pic.h @@ -1,7 +1,9 @@ -#define PIC1_ADDR 0x20 + 0xC0000000 -#define PIC2_ADDR 0xA0 + 0xC0000000 -#define PIC1_COMMAND PIC1_ADDR -#define PIC1_DATA (PIC1_ADDR+1) -#define PIC2_COMMAND PIC2_ADDR -#define PIC2_DATA (PIC2_ADDR+1) -#define PIC_EOI 0x20 \ No newline at end of file +#ifndef DPIC_H +#define DPIC_H + +void init_pic(); + +void send_eoi_master(); +void send_eoi_slave(); + +#endif \ No newline at end of file diff --git a/kernel/drivers/pit/pit_stubs.S b/kernel/drivers/pit/pit.S similarity index 84% rename from kernel/drivers/pit/pit_stubs.S rename to kernel/drivers/pit/pit.S index 2269868..c16c64d 100644 --- a/kernel/drivers/pit/pit_stubs.S +++ b/kernel/drivers/pit/pit.S @@ -1,7 +1,4 @@ -#include "drivers/pit/pit.h" - .code32 - .global init_pit init_pit: # tickrate: 1193182/1000 = 0x04A9 (1000hz) (1ms) movb $0x36, %al diff --git a/kernel/drivers/pit/pit.h b/kernel/drivers/pit/pit.h index e69de29..1e18b2d 100644 --- a/kernel/drivers/pit/pit.h +++ b/kernel/drivers/pit/pit.h @@ -0,0 +1,6 @@ +#ifndef DPIT_H +#define DPIT_H + +void init_pit(); + +#endif \ No newline at end of file diff --git a/kernel/drivers/ps2/ps2_stubs.S b/kernel/drivers/ps2/ps2.S similarity index 98% rename from kernel/drivers/ps2/ps2_stubs.S rename to kernel/drivers/ps2/ps2.S index 79a2145..7691020 100644 --- a/kernel/drivers/ps2/ps2_stubs.S +++ b/kernel/drivers/ps2/ps2.S @@ -9,8 +9,6 @@ .global ps2_write_data .global ps2_flush_output_buffer -.extern io_wait - # helpers ps2_wait_input_empty: #(void) -> void push %ebp diff --git a/kernel/drivers/ps2/ps2.c b/kernel/drivers/ps2/ps2.c index b4b06c9..36b45d8 100644 --- a/kernel/drivers/ps2/ps2.c +++ b/kernel/drivers/ps2/ps2.c @@ -1,4 +1,5 @@ #include + #include extern void ps2_wait_input_empty(void); diff --git a/kernel/drivers/ps2/ps2.h b/kernel/drivers/ps2/ps2.h index 5019f50..9819803 100644 --- a/kernel/drivers/ps2/ps2.h +++ b/kernel/drivers/ps2/ps2.h @@ -16,4 +16,10 @@ #define SELF_TEST_SUCCESS 0x55 #define PORT_TEST_SUCCESS 0x00 +#ifndef __ASSEMBLER__ +#include +int init_ps2(); +uint8_t ps2_read_data(); +#endif + #endif \ No newline at end of file diff --git a/kernel/drivers/vga/vga_stream_writer.c b/kernel/drivers/vga/vga.c similarity index 84% rename from kernel/drivers/vga/vga_stream_writer.c rename to kernel/drivers/vga/vga.c index 2672d89..c3cb02d 100644 --- a/kernel/drivers/vga/vga_stream_writer.c +++ b/kernel/drivers/vga/vga.c @@ -26,10 +26,10 @@ enum vga_color { VGA_COLOR_WHITE = 15, }; -size_t terminal_row; -size_t terminal_column; -uint8_t terminal_color; -uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY; +static size_t terminal_row; +static size_t terminal_column; +static uint8_t terminal_color; +static uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY; static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg) { @@ -41,8 +41,7 @@ static inline uint16_t vga_entry(unsigned char uc, uint8_t color) return (uint16_t) uc | (uint16_t) color << 8; } -void vga_initialize() -{ +void vga_init() { terminal_row = 0; terminal_column = 0; terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK); @@ -55,8 +54,7 @@ void vga_initialize() } } -void vga_putchar(char c) -{ +void vga_putchar(char c) { if (c == '\n') { terminal_row++; terminal_column = 0; @@ -77,9 +75,4 @@ void vga_putchar(char c) if (++terminal_row == VGA_HEIGHT) terminal_row = 0; } -} - -print_stream_t vga_print_stream = { - .putchar = vga_putchar, - .trunc = vga_initialize, -}; \ No newline at end of file +} \ No newline at end of file diff --git a/kernel/drivers/vga/vga.h b/kernel/drivers/vga/vga.h new file mode 100644 index 0000000..ca57185 --- /dev/null +++ b/kernel/drivers/vga/vga.h @@ -0,0 +1,7 @@ +#ifndef DVGA_H +#define DVGA_H + +void vga_init(); +void vga_putchar(char c); + +#endif \ No newline at end of file diff --git a/kernel/gdt_stubs.S b/kernel/gdt.S similarity index 97% rename from kernel/gdt_stubs.S rename to kernel/gdt.S index 762b276..09fddd3 100644 --- a/kernel/gdt_stubs.S +++ b/kernel/gdt.S @@ -1,4 +1,5 @@ .code32 + .extern gdtr .global load_gdt load_gdt: diff --git a/kernel/gdt.c b/kernel/gdt.c index 7db6b84..c4bf167 100644 --- a/kernel/gdt.c +++ b/kernel/gdt.c @@ -84,7 +84,7 @@ tss_entry tss; extern void load_gdt(); extern void tss_flush(); -uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) +static uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) { uint64_t descriptor; @@ -101,7 +101,7 @@ uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) return descriptor; } -uint64_t create_tss_descriptor(uint32_t base, uint32_t limit) +static uint64_t create_tss_descriptor(uint32_t base, uint32_t limit) { uint64_t descriptor; uint16_t tss_flags = SEG_PRES(1) | SEG_PRIV(0) | SEG_DESCTYPE(0) | 0x09; diff --git a/kernel/gdt.h b/kernel/gdt.h new file mode 100644 index 0000000..f90e54d --- /dev/null +++ b/kernel/gdt.h @@ -0,0 +1,6 @@ +#ifndef KGDT_H +#define KGDT_H + +void init_gdt(); + +#endif \ No newline at end of file diff --git a/kernel/globals.c b/kernel/globals.c index 1460f59..f83e2de 100644 --- a/kernel/globals.c +++ b/kernel/globals.c @@ -1,8 +1,7 @@ -#include #include + #include "multiboot.h" -print_stream_t* kout; multiboot_info* grub_boot_struct_ptr = NULL; extern char __kernel_start; diff --git a/kernel/idt.c b/kernel/idt.c deleted file mode 100644 index 41f11e6..0000000 --- a/kernel/idt.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include - -#define IDT_MAX_DESCRIPTORS 256 - -#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110) -#define ATTR_USER_32 0xEE // active, ring 3, 32bit - -#define SEGMENT_KERN 0x08 - -extern void load_idt(void); -extern void enable_int(void); - -extern void isr0(); -extern void isr1(); -extern void isr8(); -extern void isr13(); -extern void isr14(); -extern void isr32(); -extern void isr33(); - -void* isr_stub_table[256] = { - [0] = isr0, - [1] = isr1, - [8] = isr8, - [13] = isr13, - [14] = isr14, - [32] = isr32, - [33] = isr33, -}; - -idt_entry idt[IDT_MAX_DESCRIPTORS]; -idt_ptr idtr; - -void set_idtr(uint8_t vector, void* isr, uint16_t sel, uint8_t attributes) { - idt_entry* desc = &idt[vector]; - - desc->isr_low = (uint32_t)isr & 0xFFFF; - desc->selector = SEGMENT_KERN; - desc->reserved = 0; - desc->attributes = attributes; - desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF; -} - -void init_idt() { - idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1; - idtr.base = (uint32_t)&idt; - - for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) { - if (isr_stub_table[i] != 0) { - set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32); - } else { - set_idtr(i, 0, SEGMENT_KERN, 0); - } - } - - extern void syscall_handler(); - set_idtr(0x80, syscall_handler, SEGMENT_KERN, ATTR_USER_32); - - load_idt(); -} \ No newline at end of file diff --git a/kernel/idt.h b/kernel/idt.h deleted file mode 100644 index bba6043..0000000 --- a/kernel/idt.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef KIDT_H -#define KIDT_H - -#include - -typedef struct __attribute__((packed)){ - uint16_t isr_low; - uint16_t selector; - uint8_t reserved; - uint8_t attributes; - uint16_t isr_high; -} idt_entry; - -typedef struct __attribute__((packed)){ - uint16_t limit; - uint32_t base; -} idt_ptr; - -#endif \ No newline at end of file diff --git a/kernel/idt_stubs.S b/kernel/interrupts.S similarity index 76% rename from kernel/idt_stubs.S rename to kernel/interrupts.S index a2e5c24..d2765cd 100644 --- a/kernel/idt_stubs.S +++ b/kernel/interrupts.S @@ -1,5 +1,4 @@ -.code32 - +.code32 .macro ISR_NOERRCODE num .global isr\num isr\num: @@ -33,18 +32,29 @@ load_idt: lidt idtr ret -.global enable_int -enable_int: - sti - ret - ISR_NOERRCODE 0 # Divide by Zero ISR_NOERRCODE 1 # Debug ISR_ERRCODE 8 # Double Fault (Has Error Code!) ISR_ERRCODE 13 # General Protection Fault (Has Error Code!) ISR_ERRCODE 14 # Page Fault (Has Error Code!) -ISR_NOERRCODE 32 # IRQ0 - Timer +// This is a special case so we need to handle it for task switching +.global isr32 +isr32: + cli + pushal + + pushl %esp + call schedule_next_task + movl %eax, %esp + + call send_eoi_master + + popal + + sti + iret + ISR_NOERRCODE 33 # IRQ1 - Keyboard ISR_NOERRCODE 46 # IRQ14 diff --git a/kernel/interrupts.c b/kernel/interrupts.c index cae5f95..faecda2 100644 --- a/kernel/interrupts.c +++ b/kernel/interrupts.c @@ -1,23 +1,61 @@ -#include "lib/print.h" #include -extern void send_eoi_master(void); -extern void send_eoi_slave(void); -extern uint8_t read_isr_master(void); -extern uint8_t read_isr_slave(void); +#include -extern uint8_t ps2_read_data(); +#include "syscall.h" -struct registers { +#include +#include + +#define IDT_MAX_DESCRIPTORS 256 +#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110) +#define ATTR_USER_32 0xEE // active, ring 3, 32bit +#define SEGMENT_KERN 0x08 + +typedef struct __attribute__((packed)) { + uint16_t isr_low; + uint16_t selector; + uint8_t reserved; + uint8_t attributes; + uint16_t isr_high; +} idt_entry; + +typedef struct __attribute__((packed)) { + uint16_t limit; + uint32_t base; +} idt_ptr; + +typedef struct __attribute__((packed)) { uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax; uint32_t int_no; uint32_t error_code; uint32_t eip, cs, eflags, useresp, ss; +} registers; + +extern void load_idt(void); + +// isr stubs +extern void isr0(); +extern void isr1(); +extern void isr8(); +extern void isr13(); +extern void isr14(); +extern void isr32(); +extern void isr33(); + +static void* isr_stub_table[256] = { + [0] = isr0, + [1] = isr1, + [8] = isr8, + [13] = isr13, + [14] = isr14, + [32] = isr32, + [33] = isr33, }; -const char* err_messages[32] = { +static const char* err_messages[32] = { [0] = "Divide by 0", [1] = "", [8] = "", @@ -25,7 +63,37 @@ const char* err_messages[32] = { [14] = "Page Fault", }; -void common_interrupt_handler(struct registers *args) { +idt_entry idt[IDT_MAX_DESCRIPTORS]; +idt_ptr idtr; + +static void set_idtr(uint8_t vector, void* isr, uint16_t sel, uint8_t attributes) { + idt_entry* desc = &idt[vector]; + + desc->isr_low = (uint32_t)isr & 0xFFFF; + desc->selector = SEGMENT_KERN; + desc->reserved = 0; + desc->attributes = attributes; + desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF; +} + +void init_idt() { + idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1; + idtr.base = (uint32_t)&idt; + + for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) { + if (isr_stub_table[i] != 0) { + set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32); + } else { + set_idtr(i, 0, SEGMENT_KERN, 0); + } + } + + set_idtr(0x80, syscall_handler, SEGMENT_KERN, ATTR_USER_32); + + load_idt(); +} + +void common_interrupt_handler(registers *args) { switch (args->int_no) { case 0: case 1: diff --git a/kernel/interrupts.h b/kernel/interrupts.h new file mode 100644 index 0000000..83ca29a --- /dev/null +++ b/kernel/interrupts.h @@ -0,0 +1,6 @@ +#ifndef KIDT_H +#define KIDT_H + +void init_idt(); + +#endif \ No newline at end of file diff --git a/kernel/kmain.c b/kernel/kmain.c index d95be46..bbd9177 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,150 +1,62 @@ #include "multiboot.h" -#include "idt.h" +#include "interrupts.h" #include "elf.h" +#include "gdt.h" +#include "scheduler.h" #include #include #include -#include "memory/mm.h" +#include -#include "drivers/iso/iso.h" -#include "drivers/ide/ide.h" +#include +#include +#include +#include +#include +#include #include #include -extern void init_idt(); -extern void init_gdt(); -extern void init_pic(); -extern void init_pit(); -extern int init_ps2(); extern void enable_interrupts(); - -void* page = NULL; +extern void disable_interrupts(); +extern uint32_t fetch_cr3(); extern char __kernel_start; extern char __kernel_end; -void* user_page_directories[10]; - -void load_origin_program(multiboot_info* mbi) { - user_page_directories[0] = create_user_pd(); - kprintf("Created origin process page directory @ [phys] 0x%x\n", user_page_directories[0]); - extern void load_pd(void* pd); - extern void flush_tlb(); - load_pd(user_page_directories[0]); - flush_tlb(); - kprintf("switched to user address space\n"); - - uint32_t mods_virtual_addr = mbi->mods_addr + 0xC0000000; - kprintf("parsing mutliboot modules @ 0x%x\n", mods_virtual_addr); - - if (mbi->mods_count == 0) { - return; +void kernel_test_task() { + while (1) { + kprintf("task sleeping...\n"); + sleep(10000000); } - - multiboot_module_entry* modules = (multiboot_module_entry*)mods_virtual_addr; - - uint32_t elf_vbase = 0xE0000000; - uint32_t elf_pbase = modules[0].mod_start; - uint32_t elf_limit = modules[0].mod_end - modules[0].mod_start; - uint32_t elf_pages_needed = (elf_limit / 4096) + 1; - - for (uint32_t i = 0; i < elf_pages_needed; i++) { - const uint32_t vaddr = elf_vbase + (i * 4096); - const uint32_t paddr = elf_pbase + (i * 4096); - map_page(vaddr, paddr, PAGE_PRESENT | PAGE_WRITABLE); - } - - elf_header_t* elf = (elf_header_t*)elf_vbase; - elf_program_header_t* ph = (elf_program_header_t*)(elf_vbase + elf->e_phoff); - - kprintf("elf header @ 0x%x\n", elf); - kprintf("program headers @ 0x%x\n", ph); - - // load program sections into physical memory and map the pages - for (int i = 0; i < elf->e_phnum; i++) { - if (ph[i].p_type == PT_LOAD) { - uint32_t v_start = ph[i].p_vaddr & 0xFFFFF000; - uint32_t v_end = (ph[i].p_vaddr + ph[i].p_memsz + 4095) & 0xFFFFF000; - - for (uint32_t page = v_start; page < v_end; page += 4096) { - uint32_t frame_paddr = (uint32_t)p_alloc_frame(); - map_page(page, frame_paddr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); - } - - for (uint32_t j = 0; j < ph[i].p_memsz; j++) { - ((char*)ph[i].p_vaddr)[j] = 0; - } - - for (uint32_t j = 0; j < ph[i].p_filesz; j++) { - ((char*)ph[i].p_vaddr)[j] = ((char*)(elf_vbase + ph[i].p_offset))[j]; - } - } - } - - // allocate the user stack - uint32_t stack_paddr = (uint32_t)p_alloc_frame(); - map_page(0xBFFFF000, stack_paddr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); - - kprintf("program loaded into memory @ [virt] 0x%x\n", elf->e_entry); - - extern void liftoff(uint32_t entry, uint32_t stack_top); - kprintf("launching origin process\n"); - uint32_t stack_top = 0xBFFFF000 + 4095; - liftoff(elf->e_entry, stack_top); } void kmain(uint32_t magic, multiboot_info* mbi) { - extern print_stream_t vga_print_stream; - extern print_stream_t* kout; - kout = &vga_print_stream; - kout->trunc(); - - kprintf("kernel start: 0x%x\n", &__kernel_start); - kprintf("kernel end: 0x%x\n", &__kernel_end); - uint32_t size = (&__kernel_end - &__kernel_start) / 1024; - kprintf("kernel size: %dKB\n", size); - if (!(mbi->flags & (1 << 6))) { return; } - kprintf("multiboot virtual address: 0x%x\n", mbi); + vga_init(); - kprintf("parsing multiboot memory map\n"); uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000; - kprintf("mmap virtual address: 0x%x\n", mmap_virtual_addr); init_pmm((void*)mmap_virtual_addr, mbi->mmap_length); + kprintf("memory detection complete. total free memory: %dMB\n", total_free_memory() / 1024 / 1024); - kprintf("RockOS booting...\n"); init_gdt(); - extern uint64_t gdt[5]; - kprintf("GDT set @ 0x%x\n", &gdt); - init_idt(); - extern idt_entry idt[256]; - kprintf("IDT set @ 0x%x\n", &idt); - init_pic(); - kprintf("PIC initialized\n"); - init_pit(); - kprintf("PIT initialized\n"); - + init_page_tables(); - kprintf("Page tables initialized\n"); - kgrow(1); - kprintf("Allocated 4kb for kernel heap\n"); + kprintf("basic initializations complete\n"); - kprintf("scanning for drives\n"); - extern void scan_drives(); - scan_drives(); + disable_interrupts(); + init_scheduler(); + enable_interrupts(); - ide_device_t* boot_cd_rom = get_ide_device(0); - read_iso(boot_cd_rom); - - while(1); + while(1) yield(); } diff --git a/kernel/lib/memory.c b/kernel/lib/memory.c index 244c098..1905706 100644 --- a/kernel/lib/memory.c +++ b/kernel/lib/memory.c @@ -4,8 +4,9 @@ #define KHEAP_START 0xE0000000 typedef struct __attribute__((packed)) { + size_t size; uint8_t free; - uint32_t next_blk; + void* next_blk; } alloc_header_t; void memcpy(const void* src, void* dst, size_t sz) { @@ -42,18 +43,6 @@ static void* kernel_heap_end = (void*)KHEAP_START; alloc_header_t* blk_list = NULL; void kgrow(size_t pages) { - if (kernel_heap_end == kernel_heap_start) { - // probaably not great, but if we don't have a heap yet, allocate the first (or only) frame requested. - // Then initialize the first block header for the allocator - void* frame = p_alloc_frame(); - map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE); - kernel_heap_end = (void*)((uint32_t)kernel_heap_end + PAGE_SIZE); - pages--; - blk_list = kernel_heap_start; - blk_list->free = 1; - blk_list->next_blk = 0; - } - for (size_t p = 0; p < pages; p++) { void* frame = p_alloc_frame(); map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE); @@ -61,34 +50,60 @@ void kgrow(size_t pages) { } } +#define ALIGNMENT 4 +#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1)) void* kalloc(size_t sz) { - if (sz == 0) { - return NULL; + sz = ALIGN(sz); + + if (kernel_heap_end == kernel_heap_start) { + // probaably not great, but if we don't have a heap yet, allocate the first (or only) frame requested. + // Then initialize the first block header for the allocator + kgrow(4); + + blk_list = (alloc_header_t*)kernel_heap_start; + blk_list->size = ((uint32_t)kernel_heap_end - (uint32_t)kernel_heap_start) - sizeof(alloc_header_t); + blk_list->free = 1; + blk_list->next_blk = NULL; } - alloc_header_t* header = blk_list; - while (!header->free) { - if (header->next_blk == 0) { - return NULL; + alloc_header_t* curr = blk_list; + alloc_header_t* prev = NULL; + + while (curr != NULL) { + if (curr->free && curr->size >= sz) { + if (curr->size >= sz + sizeof(alloc_header_t) + ALIGNMENT) { + alloc_header_t* new_blk = (alloc_header_t*)((uint32_t)curr + sizeof(alloc_header_t) + sz); + + new_blk->size = curr->size - sz - sizeof(alloc_header_t); + new_blk->free = 1; + new_blk->next_blk = curr->next_blk; + + curr->size = sz; + curr->next_blk = new_blk; + } + + curr->free = 0; + return (void*)((uint32_t)curr + sizeof(alloc_header_t)); } - header = (alloc_header_t*)header->next_blk; + prev = curr; + curr = curr->next_blk; } - uint32_t data_ptr = (uint32_t)header + sizeof(alloc_header_t); - if (data_ptr >= (uint32_t)kernel_heap_end) { - return NULL; - } // if the start of the data is already at the end, we don't have room - - uint32_t end_of_blk = data_ptr + sz; - if (end_of_blk > (uint32_t)kernel_heap_end) { - return NULL; - } // if the end of the data is past the end, we don't have room - - if (end_of_blk != header->next_blk && end_of_blk < ((uint32_t)kernel_heap_end - sizeof(alloc_header_t))) { - header->next_blk = end_of_blk; - alloc_header_t* next_header = (alloc_header_t*)header->next_blk; - next_header->f - } // see if we have room to place the next header and at least 1 byte of data - - return (void*)data_ptr; + // no more space, grow!! + size_t required_space = sz + sizeof(alloc_header_t); + size_t pages_to_grow = (required_space + PAGE_SIZE - 1) / PAGE_SIZE; + + alloc_header_t* new_heap_blk = (alloc_header_t*)kernel_heap_end; + + kgrow(pages_to_grow); + + new_heap_blk->size = (pages_to_grow * PAGE_SIZE) - sizeof(alloc_header_t); + new_heap_blk->free = 1; + new_heap_blk->next_blk = NULL; + + if (prev != NULL) { + prev->next_blk = new_heap_blk; + } + + return kalloc(sz); } \ No newline at end of file diff --git a/kernel/lib/memory.h b/kernel/lib/memory.h index 562b757..0c721f5 100644 --- a/kernel/lib/memory.h +++ b/kernel/lib/memory.h @@ -11,7 +11,7 @@ int strcmp(const char *s1, const char *s2); int strlen(const char* str); void kgrow(size_t pages); -void* alloc(size_t sz); +void* kalloc(size_t sz); #endif \ No newline at end of file diff --git a/kernel/lib/print.c b/kernel/lib/print.c index 9a938a6..099ec59 100644 --- a/kernel/lib/print.c +++ b/kernel/lib/print.c @@ -1,20 +1,25 @@ #include "print.h" #include "stream.h" +#include "tasks.h" + #include -extern print_stream_t* kout; +#include + +spinlock_t kwrite_lock = {0}; + static char* hex_chars = "0123456789abcdef"; static void kprint(const char *str) { while (*str) { - kout->putchar(*str); + vga_putchar(*str); str++; } } static void kputd(int d) { if (d == 0) { - kout->putchar('0'); + vga_putchar('0'); return; } char buffer[12]; @@ -24,13 +29,13 @@ static void kputd(int d) { d /= 10; } for (int j = i - 1; j >= 0; j--) { - kout->putchar(buffer[j]); + vga_putchar(buffer[j]); } } static void kputx(unsigned int x) { if (x == 0) { - kout->putchar('0'); + vga_putchar('0'); return; } char buffer[8]; @@ -41,15 +46,18 @@ static void kputx(unsigned int x) { x >>= 4; } for (int j = i - 1; j >= 0; j--) { - kout->putchar(buffer[j]); + vga_putchar(buffer[j]); } } void kputc(const char c) { - kout->putchar(c); + spin_lock(&kwrite_lock); + vga_putchar(c); + spin_unlock(&kwrite_lock); } void kprintf(const char* fmt, ...) { + spin_lock(&kwrite_lock); va_list args; va_start(args, fmt); @@ -73,19 +81,20 @@ void kprintf(const char* fmt, ...) { break; } case '%': - kout->putchar('%'); + vga_putchar('%'); break; default: - kout->putchar('%'); - kout->putchar(*fmt); + vga_putchar('%'); + vga_putchar(*fmt); break; } fmt++; } else { - kout->putchar(*fmt); + vga_putchar(*fmt); fmt++; } } va_end(args); + spin_unlock(&kwrite_lock); } \ No newline at end of file diff --git a/kernel/lib/tasks.c b/kernel/lib/tasks.c new file mode 100644 index 0000000..64f2751 --- /dev/null +++ b/kernel/lib/tasks.c @@ -0,0 +1,11 @@ +#include + +void spin_lock(spinlock_t *lock) { + while (__sync_lock_test_and_set(&lock->locked, 1)) { + asm volatile("pause"); + } +} + +void spin_unlock(spinlock_t *lock) { + __sync_lock_release(&lock->locked); +} \ No newline at end of file diff --git a/kernel/lib/tasks.h b/kernel/lib/tasks.h new file mode 100644 index 0000000..b6e67a4 --- /dev/null +++ b/kernel/lib/tasks.h @@ -0,0 +1,13 @@ +#ifndef KTASKS_H +#define KTASKS_H + +#include + +typedef struct { + volatile uint32_t locked; +} spinlock_t; + +void spin_lock(spinlock_t *lock); +void spin_unlock(spinlock_t *lock); + +#endif \ No newline at end of file diff --git a/kernel/memory/mm.c b/kernel/memory/mm.c index f20c37a..9bfaf88 100644 --- a/kernel/memory/mm.c +++ b/kernel/memory/mm.c @@ -18,7 +18,7 @@ extern void disable_pae(); #define PAGE_TABLES 0xFFC00000 #define PAGE_DIRECTORY 0xFFFFF000 -#define TEMP_MAPPING_VADDR 0xE0000000 +#define TEMP_MAPPING_VADDR 0xDFFF0000 static uint32_t max_address = 0; static uint32_t total_available_memory = 0; @@ -141,8 +141,6 @@ void init_pmm(void* mmap_base, uint32_t mmap_limit) { if (mmap_base != NULL && mmap_limit > 0) { parse_multiboot_mmap(mmap_base, mmap_limit); } - - kprintf("total free memory: %dMB\n", total_available_memory / 1024 / 1024); } void init_page_tables() { @@ -165,7 +163,7 @@ uint32_t total_free_memory() { return total_available_memory; } -void* create_user_pd() { +void* create_task_pd() { uint32_t pd_address = (uint32_t)p_alloc_frame(); if (pd_address == 0) { return 0; @@ -173,18 +171,18 @@ void* create_user_pd() { map_page(TEMP_MAPPING_VADDR, pd_address, PAGE_PRESENT | PAGE_WRITABLE); - uint32_t* user_pd = (uint32_t*)TEMP_MAPPING_VADDR; + uint32_t* task_pd = (uint32_t*)TEMP_MAPPING_VADDR; uint32_t* kernel_pd = (uint32_t*)PAGE_DIRECTORY; for(int i = 0; i < 768; i++) { - user_pd[i] = 0; + task_pd[i] = 0; } for(int i = 768; i < 1023; i++) { - user_pd[i] = kernel_pd[i]; + task_pd[i] = kernel_pd[i]; } - user_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE; + task_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE; uint32_t pde = TEMP_MAPPING_VADDR >> 22; uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF; diff --git a/kernel/memory/mm.h b/kernel/memory/mm.h index 75ebd88..456d8c2 100644 --- a/kernel/memory/mm.h +++ b/kernel/memory/mm.h @@ -20,7 +20,7 @@ void* p_alloc_frame(); uint32_t total_free_memory(); -void* create_user_pd(); +void* create_task_pd(); void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags); diff --git a/kernel/process.h b/kernel/process.h new file mode 100644 index 0000000..11f7f2d --- /dev/null +++ b/kernel/process.h @@ -0,0 +1,20 @@ +#ifndef KPROCESS_H +#define KPROCESS_H + +#include + +typedef enum { + STATE_READY, + STATE_SLEEPING, + STATE_DEAD +} process_state_t; + +typedef struct { + uint32_t pid; + uint32_t esp; + uint32_t cr3; + process_state_t state; + uint32_t sleep; +} __attribute__((packed)) process_t; + +#endif \ No newline at end of file diff --git a/kernel/scheduler.S b/kernel/scheduler.S new file mode 100644 index 0000000..8f1d91e --- /dev/null +++ b/kernel/scheduler.S @@ -0,0 +1,12 @@ +.code32 +.extern schedule_next_task +.global yield +yield: + cli + pushal + push %esp + call schedule_next_task + movl %eax, %esp + popal + sti + ret \ No newline at end of file diff --git a/kernel/scheduler.c b/kernel/scheduler.c new file mode 100644 index 0000000..ab80e57 --- /dev/null +++ b/kernel/scheduler.c @@ -0,0 +1,136 @@ +#include +#include + +#include + +#include + +#include "process.h" +#include "scheduler.h" + +static process_t* process_table; +static spinlock_t process_table_lock = {0}; + +static int current_process = 0; +static int total_processes = 0; + +extern uint32_t fetch_cr3(); + +#define IDLE_TASK_PID 1 +static void idle_task() { + while (1) asm volatile("hlt"); +} + +uint32_t schedule_next_task(uint32_t current_esp) { + spin_lock(&process_table_lock); + process_table[current_process].esp = current_esp; + + for (int i = 0; i < total_processes; i++) { + if (process_table[i].state == STATE_SLEEPING) { + if (process_table[i].sleep > 0) { + process_table[i].sleep--; + } + + if (process_table[i].sleep == 0) { + process_table[i].state = STATE_READY; + } + } + } + + int next_process = current_process; + int found_ready = 0; + while (1) { + next_process = (next_process + 1) % total_processes; + if (next_process != IDLE_TASK_PID && process_table[next_process].state == STATE_READY) { + found_ready = 1; + break; + } + + if (next_process == current_process) { + break; + } + } + + if (!found_ready) { + if (process_table[current_process].state == STATE_READY) { + next_process = current_process; + } else { + next_process = IDLE_TASK_PID; + } + } + + current_process = next_process; + + if (fetch_cr3() != process_table[current_process].cr3) { + extern void load_pd(uint32_t table); + load_pd(process_table[current_process].cr3); + } + + uint32_t rtn = process_table[current_process].esp; + spin_unlock(&process_table_lock); + + return rtn; +} + +void init_scheduler() { + process_table = kalloc(16 * sizeof(process_t)); + total_processes = 0; + + process_t* process = &process_table[total_processes]; + process->pid = total_processes; + process->esp = 0; + process->cr3 = fetch_cr3(); + process->state = STATE_READY; + process->sleep = 0; + total_processes++; + + create_task((uint32_t)idle_task, fetch_cr3()); + + current_process = 0; +} + +int create_task(uint32_t entry_point, uint32_t cr3) { + if (total_processes >= 16) { + return 0; + } + + spin_lock(&process_table_lock); + process_t* process = &process_table[total_processes]; + process->pid = total_processes; + process->cr3 = cr3; + process->state = STATE_READY; + process->sleep = 0; + + void* stack_bottom = kalloc(4096); + uint32_t* esp = (uint32_t*)((uint32_t)stack_bottom + 4096); + + *(--esp) = 0x0202; // EFLAGS + *(--esp) = 0x08; // CS + *(--esp) = entry_point; // EIP + + *(--esp) = 0; // EAX + *(--esp) = 0; // ECX + *(--esp) = 0; // EDX + *(--esp) = 0; // EBX + *(--esp) = 0; // ESP + *(--esp) = 0; // EBP + *(--esp) = 0; // ESI + *(--esp) = 0; // EDI + + process->esp = (uint32_t)esp; + spin_unlock(&process_table_lock); + + total_processes++; + return 1; +} + +void sleep(uint32_t ticks) { + if (ticks == 0) return; + + spin_lock(&process_table_lock); + process_table[current_process].sleep = ticks; + process_table[current_process].state = STATE_SLEEPING; + spin_unlock(&process_table_lock); + + yield(); +} \ No newline at end of file diff --git a/kernel/scheduler.h b/kernel/scheduler.h new file mode 100644 index 0000000..a0d825e --- /dev/null +++ b/kernel/scheduler.h @@ -0,0 +1,13 @@ +#ifndef KSCHEDULER_H +#define KSCHEDULER_H + +#include + +void init_scheduler(); + +int create_task(uint32_t entry_point, uint32_t cr3); + +void sleep(uint32_t ticks); +void yield(); + +#endif \ No newline at end of file diff --git a/kernel/syscall_stubs.S b/kernel/syscall.S similarity index 100% rename from kernel/syscall_stubs.S rename to kernel/syscall.S diff --git a/kernel/syscall.h b/kernel/syscall.h new file mode 100644 index 0000000..7d0387f --- /dev/null +++ b/kernel/syscall.h @@ -0,0 +1,6 @@ +#ifndef KSYSCALL_H +#define KSYSCALL_H + +void syscall_handler(); + +#endif \ No newline at end of file diff --git a/makefile b/makefile index 414375c..d06f6ac 100644 --- a/makefile +++ b/makefile @@ -6,8 +6,7 @@ OSNAME := rockos C_SOURCES := $(shell find kernel -type f -name '*.c') S_SOURCES := $(shell find kernel -type f -name '*.S') -# This correctly generates paths like obj/kernel/main.o -OBJECTS := $(patsubst %.c, obj/%.o, $(C_SOURCES)) $(patsubst %.S, obj/%.o, $(S_SOURCES)) +OBJECTS := $(patsubst %, obj/%.o, $(C_SOURCES) $(S_SOURCES)) CFLAGS := -ffreestanding -O2 -Wall -Wextra -Ikernel LDFLAGS := -T kernel/linker.ld @@ -25,11 +24,11 @@ $(OSNAME).iso: $(OSNAME).bin grub.cfg cp grub.cfg isodir/boot/grub/grub.cfg grub-mkrescue -o $(OSNAME).iso isodir -obj/kernel/%.o: kernel/%.c +obj/%.c.o: %.c @mkdir -p $(dir $@) $(CC) -c $< -o $@ $(CFLAGS) -obj/kernel/%.o: kernel/%.S +obj/%.S.o: %.S @mkdir -p $(dir $@) $(CC) -c $< -o $@ $(CFLAGS)