From afe216263e0dd556bf3a455c29de39ed7e9e2225 Mon Sep 17 00:00:00 2001 From: Kumi Date: Tue, 9 Jan 2024 10:57:16 +0100 Subject: [PATCH] Add STB submodule and implement text rendering Introduced the STB (Sean Barrett's libraries) submodule to handle different utilities such as image loading and text rendering. The necessary makefile adjustments have been made to include this third-party library. Separated memory management functions into a new `memory.c` file to clean up `kernel.c`. Defined a basic `draw_text` function as a placeholder in `fonts.c` to set up the text rendering functionality. This change lays the groundwork for enhanced graphical capabilities in the console, utilizing STB for fonts and other graphical tasks. Included are forward declarations and initial integration into the build system, as well as function stubs and associated header files. This refactor promotes modular code organization and paves the way for future graphical feature implementations, although the `draw_text` function is currently non-operative and serves as a template for future development. Note: SSE and SSE2 optimizations have been re-commented out within the makefile, suggesting a decision to possibly defer or revisit this optimization approach. --- .gitmodules | 3 + GNUmakefile | 12 ++- src/console/fonts.c | 6 ++ src/console/fonts.h | 9 +++ src/kernel.c | 144 +++++++++++---------------------- src/memory.c | 192 ++++++++++++++++++++++++++++++++++++++++++++ src/memory.h | 8 ++ vendor/stb | 1 + 8 files changed, 278 insertions(+), 97 deletions(-) create mode 100644 src/console/fonts.h create mode 100644 src/memory.c create mode 100644 src/memory.h create mode 160000 vendor/stb diff --git a/.gitmodules b/.gitmodules index 6ff1c0d..06c99a1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ path = vendor/limine url = https://github.com/limine-bootloader/limine.git branch = v6.x-branch-binary +[submodule "vendor/stb"] + path = vendor/stb + url = https://github.com/nothings/stb.git diff --git a/GNUmakefile b/GNUmakefile index 8c1304e..d6917aa 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -55,10 +55,11 @@ override CFLAGS += \ -march=x86-64 \ -mno-80387 \ -mno-mmx \ - -mno-sse \ - -mno-sse2 \ -mno-red-zone +#-mno-sse \ + -mno-sse2 \ + # Internal C preprocessor flags that should not be changed by the user. override CPPFLAGS := \ -I src \ @@ -90,6 +91,13 @@ override NASMFILES := $(shell cd src && find -L * -type f -name '*.asm') override OBJ := $(addprefix obj/,$(CFILES:.c=.c.o) $(ASFILES:.S=.S.o) $(NASMFILES:.asm=.asm.o)) override HEADER_DEPS := $(addprefix obj/,$(CFILES:.c=.c.d) $(ASFILES:.S=.S.d)) +## STB + +STB_INCLUDE_PATH = vendor/stb +override CFLAGS += -I$(STB_INCLUDE_PATH) + +## End STB + # Default target. .PHONY: all all: bin/$(KERNEL) iso hdd diff --git a/src/console/fonts.c b/src/console/fonts.c index e69de29..ab5eacc 100644 --- a/src/console/fonts.c +++ b/src/console/fonts.c @@ -0,0 +1,6 @@ +#include "fonts.h" +#include // For malloc/free + +void draw_text(struct limine_framebuffer *framebuffer, const char *text, float x, float y, uint32_t fg_color, uint32_t bg_color) { + return; +} \ No newline at end of file diff --git a/src/console/fonts.h b/src/console/fonts.h new file mode 100644 index 0000000..2a7157f --- /dev/null +++ b/src/console/fonts.h @@ -0,0 +1,9 @@ +#ifndef FONTS_H +#define FONTS_H + +#include "../limine.h" // Make sure Limine types are available for use + +void draw_text(struct limine_framebuffer *framebuffer, const char *text, + float x, float y, uint32_t fg_color, uint32_t bg_color); + +#endif // FONTS_H diff --git a/src/kernel.c b/src/kernel.c index d2dec58..06da0d0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,114 +1,68 @@ -#include -#include #include -#include - -#include +#include +#include +#include + +#include "limine.h" +#include "memory.h" + +#include "console/fonts.h" // Set the base revision to 1, this is recommended as this is the latest // base revision described by the Limine boot protocol specification. // See specification for further info. - + LIMINE_BASE_REVISION(1) - + // The Limine requests can be placed anywhere, but it is important that // the compiler does not optimise them away, so, in C, they should // NOT be made "static". - + struct limine_framebuffer_request framebuffer_request = { - .id = LIMINE_FRAMEBUFFER_REQUEST, - .revision = 0 -}; - -// GCC and Clang reserve the right to generate calls to the following -// 4 functions even if they are not directly called. -// Implement them as the C specification mandates. -// DO NOT remove or rename these functions, or stuff will eventually break! -// They CAN be moved to a different .c file. - -void *memcpy(void *dest, const void *src, size_t n) { - uint8_t *pdest = (uint8_t *)dest; - const uint8_t *psrc = (const uint8_t *)src; - - for (size_t i = 0; i < n; i++) { - pdest[i] = psrc[i]; - } - - return dest; -} - -void *memset(void *s, int c, size_t n) { - uint8_t *p = (uint8_t *)s; - - for (size_t i = 0; i < n; i++) { - p[i] = (uint8_t)c; - } - - return s; -} - -void *memmove(void *dest, const void *src, size_t n) { - uint8_t *pdest = (uint8_t *)dest; - const uint8_t *psrc = (const uint8_t *)src; - - if (src > dest) { - for (size_t i = 0; i < n; i++) { - pdest[i] = psrc[i]; - } - } else if (src < dest) { - for (size_t i = n; i > 0; i--) { - pdest[i-1] = psrc[i-1]; - } - } - - return dest; -} - -int memcmp(const void *s1, const void *s2, size_t n) { - const uint8_t *p1 = (const uint8_t *)s1; - const uint8_t *p2 = (const uint8_t *)s2; - - for (size_t i = 0; i < n; i++) { - if (p1[i] != p2[i]) { - return p1[i] < p2[i] ? -1 : 1; - } - } - - return 0; -} - + .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0}; + // Halt and catch fire function. static void hcf(void) { - asm ("cli"); - for (;;) { - asm ("hlt"); - } + asm("cli"); + for (;;) { + asm("hlt"); + } } - + // The following will be our kernel's entry point. // If renaming _start() to something else, make sure to change the // linker script accordingly. void _start(void) { - // Ensure the bootloader actually understands our base revision (see spec). - if (LIMINE_BASE_REVISION_SUPPORTED == false) { - hcf(); - } - - // Ensure we got a framebuffer. - if (framebuffer_request.response == NULL - || framebuffer_request.response->framebuffer_count < 1) { - hcf(); - } - - // Fetch the first framebuffer. - struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0]; - - // Note: we assume the framebuffer model is RGB with 32-bit pixels. - for (size_t i = 0; i < 100; i++) { - uint32_t *fb_ptr = framebuffer->address; - fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff; - } - - // Write to framebuffer + // Ensure the bootloader actually understands our base revision (see spec). + if (LIMINE_BASE_REVISION_SUPPORTED == false) { + hcf(); + } + // Ensure we got a framebuffer. + if (framebuffer_request.response == NULL || + framebuffer_request.response->framebuffer_count < 1) { + hcf(); + } + + // Fetch the first framebuffer. + struct limine_framebuffer *framebuffer = + framebuffer_request.response->framebuffers[0]; + + // Note: we assume the framebuffer model is RGB with 32-bit pixels. + for (size_t i = 0; i < 100; i++) { + uint32_t *fb_ptr = framebuffer->address; + fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff; + } + + // Write to framebuffer + float x = 10.0f; + float y = 10.0f; + uint32_t fg_color = 0xFFFFFFFF; // White text + uint32_t bg_color = 0x00000000; // Black background + + // Draw some text + draw_text(framebuffer, "Hello, World!", x, y, fg_color, bg_color); + + // Now die. + hcf(); } \ No newline at end of file diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..6fb0004 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,192 @@ +// GCC and Clang reserve the right to generate calls to the following +// 4 functions even if they are not directly called. +// Implement them as the C specification mandates. +// DO NOT remove or rename these functions, or stuff will eventually break! + +#include +#include +#include + +#include "memory.h" + +size_t align(size_t size); +header_t *head, *tail; + +void *memcpy(void *dest, const void *src, size_t n) { + uint8_t *pdest = (uint8_t *)dest; + const uint8_t *psrc = (const uint8_t *)src; + + for (size_t i = 0; i < n; i++) { + pdest[i] = psrc[i]; + } + + return dest; +} + +void *memset(void *s, int c, size_t n) { + uint8_t *p = (uint8_t *)s; + + for (size_t i = 0; i < n; i++) { + p[i] = (uint8_t)c; + } + + return s; +} + +void *memmove(void *dest, const void *src, size_t n) { + uint8_t *pdest = (uint8_t *)dest; + const uint8_t *psrc = (const uint8_t *)src; + + if (src > dest) { + for (size_t i = 0; i < n; i++) { + pdest[i] = psrc[i]; + } + } else if (src < dest) { + for (size_t i = n; i > 0; i--) { + pdest[i - 1] = psrc[i - 1]; + } + } + + return dest; +} + +int memcmp(const void *s1, const void *s2, size_t n) { + const uint8_t *p1 = (const uint8_t *)s1; + const uint8_t *p2 = (const uint8_t *)s2; + + for (size_t i = 0; i < n; i++) { + if (p1[i] != p2[i]) { + return p1[i] < p2[i] ? -1 : 1; + } + } + + return 0; +} + +union header { + struct { + size_t size; + unsigned is_free; + union header *next; + } s; + ALIGN stub; // force alignment to 16 bytes +}; + +header_t *get_free_block(size_t size) { + header_t *current = head; + while (current) { + if (current->s.is_free && current->s.size >= size) { + return current; + } + current = current->s.next; + } + return NULL; +} + +void *malloc(size_t size) { + size_t total_size; + void *block; + header_t *header; + + if (!size) + return NULL; + + // Align header size to ensure proper alignment + size = align(size); + // Allocate space for the header too + total_size = align(sizeof(header_t)) + size; + + // Use total_size to search for a free block that is large enough + header = get_free_block(total_size); + + if (header) { + header->s.is_free = 0; + return (void *)(header + 1); + } + + // sbrk is called with total_size to increase the memory pool + block = sbrk(total_size); + + if (block == (void *)-1) { + return NULL; // sbrk failed to allocate memory + } + + header = block; + header->s.size = size; // Set the user's requested size + header->s.is_free = 0; + header->s.next = NULL; + + if (!head) + head = header; + + if (tail) + tail->s.next = header; + + tail = header; + + return (void *)(header + 1); +} + +void free(void *block) { + header_t *header, *tmp; + void *programbreak; + + if (!block) + return; + + header = (header_t *)block - 1; + programbreak = sbrk(0); + + if ((char *)block + header->s.size == programbreak) { + if (head == tail) { + head = tail = NULL; + } else { + tmp = head; + while (tmp) { + if (tmp->s.next == tail) { + tmp->s.next = NULL; + tail = tmp; + } + tmp = tmp->s.next; + } + } + + sbrk(0 - sizeof(header_t) - header->s.size); + return; + } + header->s.is_free = 1; +} + +static char + memory_pool[MEMORY_POOL_SIZE]; // Adjust size as necessary for your use +static size_t current_memory_position = 0; + +// This function aligns the given size to the defined ALIGNMENT +size_t align(size_t size) { + return (size + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1); +} + +void *sbrk(intptr_t increment) { + size_t aligned_increment; + void *previous_position; + + // First, align the increment to ensure we provide aligned memory + aligned_increment = align(increment); + + // Now, check if we have enough memory left in our pool + if (current_memory_position + aligned_increment > MEMORY_POOL_SIZE || + current_memory_position + aligned_increment < current_memory_position) { + // Not enough memory left, or we would wrap around + return (void *)-1; + } + + // Get the current position to return + previous_position = &memory_pool[current_memory_position]; + + // Advance the current position by the aligned increment amount + current_memory_position += aligned_increment; + + // Return the previous position, which is the start of the newly allocated + // block + return previous_position; +} \ No newline at end of file diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 0000000..4316df0 --- /dev/null +++ b/src/memory.h @@ -0,0 +1,8 @@ +#include + +#define MEMORY_POOL_SIZE 1024 * 1024 * 64 // 64 MB +#define ALIGNMENT 16 + +typedef char ALIGN[16]; +typedef union header header_t; + diff --git a/vendor/stb b/vendor/stb new file mode 160000 index 0000000..f4a71b1 --- /dev/null +++ b/vendor/stb @@ -0,0 +1 @@ +Subproject commit f4a71b13373436a2866c5d68f8f80ac6f0bc1ffe