formatting

This commit is contained in:
Liam Kerr 2026-02-09 18:55:51 +00:00
parent 821716adcc
commit 9e91024f35
9 changed files with 295 additions and 199 deletions

View file

@ -3,43 +3,54 @@
#include <stdarg.h> #include <stdarg.h>
#include <drivers/uart.h> #include <drivers/uart.h>
void uart_put(size_t base_addr, uint8_t data) { void uart_put(size_t base_addr, uint8_t data)
{
*(volatile uint8_t *)base_addr = data; *(volatile uint8_t *)base_addr = data;
} }
int kputchar(int ch) { int kputchar(int ch)
{
uart_put(UART_ADDRESS, ch); uart_put(UART_ADDRESS, ch);
return ch; return ch;
} }
void kprint(const char *str) { void kprint(const char *str)
while (*str) { {
while (*str)
{
kputchar(*str++); kputchar(*str++);
} }
} }
void kprint_int(int num) { void kprint_int(int num)
{
char buffer[21]; char buffer[21];
int i = 0; int i = 0;
if (num == 0) { if (num == 0)
{
kputchar('0'); kputchar('0');
return; return;
} }
if (num < 0) { if (num < 0)
{
kputchar('-'); kputchar('-');
num = -num; num = -num;
} }
while (num > 0) { while (num > 0)
{
buffer[i++] = '0' + (num % 10); buffer[i++] = '0' + (num % 10);
num /= 10; num /= 10;
} }
while (i > 0) { while (i > 0)
{
kputchar(buffer[--i]); kputchar(buffer[--i]);
} }
} }
void kprint_float(float num) { void kprint_float(float num)
if (num < 0) { {
if (num < 0)
{
kputchar('-'); kputchar('-');
num = -num; num = -num;
} }
@ -47,73 +58,88 @@ void kprint_float(float num) {
float frac_part = num - int_part; float frac_part = num - int_part;
kprint_int(int_part); kprint_int(int_part);
kputchar('.'); kputchar('.');
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++)
{
frac_part *= 10.0f; frac_part *= 10.0f;
} }
int fraction = (int)(frac_part + 0.5f); // Round to nearest int fraction = (int)(frac_part + 0.5f); // Round to nearest
kprint_int(fraction); kprint_int(fraction);
} }
void kprint_hex(uint64_t val) { void kprint_hex(uint64_t val)
char *digits = "0123456789ABCDEF"; {
char buffer[17]; // 64-bit hex is 16 chars char *digits = "0123456789ABCDEF";
char buffer[17]; // 64-bit hex is 16 chars
buffer[16] = '\0'; // Null-terminate the string buffer[16] = '\0'; // Null-terminate the string
// We process from right to left // We process from right to left
for (int i = 15; i >= 0; i--) { for (int i = 15; i >= 0; i--)
buffer[i] = digits[val & 0xF]; {
val >>= 4; buffer[i] = digits[val & 0xF];
} val >>= 4;
}
kprint("0x"); kprint("0x");
kprint(buffer); kprint(buffer);
} }
void knewline(void) { void knewline(void)
{
kputchar('\n'); kputchar('\n');
} }
void kputs(const char *str) { void kputs(const char *str)
{
kprint(str); kprint(str);
knewline(); knewline();
} }
void kprintf(const char *format, ...) { void kprintf(const char *format, ...)
{
va_list args; va_list args;
va_start(args, format); va_start(args, format);
for(char *p = format; *p != '\0'; p++) { for (char *p = format; *p != '\0'; p++)
if (*p == '%') { {
if (*p == '%')
{
p++; p++;
switch (*p) { switch (*p)
case 's': { {
char *s = va_arg(args, char *); case 's':
kprint(s); {
break; char *s = va_arg(args, char *);
} kprint(s);
case 'd': { break;
int d = va_arg(args, int);
kprint_int(d);
break;
}
case 'f': {
double f = va_arg(args, double);
kprint_float((float)f);
break;
}
case 'x': // Hex
case 'p': { // Pointer
uint64_t x = va_arg(args, uint64_t);
kprint_hex(x);
break;
}
case '%':
kputchar('%');
break;
default:
kputchar('%');
kputchar(*p);
} }
} else { case 'd':
{
int d = va_arg(args, int);
kprint_int(d);
break;
}
case 'f':
{
double f = va_arg(args, double);
kprint_float((float)f);
break;
}
case 'x': // Hex
case 'p':
{ // Pointer
uint64_t x = va_arg(args, uint64_t);
kprint_hex(x);
break;
}
case '%':
kputchar('%');
break;
default:
kputchar('%');
kputchar(*p);
}
}
else
{
kputchar(*p); kputchar(*p);
} }
} }

View file

@ -5,17 +5,12 @@
#include <kernel/panic.h> #include <kernel/panic.h>
#include <kernel/memory.h> #include <kernel/memory.h>
void kmain() { void kmain()
kprintf("Hello, from %s!" , "SquidgeOS"); {
kprintf("Hello, from %s!", "SquidgeOS");
kputs("-------------------"); kputs("-------------------");
knewline(); knewline();
page_init(); page_init();
//kprint("Stress testing memory...\n");
//while(1) {
// void *p = page_alloc();
//}
test_memory_integrity(); test_memory_integrity();
test_memory_alignment(); test_memory_alignment();
test_memory_stress(); test_memory_stress();

View file

@ -4,51 +4,60 @@
#include "memory.h" #include "memory.h"
#include "panic.h" #include "panic.h"
HeapHeader *heap_free_list;
HeapHeader* heap_free_list;
extern uint8_t _heap_start[]; // named in the linker script extern uint8_t _heap_start[]; // named in the linker script
void page_init() { void page_init()
{
kprint("Initialising page allocator.\n"); kprint("Initialising page allocator.\n");
uintptr_t start = ((uintptr_t)_heap_start + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); uintptr_t start = ((uintptr_t)_heap_start + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
uintptr_t end = 0x88000000; // Default QEMU RAM limit uintptr_t end = 0x88000000; // Default QEMU RAM limit
for (uintptr_t addr = start; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) { for (uintptr_t addr = start; addr + PAGE_SIZE <= end; addr += PAGE_SIZE)
{
page_free((void *)addr); page_free((void *)addr);
} }
} }
void page_free(void *addr) { void page_free(void *addr)
if (addr == NULL) return; {
if (addr == NULL)
return;
struct Page *p = (struct Page *)addr; struct Page *p = (struct Page *)addr;
p->next = free_list; p->next = free_list;
free_list = p; free_list = p;
} }
void *page_alloc() { void *page_alloc()
if (free_list == NULL) { {
if (free_list == NULL)
{
kpanic("No free pages!"); kpanic("No free pages!");
} }
struct Page *p = free_list; struct Page *p = free_list;
free_list = free_list->next; free_list = free_list->next;
//zero out the page // zero out the page
for (int i = 0; i < (PAGE_SIZE); i++) { for (int i = 0; i < (PAGE_SIZE); i++)
{
((uint8_t *)p)[i] = 0; ((uint8_t *)p)[i] = 0;
} }
return (void *)p; return (void *)p;
} }
void *kmalloc(size_t size) { void *kmalloc(size_t size)
if (size == 0) return NULL; {
if (size == 0)
return NULL;
// Align size to 8 bytes // Align size to 8 bytes
size = (size + 7) & ~7; size = (size + 7) & ~7;
if (heap_free_list == NULL) { if (heap_free_list == NULL)
HeapHeader* header = (HeapHeader *)page_alloc(); {
HeapHeader *header = (HeapHeader *)page_alloc();
header->size = PAGE_SIZE - sizeof(HeapHeader); header->size = PAGE_SIZE - sizeof(HeapHeader);
header->is_free = 1; header->is_free = 1;
header->next = NULL; header->next = NULL;
@ -60,22 +69,26 @@ void *kmalloc(size_t size) {
HeapHeader *current = heap_free_list; HeapHeader *current = heap_free_list;
HeapHeader *prev = NULL; HeapHeader *prev = NULL;
while (current != NULL) { while (current != NULL)
if (current->is_free && current->size >= size) { {
if (current->is_free && current->size >= size)
{
break; break;
} }
prev = current; prev = current;
current = current->next; current = current->next;
} }
if(current == NULL) { if (current == NULL)
{
// No suitable block found, allocate a new page // No suitable block found, allocate a new page
HeapHeader* header = (HeapHeader *)page_alloc(); HeapHeader *header = (HeapHeader *)page_alloc();
header->size = PAGE_SIZE - sizeof(HeapHeader); header->size = PAGE_SIZE - sizeof(HeapHeader);
header->is_free = 1; header->is_free = 1;
header->next = heap_free_list; header->next = heap_free_list;
header->prev = NULL; header->prev = NULL;
if(heap_free_list) { if (heap_free_list)
{
heap_free_list->prev = header; heap_free_list->prev = header;
} }
heap_free_list = header; heap_free_list = header;
@ -83,90 +96,112 @@ void *kmalloc(size_t size) {
} }
// Now, current is a block that can be used // Now, current is a block that can be used
if (!current) { if (!current)
return NULL; {
} return NULL;
}
current->is_free = 0; current->is_free = 0;
// If the block is larger than needed, split it // If the block is larger than needed, split it
size_t min_split_size = sizeof(HeapHeader) + 16; size_t min_split_size = sizeof(HeapHeader) + 16;
if (current->size >= size + min_split_size) { if (current->size >= size + min_split_size)
{
HeapHeader *new_header = (HeapHeader *)((uint8_t *)current + sizeof(HeapHeader) + size); HeapHeader *new_header = (HeapHeader *)((uint8_t *)current + sizeof(HeapHeader) + size);
// Safety check: if new_header address is wild, abort! // Safety check: if new_header address is wild, abort!
if ((uintptr_t)new_header < 0x80000000 || (uintptr_t)new_header > 0x88000000) { if ((uintptr_t)new_header < 0x80000000 || (uintptr_t)new_header > 0x88000000)
kpanic("Splitting created invalid pointer!"); {
} kpanic("Splitting created invalid pointer!");
}
new_header->size = current->size - size - sizeof(HeapHeader); new_header->size = current->size - size - sizeof(HeapHeader);
new_header->is_free = 1; new_header->is_free = 1;
new_header->next = current->next; new_header->next = current->next;
new_header->prev = current; new_header->prev = current;
if(current->next) { if (current->next)
{
current->next->prev = new_header; current->next->prev = new_header;
} }
current->size = size; current->size = size;
current->next = new_header; current->next = new_header;
} }
return (void*)((char*)current + sizeof(HeapHeader)); return (void *)((char *)current + sizeof(HeapHeader));
} }
void kfree(void *ptr) { void kfree(void *ptr)
if (ptr == NULL) return; {
if (ptr == NULL)
return;
HeapHeader *header = (HeapHeader *)((uint8_t *)ptr - sizeof(HeapHeader)); HeapHeader *header = (HeapHeader *)((uint8_t *)ptr - sizeof(HeapHeader));
if(header->is_free) { if (header->is_free)
{
kpanic("Double free detected!"); kpanic("Double free detected!");
} }
header->is_free = 1; header->is_free = 1;
kcoalesce(header); kcoalesce(header);
} }
void kcoalesce(HeapHeader *header) { void kcoalesce(HeapHeader *header)
if(!header || !header->is_free) return; {
//merge backward if (!header || !header->is_free)
while (header->prev && header->prev->is_free) { return;
// merge backward
while (header->prev && header->prev->is_free)
{
header = header->prev; header = header->prev;
} }
//merge forward // merge forward
while (header->next && header->next->is_free){ while (header->next && header->next->is_free)
{
uintptr_t current_end = (uintptr_t)header + sizeof(HeapHeader) + header->size; uintptr_t current_end = (uintptr_t)header + sizeof(HeapHeader) + header->size;
if (current_end == (uintptr_t)header->next) { if (current_end == (uintptr_t)header->next)
{
header->size += sizeof(HeapHeader) + header->next->size; header->size += sizeof(HeapHeader) + header->next->size;
header->next = header->next->next; header->next = header->next->next;
if(header->next) { if (header->next)
{
header->next->prev = header; header->next->prev = header;
} }
} else { }
else
{
break; break;
} }
} }
} }
void test_memory_integrity() { void test_memory_integrity()
kprint("Running Integrity Test...\n"); {
uint64_t *a = (uint64_t*)kmalloc(16); kprint("Running Integrity Test...\n");
uint64_t *b = (uint64_t*)kmalloc(16); uint64_t *a = (uint64_t *)kmalloc(16);
uint64_t *b = (uint64_t *)kmalloc(16);
*a = 0x1122334455667788; *a = 0x1122334455667788;
*b = 0x99AABBCCDDEEFF00; *b = 0x99AABBCCDDEEFF00;
if (*a == 0x1122334455667788) { if (*a == 0x1122334455667788)
kprint("Integrity Pass!\n"); {
} else { kprint("Integrity Pass!\n");
kprint("CORRUPTION DETECTED!\n"); }
} else
kfree(a); {
kfree(b); kprint("CORRUPTION DETECTED!\n");
}
kfree(a);
kfree(b);
} }
void test_memory_alignment() { void test_memory_alignment()
{
kprint("Running Alignment Test...\n"); kprint("Running Alignment Test...\n");
for (int i = 1; i <= 64; i++) { for (int i = 1; i <= 64; i++)
{
void *ptr = kmalloc(i); void *ptr = kmalloc(i);
if (((uintptr_t)ptr % 8) != 0) { if (((uintptr_t)ptr % 8) != 0)
{
kprint("Misaligned allocation detected!\n"); kprint("Misaligned allocation detected!\n");
return; return;
} }
@ -175,32 +210,39 @@ void test_memory_alignment() {
kprint("All allocations are properly aligned!\n"); kprint("All allocations are properly aligned!\n");
} }
void test_memory_stress() { void test_memory_stress()
kprintf("Starting Stress Test...\n"); {
kprintf("Starting Stress Test...\n");
heap_stats(); heap_stats();
void *ptrs[100] = {0}; // Track allocated pointers void *ptrs[100] = {0}; // Track allocated pointers
uint32_t seed = 0xACE2026; // Example seed uint32_t seed = 0xACE2026; // Example seed
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++)
// 1. Randomly allocate or free {
int idx = (seed >> 16) % 50; // 1. Randomly allocate or free
if (ptrs[idx] == NULL) { int idx = (seed >> 16) % 50;
size_t size = (seed % 256) + 1; if (ptrs[idx] == NULL)
ptrs[idx] = kmalloc(size); {
// Optional: fill with data to check integrity later size_t size = (seed % 256) + 1;
} else { ptrs[idx] = kmalloc(size);
kfree(ptrs[idx]); // Optional: fill with data to check integrity later
ptrs[idx] = NULL; }
} else
// Simple LCG to "randomize" seed {
seed = (seed * 1103515245 + 12345) & 0x7fffffff; kfree(ptrs[idx]);
} ptrs[idx] = NULL;
kprintf("Stress Test Finished. Check heap_stats() for sanity.\n"); }
// Simple LCG to "randomize" seed
seed = (seed * 1103515245 + 12345) & 0x7fffffff;
}
kprintf("Stress Test Finished. Check heap_stats() for sanity.\n");
kprintf("HeadHeader size: %d bytes\n", sizeof(HeapHeader)); kprintf("HeadHeader size: %d bytes\n", sizeof(HeapHeader));
heap_stats(); heap_stats();
kprintf("Cleaning up remaining allocations...\n"); kprintf("Cleaning up remaining allocations...\n");
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++)
if (ptrs[i] != NULL) { {
if (ptrs[i] != NULL)
{
kfree(ptrs[i]); kfree(ptrs[i]);
ptrs[i] = NULL; ptrs[i] = NULL;
} }
@ -208,32 +250,37 @@ void test_memory_stress() {
heap_stats(); heap_stats();
} }
void heap_stats() { void heap_stats()
size_t free_size = 0; {
size_t used_size = 0; size_t free_size = 0;
size_t free_blocks = 0; size_t used_size = 0;
size_t used_blocks = 0; size_t free_blocks = 0;
size_t used_blocks = 0;
HeapHeader *current = heap_free_list; HeapHeader *current = heap_free_list;
while (current != NULL) { while (current != NULL)
if (current->is_free) { {
free_size += current->size; if (current->is_free)
free_blocks++; {
} else { free_size += current->size;
used_size += current->size; free_blocks++;
used_blocks++; }
} else
current = current->next; {
} used_size += current->size;
used_blocks++;
}
current = current->next;
}
kprint("--- Kernel Heap Stats ---\n"); kprint("--- Kernel Heap Stats ---\n");
kprintf("Page Size: %d bytes", PAGE_SIZE); kprintf("Page Size: %d bytes", PAGE_SIZE);
kprintf("HeapHeader size: %d bytes", sizeof(HeapHeader)); kprintf("HeapHeader size: %d bytes", sizeof(HeapHeader));
kprintf("Pages allocated: %d", (used_size + free_size + used_blocks * sizeof(HeapHeader) + free_blocks * sizeof(HeapHeader)) / PAGE_SIZE); kprintf("Pages allocated: %d", (used_size + free_size + used_blocks * sizeof(HeapHeader) + free_blocks * sizeof(HeapHeader)) / PAGE_SIZE);
kprintf("Used: %x bytes in %d blocks",used_size, used_blocks); kprintf("Used: %x bytes in %d blocks", used_size, used_blocks);
kprintf("Used (with overhead): %x bytes", used_size + used_blocks * sizeof(HeapHeader)); kprintf("Used (with overhead): %x bytes", used_size + used_blocks * sizeof(HeapHeader));
kprintf("Free: %x bytes in %d blocks", free_size, free_blocks); kprintf("Free: %x bytes in %d blocks", free_size, free_blocks);
kprintf("Total metadata overhead: %d bytes", ((used_blocks + free_blocks) * sizeof(HeapHeader))); kprintf("Total metadata overhead: %d bytes", ((used_blocks + free_blocks) * sizeof(HeapHeader)));
kprint("-------------------------\n"); kprint("-------------------------\n");
} }

View file

@ -3,15 +3,17 @@
#define PAGE_SIZE 4096 #define PAGE_SIZE 4096
typedef struct Page { typedef struct Page
{
struct Page *next; struct Page *next;
} Page; } Page;
typedef struct HeapHeader { typedef struct HeapHeader
{
size_t size; size_t size;
int is_free; int is_free;
struct HeapHeader *next; struct HeapHeader *next;
struct HeapHeader *prev; struct HeapHeader *prev;
} HeapHeader; } HeapHeader;
static struct Page *free_list = NULL; static struct Page *free_list = NULL;

View file

@ -4,14 +4,16 @@
#include <syscon/syscon.h> #include <syscon/syscon.h>
#include "memory.h" #include "memory.h"
void kpanic(const char *reason){ void kpanic(const char *reason)
{
kputs("\n!!! PANIC !!!\n"); kputs("\n!!! PANIC !!!\n");
kputs(reason); kputs(reason);
kputs("\n!!! PANIC !!!\n"); kputs("\n!!! PANIC !!!\n");
poweroff(); poweroff();
} }
void kpanic_force() { void kpanic_force()
{
kprint("\n!!! FORCE PANIC !!!\n"); kprint("\n!!! FORCE PANIC !!!\n");
// 'ebreak' is the standard RISC-V way to trigger a debug trap. // 'ebreak' is the standard RISC-V way to trigger a debug trap.
@ -21,12 +23,14 @@ void kpanic_force() {
poweroff(); poweroff();
kprint("Force panic falled. Power off failed. sleep until interupt. \n"); kprint("Force panic falled. Power off failed. sleep until interupt. \n");
while(1) { while (1)
{
__asm__ volatile("wfi"); __asm__ volatile("wfi");
} }
} }
void handle_trap() { void handle_trap()
{
kprint("\n!!! HARDWARE EXCEPTION DETECTED !!!\n"); kprint("\n!!! HARDWARE EXCEPTION DETECTED !!!\n");
// Read the 'mcause' register to see WHY we trapped // Read the 'mcause' register to see WHY we trapped
@ -37,17 +41,34 @@ void handle_trap() {
uintptr_t mtval; uintptr_t mtval;
asm volatile("csrr %0, mtval" : "=r"(mtval)); asm volatile("csrr %0, mtval" : "=r"(mtval));
switch(cause) { switch (cause)
case 0: kprint("Reason: Instruction Address Misaligned\n"); break; {
case 1: kprint("Reason: Instruction Access Fault\n"); break; case 0:
case 2: kprint("Reason: Illegal Instruction\n"); break; kprint("Reason: Instruction Address Misaligned\n");
case 3: kprint("Reason: Breakpoint (ebreak)\n"); break; break;
case 4: kprint("Reason: Load Address Misaligned\n"); break; case 1:
case 5: kprint("Reason: Load Access Fault\n"); break; kprint("Reason: Instruction Access Fault\n");
case 6: kprint("Reason: Store/AMO Address Misaligned\n"); break; break;
case 7: kprint("Reason: Store/AMO Access Fault\n"); break; case 2:
default: kprint("Reason: Illegal Instruction\n");
kprintf("Reason: Unknown Exception Code %d\n", cause); break;
case 3:
kprint("Reason: Breakpoint (ebreak)\n");
break;
case 4:
kprint("Reason: Load Address Misaligned\n");
break;
case 5:
kprint("Reason: Load Access Fault\n");
break;
case 6:
kprint("Reason: Store/AMO Address Misaligned\n");
break;
case 7:
kprint("Reason: Store/AMO Access Fault\n");
break;
default:
kprintf("Reason: Unknown Exception Code %d\n", cause);
} }
kprintf("Faulting Address (if applicable): %x\n", mtval); kprintf("Faulting Address (if applicable): %x\n", mtval);

View file

@ -4,13 +4,14 @@
void kpanic(const char *reason); void kpanic(const char *reason);
void kpanic_force(); void kpanic_force();
#define KASSERT(cond, msg) \ #define KASSERT(cond, msg) \
if (!(cond)) { \ if (!(cond)) \
kprint("ASSERTION FAILED: "); \ { \
kprint(__FILE__); \ kprint("ASSERTION FAILED: "); \
kprint(":"); \ kprint(__FILE__); \
kprint(":"); \
/* Note: Printing line numbers requires a custom itoa/printf */ \ /* Note: Printing line numbers requires a custom itoa/printf */ \
kpanic(msg); \ kpanic(msg); \
} }
#endif #endif

View file

@ -1,9 +1,11 @@
#include <stddef.h> #include <stddef.h>
#include "string.h" #include "string.h"
void *memset(void *s, int c, size_t n) { void *memset(void *s, int c, size_t n)
{
unsigned char *p = s; unsigned char *p = s;
while (n--) { while (n--)
{
*p++ = (unsigned char)c; *p++ = (unsigned char)c;
} }
return s; return s;

View file

@ -3,18 +3,20 @@
#include "syscon.h" #include "syscon.h"
#include "drivers/uart.h" #include "drivers/uart.h"
void poweroff(void) { void poweroff(void)
{
knewline(); knewline();
kputs("-------"); kputs("-------");
knewline(); knewline();
kputs("Poweroff requested"); kputs("Poweroff requested");
*(volatile uint32_t *)SYSCON_ADDR = SYSCON_POWEROFF; *(volatile uint32_t *)SYSCON_ADDR = SYSCON_POWEROFF;
} }
void reboot(void) { void reboot(void)
{
knewline(); knewline();
kputs("-------"); kputs("-------");
knewline(); knewline();
kputs("Reboot requested"); kputs("Reboot requested");
*(volatile uint32_t *)SYSCON_ADDR = SYSCON_REBOOT; *(volatile uint32_t *)SYSCON_ADDR = SYSCON_REBOOT;
} }

View file

@ -6,7 +6,7 @@
// Magic values for the Sifive Test device // Magic values for the Sifive Test device
#define SYSCON_POWEROFF 0x5555 #define SYSCON_POWEROFF 0x5555
#define SYSCON_REBOOT 0x7777 #define SYSCON_REBOOT 0x7777
void poweroff(void); void poweroff(void);
void reboot(void); void reboot(void);