diff --git a/kernel/gdt.asm b/kernel/gdt.asm index e69de29..68cf4f2 100644 --- a/kernel/gdt.asm +++ b/kernel/gdt.asm @@ -0,0 +1,21 @@ +; gdt.asm +; Assembler function to load the GDT and update segment registers + +global gdt_flush + +gdt_flush: + mov eax, [esp + 4] ; Argument: pointer to GDT descriptor + lgdt [eax] ; Load GDT + + ; Reload segment registers + mov ax, 0x10 ; 0x10 = offset to kernel data segment (3rd entry) + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; Jump to flush the instruction pipeline and load CS + jmp 0x08:.flush ; 0x08 = offset to code segment (2nd entry) +.flush: + ret diff --git a/kernel/gdt.c b/kernel/gdt.c index e69de29..625b496 100644 --- a/kernel/gdt.c +++ b/kernel/gdt.c @@ -0,0 +1,48 @@ +#include "gdt.h" + +// Structure of a GDT entry (8 bytes) +struct gdt_entry { + uint16_t limit_low; // Limit bits 0–15 + uint16_t base_low; // Base bits 0–15 + uint8_t base_middle; // Base bits 16–23 + uint8_t access; // Access flags + uint8_t granularity; // Granularity + limit bits 16–19 + uint8_t base_high; // Base bits 24–31 +} __attribute__((packed)); + +// Structure of the GDT pointer +struct gdt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +// Declare GDT with 3 entries +static struct gdt_entry gdt[3]; +static struct gdt_ptr gp; + +// External ASM function to load GDT +extern void gdt_flush(uint32_t); + +// Set an individual GDT entry +static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity) { + gdt[num].base_low = (base & 0xFFFF); + gdt[num].base_middle = (base >> 16) & 0xFF; + gdt[num].base_high = (base >> 24) & 0xFF; + + gdt[num].limit_low = (limit & 0xFFFF); + gdt[num].granularity = ((limit >> 16) & 0x0F) | (granularity & 0xF0); + + gdt[num].access = access; +} + +// Initialize the GDT +void gdt_init(void) { + gp.limit = (sizeof(struct gdt_entry) * 3) - 1; + gp.base = (uint32_t)&gdt; + + gdt_set_gate(0, 0, 0, 0, 0); // Null segment + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment + + gdt_flush((uint32_t)&gp); +} diff --git a/kernel/gdt.h b/kernel/gdt.h index e69de29..c49f230 100644 --- a/kernel/gdt.h +++ b/kernel/gdt.h @@ -0,0 +1,8 @@ +#ifndef GDT_H +#define GDT_H + +#include + +void gdt_init(void); + +#endif diff --git a/kernel/isr.c b/kernel/isr.c index 37ba3ec..9342a2d 100644 --- a/kernel/isr.c +++ b/kernel/isr.c @@ -1,21 +1,34 @@ #include "terminal.h" #include "serial.h" +#include "isr.h" + +static isr_callback_t interrupt_handlers[MAX_INTERRUPTS] = { 0 }; void isr_handler(uint32_t int_num, uint32_t err_code) { terminal_write("Interrupt occurred: "); - // Add simple int-to-string printing here + // Here you can add a basic itoa to print int_num serial_write("INT triggered\n"); - if (int_num == 0) { - terminal_write(" -> Divide by zero error!\n"); - } else if (int_num == 13) { - terminal_write(" -> General Protection Fault!\n"); + if (interrupt_handlers[int_num]) { + interrupt_handlers[int_num](); // Call registered handler } else { - terminal_write(" -> Unknown interrupt\n"); - } + terminal_write(" -> No handler registered\n"); - // Halt CPU - while (1) { - asm volatile ("hlt"); + if (int_num == 0) { + terminal_write(" -> Divide by zero error!\n"); + } else if (int_num == 13) { + terminal_write(" -> General Protection Fault!\n"); + } else { + terminal_write(" -> Unknown interrupt\n"); + } + + // Halt CPU + while (1) { + asm volatile ("hlt"); + } } } + +void register_interrupt_handler(uint8_t n, isr_callback_t handler) { + interrupt_handlers[n] = handler; +} diff --git a/kernel/isr.h b/kernel/isr.h index e69de29..75d5af1 100644 --- a/kernel/isr.h +++ b/kernel/isr.h @@ -0,0 +1,13 @@ +#ifndef ISR_H +#define ISR_H + +#include + +#define MAX_INTERRUPTS 256 + +typedef void (*isr_callback_t)(void); + +void isr_handler(uint32_t int_num, uint32_t err_code); +void register_interrupt_handler(uint8_t n, isr_callback_t handler); + +#endif diff --git a/kernel/kmain.c b/kernel/kmain.c index c3d6031..7a40550 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -31,6 +31,17 @@ void kmain(void) { paging_init(); serial_write("Paging initialized.\n"); + terminal_write("Initializing memory allocator...\n"); + kmalloc_init(0xC0100000); // Virtual heap start address (must be mapped!) + serial_write("kmalloc initialized.\n"); + + void* ptr = kmalloc(128); // Allocation test + serial_write("Allocated 128 bytes.\n"); + + terminal_write("Initializing timer...\n"); + timer_init(100); // 100 Hz (10 ms interval) + serial_write("Timer initialized.\n"); + terminal_write("Getting memory map...\n"); memory_map_entry_t mmap[32]; uint32_t mmap_size = get_memory_map(mmap, 32); diff --git a/kernel/kmalloc.c b/kernel/kmalloc.c index e69de29..6e54aa2 100644 --- a/kernel/kmalloc.c +++ b/kernel/kmalloc.c @@ -0,0 +1,38 @@ +#include "kmalloc.h" +#include "terminal.h" // Optional: for debug output + +static uint32_t current_heap = 0; + +// Initialize the allocator with a starting heap address +void kmalloc_init(uint32_t heap_start) { + current_heap = heap_start; +} + +// Simple bump allocator +void* kmalloc(size_t size) { + if (current_heap == 0) { + terminal_write("kmalloc used before initialization!\n"); + return 0; + } + + void* addr = (void*)current_heap; + current_heap += size; + return addr; +} + +// Allocate memory aligned to a power-of-two boundary (e.g., 0x1000) +void* kmalloc_aligned(size_t size, uint32_t alignment) { + if (current_heap == 0) { + terminal_write("kmalloc_aligned used before initialization!\n"); + return 0; + } + + // Align the current_heap pointer + if ((current_heap & (alignment - 1)) != 0) { + current_heap = (current_heap + alignment) & ~(alignment - 1); + } + + void* addr = (void*)current_heap; + current_heap += size; + return addr; +} diff --git a/kernel/kmalloc.h b/kernel/kmalloc.h index e69de29..6564bb8 100644 --- a/kernel/kmalloc.h +++ b/kernel/kmalloc.h @@ -0,0 +1,11 @@ +#ifndef KMALLOC_H +#define KMALLOC_H + +#include +#include // for size_t + +void kmalloc_init(uint32_t heap_start); +void* kmalloc(size_t size); +void* kmalloc_aligned(size_t size, uint32_t alignment); + +#endif diff --git a/kernel/paging.c b/kernel/paging.c index 6028a69..cbf329c 100644 --- a/kernel/paging.c +++ b/kernel/paging.c @@ -2,20 +2,18 @@ #include "io.h" page_directory_entry_t *page_directory = (page_directory_entry_t *)0x100000; -page_table_entry_t *page_table = (page_table_entry_t *)0x101000; // Located right after the page directory +page_table_entry_t *page_table = (page_table_entry_t *)0x101000; +page_table_entry_t *heap_page_table = (page_table_entry_t *)0x102000; // Located right after the page directory // Helper function to set up the page directory entry void set_page_directory(page_directory_entry_t *dir) { for (int i = 0; i < PAGE_DIRECTORY_SIZE; i++) { - // Set up a page directory entry with identity mapping - dir[i].present = 9; - dir[i].rw = 0; // Read/Write - dir[i].user = 0; // Kernel mode - dir[i].write_through = 0; - dir[i].cache_disabled = 0; - dir[i].accessed = 0; - dir[0].frame = (uint32_t)page_table >> 12; + dir[i].present = 0; } + dir[0].present = 1; + dir[0].rw = 1; + dir[0].user = 0; + dir[0].frame = (uint32_t)page_table >> 12; } // Helper function to set up the page table entry @@ -47,10 +45,26 @@ void enable_paging() { // Initialize paging: set up the page directory and enable paging void paging_init() { - // Set up the page directory and page tables + // Set up identity-mapped page directory + table set_page_directory(page_directory); set_page_table(page_table); - // Enable paging + // === Set up heap mapping at 0xC0100000 === + for (int i = 0; i < PAGE_TABLE_SIZE; i++) { + heap_page_table[i].present = 1; + heap_page_table[i].rw = 1; + heap_page_table[i].user = 0; + heap_page_table[i].write_through = 0; + heap_page_table[i].cache_disabled = 0; + heap_page_table[i].accessed = 0; + heap_page_table[i].frame = (256 + i); // Start physical heap at 1MB (256*4KB = 1MB) + } + + // Index 772 = 0xC0100000 / 4MB + page_directory[772].present = 1; + page_directory[772].rw = 1; + page_directory[772].user = 0; + page_directory[772].frame = (uint32_t)heap_page_table >> 12; + enable_paging(); } diff --git a/kernel/paging.h b/kernel/paging.h index af0a0f6..3c8a377 100644 --- a/kernel/paging.h +++ b/kernel/paging.h @@ -6,6 +6,7 @@ #define PAGE_SIZE 4096 // Page size in bytes #define PAGE_DIRECTORY_SIZE 1024 // 1024 entries in page directory #define PAGE_TABLE_SIZE 1024 // 1024 entries in a page table +#define KERNEL_HEAP_START 0xC0100000 // Page Directory and Page Table structure typedef struct { diff --git a/kernel/timer.c b/kernel/timer.c index e69de29..3804ec8 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -0,0 +1,28 @@ +#include "timer.h" +#include "io.h" +#include "isr.h" +#include "terminal.h" + +static uint32_t tick = 0; + +void timer_callback(void) { + tick++; + // Optional: Print every 100 ticks + // if (tick % 100 == 0) { + // terminal_write("Tick\n"); + // } +} + +void timer_init(uint32_t frequency) { + register_interrupt_handler(32, timer_callback); // IRQ0 = Interrupt 32 + + uint32_t divisor = 1193180 / frequency; + + outb(0x43, 0x36); // Command byte + outb(0x40, divisor & 0xFF); // Low byte + outb(0x40, (divisor >> 8)); // High byte +} + +uint32_t timer_get_ticks(void) { + return tick; +} \ No newline at end of file diff --git a/kernel/timer.h b/kernel/timer.h index e69de29..08e6e3b 100644 --- a/kernel/timer.h +++ b/kernel/timer.h @@ -0,0 +1,9 @@ +#ifndef TIMER_H +#define TIMER_H + +#include + +void timer_init(uint32_t frequency); +uint32_t timer_get_ticks(void); + +#endif \ No newline at end of file diff --git a/kernel/vga.c b/kernel/vga.c index e69de29..ee5e358 100644 --- a/kernel/vga.c +++ b/kernel/vga.c @@ -0,0 +1,9 @@ +#include "vga.h" + +uint8_t vga_entry_color(vga_color fg, vga_color bg) { + return fg | bg << 4; +} + +uint16_t vga_entry(unsigned char uc, uint8_t color) { + return (uint16_t)uc | (uint16_t)color << 8; +} \ No newline at end of file diff --git a/kernel/vga.h b/kernel/vga.h index e69de29..f3a4883 100644 --- a/kernel/vga.h +++ b/kernel/vga.h @@ -0,0 +1,28 @@ +#ifndef VGA_H +#define VGA_H + +#include + +typedef enum { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15, +} vga_color; + +uint8_t vga_entry_color(vga_color fg, vga_color bg); +uint16_t vga_entry(unsigned char uc, uint8_t color); + +#endif