1
0
Fork 0

feat: Added nanoprintf, kprintf and GDT

This commit is contained in:
Kevin Alavik 2025-05-14 13:57:53 +02:00
parent aa5a1e8e1a
commit 248879c099
Signed by: cmpsb
GPG key ID: 10D1CC0526FDC6D7
9 changed files with 1346 additions and 5 deletions

View file

@ -3,7 +3,6 @@ MAKEFLAGS += -rR
.SUFFIXES:
SRCDIR := src
INCDIR := src
OBJDIR := build
BINDIR := bin
@ -18,7 +17,7 @@ CFLAGS := -g -O2 -pipe -Wall -Wextra -Werror -std=gnu11 -ffreestanding \
-ffunction-sections -fdata-sections -m64 -march=x86-64 \
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
-mcmodel=kernel -Wno-unused-variable
CPPFLAGS := -I$(INCDIR) -I$(SRCDIR) -MMD -MP -DLIMINE_API_REVISION=3
CPPFLAGS := -I../external -I$(SRCDIR) -MMD -MP -DLIMINE_API_REVISION=3
NASMFLAGS := -F dwarf -g
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
-T linker.ld -Wl,-m,elf_x86_64

39
kernel/src/arch/gdt.c Normal file
View file

@ -0,0 +1,39 @@
#include <arch/gdt.h>
gdt_entry_t gdt[5];
gdt_ptr_t gdt_ptr;
void gdt_init()
{
gdt[0] = (gdt_entry_t){0, 0, 0, 0x00, 0x00, 0}; // Null descriptor
gdt[1] = (gdt_entry_t){0, 0, 0, GDT_KERNEL_CODE, GDT_GRANULARITY_FLAT, 0}; // Kernel code segment
gdt[2] = (gdt_entry_t){0, 0, 0, GDT_KERNEL_DATA, GDT_GRANULARITY_FLAT, 0}; // Kernel data segment
gdt[3] = (gdt_entry_t){0, 0, 0, GDT_USER_CODE, GDT_GRANULARITY_LONG_MODE, 0}; // User code segment
gdt[4] = (gdt_entry_t){0, 0, 0, GDT_USER_DATA, 0x00, 0}; // User data segment
gdt_ptr.limit = (uint16_t)(sizeof(gdt) - 1);
gdt_ptr.base = (uint64_t)&gdt;
gdt_flush(gdt_ptr);
}
void gdt_flush(gdt_ptr_t gdt_ptr)
{
__asm__ volatile(
"mov %0, %%rdi\n"
"lgdt (%%rdi)\n"
"push $0x8\n"
"lea 1f(%%rip), %%rax\n"
"push %%rax\n"
"lretq\n"
"1:\n"
"mov $0x10, %%ax\n"
"mov %%ax, %%es\n"
"mov %%ax, %%ss\n"
"mov %%ax, %%gs\n"
"mov %%ax, %%ds\n"
"mov %%ax, %%fs\n"
:
: "r"(&gdt_ptr)
: "memory");
}

52
kernel/src/arch/gdt.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef GDT_H
#define GDT_H
#include <stdint.h>
// GDT Access Flags
#define GDT_ACCESS_PRESENT 0x80 // Segment is present
#define GDT_ACCESS_RING0 0x00 // Privilege Level 0 (Kernel)
#define GDT_ACCESS_RING3 0x60 // Privilege Level 3 (User)
#define GDT_ACCESS_SYSTEM 0x00 // System segment (e.g., TSS)
#define GDT_ACCESS_CODE 0x18 // Code segment (Executable)
#define GDT_ACCESS_DATA 0x10 // Data segment (Readable/Writable)
#define GDT_ACCESS_DIRECTION 0x04 // Direction bit (0 = Grows up, 1 = Grows down)
#define GDT_ACCESS_EXECUTABLE 0x08 // Executable segment
#define GDT_ACCESS_RW 0x02 // Readable for code, Writable for data
#define GDT_ACCESS_ACCESSED 0x01 // CPU sets this when accessed
// Common Access Flags
#define GDT_KERNEL_CODE (GDT_ACCESS_PRESENT | GDT_ACCESS_RING0 | GDT_ACCESS_CODE | GDT_ACCESS_EXECUTABLE | GDT_ACCESS_RW)
#define GDT_KERNEL_DATA (GDT_ACCESS_PRESENT | GDT_ACCESS_RING0 | GDT_ACCESS_DATA | GDT_ACCESS_RW)
#define GDT_USER_CODE (GDT_ACCESS_PRESENT | GDT_ACCESS_RING3 | GDT_ACCESS_CODE | GDT_ACCESS_EXECUTABLE | GDT_ACCESS_RW)
#define GDT_USER_DATA (GDT_ACCESS_PRESENT | GDT_ACCESS_RING3 | GDT_ACCESS_DATA | GDT_ACCESS_RW)
#define GDT_TSS 0xE9
// Granularity Flags
#define GDT_GRANULARITY_4K 0x80
#define GDT_GRANULARITY_32B 0x40
#define GDT_GRANULARITY_LONG_MODE 0x20
#define GDT_GRANULARITY_FLAT (GDT_GRANULARITY_4K | GDT_GRANULARITY_LONG_MODE)
typedef struct gdt_entry
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed)) gdt_entry_t;
typedef struct gdt_ptr
{
uint16_t limit;
uint64_t base;
} __attribute__((packed)) gdt_ptr_t;
extern gdt_ptr_t gdt_ptr;
void gdt_init();
void gdt_flush(gdt_ptr_t gdt_ptr);
#endif // GDT_H

View file

@ -3,6 +3,9 @@
#include <arch/cpu.h>
#include <arch/io.h>
#include <dev/serial.h>
#include <util/kprintf.h>
#include <util/log.h>
#include <arch/gdt.h>
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
__attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
@ -18,10 +21,11 @@ void emk_entry(void)
if (!LIMINE_BASE_REVISION_SUPPORTED)
{
serial_write(COM1, (uint8_t *)"ERROR: Limine base revision is not supported\n", 45);
early("ERROR: Limine base revision is not supported\n");
hcf();
}
serial_write(COM1, (uint8_t *)"Hello, World!\n", 14);
gdt_init();
early("Initialized GDT");
hlt();
}

28
kernel/src/util/kprintf.c Normal file
View file

@ -0,0 +1,28 @@
#include <dev/serial.h>
#include <util/kprintf.h>
#define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_SMALL_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 0
#define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 1
#define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0
#define NANOPRINTF_IMPLEMENTATION
#include <nanoprintf.h>
int kprintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
char buffer[1024];
int length = npf_vsnprintf(buffer, sizeof(buffer), fmt, args);
if (length >= 0 && length < (int)sizeof(buffer))
{
serial_write(COM1, (uint8_t *)buffer, length);
}
va_end(args);
return length;
}

View file

@ -0,0 +1,7 @@
#ifndef KPRINTF_H
#define KPRINTF_H
/* Minimal kprintf using nanoprintf, see external/nanoprintf.h */
int kprintf(const char *fmt, ...);
#endif // KPRINTF_H

8
kernel/src/util/log.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef LOG_H
#define LOG_H
#include <util/kprintf.h>
#define early(fmt, ...) kprintf("early: " fmt "\n", ##__VA_ARGS__)
#endif // LOG_H