Added <errno.h> and made kernel use it

This commit is contained in:
2026-03-25 18:17:42 +01:00
parent 7a57999d05
commit 2f05396651
15 changed files with 189 additions and 135 deletions
+8 -10
View File
@@ -1,14 +1,12 @@
#include <bootloader.h>
#include <kernel.h>
#include <limine.h>
#include <errno.h>
/*
* This defines our expected Limine version
*/
// This defines our expected Limine version
static volatile uint64_t lim_base_revision[] = LIMINE_BASE_REVISION(4);
struct bootloader bootloader = { 0 };
// Limine requests
static struct limine_paging_mode_request lim_paging_req =
{ .id = LIMINE_PAGING_MODE_REQUEST_ID, .revision = 4,
.mode = LIMINE_PAGING_MODE_X86_64_4LVL, };
@@ -28,6 +26,9 @@ static struct limine_framebuffer_request lim_fbuf_req =
static struct limine_executable_file_request lim_exe_req =
{ .id = LIMINE_EXECUTABLE_FILE_REQUEST_ID, .revision = 4 };
// Bootloader data struct
struct bootloader bootloader = { 0 };
int boot_init(void) {
if (LIMINE_BASE_REVISION_SUPPORTED(lim_base_revision) == false) panic("Unsupported Limine base revision.");
@@ -38,10 +39,7 @@ int boot_init(void) {
struct limine_framebuffer_response* lim_fbuf_res = lim_fbuf_req.response;
struct limine_executable_file_response* lim_exe_res = lim_exe_req.response;
if (lim_paging_res->mode != LIMINE_PAGING_MODE_X86_64_4LVL) {
debugf("[boot] Expected 4 level paging.\n");
return 1;
}
if (lim_paging_res->mode != LIMINE_PAGING_MODE_X86_64_4LVL) panic("Expected 4 level paging.");
bootloader.hhdm_offset = lim_hhdm_res->offset;
bootloader.kernel_phys_base = lim_kaddr_res->physical_base;
bootloader.kernel_virt_base = lim_kaddr_res->virtual_base;
@@ -58,6 +56,6 @@ int boot_init(void) {
bootloader.fb_entries = lim_fbuf_res->framebuffers;
bootloader.fb_entry_count = lim_fbuf_res->framebuffer_count;
return 0;
return SUCCESS;
}
+2 -5
View File
@@ -1,7 +1,6 @@
#include "paging.h"
#include "pmm.h"
#include <kernel.h>
#include <string.h>
#include <errno.h>
#include <gdt.h>
static struct gdt_entries gdt;
@@ -105,8 +104,6 @@ int gdt_init(void) {
memset(&tss, 0, sizeof(tss));
tss_load(&tss);
debugf("[gdt] GDT loaded.\n");
return 0;
return SUCCESS;
}
+10 -6
View File
@@ -1,5 +1,7 @@
#include <kernel.h>
#include <string.h>
#include <system.h>
#include <errno.h>
#include <gdt.h>
#include <idt.h>
@@ -7,25 +9,27 @@ __align(16) // performace
static struct idt_entry idt[IDT_ENTRIES];
static struct idt_pointer idtp;
void idt_set_gate(uint8_t i, void* handler, uint8_t attrib) {
void idt_set_gate(uint8_t i, void* handler, uint8_t attrib, uint8_t ist) {
size_t addr = (size_t)handler;
idt[i].offset_low = (uint16_t)addr;
idt[i].selector = GDT_KERNEL_CODE;
idt[i].ist = 0;
idt[i].__reserved = 0;
idt[i].ist = ist & 7;
idt[i].attrib = attrib;
idt[i].offset_mid = (uint16_t)(addr >> 16);
idt[i].offset_high = (uint32_t)(addr >> 32);
idt[i].__reserved = 0;
}
int idt_init(void) {
memset(idt, 0, sizeof(idt));
idtp.size = sizeof(idt) - 1;
idtp.offset = (size_t)&idt;
idtp.offset = (uintptr_t)&idt;
// Load IDT instruction
cli();
__asm__ volatile ("lidt %0" : : "m"(idtp));
debugf("[idt] IDT initalized.\n");
return 0;
return SUCCESS;
}
+9 -9
View File
@@ -2,6 +2,7 @@
#include <serial.h>
#include <string.h>
#include <system.h>
#include <errno.h>
#include <idt.h>
#include <isr.h>
@@ -64,24 +65,23 @@ void pic_remap(void) {
int isr_init(void) {
memset(irq_handlers, 0, sizeof(irq_handlers));
if (idt_init() != 0) {
debugf("[isr] Could not load IDT.");
return 1;
}
idt_init();
for (int i = 0; i < 48; i++) {
// First 32 IRSs are exceptions (traps) and the next 16 are hardware interrupts
idt_set_gate(i, isr_redirect_table[i], IDT_FLAG_INT);
idt_set_gate(i, isr_redirect_table[i], i < 32 ? IDT_FLAG_TRAP : IDT_FLAG_INT, 0);
}
idt_set_gate(0x03, isr_redirect_table[3], IDT_FLAG_USER); // Allow breakpoints
idt_set_gate(0x80, isr128, IDT_FLAG_USER); // Syscall
idt_set_gate(0x02, isr_redirect_table[2], IDT_FLAG_TRAP, 2); // Use IST2 for NMIs
idt_set_gate(0x03, isr_redirect_table[3], IDT_FLAG_USER, 0); // Allow breakpoints
idt_set_gate(0x08, isr_redirect_table[8], IDT_FLAG_TRAP, 1); // Use IST1 for Double Faults
idt_set_gate(0x80, isr128, IDT_FLAG_USER, 0); // Syscall
pic_remap();
// TODO: apic_init();
sti();
debugf("[isr] ISR initialized.\n");
return 0;
return SUCCESS;
}
void isr_register(uint8_t i, isr_handler_ptr handler) {
+6 -7
View File
@@ -1,5 +1,4 @@
#include <bootloader.h>
#include <kmalloc.h>
#include <paging.h>
#include <serial.h>
#include <splash.h>
@@ -13,10 +12,10 @@
__noreturn
void _start(void) {
// Serial console for debugging
if (serial_init(COM1) != 0) panic("Failed to initialize Serial driver.");
if (serial_init(COM1) < 0) panic("Failed to initialize Serial driver.");
// Load structures from bootloader
if (boot_init() != 0) panic("Failed to parse bootloader structures.");
if (boot_init() < 0) panic("Failed to parse bootloader structures.");
// The most important function in the world.
splash();
@@ -28,12 +27,12 @@ void _start(void) {
debugf("[kernel] CPUID_GETVENDORID: %s\n", s);
// System init
if (gdt_init() != 0) panic("Failed to initalize GDT.");
if (isr_init() != 0) panic("Failed to initalize ISRs.");
if (gdt_init() < 0) panic("Failed to initalize GDT.");
if (isr_init() < 0) panic("Failed to initalize ISRs.");
// Memory management
if (pmm_init() != 0) panic("Failed to initalize Physical Memory Manager.");
if (pag_init() != 0) panic("Failed to initalize Paging.");
if (pmm_init() < 0) panic("Failed to initalize Physical Memory Manager.");
if (pag_init() < 0) panic("Failed to initalize Paging.");
// Patiently wait for things to do :)
while (1);
+55 -66
View File
@@ -3,6 +3,7 @@
#include <limine.h>
#include <string.h>
#include <serial.h>
#include <errno.h>
#include <pmm.h>
#include <paging.h>
@@ -12,19 +13,17 @@ uint64_t* pag_kernel_pml4 = NULL;
int pag_init(void) {
pag_kernel_pml4 = TO_VIRT(pmm_alloc());
if (pag_kernel_pml4 == NULL) {
debugf("[pag] Failed to allocate kernel PML4. Not enough memory.\n");
return 1;
}
if (IS_ERR(pag_kernel_pml4)) return PTR_ERR(pag_kernel_pml4);
memset(pag_kernel_pml4, 0, PAGE_SIZE);
pag_map_region(
int ret = pag_map_region(
pag_kernel_pml4,
(void*)bootloader.kernel_virt_base,
(void*)bootloader.kernel_phys_base,
dceil(bootloader.executable->size, PAGE_SIZE),
PTE_FLAG_WRITE | PTE_FLAG_PRESENT
);
if (ret != SUCCESS) return ret;
for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
struct limine_memmap_entry* entry = bootloader.mm_entries[i];
@@ -48,115 +47,106 @@ int pag_init(void) {
continue;
}
pag_map_region(
ret = pag_map_region(
pag_kernel_pml4,
(void*)(entry->base + bootloader.hhdm_offset), (void*)entry->base,
dceil(entry->length, PAGE_SIZE),
flags | PTE_FLAG_PRESENT
);
if (ret != SUCCESS) return ret;
}
debugf("[pag] Switching to kernel PML4 at %p.\n", pag_kernel_pml4);
pag_set_pml4(pag_kernel_pml4);
debugf("[pag] Paging initialized.\n");
return 0;
}
uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr) {
uintptr_t v = (uintptr_t)vaddr;
if (v % PAGE_SIZE != 0) {
debugf("[pag] Could not get PTE from non-aligned virtual address %p.\n", vaddr);
return NULL;
}
if (v % PAGE_SIZE != 0) return ERR_PTR(-EALIGN);
uint64_t* pdpt = pag_get_next_tab(pml4, PML4_IDX(v));
if (pdpt == NULL) {
debugf("[pag] Could not get PTE. %p was not found in PML4.\n");
return NULL;
}
if (IS_ERR(pdpt)) return pdpt;
uint64_t* pd = pag_get_next_tab(pdpt, PDPT_IDX(v));
if (pd == NULL) {
debugf("[pag] Could not get PTE. %p was not found in PDPT.\n");
return NULL;
}
if (IS_ERR(pd)) return pd;
uint64_t* pt = pag_get_next_tab(pd, PD_IDX(v));
if (pt == NULL) {
debugf("[pag] Could not get PTE. %p was not found in PD.\n");
return NULL;
}
if (IS_ERR(pt)) return pt;
return &pt[PT_IDX(v)];
}
uint64_t* pag_new_pte(uint64_t* pml4, void* vaddr) {
uintptr_t v = (uintptr_t)vaddr;
if (v % PAGE_SIZE != 0) {
debugf("[pag] Could not create PTE for non-aligned virtual address %p.\n", vaddr);
return NULL;
}
if (v % PAGE_SIZE != 0) return ERR_PTR(-EALIGN);
uint64_t* pdpt = pag_new_next_tab(pml4, PML4_IDX(v));
if (pdpt == NULL) {
debugf("[pag] Failed to create PDPT. Not enough memory.\n");
return NULL;
}
if (IS_ERR(pdpt)) return pdpt;
uint64_t* pd = pag_new_next_tab(pdpt, PDPT_IDX(v));
if (pd == NULL) {
debugf("[pag] Failed to create PD. Not enough memory.\n");
if (pdpt != NULL) pmm_free(pdpt);
return NULL;
}
if (IS_ERR(pd)) return pd;
uint64_t* pt = pag_new_next_tab(pd, PD_IDX(v));
if (pt == NULL) {
debugf("[pag] Failed to create PT. Not enough memory.\n");
if (pd != NULL) pmm_free(pd);
if (pdpt != NULL) pmm_free(pdpt);
return NULL;
}
if (IS_ERR(pt)) return pt;
return &pt[PT_IDX(v)];
}
void pag_map(uint64_t* pml4, void* vaddr, void* paddr, uint64_t flags) {
int pag_map(uint64_t* pml4, void* vaddr, void* paddr, uint64_t flags) {
uintptr_t p = (uintptr_t)paddr;
if (p % PAGE_SIZE != 0) {
debugf("[pag] Could not map %p to %p. Physical address is not aligned.\n", paddr, vaddr);
return;
}
uint64_t* page = pag_new_pte(pml4, vaddr);
*page = PTE_ADDR(p) | flags | PTE_FLAG_PRESENT;
if (p % PAGE_SIZE != 0) return -EALIGN;
uint64_t* pte = pag_new_pte(pml4, vaddr);
if (IS_ERR(pte)) return PTR_ERR(pte);
*pte = PTE_ADDR(p) | flags | PTE_FLAG_PRESENT;
pag_invalidate(vaddr);
return SUCCESS;
}
void pag_map_region(uint64_t* pml4, void* vaddr, void* paddr, size_t count, uint64_t flags) {
int pag_map_region(uint64_t* pml4, void* vaddr, void* paddr, size_t count, uint64_t flags) {
for (size_t i = 0; i < count; i++) {
pag_map(pml4, vaddr + i * PAGE_SIZE, paddr + i * PAGE_SIZE, flags);
int ret = pag_map(pml4, vaddr + i * PAGE_SIZE, paddr + i * PAGE_SIZE, flags);
if (ret != SUCCESS) return ret;
}
return SUCCESS;
}
// TODO: This is a pmm memory leak. If all pages in a PT are unmapped, remove
// that PT from it's PD. This applies to PDs & PDPTs too.
void pag_unmap(uint64_t* pml4, void* vaddr) {
int pag_unmap(uint64_t* pml4, void* vaddr) {
uint64_t* pte = pag_get_pte(pml4, vaddr);
if (IS_ERR(pte)) return PTR_ERR(pte);
*pte = 0;
pag_invalidate(vaddr);
return SUCCESS;
}
void pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count) {
int pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count) {
for (size_t i = 0; i < count; i++) {
pag_unmap(pml4, vaddr + i * PAGE_SIZE);
int ret = pag_unmap(pml4, vaddr + i * PAGE_SIZE);
if (ret != SUCCESS) return ret;
}
return SUCCESS;
}
void pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags) {
int pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags) {
uint64_t* pte = pag_get_pte(pml4, vaddr);
if (IS_ERR(pte)) return PTR_ERR(pte);
*pte = PTE_ADDR(*pte) | flags | PTE_FLAG_PRESENT;
return SUCCESS;
}
void* pag_get_phys(uint64_t* pml4, void* vaddr) {
uint64_t* pte = pag_get_pte(pml4, vaddr);
if (IS_ERR(pte)) return pte;
return (void*)PTE_ADDR(*pte);
}
@@ -171,21 +161,20 @@ uint64_t* pag_get_pml4(void) {
}
uint64_t* pag_get_next_tab(uint64_t* tab, offset_t index) {
if (index >= 512 || tab == NULL) return NULL;
else if (tab[index] & PTE_FLAG_PRESENT) return TO_VIRT(tab[index] & PTE_ADDR_MASK);
else return NULL;
if (tab == NULL || IS_ERR(tab)) return ERR_PTR(-EFAULT);
if (index >= 512) return ERR_PTR(-EINVAL);
if (tab[index] & PTE_FLAG_PRESENT) return TO_VIRT(PTE_ADDR(tab[index]));
else return ERR_PTR(-ENOENT);
}
uint64_t* pag_new_next_tab(uint64_t* tab, offset_t index) {
if (tab == NULL) return NULL;
uint64_t* vaddr = pag_get_next_tab(tab, index);
if (vaddr != NULL) return vaddr;
if (!IS_ERR(vaddr)) return vaddr;
if (PTR_ERR(vaddr) != -ENOENT) return vaddr;
void* paddr = pmm_alloc();
if (!paddr) {
debugf("[pag] Failed to allocate page for new table.\n");
return NULL;
}
if (IS_ERR(paddr)) return paddr;
vaddr = TO_VIRT(paddr);
memset(vaddr, 0, PAGE_SIZE);
+13 -21
View File
@@ -3,6 +3,7 @@
#include <limine.h>
#include <paging.h>
#include <serial.h>
#include <errno.h>
#include <pmm.h>
@@ -10,7 +11,6 @@ uint64_t* pmm_head = NULL;
size_t pmm_total_mem = 0;
int pmm_init(void) {
debugf("[pmm] Physical memory map:\n"); // We're gonna use the loop to also print the memmap
for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
struct limine_memmap_entry* entry = bootloader.mm_entries[i];
@@ -39,37 +39,29 @@ int pmm_init(void) {
}
debugf("[pmm] %d bytes of available memory.\n", pmm_total_mem);
if (pmm_total_mem == 0) return -ENOMEM;
return 0;
return SUCCESS;
}
void* pmm_alloc() {
if (pmm_head == NULL) {
debugf("[pmm] Could not allocate page, not enough memory.\n");
return NULL;
}
if (pmm_head == NULL) return ERR_PTR(-ENOMEM);
uint64_t* addr = pmm_head;
if ((uintptr_t)addr % PAGE_SIZE != 0) {
debugf("[pmm] Tried to allocate non-aligned page.\n");
// It may fix itself if a page gets freed
// panic("pmm_head corrupted.");
return NULL;
}
if ((uintptr_t)addr % PAGE_SIZE != 0) panic("pmm_head corrupted.");
pmm_head = (uint64_t*)(*addr);
return TO_PHYS(addr);
}
void pmm_free(void* page) {
if (page == NULL) {
debugf("[pmm] Tried to free NULL.\n");
return;
}
if ((uintptr_t)page % PAGE_SIZE != 0) {
debugf("[pmm] Tried to free non-aligned page.\n");
return;
}
int pmm_free(void* page) {
if (page == NULL || IS_ERR(page)) return -EFAULT;
if ((uintptr_t)page % PAGE_SIZE != 0) return -EALIGN;
uint64_t* addr = TO_VIRT(page);
*addr = (uint64_t)pmm_head;
pmm_head = addr;
return SUCCESS;
}
+10 -3
View File
@@ -1,3 +1,4 @@
#include "errno.h"
#include <vsnprintf.h>
#include <kernel.h>
#include <system.h>
@@ -11,13 +12,15 @@ int serial_init(int dev) {
outb(dev + 3, 0x03); // 8 bits, no parity, one stop bit
outb(dev + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold
outb(dev + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(dev + 4, 0x1E); // Set in loopback mode, test the serial chip
outb(dev + 0, 0xAE); // Test serial chip (send byte 0xAE and check if it returns)
if (inb(dev + 0) != 0xAE) return 1;
if (inb(dev + 0) != 0xAE) return -ENODEV;
outb(dev + 4, 0x0F); // non-loopback, IRQs enabled, OUT#1 and OUT#2 bits enabled
debugf("\x1b[H\x1b[JSerial display initiated!\n\n");
serial_cls(COM1);
serial_puts(COM1, "Serial display (COM1)\n\n");
return 0;
}
@@ -54,6 +57,10 @@ void serial_puts(int dev, char* s) {
serial_write(dev, s, len);
}
void serial_cls(int dev) {
serial_write(dev, "\x1b[H\x1b[J", 6);
}
int debugf(char* fmt, ...) {
va_list args;
va_start(args, fmt);