diff --git a/GNUmakefile b/GNUmakefile index d6917aa..97b6d43 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -18,7 +18,7 @@ endef # It is suggested to use a custom built cross toolchain to build a kernel. # We are using the standard "cc" here, it may work by using # the host system's toolchain, but this is not guaranteed. -override DEFAULT_CC := cc +override DEFAULT_CC := clang $(eval $(call DEFAULT_VAR,CC,$(DEFAULT_CC))) # Same thing for "ld" (the linker). @@ -49,16 +49,16 @@ override CFLAGS += \ -ffreestanding \ -fno-stack-protector \ -fno-stack-check \ + -fno-tree-vectorize \ -fno-lto \ -fPIE \ -m64 \ -march=x86-64 \ -mno-80387 \ -mno-mmx \ - -mno-red-zone - -#-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 := \ diff --git a/src/clib/stdlib.c b/src/clib/stdlib.c new file mode 100644 index 0000000..fb83593 --- /dev/null +++ b/src/clib/stdlib.c @@ -0,0 +1,3 @@ +int abs(int x) { + return x < 0 ? -x : x; +} \ No newline at end of file diff --git a/src/clib/stdlib.h b/src/clib/stdlib.h new file mode 100644 index 0000000..5bddd05 --- /dev/null +++ b/src/clib/stdlib.h @@ -0,0 +1,6 @@ +#ifndef STDLIB_H +#define STDLIB_H 1 + +int abs(int x); + +#endif // STDLIB_H \ No newline at end of file diff --git a/src/clib/string.c b/src/clib/string.c new file mode 100644 index 0000000..e02e8b1 --- /dev/null +++ b/src/clib/string.c @@ -0,0 +1,15 @@ +char *strcpy(char *dest, const char *src) { + char *saved = dest; + while (*src) { + *dest++ = *src++; + } + *dest = 0; // Null-terminate the destination string + return saved; // Return the start of the destination string +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 && (*s1 == *s2)) { + s1++, s2++; + } + return *(const unsigned char *)s1 - *(const unsigned char *)s2; +} diff --git a/src/clib/string.h b/src/clib/string.h new file mode 100644 index 0000000..160e195 --- /dev/null +++ b/src/clib/string.h @@ -0,0 +1,7 @@ +#ifndef STRING_H +#define STRING_H 1 + +char *strcpy(char *dest, const char *src); +int strcmp(const char *s1, const char *s2); + +#endif // STRING_H \ No newline at end of file diff --git a/src/console/fonts.c b/src/console/fonts.c index ab5eacc..a4f3ed1 100644 --- a/src/console/fonts.c +++ b/src/console/fonts.c @@ -1,6 +1,50 @@ #include "fonts.h" -#include // For malloc/free +#include "graphics.h" +#include "../../vendor/stb/stb_easy_font.h" -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 +void draw_text(struct limine_framebuffer *framebuffer, const char *text, + float x, float y, uint32_t fg_color, uint32_t bg_color) { + // First call to get the total number of quads needed to draw the text + int quads = stb_easy_font_print(0, 0, (char *)text, NULL, NULL, 0); + float *vertex_data = (float *)malloc(quads * 4 * 6 * sizeof(float)); + if (!vertex_data) { + // Handle memory allocation failure + draw_line(framebuffer, 0, 0, framebuffer->width, framebuffer->height, + 0xFF0000); + draw_line(framebuffer, framebuffer->width, 0, 0, framebuffer->height, + 0xFF0000); + } + + // Second call to actually generate the vertex data + stb_easy_font_print(x, y, (char *)text, NULL, vertex_data, 0); + + // Loop over each quad and each vertex + for (int i = 0; i < quads * 4 * 6; i += 6) { + // Extract the position of the quad from the vertex data + float quad_x = vertex_data[i + 0]; + float quad_y = vertex_data[i + 1]; + + // Draw each pixel of the quad onto the framebuffer + int pixel_x = (int)quad_x; + int pixel_y = (int)quad_y; + if (pixel_x >= 0 && pixel_y >= 0 && pixel_x < framebuffer->width && + pixel_y < framebuffer->height) { + uint32_t *pixel = + (uint32_t *)((uintptr_t)framebuffer->address + + (pixel_y * framebuffer->pitch) + (pixel_x * 4)); + + // Check the fourth value that stb_easy_font_print puts in vertex_data, + // if it's below a threshold, it's considered the background. + if (vertex_data[i + 4] < 0.1f) { + if (bg_color != fg_color) { + *pixel = bg_color; + } + } else { + *pixel = fg_color; + } + } + } + + // Free the vertex data after drawing + free(vertex_data); +} diff --git a/src/console/fonts.h b/src/console/fonts.h index 2a7157f..6dd14c5 100644 --- a/src/console/fonts.h +++ b/src/console/fonts.h @@ -1,7 +1,7 @@ #ifndef FONTS_H -#define FONTS_H +#define FONTS_H 1 -#include "../limine.h" // Make sure Limine types are available for use +#include "../limine.h" void draw_text(struct limine_framebuffer *framebuffer, const char *text, float x, float y, uint32_t fg_color, uint32_t bg_color); diff --git a/src/console/graphics.c b/src/console/graphics.c new file mode 100644 index 0000000..781e65a --- /dev/null +++ b/src/console/graphics.c @@ -0,0 +1,46 @@ +#include "graphics.h" + +void draw_pixel(struct limine_framebuffer *framebuffer, int x, int y, + uint32_t color) { + if (x >= 0 && y >= 0 && x < framebuffer->width && y < framebuffer->height) { + uint32_t *fb_ptr = framebuffer->address; + fb_ptr[y * (framebuffer->pitch / 4) + x] = color; + } +} + +void draw_line(struct limine_framebuffer *framebuffer, int x1, int y1, int x2, + int y2, uint32_t color) { + + int dx = abs(x2 - x1); + int sx = x1 < x2 ? 1 : -1; + int dy = -abs(y2 - y1); + int sy = y1 < y2 ? 1 : -1; + + int error = dx + dy; + + while (1) { + draw_pixel(framebuffer, x1, y1, color); + if (x1 == x2 && y1 == y2) + break; + int e2 = 2 * error; + if (e2 >= dy) { + if (x1 == x2) + break; + error = error + dy; + x1 = x1 + sx; + } + if (e2 <= dx) { + if (y1 == y2) + break; + error = error + dx; + y1 = y1 + sy; + } + } +} + +void draw_demo_line(struct limine_framebuffer *framebuffer, uint32_t color) { + // Note: we assume the framebuffer model is RGB with 32-bit pixels. + for (size_t i = 0; i < 100; i++) { + draw_pixel(framebuffer, i, i, color); + } +} diff --git a/src/console/graphics.h b/src/console/graphics.h new file mode 100644 index 0000000..c524d98 --- /dev/null +++ b/src/console/graphics.h @@ -0,0 +1,15 @@ +#include +#ifndef GRAPHICS_H +#define GRAPHICS_H 1 + +#include +#include + +#include "../limine.h" + +void draw_line(struct limine_framebuffer *framebuffer, int x1, int y1, int x2, + int y2, uint32_t color); + +void draw_demo_line(struct limine_framebuffer *framebuffer, uint32_t color); + +#endif // GRAPHICS_H \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index 06da0d0..94a737a 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -6,7 +6,10 @@ #include "limine.h" #include "memory.h" +#include "clib/stdlib.h" + #include "console/fonts.h" +#include "console/graphics.h" // Set the base revision to 1, this is recommended as this is the latest // base revision described by the Limine boot protocol specification. @@ -48,18 +51,15 @@ void _start(void) { 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_demo_line(framebuffer, 0x880000); + draw_line(framebuffer, 100, 0, 1000, 1000, 0x00ffff); + // Draw some text draw_text(framebuffer, "Hello, World!", x, y, fg_color, bg_color); diff --git a/src/memory.c b/src/memory.c index 6fb0004..94e9915 100644 --- a/src/memory.c +++ b/src/memory.c @@ -1,8 +1,3 @@ -// 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 diff --git a/src/memory.h b/src/memory.h index 4316df0..4854d85 100644 --- a/src/memory.h +++ b/src/memory.h @@ -1,3 +1,6 @@ +#ifndef MEMORY_H +#define MEMORY_H 1 + #include #define MEMORY_POOL_SIZE 1024 * 1024 * 64 // 64 MB @@ -6,3 +9,7 @@ typedef char ALIGN[16]; typedef union header header_t; +void *malloc(size_t size); +void free(void *ptr); + +#endif // MEMORY_H diff --git a/src/tests/memory.c b/src/tests/memory.c new file mode 100644 index 0000000..dc25bea --- /dev/null +++ b/src/tests/memory.c @@ -0,0 +1,64 @@ +#include + +#include "../clib/string.h" +#include "../memory.h" + +void test_basic_allocation() { + size_t big_size = 0x0F; // An unreasonably large size + void *ptr = malloc(big_size); + if (ptr != NULL) { + //printf("Basic allocation test passed.\n"); + free(ptr); + } else { + //printf("Basic allocation test failed!\n"); + } +} + +void test_allocation_failure() { + size_t big_size = 0xFFFFFFFF; // An unreasonably large size + void *ptr = malloc(big_size); + if (ptr == NULL) { + //printf("Allocation failure test passed.\n"); + } else { + //printf("Allocation failure test failed!\n"); + free(ptr); + } +} + +void test_memory_writing() { + char *ptr = (char *)malloc(10); + if (ptr != NULL) { + strcpy(ptr, "test"); + if (strcmp(ptr, "test") == 0) { + //printf("Memory writing test passed.\n"); + } else { + //printf("Memory writing test failed!\n"); + } + free(ptr); + } else { + //printf("Memory writing test skipped, allocation failed!\n"); + } +} + +void test_free_and_reuse() { + void *ptr1 = malloc(10); + free(ptr1); + void *ptr2 = malloc(10); + if (ptr1 == ptr2) { + //printf("Free and reuse test passed.\n"); + free(ptr2); + } else { + //printf("Free and reuse test failed!\n"); + } +} + +int main() { + test_basic_allocation(); + test_allocation_failure(); + test_memory_writing(); + test_free_and_reuse(); + + // Add other tests as necessary + + return 0; +}