Compare commits

..

No commits in common. "799f744f47d29f917e309d9a2da391060e5fd205" and "ecfa54e2259b0dd1fb657e0d35ce953b59e5d410" have entirely different histories.

36 changed files with 47 additions and 537 deletions

Binary file not shown.

View File

View File

View File

View File

View File

@ -1,21 +0,0 @@
; 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

View File

@ -1,48 +0,0 @@
#include "gdt.h"
// Structure of a GDT entry (8 bytes)
struct gdt_entry {
uint16_t limit_low; // Limit bits 015
uint16_t base_low; // Base bits 015
uint8_t base_middle; // Base bits 1623
uint8_t access; // Access flags
uint8_t granularity; // Granularity + limit bits 1619
uint8_t base_high; // Base bits 2431
} __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);
}

View File

@ -1,8 +0,0 @@
#ifndef GDT_H
#define GDT_H
#include <stdint.h>
void gdt_init(void);
#endif

View File

View File

View File

@ -8,37 +8,7 @@ idt_ptr_t idt_ptr;
// External assembly stubs for ISRs (provided below)
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
extern void isr_default();
// Helper to set an IDT gate
@ -66,40 +36,8 @@ void idt_init() {
}
// Set specific handlers
// Assign CPU exception handlers
idt_set_gate(0, (uint32_t)isr0);
idt_set_gate(1, (uint32_t)isr1);
idt_set_gate(2, (uint32_t)isr2);
idt_set_gate(3, (uint32_t)isr3);
idt_set_gate(4, (uint32_t)isr4);
idt_set_gate(5, (uint32_t)isr5);
idt_set_gate(6, (uint32_t)isr6);
idt_set_gate(7, (uint32_t)isr7);
idt_set_gate(8, (uint32_t)isr8);
idt_set_gate(9, (uint32_t)isr9);
idt_set_gate(10, (uint32_t)isr10);
idt_set_gate(11, (uint32_t)isr11);
idt_set_gate(12, (uint32_t)isr12);
idt_set_gate(13, (uint32_t)isr13);
idt_set_gate(14, (uint32_t)isr14);
idt_set_gate(15, (uint32_t)isr15);
idt_set_gate(16, (uint32_t)isr16);
idt_set_gate(17, (uint32_t)isr17);
idt_set_gate(18, (uint32_t)isr18);
idt_set_gate(19, (uint32_t)isr19);
idt_set_gate(20, (uint32_t)isr20);
idt_set_gate(21, (uint32_t)isr21);
idt_set_gate(22, (uint32_t)isr22);
idt_set_gate(23, (uint32_t)isr23);
idt_set_gate(24, (uint32_t)isr24);
idt_set_gate(25, (uint32_t)isr25);
idt_set_gate(26, (uint32_t)isr26);
idt_set_gate(27, (uint32_t)isr27);
idt_set_gate(28, (uint32_t)isr28);
idt_set_gate(29, (uint32_t)isr29);
idt_set_gate(30, (uint32_t)isr30);
idt_set_gate(31, (uint32_t)isr31);
idt_set_gate(0, (uint32_t)isr0); // Divide by zero
idt_set_gate(13, (uint32_t)isr13); // General protection fault
idt_load();
}

View File

View File

View File

@ -1,77 +1,29 @@
; isr.asm
[BITS 32]
[GLOBAL isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7, isr8, isr9]
[GLOBAL isr10, isr11, isr12, isr13, isr14, isr15, isr16, isr17, isr18, isr19]
[GLOBAL isr20, isr21, isr22, isr23, isr24, isr25, isr26, isr27, isr28, isr29]
[GLOBAL isr30, isr31, isr_default]
[GLOBAL isr0, isr13, isr_default]
%macro ISR_NOERR 1
isr%1:
isr0:
cli
push dword 0 ; Dummy error code
push dword %1 ; Interrupt number
push byte 0
push byte 0
call isr_handler
add esp, 8
sti
iret
%endmacro
%macro ISR_ERR 1
isr%1:
isr13:
cli
push dword %1 ; Interrupt number
push byte 13
push byte 0
call isr_handler
add esp, 8
sti
iret
%endmacro
; ISR 07: No error code
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 814: Error code pushed automatically
ISR_ERR 8
ISR_NOERR 9 ; Coprocessor Segment Overrun (obsolete, no error code)
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
; ISR 15 is reserved
ISR_NOERR 15
; ISR 1619 (FPU, Alignment Check, etc.)
ISR_NOERR 16
ISR_ERR 17
ISR_NOERR 18
ISR_NOERR 19
; ISR 2031 (reserved or future use)
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_NOERR 30
ISR_NOERR 31
; Fallback handler
isr_default:
cli
push dword 255
push dword 0
push byte 255
push byte 0
call isr_handler
add esp, 8
sti

View File

@ -1,19 +1,11 @@
#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: ");
// Here you can add a basic itoa to print int_num
// Add simple int-to-string printing here
serial_write("INT triggered\n");
if (interrupt_handlers[int_num]) {
interrupt_handlers[int_num](); // Call registered handler
} else {
terminal_write(" -> No handler registered\n");
if (int_num == 0) {
terminal_write(" -> Divide by zero error!\n");
} else if (int_num == 13) {
@ -27,8 +19,3 @@ void isr_handler(uint32_t int_num, uint32_t err_code) {
asm volatile ("hlt");
}
}
}
void register_interrupt_handler(uint8_t n, isr_callback_t handler) {
interrupt_handlers[n] = handler;
}

View File

@ -1,13 +0,0 @@
#ifndef ISR_H
#define ISR_H
#include <stdint.h>
#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

View File

@ -1,53 +0,0 @@
#include "keyboard.h"
#include "io.h"
#include "isr.h"
#include "terminal.h"
#define KEYBOARD_DATA_PORT 0x60
static char key_buffer[256];
static uint8_t buffer_index = 0;
// Basic US QWERTY keymap (scancode to ASCII)
static const char scancode_map[128] = {
0, 27, '1', '2', '3', '4', '5', '6', '7', '8', // 0x00 - 0x09
'9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', // 0x0A - 0x13
't', 'y', 'z', 'u', 'i', 'o', 'p', '[', ']', '\n', // 0x14 - 0x1D
0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', // 0x1E - 0x27
';', '\'', '`', 0, '\\', 'y', 'x', 'c', 'v', 'b', // 0x28 - 0x31
'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, // 0x32 - 0x3B
// rest can be filled as needed
};
// Interrupt handler for IRQ1
void keyboard_callback() {
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
// Ignore key releases (scancodes with high bit set)
if (scancode & 0x80)
return;
char c = scancode_map[scancode];
if (c && buffer_index < sizeof(key_buffer)) {
key_buffer[buffer_index++] = c;
terminal_putchar(c); // Echo to terminal (optional)
}
}
void keyboard_init() {
register_interrupt_handler(33, keyboard_callback); // IRQ1 = int 33 (0x21)
}
// Blocking read (returns one char)
char keyboard_get_char() {
while (buffer_index == 0);
char c = key_buffer[0];
// Shift buffer left
for (uint8_t i = 1; i < buffer_index; i++) {
key_buffer[i - 1] = key_buffer[i];
}
buffer_index--;
return c;
}

View File

@ -1,7 +0,0 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
void keyboard_init(void);
char keyboard_get_char(void); // Blocking read from buffer
#endif

View File

@ -31,17 +31,6 @@ 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);

View File

@ -1,38 +0,0 @@
#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;
}

View File

@ -1,11 +0,0 @@
#ifndef KMALLOC_H
#define KMALLOC_H
#include <stdint.h>
#include <stddef.h> // 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

View File

View File

@ -2,18 +2,20 @@
#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;
page_table_entry_t *heap_page_table = (page_table_entry_t *)0x102000; // Located right after the page directory
page_table_entry_t *page_table = (page_table_entry_t *)0x101000; // 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++) {
dir[i].present = 0;
// Set up a page directory entry with identity mapping
dir[i].present = 1;
dir[i].rw = 1; // Read/Write
dir[i].user = 0; // Kernel mode
dir[i].write_through = 0;
dir[i].cache_disabled = 0;
dir[i].accessed = 0;
dir[i].frame = (uint32_t)&page_table[i] >> 12; // Page table frame address
}
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
@ -45,26 +47,10 @@ void enable_paging() {
// Initialize paging: set up the page directory and enable paging
void paging_init() {
// Set up identity-mapped page directory + table
// Set up the page directory and page tables
set_page_directory(page_directory);
set_page_table(page_table);
// === 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
enable_paging();
}

View File

@ -6,7 +6,6 @@
#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 {

View File

@ -1,39 +1,20 @@
#include "io.h"
#include "serial.h"
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
void serial_init_port(uint16_t port) {
outb(port + 1, 0x00);
outb(port + 3, 0x80);
outb(port + 0, 0x03);
outb(port + 1, 0x00);
outb(port + 3, 0x03);
outb(port + 2, 0xC7);
outb(port + 4, 0x0B);
}
void serial_init(void) {
serial_init_port(COM1);
serial_init_port(COM2);
serial_init_port(COM3);
serial_init_port(COM4);
}
void serial_write_char(char c) {
while (!(inb(COM1 + 5) & 0x20));
outb(COM1, c);
outb(COM1 + 1, 0x00); // Disable interrupts
outb(COM1 + 3, 0x80); // Enable DLAB
outb(COM1 + 0, 0x03); // Set baud rate to 38400
outb(COM1 + 1, 0x00);
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
outb(COM1 + 2, 0xC7); // Enable FIFO, clear, 14-byte threshold
outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
void serial_write(const char *str) {
while (*str) {
serial_write_char(*str++);
while (!(inb(COM1 + 5) & 0x20)); // Wait for the transmitter holding register to be empty
outb(COM1, *str++);
}
}
void serial_write_string(const char* str) {
serial_write(str);
}

View File

@ -4,9 +4,7 @@
#include <stdint.h>
void serial_init(void);
void serial_init_port(uint16_t port);
void serial_write_char(char c);
void serial_write(const char *str);
void serial_write(char c);
void serial_write_string(const char *str);
#endif

View File

View File

View File

@ -1,6 +1,5 @@
#include <stdint.h>
#include "io.h"
#include "terminal.h"
#define VGA_ADDRESS 0xB8000
#define VGA_WIDTH 80
@ -10,7 +9,6 @@
static uint16_t* const vga_buffer = (uint16_t*) VGA_ADDRESS;
static uint8_t cursor_x = 0;
static uint8_t cursor_y = 0;
static uint8_t current_color = WHITE_ON_BLACK;
static uint16_t vga_entry(char c, uint8_t color) {
return (uint16_t) color << 8 | (uint8_t) c;
@ -20,35 +18,20 @@ void terminal_initialize(void) {
for (uint16_t y = 0; y < VGA_HEIGHT; y++) {
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
vga_buffer[index] = vga_entry(' ', current_color);
vga_buffer[index] = vga_entry(' ', WHITE_ON_BLACK);
}
}
cursor_x = 0;
cursor_y = 0;
update_cursor(); // Optional: good idea to reset position
}
void terminal_putchar(char c) {
// Handle backspace
if (c == '\b') {
if (cursor_x > 0) {
cursor_x--;
} else if (cursor_y > 0) {
cursor_y--;
cursor_x = VGA_WIDTH - 1;
}
vga_buffer[cursor_y * VGA_WIDTH + cursor_x] = vga_entry(' ', current_color);
update_cursor(); // Optional, if you add cursor updating
return;
}
// Handle newline
if (c == '\n') {
cursor_x = 0;
cursor_y++;
} else {
const size_t index = cursor_y * VGA_WIDTH + cursor_x;
vga_buffer[index] = vga_entry(c, current_color);
vga_buffer[index] = vga_entry(c, WHITE_ON_BLACK);
cursor_x++;
if (cursor_x >= VGA_WIDTH) {
cursor_x = 0;
@ -66,44 +49,15 @@ void terminal_putchar(char c) {
// Clear the last line
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
vga_buffer[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', current_color);
vga_buffer[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', WHITE_ON_BLACK);
}
cursor_y = VGA_HEIGHT - 1;
}
update_cursor(); // Optional, if you want the hardware cursor to follow
}
void terminal_write(const char* str) {
for (size_t i = 0; str[i] != '\0'; i++) {
terminal_putchar(str[i]);
}
}
void terminal_setcolor(uint8_t color)
{
current_color = color;
}
void terminal_clear(void) {
for (uint16_t y = 0; y < VGA_HEIGHT; y++) {
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
const size_t index = y * VGA_WIDTH + x;
vga_buffer[index] = vga_entry(' ', current_color);
}
}
cursor_x = 0;
cursor_y = 0;
update_cursor();
}
static void update_cursor() {
uint16_t pos = cursor_y * VGA_WIDTH + cursor_x;
outb(0x3D4, 0x0F);
outb(0x3D5, (uint8_t)(pos & 0xFF));
outb(0x3D4, 0x0E);
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
}

View File

@ -7,6 +7,5 @@ void terminal_initialize(void);
void terminal_putchar(char c);
void terminal_write(const char *str);
void terminal_setcolor(uint8_t color);
void terminal_clear(void);
#endif

View File

View File

View File

@ -1,28 +0,0 @@
#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;
}

View File

@ -1,9 +0,0 @@
#ifndef TIMER_H
#define TIMER_H
#include <stdint.h>
void timer_init(uint32_t frequency);
uint32_t timer_get_ticks(void);
#endif

View File

@ -1,9 +0,0 @@
#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;
}

View File

@ -1,28 +0,0 @@
#ifndef VGA_H
#define VGA_H
#include <stdint.h>
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