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