Updated toolchain and implemented basic C library functions
Switched the makefile to use `clang` as the default compiler, enhancing portability and potentially optimizing the build process. New implementations of `abs`, `strcpy`, and `strcmp` provide foundational C library support. Enhanced text and line rendering in the graphics subsystem with the inclusion of STB's easy font printing library, facilitating on-screen debug message display. Memory management functions `malloc` and `free` have been introduced, paving the way for dynamic memory allocation. Accompanying test cases for memory operations validate basic functionality and robustness of the new implementations. The adjustment and enablement of compiler flags further tailor the compilation process to the system's requirements.
This commit is contained in:
parent
afe216263e
commit
90a3fc18e2
13 changed files with 224 additions and 22 deletions
10
GNUmakefile
10
GNUmakefile
|
@ -18,7 +18,7 @@ endef
|
||||||
# It is suggested to use a custom built cross toolchain to build a kernel.
|
# 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
|
# We are using the standard "cc" here, it may work by using
|
||||||
# the host system's toolchain, but this is not guaranteed.
|
# 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)))
|
$(eval $(call DEFAULT_VAR,CC,$(DEFAULT_CC)))
|
||||||
|
|
||||||
# Same thing for "ld" (the linker).
|
# Same thing for "ld" (the linker).
|
||||||
|
@ -49,16 +49,16 @@ override CFLAGS += \
|
||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
-fno-stack-protector \
|
-fno-stack-protector \
|
||||||
-fno-stack-check \
|
-fno-stack-check \
|
||||||
|
-fno-tree-vectorize \
|
||||||
-fno-lto \
|
-fno-lto \
|
||||||
-fPIE \
|
-fPIE \
|
||||||
-m64 \
|
-m64 \
|
||||||
-march=x86-64 \
|
-march=x86-64 \
|
||||||
-mno-80387 \
|
-mno-80387 \
|
||||||
-mno-mmx \
|
-mno-mmx \
|
||||||
-mno-red-zone
|
-mno-red-zone \
|
||||||
|
-mno-sse \
|
||||||
#-mno-sse \
|
-mno-sse2
|
||||||
-mno-sse2 \
|
|
||||||
|
|
||||||
# Internal C preprocessor flags that should not be changed by the user.
|
# Internal C preprocessor flags that should not be changed by the user.
|
||||||
override CPPFLAGS := \
|
override CPPFLAGS := \
|
||||||
|
|
3
src/clib/stdlib.c
Normal file
3
src/clib/stdlib.c
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
int abs(int x) {
|
||||||
|
return x < 0 ? -x : x;
|
||||||
|
}
|
6
src/clib/stdlib.h
Normal file
6
src/clib/stdlib.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#define STDLIB_H 1
|
||||||
|
|
||||||
|
int abs(int x);
|
||||||
|
|
||||||
|
#endif // STDLIB_H
|
15
src/clib/string.c
Normal file
15
src/clib/string.c
Normal file
|
@ -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;
|
||||||
|
}
|
7
src/clib/string.h
Normal file
7
src/clib/string.h
Normal file
|
@ -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
|
|
@ -1,6 +1,50 @@
|
||||||
#include "fonts.h"
|
#include "fonts.h"
|
||||||
#include <stdlib.h> // 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) {
|
void draw_text(struct limine_framebuffer *framebuffer, const char *text,
|
||||||
return;
|
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);
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef FONTS_H
|
#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,
|
void draw_text(struct limine_framebuffer *framebuffer, const char *text,
|
||||||
float x, float y, uint32_t fg_color, uint32_t bg_color);
|
float x, float y, uint32_t fg_color, uint32_t bg_color);
|
||||||
|
|
46
src/console/graphics.c
Normal file
46
src/console/graphics.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
15
src/console/graphics.h
Normal file
15
src/console/graphics.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifndef GRAPHICS_H
|
||||||
|
#define GRAPHICS_H 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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
|
12
src/kernel.c
12
src/kernel.c
|
@ -6,7 +6,10 @@
|
||||||
#include "limine.h"
|
#include "limine.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include "clib/stdlib.h"
|
||||||
|
|
||||||
#include "console/fonts.h"
|
#include "console/fonts.h"
|
||||||
|
#include "console/graphics.h"
|
||||||
|
|
||||||
// Set the base revision to 1, this is recommended as this is the latest
|
// Set the base revision to 1, this is recommended as this is the latest
|
||||||
// base revision described by the Limine boot protocol specification.
|
// base revision described by the Limine boot protocol specification.
|
||||||
|
@ -48,18 +51,15 @@ void _start(void) {
|
||||||
struct limine_framebuffer *framebuffer =
|
struct limine_framebuffer *framebuffer =
|
||||||
framebuffer_request.response->framebuffers[0];
|
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
|
// Write to framebuffer
|
||||||
float x = 10.0f;
|
float x = 10.0f;
|
||||||
float y = 10.0f;
|
float y = 10.0f;
|
||||||
uint32_t fg_color = 0xFFFFFFFF; // White text
|
uint32_t fg_color = 0xFFFFFFFF; // White text
|
||||||
uint32_t bg_color = 0x00000000; // Black background
|
uint32_t bg_color = 0x00000000; // Black background
|
||||||
|
|
||||||
|
draw_demo_line(framebuffer, 0x880000);
|
||||||
|
draw_line(framebuffer, 100, 0, 1000, 1000, 0x00ffff);
|
||||||
|
|
||||||
// Draw some text
|
// Draw some text
|
||||||
draw_text(framebuffer, "Hello, World!", x, y, fg_color, bg_color);
|
draw_text(framebuffer, "Hello, World!", x, y, fg_color, bg_color);
|
||||||
|
|
||||||
|
|
|
@ -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 <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef MEMORY_H
|
||||||
|
#define MEMORY_H 1
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define MEMORY_POOL_SIZE 1024 * 1024 * 64 // 64 MB
|
#define MEMORY_POOL_SIZE 1024 * 1024 * 64 // 64 MB
|
||||||
|
@ -6,3 +9,7 @@
|
||||||
typedef char ALIGN[16];
|
typedef char ALIGN[16];
|
||||||
typedef union header header_t;
|
typedef union header header_t;
|
||||||
|
|
||||||
|
void *malloc(size_t size);
|
||||||
|
void free(void *ptr);
|
||||||
|
|
||||||
|
#endif // MEMORY_H
|
||||||
|
|
64
src/tests/memory.c
Normal file
64
src/tests/memory.c
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in a new issue