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.
This commit is contained in:
parent
877dcc247d
commit
afe216263e
8 changed files with 278 additions and 97 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -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
|
||||
|
|
12
GNUmakefile
12
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
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#include "fonts.h"
|
||||
#include <stdlib.h> // 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;
|
||||
}
|
9
src/console/fonts.h
Normal file
9
src/console/fonts.h
Normal file
|
@ -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
|
124
src/kernel.c
124
src/kernel.c
|
@ -1,9 +1,12 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <limine.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <console/fonts.c>
|
||||
#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.
|
||||
|
@ -16,99 +19,50 @@ LIMINE_BASE_REVISION(1)
|
|||
// 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 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();
|
||||
}
|
||||
// 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];
|
||||
// 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;
|
||||
}
|
||||
// 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 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();
|
||||
}
|
192
src/memory.c
Normal file
192
src/memory.c
Normal file
|
@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
8
src/memory.h
Normal file
8
src/memory.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#define MEMORY_POOL_SIZE 1024 * 1024 * 64 // 64 MB
|
||||
#define ALIGNMENT 16
|
||||
|
||||
typedef char ALIGN[16];
|
||||
typedef union header header_t;
|
||||
|
1
vendor/stb
vendored
Submodule
1
vendor/stb
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit f4a71b13373436a2866c5d68f8f80ac6f0bc1ffe
|
Loading…
Reference in a new issue