From a9f282601410db1caaafeac0b36e9763514179cf Mon Sep 17 00:00:00 2001 From: Gregory Bowne Date: Thu, 15 May 2025 02:37:06 -0700 Subject: [PATCH] addind more important kernel files and also fixing bugs --- .vscode/settings.json | 3 +- kernel/cpu.c | 35 ++++++++++++++++ kernel/cpu.h | 9 ++++ kernel/elf.c | 0 kernel/elf.h | 0 kernel/isr.c | 12 +++++- kernel/malloc.c | 97 +++++++++++++++++++++++++++++++++++++++++++ kernel/malloc.h | 27 ++++++++++++ kernel/panic.c | 16 ++++++- kernel/print.c | 6 +++ kernel/print.h | 6 +++ kernel/scheduler.c | 59 +++++++++++++++++++++++++- kernel/scheduler.h | 15 +++++++ kernel/shell.c | 60 ++++++++++++++++++++++++++ kernel/shell.h | 7 ++++ kernel/syscalls.c | 29 ++++++++++++- kernel/syscalls.h | 11 +++++ kernel/terminal.c | 5 +-- kernel/timer.c | 11 +++-- kernel/utils.c | 88 ++++++++++++++++++++++++++++++++++++++- kernel/utils.h | 10 ++++- 21 files changed, 489 insertions(+), 17 deletions(-) create mode 100644 kernel/cpu.c create mode 100644 kernel/cpu.h create mode 100644 kernel/elf.c create mode 100644 kernel/elf.h create mode 100644 kernel/malloc.c create mode 100644 kernel/malloc.h create mode 100644 kernel/print.c create mode 100644 kernel/print.h create mode 100644 kernel/shell.c create mode 100644 kernel/shell.h diff --git a/.vscode/settings.json b/.vscode/settings.json index a14d0a1..1ada35b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "files.associations": { ".fantomasignore": "ignore", - "stddef.h": "c" + "stddef.h": "c", + "io.h": "c" } } \ No newline at end of file diff --git a/kernel/cpu.c b/kernel/cpu.c new file mode 100644 index 0000000..cb043f6 --- /dev/null +++ b/kernel/cpu.c @@ -0,0 +1,35 @@ +#include "cpu.h" +#include "serial.h" +#include "terminal.h" + +void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + asm volatile ( + "cpuid" + : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) + : "a"(function) + ); +} + +void identify_cpu() { + uint32_t eax, ebx, ecx, edx; + char vendor[13]; + + cpuid(0, &eax, &ebx, &ecx, &edx); + + *(uint32_t *)&vendor[0] = ebx; + *(uint32_t *)&vendor[4] = edx; + *(uint32_t *)&vendor[8] = ecx; + vendor[12] = '\0'; + + terminal_write("CPU Vendor: "); + terminal_write(vendor); + terminal_write("\n"); + + serial_write("CPU Vendor: "); + serial_write(vendor); + serial_write("\n"); + + terminal_write("CPUID max leaf: "); + print_hex(eax); // You must implement this (see below) + terminal_write("\n"); +} diff --git a/kernel/cpu.h b/kernel/cpu.h new file mode 100644 index 0000000..d2e165f --- /dev/null +++ b/kernel/cpu.h @@ -0,0 +1,9 @@ +#ifndef CPU_H +#define CPU_H + +#include + +void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); +void identify_cpu(void); + +#endif // CPU_H diff --git a/kernel/elf.c b/kernel/elf.c new file mode 100644 index 0000000..e69de29 diff --git a/kernel/elf.h b/kernel/elf.h new file mode 100644 index 0000000..e69de29 diff --git a/kernel/isr.c b/kernel/isr.c index 9342a2d..f23a850 100644 --- a/kernel/isr.c +++ b/kernel/isr.c @@ -1,12 +1,12 @@ #include "terminal.h" #include "serial.h" #include "isr.h" +#include "io.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 serial_write("INT triggered\n"); if (interrupt_handlers[int_num]) { @@ -27,6 +27,16 @@ void isr_handler(uint32_t int_num, uint32_t err_code) { asm volatile ("hlt"); } } + + // === Send End Of Interrupt to PIC(s) === + if (int_num >= 40) { + // Send reset signal to slave PIC + outb(0xA0, 0x20); + } + if (int_num >= 32) { + // Send reset signal to master PIC + outb(0x20, 0x20); + } } void register_interrupt_handler(uint8_t n, isr_callback_t handler) { diff --git a/kernel/malloc.c b/kernel/malloc.c new file mode 100644 index 0000000..dd11d8e --- /dev/null +++ b/kernel/malloc.c @@ -0,0 +1,97 @@ +#include "malloc.h" +#include + +static void *heap_start; // Start of the heap +static void *heap_end; // End of the heap +static struct memory_block *free_blocks; // List of free blocks + +void init_heap(void *start, void *end) +{ + heap_start = start; + heap_end = end; + + // Initialize the heap with a single large free block + free_blocks = (struct memory_block *)start; + free_blocks->size = (uintptr_t)end - (uintptr_t)start - sizeof(struct memory_block); + free_blocks->next = NULL; + free_blocks->is_free = 1; +} + +void *find_free_block(size_t size) { + struct memory_block *current = free_blocks; + while (current != NULL) { + if (current->is_free && current->size >= size) { + return current; + } + current = current->next; + } + // No suitable block found + return NULL; +} + +void mark_as_used(void *ptr, size_t size) { + struct memory_block *block = (struct memory_block *)ptr; + block->is_free = 0; + + // If the block is larger than needed, split it + if (block->size > size + sizeof(struct memory_block)) { + struct memory_block *new_block = (struct memory_block *)((uintptr_t)ptr + size + sizeof(struct memory_block)); + new_block->size = block->size - size - sizeof(struct memory_block); + new_block->next = block->next; + new_block->is_free = 1; + + block->size = size; + block->next = new_block; + } +} + +void mark_as_free(void *ptr) { + struct memory_block *block = (struct memory_block *)ptr; + block->is_free = 1; + + // Coalesce with next block if it's free + if (block->next && block->next->is_free) { + block->size += block->next->size + sizeof(struct memory_block); + block->next = block->next->next; + } + + // TODO: Implement coalescing with previous block +} + +void *malloc(size_t size) +{ + if (heap_start == NULL || heap_end == NULL) + { + // Heap not initialized, cannot allocate + return NULL; + } + + // Align the size to the word size for efficiency + size = (size + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1); + + // Search for a free block of sufficient size + void *block = find_free_block(size); + if (block != NULL) + { + // Mark the block as used + mark_as_used(block, size); + return (void *)((uintptr_t)block + sizeof(struct memory_block)); + } + + // No suitable block found, out of memory + return NULL; +} + +void free(void *ptr) +{ + if (ptr == NULL) + { + return; + } + + // Adjust pointer to the start of the memory block + struct memory_block *block = (struct memory_block *)((uintptr_t)ptr - sizeof(struct memory_block)); + + // Mark the block as free + mark_as_free(block); +} \ No newline at end of file diff --git a/kernel/malloc.h b/kernel/malloc.h new file mode 100644 index 0000000..dacbd5d --- /dev/null +++ b/kernel/malloc.h @@ -0,0 +1,27 @@ +#ifndef MALLOC_H +#define MALLOC_H + +#include // For size_t + +// Define the memory block structure +struct memory_block { + size_t size; + struct memory_block *next; + int is_free; +}; + +// Function prototypes +void init_heap(void *start, void *end); +void *malloc(size_t size); +void free(void *ptr); + +// Helper function prototypes +void *find_free_block(size_t size); +void mark_as_used(void *ptr, size_t size); +void mark_as_free(void *ptr); + +// External heap boundaries +extern void *user_heap_start; +extern void *user_heap_end; + +#endif // MALLOC_H \ No newline at end of file diff --git a/kernel/panic.c b/kernel/panic.c index ad28b18..477ff66 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -1,5 +1,19 @@ #include "panic.h" +#include "terminal.h" +#include "serial.h" +#include void panic(const char *message) { - // Panic handling code + terminal_write("KERNEL PANIC: "); + terminal_write(message); + terminal_write("\nSystem halted.\n"); + + serial_write("KERNEL PANIC: "); + serial_write(message); + serial_write("\nSystem halted.\n"); + + // Halt the system + while (true) { + asm volatile ("cli; hlt"); + } } diff --git a/kernel/print.c b/kernel/print.c new file mode 100644 index 0000000..2ab9055 --- /dev/null +++ b/kernel/print.c @@ -0,0 +1,6 @@ +#include + +void print_string(const char *str) +{ + printf("%s", str); +} \ No newline at end of file diff --git a/kernel/print.h b/kernel/print.h new file mode 100644 index 0000000..66454fb --- /dev/null +++ b/kernel/print.h @@ -0,0 +1,6 @@ +#ifndef PRINT_H +#define PRINT_H + +void print_string(const char *str); + +#endif diff --git a/kernel/scheduler.c b/kernel/scheduler.c index 334f98e..cdb8812 100644 --- a/kernel/scheduler.c +++ b/kernel/scheduler.c @@ -1,5 +1,62 @@ #include "scheduler.h" +#include + +static task_t tasks[MAX_TASKS]; +static uint32_t task_stacks[MAX_TASKS][STACK_SIZE / sizeof(uint32_t)]; + +static int task_count = 0; +static task_t *task_list = NULL; +static task_t *current_task = NULL; void scheduler_init() { - // Scheduler initialization code + // Initialize task list, etc. + task_list = NULL; + current_task = NULL; + task_count = 0; +} + +void scheduler_add_task(void (*entry)(void)) { + if (task_count >= MAX_TASKS || entry == NULL) return; + + task_t *new_task = &tasks[task_count]; + new_task->id = task_count; + new_task->entry = entry; + + // Simulate a stack pointer pointing to the "top" of the stack + new_task->stack_ptr = &task_stacks[task_count][STACK_SIZE / sizeof(uint32_t) - 1]; + + new_task->next = NULL; + + // Add to task list + if (task_list == NULL) { + task_list = new_task; + } else { + task_t *tail = task_list; + while (tail->next) { + tail = tail->next; + } + tail->next = new_task; + } + + task_count++; +} + +void scheduler_schedule() { + // Very basic round-robin switch + if (current_task && current_task->next) { + current_task = current_task->next; + } else { + current_task = task_list; // Loop back + } + + // Call context switch or simulate yielding to current_task + // In real system: context_switch_to(current_task) + if (current_task && current_task->entry) { + current_task->entry(); // Simulate switching by calling + } +} + +void scheduler_yield() { + // Stub: manually call schedule for cooperative multitasking + scheduler_schedule(); } diff --git a/kernel/scheduler.h b/kernel/scheduler.h index 34753c7..d6b6515 100644 --- a/kernel/scheduler.h +++ b/kernel/scheduler.h @@ -1,6 +1,21 @@ #ifndef SCHEDULER_H #define SCHEDULER_H +#include + +#define MAX_TASKS 8 +#define STACK_SIZE 1024 + +typedef struct task { + uint32_t id; + void (*entry)(void); + uint32_t *stack_ptr; + struct task *next; +} task_t; + void scheduler_init(); +void scheduler_add_task(void (*entry)(void)); +void scheduler_schedule(); +void scheduler_yield(); // Optional for cooperative scheduling #endif // SCHEDULER_H diff --git a/kernel/shell.c b/kernel/shell.c new file mode 100644 index 0000000..c634d95 --- /dev/null +++ b/kernel/shell.c @@ -0,0 +1,60 @@ +#include "shell.h" +#include "keyboard.h" +#include "terminal.h" +#include +#include + +void execute(char *input) { + if (strcmp(input, "help") == 0) { + printf("Available commands: help, clear, exit\n"); + } else if (strcmp(input, "clear") == 0) { + terminal_clear(); + } else { + printf("Unknown command: %s\n", input); + } +} + +void shell_loop() +{ + char input[256]; + int index = 0; + char c; + + while (1) + { + printf("> "); + index = 0; + + while (1) + { + c = keyboard_get_char(); // Waits for input + + if (c == '\n' || c == '\r') // Enter key + { + input[index] = '\0'; + printf("\n"); + break; + } + else if (c == '\b' || c == 127) // Backspace + { + if (index > 0) + { + index--; + printf("\b \b"); // Erase last char on screen + } + } + else + { + if (index < sizeof(input) - 1) { + input[index++] = c; + putchar(c); + } + } + } + + if (strcmp(input, "exit") == 0) + break; + + execute(input); + } +} diff --git a/kernel/shell.h b/kernel/shell.h new file mode 100644 index 0000000..f1b0939 --- /dev/null +++ b/kernel/shell.h @@ -0,0 +1,7 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell_loop(void); +void execute(char *input); + +#endif diff --git a/kernel/syscalls.c b/kernel/syscalls.c index 20ed1de..c86abf8 100644 --- a/kernel/syscalls.c +++ b/kernel/syscalls.c @@ -1,5 +1,30 @@ #include "syscalls.h" +#include "scheduler.h" +#include -void syscall_handler() { - // Syscall handling code +void syscall_handler(int code, va_list args) { + switch (code) { + case SYSCALL_INIT: + scheduler_init(); + break; + case SYSCALL_SPAWN: { + void (*entry)(void) = va_arg(args, void (*)(void)); + scheduler_add_task(entry); + break; + } + case SYSCALL_YIELD: + scheduler_yield(); + break; + default: + // Unknown syscall + break; + } +} + +void syscall(int code, ...) +{ + va_list args; + va_start(args, code); + syscall_handler(code, args); + va_end(args); } diff --git a/kernel/syscalls.h b/kernel/syscalls.h index fc63d06..cdec5a3 100644 --- a/kernel/syscalls.h +++ b/kernel/syscalls.h @@ -1,6 +1,17 @@ #ifndef SYSCALLS_H #define SYSCALLS_H +// Syscall numbers +typedef enum { + SYSCALL_INIT = 0, + SYSCALL_SPAWN, + SYSCALL_YIELD +} syscall_code_t; + +// Syscall dispatcher void syscall_handler(); +// Syscall interface +void syscall(int code, ...); + #endif // SYSCALLS_H diff --git a/kernel/terminal.c b/kernel/terminal.c index 40d0265..c649803 100644 --- a/kernel/terminal.c +++ b/kernel/terminal.c @@ -1,6 +1,7 @@ #include #include "io.h" #include "terminal.h" +#include "vga.h" #define VGA_ADDRESS 0xB8000 #define VGA_WIDTH 80 @@ -12,10 +13,6 @@ 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; -} - void terminal_initialize(void) { for (uint16_t y = 0; y < VGA_HEIGHT; y++) { for (uint16_t x = 0; x < VGA_WIDTH; x++) { diff --git a/kernel/timer.c b/kernel/timer.c index 3804ec8..afbe5b8 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -7,10 +7,13 @@ static uint32_t tick = 0; void timer_callback(void) { tick++; - // Optional: Print every 100 ticks - // if (tick % 100 == 0) { - // terminal_write("Tick\n"); - // } + + // Print every 100 ticks for debugging purposes + if (tick % 100 == 0) { + char tick_msg[50]; + snprintf(tick_msg, sizeof(tick_msg), "Tick count: %u\n", tick); + terminal_write(tick_msg); + } } void timer_init(uint32_t frequency) { diff --git a/kernel/utils.c b/kernel/utils.c index adcc060..06d4494 100644 --- a/kernel/utils.c +++ b/kernel/utils.c @@ -1,5 +1,89 @@ #include "utils.h" -void util_function() { - // Utility function code +static void reverse(char* str, int len) { + int start = 0; + int end = len - 1; + while (start < end) { + char temp = str[start]; + str[start++] = str[end]; + str[end--] = temp; + } } + +// Integer to ASCII for signed ints +char* itoa(int value, char* str, int base) { + int i = 0; + int isNegative = 0; + unsigned int uval; + + if (base < 2 || base > 36) { + str[0] = '\0'; + return str; + } + + // Handle zero explicitly + if (value == 0) { + str[i++] = '0'; + str[i] = '\0'; + return str; + } + + // Handle negative numbers (only for base 10) + if (value < 0 && base == 10) { + isNegative = 1; + uval = (unsigned int)(-value); + } else { + uval = (unsigned int)value; + } + + while (uval != 0) { + int rem = uval % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + uval /= base; + } + + if (isNegative) { + str[i++] = '-'; + } + + str[i] = '\0'; + reverse(str, i); + return str; +} + +// Integer to ASCII for unsigned ints +char* utoa(unsigned int value, char* str, int base) { + int i = 0; + + if (base < 2 || base > 36) { + str[0] = '\0'; + return str; + } + + if (value == 0) { + str[i++] = '0'; + str[i] = '\0'; + return str; + } + + while (value != 0) { + int rem = value % base; + str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; + value /= base; + } + + str[i] = '\0'; + reverse(str, i); + return str; +} + +void print_hex(uint32_t val) { + char hex_chars[] = "0123456789ABCDEF"; + char buf[11] = "0x00000000"; + for (int i = 9; i >= 2; i--) { + buf[i] = hex_chars[val & 0xF]; + val >>= 4; + } + terminal_write(buf); + serial_write(buf); +} \ No newline at end of file diff --git a/kernel/utils.h b/kernel/utils.h index f2f9aaa..9ef78d9 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -1,6 +1,14 @@ #ifndef UTILS_H #define UTILS_H +#include -void util_function(); + +// Convert integer to string (base is typically 10, 16, etc.) +char* itoa(int value, char* str, int base); + +// Convert unsigned integer to string (base is typically 10, 16, etc.) +char* utoa(unsigned int value, char* str, int base); + +void print_hex(uint32_t val); #endif // UTILS_H