feat: Added nanoprintf, kprintf and GDT
This commit is contained in:
parent
aa5a1e8e1a
commit
248879c099
9 changed files with 1346 additions and 5 deletions
|
@ -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
39
kernel/src/arch/gdt.c
Normal 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
52
kernel/src/arch/gdt.h
Normal 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
|
|
@ -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
28
kernel/src/util/kprintf.c
Normal 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;
|
||||
}
|
7
kernel/src/util/kprintf.h
Normal file
7
kernel/src/util/kprintf.h
Normal 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
8
kernel/src/util/log.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue