mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2025-06-07 09:01:27 -07:00
Compare commits
2 Commits
ecfa54e225
...
799f744f47
Author | SHA1 | Date | |
---|---|---|---|
799f744f47 | |||
10b8fdc33f |
BIN
bootloader/boot.bin
Normal file
BIN
bootloader/boot.bin
Normal file
Binary file not shown.
0
kernel/debug.c
Normal file
0
kernel/debug.c
Normal file
0
kernel/debug.h
Normal file
0
kernel/debug.h
Normal file
0
kernel/fs.c
Normal file
0
kernel/fs.c
Normal file
0
kernel/fs.h
Normal file
0
kernel/fs.h
Normal file
21
kernel/gdt.asm
Normal file
21
kernel/gdt.asm
Normal file
@ -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
|
48
kernel/gdt.c
Normal file
48
kernel/gdt.c
Normal file
@ -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);
|
||||||
|
}
|
8
kernel/gdt.h
Normal file
8
kernel/gdt.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef GDT_H
|
||||||
|
#define GDT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void gdt_init(void);
|
||||||
|
|
||||||
|
#endif
|
0
kernel/heap.c
Normal file
0
kernel/heap.c
Normal file
0
kernel/heap.h
Normal file
0
kernel/heap.h
Normal file
66
kernel/idt.c
66
kernel/idt.c
@ -8,7 +8,37 @@ idt_ptr_t idt_ptr;
|
|||||||
|
|
||||||
// External assembly stubs for ISRs (provided below)
|
// External assembly stubs for ISRs (provided below)
|
||||||
extern void isr0();
|
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 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();
|
extern void isr_default();
|
||||||
|
|
||||||
// Helper to set an IDT gate
|
// Helper to set an IDT gate
|
||||||
@ -36,8 +66,40 @@ void idt_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set specific handlers
|
// Set specific handlers
|
||||||
idt_set_gate(0, (uint32_t)isr0); // Divide by zero
|
// Assign CPU exception handlers
|
||||||
idt_set_gate(13, (uint32_t)isr13); // General protection fault
|
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_load();
|
idt_load();
|
||||||
}
|
}
|
||||||
|
0
kernel/irq.c
Normal file
0
kernel/irq.c
Normal file
0
kernel/irq.h
Normal file
0
kernel/irq.h
Normal file
@ -1,29 +1,77 @@
|
|||||||
; isr.asm
|
|
||||||
[BITS 32]
|
[BITS 32]
|
||||||
[GLOBAL isr0, isr13, isr_default]
|
[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]
|
||||||
|
|
||||||
isr0:
|
%macro ISR_NOERR 1
|
||||||
|
isr%1:
|
||||||
cli
|
cli
|
||||||
push byte 0
|
push dword 0 ; Dummy error code
|
||||||
push byte 0
|
push dword %1 ; Interrupt number
|
||||||
call isr_handler
|
call isr_handler
|
||||||
add esp, 8
|
add esp, 8
|
||||||
sti
|
sti
|
||||||
iret
|
iret
|
||||||
|
%endmacro
|
||||||
|
|
||||||
isr13:
|
%macro ISR_ERR 1
|
||||||
|
isr%1:
|
||||||
cli
|
cli
|
||||||
push byte 13
|
push dword %1 ; Interrupt number
|
||||||
push byte 0
|
|
||||||
call isr_handler
|
call isr_handler
|
||||||
add esp, 8
|
add esp, 8
|
||||||
sti
|
sti
|
||||||
iret
|
iret
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
; ISR 0–7: 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 8–14: 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 16–19 (FPU, Alignment Check, etc.)
|
||||||
|
ISR_NOERR 16
|
||||||
|
ISR_ERR 17
|
||||||
|
ISR_NOERR 18
|
||||||
|
ISR_NOERR 19
|
||||||
|
|
||||||
|
; ISR 20–31 (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:
|
isr_default:
|
||||||
cli
|
cli
|
||||||
push byte 255
|
push dword 255
|
||||||
push byte 0
|
push dword 0
|
||||||
call isr_handler
|
call isr_handler
|
||||||
add esp, 8
|
add esp, 8
|
||||||
sti
|
sti
|
||||||
|
15
kernel/isr.c
15
kernel/isr.c
@ -1,11 +1,19 @@
|
|||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "serial.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) {
|
void isr_handler(uint32_t int_num, uint32_t err_code) {
|
||||||
terminal_write("Interrupt occurred: ");
|
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");
|
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) {
|
if (int_num == 0) {
|
||||||
terminal_write(" -> Divide by zero error!\n");
|
terminal_write(" -> Divide by zero error!\n");
|
||||||
} else if (int_num == 13) {
|
} else if (int_num == 13) {
|
||||||
@ -18,4 +26,9 @@ void isr_handler(uint32_t int_num, uint32_t err_code) {
|
|||||||
while (1) {
|
while (1) {
|
||||||
asm volatile ("hlt");
|
asm volatile ("hlt");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_interrupt_handler(uint8_t n, isr_callback_t handler) {
|
||||||
|
interrupt_handlers[n] = handler;
|
||||||
}
|
}
|
||||||
|
13
kernel/isr.h
Normal file
13
kernel/isr.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#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
|
53
kernel/keyboard.c
Normal file
53
kernel/keyboard.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#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;
|
||||||
|
}
|
7
kernel/keyboard.h
Normal file
7
kernel/keyboard.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef KEYBOARD_H
|
||||||
|
#define KEYBOARD_H
|
||||||
|
|
||||||
|
void keyboard_init(void);
|
||||||
|
char keyboard_get_char(void); // Blocking read from buffer
|
||||||
|
|
||||||
|
#endif
|
@ -31,6 +31,17 @@ void kmain(void) {
|
|||||||
paging_init();
|
paging_init();
|
||||||
serial_write("Paging initialized.\n");
|
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");
|
terminal_write("Getting memory map...\n");
|
||||||
memory_map_entry_t mmap[32];
|
memory_map_entry_t mmap[32];
|
||||||
uint32_t mmap_size = get_memory_map(mmap, 32);
|
uint32_t mmap_size = get_memory_map(mmap, 32);
|
||||||
|
38
kernel/kmalloc.c
Normal file
38
kernel/kmalloc.c
Normal file
@ -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;
|
||||||
|
}
|
11
kernel/kmalloc.h
Normal file
11
kernel/kmalloc.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#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
|
0
kernel/multiboot.h
Normal file
0
kernel/multiboot.h
Normal file
@ -2,20 +2,18 @@
|
|||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
page_directory_entry_t *page_directory = (page_directory_entry_t *)0x100000;
|
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
|
// Helper function to set up the page directory entry
|
||||||
void set_page_directory(page_directory_entry_t *dir) {
|
void set_page_directory(page_directory_entry_t *dir) {
|
||||||
for (int i = 0; i < PAGE_DIRECTORY_SIZE; i++) {
|
for (int i = 0; i < PAGE_DIRECTORY_SIZE; i++) {
|
||||||
// Set up a page directory entry with identity mapping
|
dir[i].present = 0;
|
||||||
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
|
// 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
|
// Initialize paging: set up the page directory and enable paging
|
||||||
void paging_init() {
|
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_directory(page_directory);
|
||||||
set_page_table(page_table);
|
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();
|
enable_paging();
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#define PAGE_SIZE 4096 // Page size in bytes
|
#define PAGE_SIZE 4096 // Page size in bytes
|
||||||
#define PAGE_DIRECTORY_SIZE 1024 // 1024 entries in page directory
|
#define PAGE_DIRECTORY_SIZE 1024 // 1024 entries in page directory
|
||||||
#define PAGE_TABLE_SIZE 1024 // 1024 entries in a page table
|
#define PAGE_TABLE_SIZE 1024 // 1024 entries in a page table
|
||||||
|
#define KERNEL_HEAP_START 0xC0100000
|
||||||
|
|
||||||
// Page Directory and Page Table structure
|
// Page Directory and Page Table structure
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -1,20 +1,39 @@
|
|||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
#define COM1 0x3F8
|
#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) {
|
void serial_init(void) {
|
||||||
outb(COM1 + 1, 0x00); // Disable interrupts
|
serial_init_port(COM1);
|
||||||
outb(COM1 + 3, 0x80); // Enable DLAB
|
serial_init_port(COM2);
|
||||||
outb(COM1 + 0, 0x03); // Set baud rate to 38400
|
serial_init_port(COM3);
|
||||||
outb(COM1 + 1, 0x00);
|
serial_init_port(COM4);
|
||||||
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_char(char c) {
|
||||||
|
while (!(inb(COM1 + 5) & 0x20));
|
||||||
|
outb(COM1, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serial_write(const char *str) {
|
void serial_write(const char *str) {
|
||||||
while (*str) {
|
while (*str) {
|
||||||
while (!(inb(COM1 + 5) & 0x20)); // Wait for the transmitter holding register to be empty
|
serial_write_char(*str++);
|
||||||
outb(COM1, *str++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void serial_write_string(const char* str) {
|
||||||
|
serial_write(str);
|
||||||
|
}
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void serial_init(void);
|
void serial_init(void);
|
||||||
void serial_write(char c);
|
void serial_init_port(uint16_t port);
|
||||||
|
void serial_write_char(char c);
|
||||||
|
void serial_write(const char *str);
|
||||||
void serial_write_string(const char *str);
|
void serial_write_string(const char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
0
kernel/syscalls.c
Normal file
0
kernel/syscalls.c
Normal file
0
kernel/syscalls.h
Normal file
0
kernel/syscalls.h
Normal file
@ -1,5 +1,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
|
||||||
#define VGA_ADDRESS 0xB8000
|
#define VGA_ADDRESS 0xB8000
|
||||||
#define VGA_WIDTH 80
|
#define VGA_WIDTH 80
|
||||||
@ -9,6 +10,7 @@
|
|||||||
static uint16_t* const vga_buffer = (uint16_t*) VGA_ADDRESS;
|
static uint16_t* const vga_buffer = (uint16_t*) VGA_ADDRESS;
|
||||||
static uint8_t cursor_x = 0;
|
static uint8_t cursor_x = 0;
|
||||||
static uint8_t cursor_y = 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) {
|
static uint16_t vga_entry(char c, uint8_t color) {
|
||||||
return (uint16_t) color << 8 | (uint8_t) c;
|
return (uint16_t) color << 8 | (uint8_t) c;
|
||||||
@ -18,20 +20,35 @@ void terminal_initialize(void) {
|
|||||||
for (uint16_t y = 0; y < VGA_HEIGHT; y++) {
|
for (uint16_t y = 0; y < VGA_HEIGHT; y++) {
|
||||||
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
|
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
|
||||||
const size_t index = y * VGA_WIDTH + x;
|
const size_t index = y * VGA_WIDTH + x;
|
||||||
vga_buffer[index] = vga_entry(' ', WHITE_ON_BLACK);
|
vga_buffer[index] = vga_entry(' ', current_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
cursor_y = 0;
|
cursor_y = 0;
|
||||||
|
update_cursor(); // Optional: good idea to reset position
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminal_putchar(char c) {
|
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') {
|
if (c == '\n') {
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
cursor_y++;
|
cursor_y++;
|
||||||
} else {
|
} else {
|
||||||
const size_t index = cursor_y * VGA_WIDTH + cursor_x;
|
const size_t index = cursor_y * VGA_WIDTH + cursor_x;
|
||||||
vga_buffer[index] = vga_entry(c, WHITE_ON_BLACK);
|
vga_buffer[index] = vga_entry(c, current_color);
|
||||||
cursor_x++;
|
cursor_x++;
|
||||||
if (cursor_x >= VGA_WIDTH) {
|
if (cursor_x >= VGA_WIDTH) {
|
||||||
cursor_x = 0;
|
cursor_x = 0;
|
||||||
@ -49,15 +66,44 @@ void terminal_putchar(char c) {
|
|||||||
|
|
||||||
// Clear the last line
|
// Clear the last line
|
||||||
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
|
for (uint16_t x = 0; x < VGA_WIDTH; x++) {
|
||||||
vga_buffer[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', WHITE_ON_BLACK);
|
vga_buffer[(VGA_HEIGHT - 1) * VGA_WIDTH + x] = vga_entry(' ', current_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor_y = VGA_HEIGHT - 1;
|
cursor_y = VGA_HEIGHT - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_cursor(); // Optional, if you want the hardware cursor to follow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void terminal_write(const char* str) {
|
void terminal_write(const char* str) {
|
||||||
for (size_t i = 0; str[i] != '\0'; i++) {
|
for (size_t i = 0; str[i] != '\0'; i++) {
|
||||||
terminal_putchar(str[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));
|
||||||
|
}
|
||||||
|
@ -7,5 +7,6 @@ void terminal_initialize(void);
|
|||||||
void terminal_putchar(char c);
|
void terminal_putchar(char c);
|
||||||
void terminal_write(const char *str);
|
void terminal_write(const char *str);
|
||||||
void terminal_setcolor(uint8_t color);
|
void terminal_setcolor(uint8_t color);
|
||||||
|
void terminal_clear(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
0
kernel/threading.c
Normal file
0
kernel/threading.c
Normal file
0
kernel/threading.h
Normal file
0
kernel/threading.h
Normal file
28
kernel/timer.c
Normal file
28
kernel/timer.c
Normal file
@ -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;
|
||||||
|
}
|
9
kernel/timer.h
Normal file
9
kernel/timer.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef TIMER_H
|
||||||
|
#define TIMER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void timer_init(uint32_t frequency);
|
||||||
|
uint32_t timer_get_ticks(void);
|
||||||
|
|
||||||
|
#endif
|
9
kernel/vga.c
Normal file
9
kernel/vga.c
Normal file
@ -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;
|
||||||
|
}
|
28
kernel/vga.h
Normal file
28
kernel/vga.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#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
|
Loading…
x
Reference in New Issue
Block a user