From 19cb152049d9dc93d9ef7a601695afaeea0d89a1 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 12:58:11 -0800 Subject: [PATCH 1/9] updated doxygen setting to include inline source code + class diagram --- Doxyfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index 966abc1..d489e23 100644 --- a/Doxyfile +++ b/Doxyfile @@ -27,7 +27,7 @@ EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES INTERNAL_DOCS = YES SOURCE_BROWSER = YES -INLINE_SOURCES = NO # Set to YES if you want code in docs +INLINE_SOURCES = YES #---------------------------------------------------------- # Preprocessing / Macros @@ -38,7 +38,9 @@ EXPAND_ONLY_PREDEF = NO PREDEFINED = __attribute__(x)= \ asm(x)= \ __asm__= \ - KERNEL=1 + KERNEL=1 \ + __packed \ + __aligned(x) #---------------------------------------------------------- # Warnings @@ -64,6 +66,7 @@ DOT_IMAGE_FORMAT = svg CALL_GRAPH = YES CALLER_GRAPH = YES DOT_MULTI_TARGETS = YES +CLASS_DIAGRAMS = YES #---------------------------------------------------------- # Markdown / Main Page From 694a5d2a8468108d0247478368dadcb7e68a513f Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 12:58:32 -0800 Subject: [PATCH 2/9] Added Doxygen documentation for memory management --- docs/pages/memory.md | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 docs/pages/memory.md diff --git a/docs/pages/memory.md b/docs/pages/memory.md new file mode 100644 index 0000000..1da7b33 --- /dev/null +++ b/docs/pages/memory.md @@ -0,0 +1,57 @@ +# Memory Management + +The memory management subsystem is responsible for handling the allocation, +deallocation, and organization of memory within the kernel. It ensures that +memory is used efficiently and safely, preventing leaks and corruption. + +This subsystem provides a simple kernel heap allocator (`kmalloc`/`kfree`) +and manages memory blocks using a linked list of headers. + +## Design + +- Implements a **first-fit heap allocator** for dynamic memory allocation. +- Provides **public API functions**: + - `kmalloc_init()` – Initialize the heap region. + - `kmalloc()` – Allocate a memory block. + - `kfree()` – Free a previously allocated block. + - `kmalloc_get_head()` – Retrieve the head of the heap (mainly for testing). +- Uses **linked list of headers** to track free and used memory blocks. +- Performs **block splitting and merging** to reduce fragmentation. +- Aligns allocations to `KMALLOC_ALIGN` for proper memory access. + +## Usage Example + +```c +#include "memory.h" + +extern char heap_start[]; +extern char heap_end[]; + +void kernel_main(void) +{ + // Initialize the kernel heap + kmalloc_init(heap_start, heap_end); + + // Allocate 128 bytes + void *ptr = kmalloc(128); + if (!ptr) + { + // Handle allocation failure + } + + // Use memory + char *data = (char*)ptr; + data[0] = 'X'; + + // Free the memory + kfree(ptr); +} +``` +> **Note**: Always initialize the heap before using `kmalloc`. + +## Future Plans +- Implement thread-safe operations for concurrent memory access. +- Integrate virtual memory support for better isolation and protection. +- Implement memory paging and swapping mechanisms. +- Add support for memory-mapped files and devices. +- Provide user-space memory management interfaces. From 75385b83f311f19f409d5fc75918b2b0a5321737 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 12:59:55 -0800 Subject: [PATCH 3/9] Moved testing functions from memory.c to its own test file --- src/kernel/tests/test_memory.c | 202 +++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 src/kernel/tests/test_memory.c diff --git a/src/kernel/tests/test_memory.c b/src/kernel/tests/test_memory.c new file mode 100644 index 0000000..6a1369f --- /dev/null +++ b/src/kernel/tests/test_memory.c @@ -0,0 +1,202 @@ +#include "memory.h" +#include "printf.h" + + +#define TEST_HEAP_SIZE (1024 * 1024) +static uint8_t heap_space[TEST_HEAP_SIZE]; +static size_t initial_heap_size = 0; + +// --- Setup and teardown --- +static void setup() +{ + kmalloc_init(heap_space, heap_space + sizeof(heap_space)); + initial_heap_size = kmalloc_get_head()->size; +} + +static void tear_down() +{ +} + +// --- Basic alloc/free correctness --- +static int kmalloc_test_single_alloc() +{ + void *ptr = kmalloc(128); + if (!ptr) + { + printf("kmalloc returned NULL\n"); + return 0; + } + struct header *head = kmalloc_get_head(); + if (head->state != BLOCK_USED) + { + printf("Block not marked as used after kmalloc\n"); + return 0; + } + return 1; +} + +static int kmalloc_test_single_alloc_and_free() +{ + void *ptr = kmalloc(128); + kfree(ptr); + struct header *head = kmalloc_get_head(); + if (head->state != BLOCK_FREE) + { + printf("Block not free after kfree\n"); + return 0; + } + if (head->size != initial_heap_size) + { + printf("Block size incorrect after kfree: got %lu expected %lu\n", head->size, initial_heap_size); + return 0; + } + return 1; +} + +static int kmalloc_test_merge_free_blocks() +{ + void *a = kmalloc(128); + void *b = kmalloc(128); + kfree(a); + kfree(b); + struct header *head = kmalloc_get_head(); + if (head->state != BLOCK_FREE) + { + printf("Head not free after merging\n"); + return 0; + } + if (head->size != initial_heap_size) + { + printf("Merged size incorrect: got %lu expected %lu\n", head->size, initial_heap_size); + return 0; + } + return 1; +} + +// --- Extended kfree edge case tests --- +// static int kfree_null_pointer_test() +// { +// struct header *before = kmalloc_get_head(); +// kfree(NULL); +// struct header *after = kmalloc_get_head(); +// if (panic_called) +// { +// printf("PANIC triggered on kfree(NULL)\n"); +// return 0; +// } +// if (before != after) +// return 0; +// return 1; +// } + +// static int kfree_double_free_test() +// { +// void *ptr = kmalloc(128); +// kfree(ptr); +// kfree(ptr); // second free should panic +// if (!panic_called) +// { +// printf("Expected panic on double free, but none occurred\n"); +// return 0; +// } +// return 1; +// } + +// static int kfree_invalid_pointer_inside_heap_test() +// { +// void *ptr = kmalloc(128); +// uint8_t *invalid = (uint8_t *)ptr + 8; +// kfree(invalid); +// if (!panic_called) +// { +// printf("Expected panic on invalid pointer inside heap\n"); +// return 0; +// } +// return 1; +// } + +// static int kfree_invalid_pointer_outside_heap_test() +// { +// uint8_t *invalid = heap_space - 32; // outside heap +// kfree(invalid); +// if (!panic_called) +// { +// printf("Expected panic on invalid pointer outside heap\n"); +// return 0; +// } +// return 1; +// } + +static int kfree_merge_order_test() +{ + void *a = kmalloc(128); + void *b = kmalloc(128); + void *c = kmalloc(128); + + // Free middle first, then ends + kfree(b); + kfree(a); + kfree(c); + + struct header *head = kmalloc_get_head(); + if (head->state != BLOCK_FREE) + { + printf("Heap not free after out-of-order merges\n"); + return 0; + } + if (head->size != initial_heap_size) + { + printf("Heap size incorrect after out-of-order merge: got %lu expected %lu\n", head->size, initial_heap_size); + return 0; + } + return 1; +} + +// --- Main test runner --- +int kmalloc_test() +{ + printf("\n\nRunning kmalloc tests...\n"); + + int (*tests[])(void) = { + kmalloc_test_single_alloc, + kmalloc_test_single_alloc_and_free, + kmalloc_test_merge_free_blocks, + // kfree_null_pointer_test, + // kfree_double_free_test, + // kfree_invalid_pointer_inside_heap_test, + // kfree_invalid_pointer_outside_heap_test, + kfree_merge_order_test, + }; + + const char *names[] = { + "single_alloc", + "single_alloc_and_free", + "merge_free_blocks", + // "kfree_null_pointer", + // "kfree_double_free", + // "kfree_invalid_inside_heap", + // "kfree_invalid_outside_heap", + "kfree_merge_order", + }; + + int num_tests = sizeof(tests) / sizeof(tests[0]); + int test_passed = 0; + + for (int i = 0; i < num_tests; i++) + { + printf("Running test %d (%s): ", i, names[i]); + setup(); + int result = tests[i](); + tear_down(); + + if (!result) + { + printf("FAILED\n"); + return 1; + } + printf("PASSED\n"); + test_passed++; + } + printf("\nkmalloc_test() -> %d/%d tests passed!\n\n", test_passed, num_tests); + return 0; +} \ No newline at end of file From 0e39c7c66a0810d02b503bd4981151979ac44dcc Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 13:00:26 -0800 Subject: [PATCH 4/9] Added tests directory as source build --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 65b395e..acdfedf 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ OUT_DIR := build/ -SRC_DIRS := src/kernel src/user +SRC_DIRS := src/kernel src/user src/kernel/tests # Find every .c in those dirs SRCS := $(foreach d,$(SRC_DIRS),$(wildcard $(d)/*.c)) From ce1b36037215ef6ce3f1fe5f605f6412227cf03a Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 13:59:26 -0800 Subject: [PATCH 5/9] added old doc in doxygen ignore --- Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doxyfile b/Doxyfile index d489e23..5228ea3 100644 --- a/Doxyfile +++ b/Doxyfile @@ -13,7 +13,7 @@ OUTPUT_DIRECTORY = docs INPUT = src include docs/pages README.md FILE_PATTERNS = *.c *.h *.md *.s *.ld RECURSIVE = YES -EXCLUDE_PATTERNS = */tests/* */build/* */literature/* +EXCLUDE_PATTERNS = */tests/* */build/* */literature/* */doc/* #---------------------------------------------------------- # Documentation Extraction From de648f5d2982dff5592c1fb6d448c4208f637006 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 12:59:01 -0800 Subject: [PATCH 6/9] Move doxygen documentatiom from implementation to heafder file --- include/memory.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/include/memory.h b/include/memory.h index d0c1e5b..126b219 100644 --- a/include/memory.h +++ b/include/memory.h @@ -32,10 +32,69 @@ extern "C" struct header *prev; /**< Pointer to the previous block in the linked list. */ }; + /** + * @brief Retrieves the head of the kmalloc allocation list. + * + * This function returns a pointer to the head of the memory allocation + * list used by kmalloc. Mainly useful for testing current allocations. + * + * @return Pointer to the head of the kmalloc allocation list. + * Returns NULL if the list is empty. + */ struct header *kmalloc_get_head(void); + /** + * @brief Initialize the kernel heap for dynamic memory allocation. + * + * This function sets up the initial heap region for `kmalloc`. It aligns + * the start and end addresses according to the kernel alignment + * requirements and initializes the first free memory block. + * + * @param start Pointer to the beginning of the heap memory region. + * Must be less than `limit`. + * @param limit Pointer to the end of the heap memory region. + * Must be greater than `start`. + * + * @note If the heap range is invalid or too small, this function + * will call `kernel_panic()`. + * + * @note The pointers `start` and `limit` are marked `restrict` to indicate + * that their memory regions do not overlap, allowing the compiler + * to optimize pointer arithmetic safely. + */ void kmalloc_init(void *start, void *limit); + + /** + * @brief Allocate a block of memory from the kernel heap. + * + * This function searches the heap for the first free block that is large + * enough to satisfy the requested `size`. If the block is larger than needed, + * it is split into an allocated block and a new free block. + * + * @param size The number of bytes to allocate. Must be > 0. + * + * @return Pointer to the usable memory area of the allocated block, or + * NULL if `size` is zero. + * + * @warning If no suitable block is found, the function will call `kernel_panic`. + * @note The returned pointer points immediately after the block header. + * + */ void* kmalloc(size_t size); + + /** + * @brief Free a previously allocated block of memory. + * + * Marks the block as free and attempts to merge it with adjacent free blocks + * to reduce fragmentation. + * + * @param block Pointer to the memory previously returned by `kmalloc`. + * Must not be NULL. + * + * @note If `block` is NULL, the function does nothing. + * @note If `block` does not correspond to a valid allocated block, + * the function calls `kernel_panic`. + */ void kfree(void *block); int kmalloc_test(void); #ifdef __cplusplus From 952a9b0c3a087b0a7aabfa0ef9d9f90ef86937cc Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 12:59:28 -0800 Subject: [PATCH 7/9] Remove doxygen from public API + removed testing functions --- src/kernel/memory.c | 266 ++------------------------------------------ 1 file changed, 7 insertions(+), 259 deletions(-) diff --git a/src/kernel/memory.c b/src/kernel/memory.c index 331d187..bebc15b 100644 --- a/src/kernel/memory.c +++ b/src/kernel/memory.c @@ -30,6 +30,11 @@ static struct header *head = NULL; /**< Default alignment: at least pointer size; 16 is a good general default. */ static const size_t KMALLOC_ALIGN = (16 < sizeof(void*) ? sizeof(void*) : 16); +struct header *kmalloc_get_head(void) +{ + return head; +} + /** * @brief Align a pointer up to the next multiple of a given alignment. * @@ -46,25 +51,6 @@ static inline uintptr_t align_up_uintptr(uintptr_t x, size_t align) return (x + (align - 1)) & ~(uintptr_t)(align - 1); } -/** - * @brief Initialize the kernel heap for dynamic memory allocation. - * - * This function sets up the initial heap region for `kmalloc`. It aligns - * the start and end addresses according to the kernel alignment - * requirements and initializes the first free memory block. - * - * @param start Pointer to the beginning of the heap memory region. - * Must be less than `limit`. - * @param limit Pointer to the end of the heap memory region. - * Must be greater than `start`. - * - * @note If the heap range is invalid or too small, this function - * will call `kernel_panic()`. - * - * @note The pointers `start` and `limit` are marked `restrict` to indicate - * that their memory regions do not overlap, allowing the compiler - * to optimize pointer arithmetic safely. - */ void kmalloc_init(void *restrict start, void *restrict limit) { const uintptr_t s = (uintptr_t)start; @@ -90,11 +76,10 @@ void kmalloc_init(void *restrict start, void *restrict limit) .next = NULL, .prev = NULL, }; - - puts("kmalloc init\n"); } /** + * @internal * @brief Split a large free memory block into two parts if it is larger than the requested size. * * This function takes a pointer to a free memory block and divides it into @@ -126,21 +111,6 @@ static void ksplit_block(struct header *curr, size_t size) curr->size = size; } -/** - * @brief Allocate a block of memory from the kernel heap. - * - * This function searches the heap for the first free block that is large - * enough to satisfy the requested `size`. If the block is larger than needed, - * it is split into an allocated block and a new free block. - * @param size The number of bytes to allocate. Must be > 0. - * - * @return Pointer to the usable memory area of the allocated block, or - * NULL if `size` is zero. - * - * @note If no suitable block is found, the function will call `kernel_panic`. - * @note The returned pointer points immediately after the block header. - * - */ void *kmalloc(size_t size) { if (size == 0) @@ -175,12 +145,8 @@ void *kmalloc(size_t size) return (void*)((char*)curr + sizeof(struct header)); } -struct header *kmalloc_get_head(void) -{ - return head; -} - /** + * @internal * @brief Merge a block with the its next free block. * * if the the block exist and both the current and next @@ -207,19 +173,6 @@ static void kmerge(struct header *curr) } } -/** - * @brief Free a previously allocated block of memory. - * - * Marks the block as free and attempts to merge it with adjacent free blocks - * to reduce fragmentation. - * - * @param block Pointer to the memory previously returned by `kmalloc`. - * Must not be NULL. - * - * @note If `block` is NULL, the function does nothing. - * @note If `block` does not correspond to a valid allocated block, - * the function calls `kernel_panic`. - */ void kfree(void *block) { if (!block) @@ -238,208 +191,3 @@ void kfree(void *block) kmerge(curr); kmerge(curr->prev); } - - -/** --------------------------------------------- - * kmalloc/kfree tests - * @todo Find a better way for testing functions - * --------------------------------------------- - */ -#define TEST_HEAP_SIZE (1024 * 1024) -static uint8_t heap_space[TEST_HEAP_SIZE]; -static size_t initial_heap_size = 0; - -// --- Setup and teardown --- -static void setup() -{ - kmalloc_init(heap_space, heap_space + sizeof(heap_space)); - initial_heap_size = kmalloc_get_head()->size; -} - -static void tear_down() -{ -} - -// --- Basic alloc/free correctness --- -static int kmalloc_test_single_alloc() -{ - void *ptr = kmalloc(128); - if (!ptr) - { - printf("kmalloc returned NULL\n"); - return 0; - } - struct header *head = kmalloc_get_head(); - if (head->state != BLOCK_USED) - { - printf("Block not marked as used after kmalloc\n"); - return 0; - } - return 1; -} - -static int kmalloc_test_single_alloc_and_free() -{ - void *ptr = kmalloc(128); - kfree(ptr); - struct header *head = kmalloc_get_head(); - if (head->state != BLOCK_FREE) - { - printf("Block not free after kfree\n"); - return 0; - } - if (head->size != initial_heap_size) - { - printf("Block size incorrect after kfree: got %lu expected %lu\n", head->size, initial_heap_size); - return 0; - } - return 1; -} - -static int kmalloc_test_merge_free_blocks() -{ - void *a = kmalloc(128); - void *b = kmalloc(128); - kfree(a); - kfree(b); - struct header *head = kmalloc_get_head(); - if (head->state != BLOCK_FREE) - { - printf("Head not free after merging\n"); - return 0; - } - if (head->size != initial_heap_size) - { - printf("Merged size incorrect: got %lu expected %lu\n", head->size, initial_heap_size); - return 0; - } - return 1; -} - -// --- Extended kfree edge case tests --- -// static int kfree_null_pointer_test() -// { -// struct header *before = kmalloc_get_head(); -// kfree(NULL); -// struct header *after = kmalloc_get_head(); -// if (panic_called) -// { -// printf("PANIC triggered on kfree(NULL)\n"); -// return 0; -// } -// if (before != after) -// return 0; -// return 1; -// } - -// static int kfree_double_free_test() -// { -// void *ptr = kmalloc(128); -// kfree(ptr); -// kfree(ptr); // second free should panic -// if (!panic_called) -// { -// printf("Expected panic on double free, but none occurred\n"); -// return 0; -// } -// return 1; -// } - -// static int kfree_invalid_pointer_inside_heap_test() -// { -// void *ptr = kmalloc(128); -// uint8_t *invalid = (uint8_t *)ptr + 8; -// kfree(invalid); -// if (!panic_called) -// { -// printf("Expected panic on invalid pointer inside heap\n"); -// return 0; -// } -// return 1; -// } - -// static int kfree_invalid_pointer_outside_heap_test() -// { -// uint8_t *invalid = heap_space - 32; // outside heap -// kfree(invalid); -// if (!panic_called) -// { -// printf("Expected panic on invalid pointer outside heap\n"); -// return 0; -// } -// return 1; -// } - -static int kfree_merge_order_test() -{ - void *a = kmalloc(128); - void *b = kmalloc(128); - void *c = kmalloc(128); - - // Free middle first, then ends - kfree(b); - kfree(a); - kfree(c); - - struct header *head = kmalloc_get_head(); - if (head->state != BLOCK_FREE) - { - printf("Heap not free after out-of-order merges\n"); - return 0; - } - if (head->size != initial_heap_size) - { - printf("Heap size incorrect after out-of-order merge: got %lu expected %lu\n", head->size, initial_heap_size); - return 0; - } - return 1; -} - -// --- Main test runner --- -int kmalloc_test() -{ - printf("Running kmalloc tests...\n"); - - int (*tests[])(void) = { - kmalloc_test_single_alloc, - kmalloc_test_single_alloc_and_free, - kmalloc_test_merge_free_blocks, - // kfree_null_pointer_test, - // kfree_double_free_test, - // kfree_invalid_pointer_inside_heap_test, - // kfree_invalid_pointer_outside_heap_test, - kfree_merge_order_test, - }; - - const char *names[] = { - "single_alloc", - "single_alloc_and_free", - "merge_free_blocks", - "kfree_null_pointer", - "kfree_double_free", - "kfree_invalid_inside_heap", - "kfree_invalid_outside_heap", - "kfree_merge_order", - }; - - int num_tests = sizeof(tests) / sizeof(tests[0]); - int test_passed = 0; - - for (int i = 0; i < num_tests; i++) - { - printf("Running test %d (%s): ", i, names[i]); - setup(); - int result = tests[i](); - tear_down(); - - if (!result) - { - printf("FAILED\n"); - return 1; - } - printf("PASSED\n"); - test_passed++; - } - printf("%d/%d tests passed\n", test_passed, num_tests); - return 0; -} From 4a005d73bff227022caec03a7d9f33575542cec1 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 18:35:20 -0800 Subject: [PATCH 8/9] Moved Doxygen documentation from implementation to header files --- include/clear.h | 4 ++- include/interrupt.h | 10 +++++++ include/memory.h | 7 ++++- include/printf.h | 64 +++++++++++++++++++++--------------------- include/string.h | 15 ++++++++++ src/kernel/interrupt.c | 10 ------- src/user/clear.c | 3 -- src/user/printf.c | 24 ---------------- src/user/string.c | 14 --------- 9 files changed, 66 insertions(+), 85 deletions(-) diff --git a/include/clear.h b/include/clear.h index ced4386..4797b81 100644 --- a/include/clear.h +++ b/include/clear.h @@ -1,4 +1,6 @@ #pragma once +/** + * @brief Clears the terminal screen and moves the cursor to the home position. + */ void clear(void); - diff --git a/include/interrupt.h b/include/interrupt.h index 8d23408..d66f29f 100644 --- a/include/interrupt.h +++ b/include/interrupt.h @@ -39,10 +39,20 @@ extern "C" // VIC line number for Timer0/1 on Versatile #define IRQ_TIMER01 4 + /** + * @brief C-level IRQ handler called from assembly stub in start.s + * Must clear the source interrupt and (for VIC) write VIC_VECTADDR to ack end of interrupt. + */ void irq_handler(void); void irq_enable(void); void irq_disable(void); + /** + * @brief VersatilePB SP804 timer clock is typically 1 MHz (can be overridden) + * + * @param tick_hz: desired tick frequency (e.g., 100) + * @param timer_clk_hz: input clock to the SP804 (e.g., 1000000) + */ void interrupts_init_timer0(uint32_t tick_hz, uint32_t timer_clk_hz); static inline void timer0_start_periodic(uint32_t load) diff --git a/include/memory.h b/include/memory.h index 126b219..c3549a6 100644 --- a/include/memory.h +++ b/include/memory.h @@ -1,7 +1,6 @@ #pragma once #include -#include #ifdef __cplusplus extern "C" @@ -96,6 +95,12 @@ extern "C" * the function calls `kernel_panic`. */ void kfree(void *block); + + /** + * @brief Entry point for testing `kmalloc` and `kfree`. + * + * @return int Return 0 on tests passing, 1 on tests failure. + */ int kmalloc_test(void); #ifdef __cplusplus } diff --git a/include/printf.h b/include/printf.h index dcfc20d..e76bf85 100644 --- a/include/printf.h +++ b/include/printf.h @@ -20,10 +20,10 @@ extern "C" { #endif /** - * @enum fmt_state_t - * @brief Finite-state machine for parsing format strings. - * - * The printf parser moves between these states as it consumes characters. + * @enum fmt_state_t + * @brief Finite-state machine for parsing format strings. + * + * The printf parser moves between these states as it consumes characters. */ typedef enum { FMT_TEXT, /**< Normal character output. */ @@ -32,7 +32,7 @@ extern "C" { } fmt_state_t; /** - * @brief Bit flags controlling number formatting. + * @brief Bit flags controlling number formatting. */ enum { FLAG_LONG = 1 << 0, /**< 'l' length modifier (long / long long). */ @@ -42,11 +42,11 @@ extern "C" { }; /** - * @struct Format_State - * @brief Stores the current numeric value and formatting flags. - * - * This structure is passed to integer-formatting functions during printf - * processing. It represents the transient state for one format specifier. + * @struct Format_State + * @brief Stores the current numeric value and formatting flags. + * + * This structure is passed to integer-formatting functions during printf + * processing. It represents the transient state for one format specifier. */ typedef struct { unsigned long long num; /**< The numeric value to be printed. */ @@ -54,36 +54,36 @@ extern "C" { } Format_State; /** - * @brief Prints a null-terminated string over UART. - * - * @param s The string to output. If NULL, no output occurs. + * @brief Transmit a null-terminated string over UART. + * + * @param s The string to output. If NULL, no output occurs. */ void puts(const char *s); /** - * @brief Prints a formatted string to the UART output. - * - * @param fmt Format string (supports %c, %s, %d, %u, %x, %X, %p, %%). - * @param ... Variable arguments matching the format specifiers. - * - * This function supports a minimal subset of standard C printf: - * - Signed/unsigned integers (`%d`, `%u`) - * - Hexadecimal (`%x`, `%X`) - * - Pointers (`%p`) - * - Characters (`%c`) - * - Strings (`%s`) - * - Length modifier (`%l`) + * @brief Prints a formatted string to the UART output. + * + * @param fmt Format string (supports %c, %s, %d, %u, %x, %X, %p, %%). + * @param ... Variable arguments matching the format specifiers. + * + * This function supports a minimal subset of standard C printf: + * - Signed/unsigned integers (`%d`, `%u`) + * - Hexadecimal (`%x`, `%X`) + * - Pointers (`%p`) + * - Characters (`%c`) + * - Strings (`%s`) + * - Length modifier (`%l`) */ void printf(const char *fmt, ...); /** - * @brief Reads a line of text from UART into the given buffer. - * - * @param buffer Destination buffer. - * @param length Maximum buffer length (including null terminator). - * - * Blocks until a newline or carriage return is received. - * Supports backspace editing and echoes input characters. + * @brief Reads a line of text from UART into the given buffer. + * + * @param buffer Destination buffer. + * @param length Maximum buffer length (including null terminator). + * + * @note Blocks until a newline or carriage return is received. + * Supports backspace editing and echoes input characters. */ void getlines(char *restrict buffer, size_t length); diff --git a/include/string.h b/include/string.h index 48bed10..afd886f 100644 --- a/include/string.h +++ b/include/string.h @@ -7,7 +7,22 @@ extern "C" { #endif + /** + * @brief Compares two null-terminated strings lexicographically. + * + * @param str_1 Pointer to the first string to compare. + * @param str_2 Pointer to the second string to compare. + * + * @return int 0 if strings are equal, -1 if `str_1` < `str_2`, 1 if `str_1` > `str_2`. + */ int strcmp(const char *str_1, const char *str_2); + + /** + * @brief Calculates the length of a null-terminated string. + * + * @param str Pointer to the null-terminated string to be measured. + * @return The number of characters in the string, excluding the null terminator. + */ size_t strlen(const char *str); #ifdef __cplusplus diff --git a/src/kernel/interrupt.c b/src/kernel/interrupt.c index fa622e6..5ee4479 100644 --- a/src/kernel/interrupt.c +++ b/src/kernel/interrupt.c @@ -5,12 +5,6 @@ volatile uint64_t systicks = 0; -/** - * @brief VersatilePB SP804 timer clock is typically 1 MHz (can be overridden) - * - * @param tick_hz: desired tick frequency (e.g., 100) - * @param timer_clk_hz: input clock to the SP804 (e.g., 1000000) - */ void interrupts_init_timer0(uint32_t tick_hz, uint32_t timer_clk_hz) { if (tick_hz == 0 || timer_clk_hz == 0) @@ -33,10 +27,6 @@ void interrupts_init_timer0(uint32_t tick_hz, uint32_t timer_clk_hz) vic_enable_timer01_irq(); } -/** - * @brief C-level IRQ handler called from assembly stub in start.s - * Must clear the source interrupt and (for VIC) write VIC_VECTADDR to ack end of interrupt. - */ void irq_handler(void) { // Check Timer0 MIS (masked interrupt status) diff --git a/src/user/clear.c b/src/user/clear.c index 827dc09..1ed07cd 100644 --- a/src/user/clear.c +++ b/src/user/clear.c @@ -1,8 +1,5 @@ #include "printf.h" -/** - * @brief Clears the terminal screen and moves the cursor to the home position. - */ void clear(void) { printf("\x1B[2J"); diff --git a/src/user/printf.c b/src/user/printf.c index dd0dbb0..b002e7f 100644 --- a/src/user/printf.c +++ b/src/user/printf.c @@ -7,7 +7,6 @@ * * @todo Refactor this file for cleaner function implementation. */ - #include "printf.h" #include "panic.h" @@ -181,11 +180,6 @@ static inline void put_integers(char control, const Format_State *restrict fs) } } -/** - * @brief Transmit a null-terminated string. - * - * @param s String to transmit. Must be non-null. - */ void puts(const char *s) { while (*s) @@ -194,16 +188,6 @@ void puts(const char *s) } } -/** - * @brief Kernel printf implementation using UART output. - * - * @param fmt Format string. - * @param ... Variable arguments for the format string. - * - * Implements a minimal printf supporting: - * - %c, %s, %p, %d, %u, %x, %X, %l modifiers - * - %% - */ void printf(const char *fmt, ...) { va_list args; @@ -337,14 +321,6 @@ static inline char getc(void) return (char)(UART0_DR & 0xFF); } -/** - * @brief Read a line of text from UART with basic editing support. - * - * @param buffer Destination buffer for the input line. - * @param length Maximum number of bytes to store (including '\0'). - * - * Handles backspace and carriage return. - */ void getlines(char *restrict buffer, size_t length) { long long index = 0; diff --git a/src/user/string.c b/src/user/string.c index 9ff0224..2162e7a 100644 --- a/src/user/string.c +++ b/src/user/string.c @@ -1,13 +1,5 @@ #include "string.h" -/** - * @brief Compares two null-terminated strings lexicographically. - * - * @param str_1 Pointer to the first string to compare. - * @param str_2 Pointer to the second string to compare. - * - * @return int 0 if strings are equal, -1 if `str_1` < `str_2`, 1 if `str_1` > `str_2`. - */ int strcmp(const char *str_1, const char *str_2) { unsigned char ch1, ch2; @@ -28,12 +20,6 @@ int strcmp(const char *str_1, const char *str_2) return 0; } -/** - * @brief Calculates the length of a null-terminated string. - * - * @param str Pointer to the null-terminated string to be measured. - * @return The number of characters in the string, excluding the null terminator. - */ size_t strlen(const char *str) { const char *s = str; From 3f43255793cf263db3fcda4394c1ca98c2682ea4 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 6 Nov 2025 18:37:06 -0800 Subject: [PATCH 9/9] remove printf and use stdint library instead --- src/kernel/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/memory.c b/src/kernel/memory.c index bebc15b..1b9cbed 100644 --- a/src/kernel/memory.c +++ b/src/kernel/memory.c @@ -24,7 +24,7 @@ */ #include "memory.h" #include "panic.h" -#include "printf.h" +#include static struct header *head = NULL; /**< Default alignment: at least pointer size; 16 is a good general default. */