Compare commits

...

2 Commits

26 changed files with 768 additions and 23 deletions

View File

@ -1,6 +1,7 @@
{
"files.associations": {
".fantomasignore": "ignore",
"stddef.h": "c"
"stddef.h": "c",
"io.h": "c"
}
}

53
kernel/acpi.c Normal file
View File

@ -0,0 +1,53 @@
#include "acpi.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
// Function to find the RSDP (Root System Description Pointer)
acpi_rsdp_t* acpi_find_rsdp() {
// Search memory from 0x000E0000 to 0x00100000 (BIOS)
for (uint32_t addr = 0x000E0000; addr < 0x00100000; addr += 16) {
acpi_rsdp_t* rsdp = (acpi_rsdp_t*)addr;
if (memcmp(rsdp->signature, "RSD PTR ", 8) == 0) {
uint8_t checksum = 0;
for (int i = 0; i < sizeof(acpi_rsdp_t); i++) {
checksum += ((uint8_t*)rsdp)[i];
}
if (checksum == 0) {
return rsdp; // Valid RSDP found
}
}
}
return NULL; // RSDP not found
}
// Function to get the RSDT or XSDT based on the RSDP revision
void* acpi_get_rsdt_or_xsdt(acpi_rsdp_t* rsdp) {
if (rsdp->revision >= 2) {
return (void*)rsdp->xsdt_addr; // ACPI 2.0+ uses XSDT
} else {
return (void*)rsdp->rsdt_addr; // ACPI 1.0 uses RSDT
}
}
// Function to find the FADT table within the RSDT or XSDT
acpi_fadt_t* acpi_find_fadt(void* rsdt_or_xsdt) {
acpi_rsdt_t* rsdt = (acpi_rsdt_t*)rsdt_or_xsdt;
uint32_t num_tables = (rsdt->length - sizeof(acpi_rsdt_t)) / sizeof(uint32_t);
for (uint32_t i = 0; i < num_tables; i++) {
uint32_t table_addr = rsdt->tables[i];
acpi_fadt_t* fadt = (acpi_fadt_t*)table_addr;
if (fadt->signature == 0x50434146) { // "FACP" in ASCII
uint8_t checksum = 0;
for (int j = 0; j < fadt->length; j++) {
checksum += ((uint8_t*)fadt)[j];
}
if (checksum == 0) {
return fadt; // Valid FADT found
}
}
}
return NULL; // FADT not found
}

47
kernel/acpi.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef ACPI_H
#define ACPI_H
#include <stdint.h>
// ACPI base address (replace with actual value)
#define ACPI_BASE 0xE0000000
#ifndef NULL
#define NULL ((void*)0)
#endif
// ACPI RSDP Structure (Root System Description Pointer)
typedef struct {
uint8_t signature[8]; // Should be "RSD PTR "
uint8_t checksum; // Checksum for the RSDP structure
uint8_t oem_id[6]; // OEM ID string
uint8_t revision; // ACPI revision
uint32_t rsdt_addr; // 32-bit RSDT address (ACPI 1.0)
uint32_t xsdt_addr; // 64-bit XSDT address (ACPI 2.0+)
} __attribute__((packed)) acpi_rsdp_t;
// ACPI RSDT Structure (Root System Description Table)
typedef struct {
uint32_t signature; // Should be "RSDT"
uint32_t length; // Length of the table
uint8_t revision; // Revision of the RSDT table
uint8_t checksum; // Checksum for the RSDT table
uint32_t tables[]; // Array of pointers to other tables (RSDT/XSDT entries)
} __attribute__((packed)) acpi_rsdt_t;
// ACPI FADT Structure (Fixed ACPI Description Table)
typedef struct {
uint32_t signature; // Should be "FACP"
uint32_t length; // Length of the table
uint8_t revision; // Revision of the FADT table
uint8_t checksum; // Checksum for the FADT table
uint32_t pm_tmr_address; // Power Management Timer Address
// ... other FADT fields
} __attribute__((packed)) acpi_fadt_t;
// Function prototypes
acpi_rsdp_t* acpi_find_rsdp();
void* acpi_get_rsdt_or_xsdt(acpi_rsdp_t* rsdp);
acpi_fadt_t* acpi_find_fadt(void* rsdt_or_xsdt);
#endif /* ACPI_H */

35
kernel/cpu.c Normal file
View File

@ -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");
}

9
kernel/cpu.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef CPU_H
#define CPU_H
#include <stdint.h>
void cpuid(uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
void identify_cpu(void);
#endif // CPU_H

50
kernel/elf.c Normal file
View File

@ -0,0 +1,50 @@
#include "elf.h"
#include <stddef.h>
#include <string.h>
// This assumes that the elf is ELF32 and little-endian Intel X86 architecture.
// Check if a binary is a valid ELF executable.
int elf_validate(const void* data) {
const Elf32_Ehdr* header = (const Elf32_Ehdr*)data;
if (*(uint32_t*)header->e_ident != ELF_MAGIC)
return 0;
if (header->e_type != ET_EXEC && header->e_type != ET_DYN)
return 0;
if (header->e_machine != EM_386)
return 0;
return 1;
}
// Load an ELF executable into memory.
int elf_load(const void* data, void (*load_segment)(uint32_t vaddr, const void* src, uint32_t size)) {
const Elf32_Ehdr* header = (const Elf32_Ehdr*)data;
const Elf32_Phdr* ph = (const Elf32_Phdr*)((uint8_t*)data + header->e_phoff);
for (int i = 0; i < header->e_phnum; i++) {
if (ph[i].p_type != PT_LOAD)
continue;
const void* src = (uint8_t*)data + ph[i].p_offset;
uint32_t vaddr = ph[i].p_vaddr;
uint32_t filesz = ph[i].p_filesz;
uint32_t memsz = ph[i].p_memsz;
// Copy data segment
load_segment(vaddr, src, filesz);
// Zero remaining BSS (if any)
if (memsz > filesz) {
uint8_t* bss_start = (uint8_t*)(vaddr + filesz);
for (uint32_t j = 0; j < memsz - filesz; j++) {
bss_start[j] = 0;
}
}
}
return header->e_entry;
}

52
kernel/elf.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
#define ELF_MAGIC 0x464C457F // "\x7FELF" in little-endian
// ELF Types
#define ET_EXEC 2
#define ET_DYN 3
// ELF Machine
#define EM_386 3
// ELF Ident indexes
#define EI_NIDENT 16
// Program header types
#define PT_NULL 0
#define PT_LOAD 1
// ELF Header (32-bit)
typedef struct {
uint8_t e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
uint32_t e_entry; // Entry point
uint32_t e_phoff; // Program header table offset
uint32_t e_shoff; // Section header table offset
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
} __attribute__((packed)) Elf32_Ehdr;
// Program Header (32-bit)
typedef struct {
uint32_t p_type;
uint32_t p_offset;
uint32_t p_vaddr;
uint32_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
} __attribute__((packed)) Elf32_Phdr;
#endif // ELF_H

View File

@ -1,6 +1,63 @@
#include "heap.h"
#include <stdint.h>
typedef struct heap_block {
size_t size;
struct heap_block *next;
int is_free;
} heap_block_t;
static heap_block_t *free_list = NULL;
static void *heap_start_ptr = NULL;
static void *heap_end_ptr = NULL;
void heap_init(void *heap_start, void *heap_end) {
heap_start_ptr = heap_start;
heap_end_ptr = heap_end;
free_list = (heap_block_t *)heap_start;
free_list->size = (uintptr_t)heap_end - (uintptr_t)heap_start - sizeof(heap_block_t);
free_list->next = NULL;
free_list->is_free = 1;
}
void *heap_alloc(size_t size) {
// Heap allocation code
return NULL;
heap_block_t *current = free_list;
while (current != NULL) {
if (current->is_free && current->size >= size) {
// If it's a large block, split it
if (current->size > size + sizeof(heap_block_t)) {
heap_block_t *new_block = (heap_block_t *)((uintptr_t)current + sizeof(heap_block_t) + size);
new_block->size = current->size - size - sizeof(heap_block_t);
new_block->next = current->next;
new_block->is_free = 1;
current->next = new_block;
current->size = size;
}
current->is_free = 0;
return (void *)((uintptr_t)current + sizeof(heap_block_t));
}
current = current->next;
}
return NULL; // Out of memory
}
void heap_free(void *ptr) {
if (ptr == NULL) return;
heap_block_t *block = (heap_block_t *)((uintptr_t)ptr - sizeof(heap_block_t));
block->is_free = 1;
// Coalesce with next block
if (block->next && block->next->is_free) {
block->size += block->next->size + sizeof(heap_block_t);
block->next = block->next->next;
}
// TODO: Coalesce with previous block for better compaction
}

View File

@ -3,6 +3,9 @@
#include <stddef.h>
void heap_init(void *heap_start, void *heap_end);
void *heap_alloc(size_t size);
void heap_free(void *ptr);
#endif // HEAP_H

View File

@ -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) {

View File

@ -7,6 +7,7 @@
#include "paging.h"
#include "memmap.h"
#include "gdt.h"
#include "cpu.h"
#define LPT1 0x378
@ -22,6 +23,10 @@ void kmain(void) {
serial_init();
serial_write("Serial port initialized.\n");
terminal_write("Identifying CPU...\n");
identify_cpu();
serial_write("CPU identification complete.\n");
lpt_write('L'); // Send 'L' to LPT1 to test
terminal_write("Initializing GDT...\n");
@ -53,11 +58,17 @@ void kmain(void) {
serial_write("Memory map retrieved.\n");
terminal_write("Memory Regions:\n");
char buf[32];
for (uint32_t i = 0; i < mmap_size; i++) {
terminal_write(" - Region: ");
// You would format and print base/length/type here
// (e.g., with a basic itoa and print_hex helper)
serial_write("Memory region entry\n");
terminal_write(" - Base: ");
print_hex((uint32_t)(mmap[i].base_addr & 0xFFFFFFFF)); // Lower 32 bits
terminal_write(", Length: ");
print_hex((uint32_t)(mmap[i].length & 0xFFFFFFFF)); // Lower 32 bits
terminal_write(", Type: ");
itoa(mmap[i].type, buf, 10);
terminal_write(buf);
terminal_write("\n");
}
terminal_write("System initialized. Halting.\n");

97
kernel/malloc.c Normal file
View File

@ -0,0 +1,97 @@
#include "malloc.h"
#include <stdint.h>
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);
}

27
kernel/malloc.h Normal file
View File

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

View File

@ -1,5 +1,19 @@
#include "panic.h"
#include "terminal.h"
#include "serial.h"
#include <stdbool.h>
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");
}
}

6
kernel/print.c Normal file
View File

@ -0,0 +1,6 @@
#include <stdio.h>
void print_string(const char *str)
{
printf("%s", str);
}

6
kernel/print.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef PRINT_H
#define PRINT_H
void print_string(const char *str);
#endif

View File

@ -1,5 +1,62 @@
#include "scheduler.h"
#include <stddef.h>
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();
}

View File

@ -1,6 +1,21 @@
#ifndef SCHEDULER_H
#define SCHEDULER_H
#include <stdint.h>
#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

60
kernel/shell.c Normal file
View File

@ -0,0 +1,60 @@
#include "shell.h"
#include "keyboard.h"
#include "terminal.h"
#include <stdio.h>
#include <string.h>
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);
}
}

7
kernel/shell.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef SHELL_H
#define SHELL_H
void shell_loop(void);
void execute(char *input);
#endif

View File

@ -1,5 +1,30 @@
#include "syscalls.h"
#include "scheduler.h"
#include <stdarg.h>
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);
}

View File

@ -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

View File

@ -1,6 +1,7 @@
#include <stdint.h>
#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++) {

View File

@ -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) {

View File

@ -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);
}

View File

@ -1,6 +1,14 @@
#ifndef UTILS_H
#define UTILS_H
#include <stdint.h>
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