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
+32
View File
@@ -0,0 +1,32 @@
Error handling
==============
Functions that can fail must have a way of telling the caller that something
went wrong and preferably what went wrong. The simplest and cleanest way of
indicating an error is a return code. Error codes are defined in the <errno.h>
header alongside some helpfull macros.
Error codes have identifiers like these: ENOMEM, ENOENT, EALIGN, ...
They are defined as positive values, however all functions should return a
negative integer on error, so it would look something like 'return -EFAULT;'.
Also theres SUCCESS which is just 0. You can use it, but don't need to.
If you are returning a pointer/address, the highest address is almost certainly
unused, so returning '(void*)-EINVAL', should work just fine. This is quite an
eyesore, so there are three macros for working with these "errno-in-pointer"s.
IS_ERR(ptr) just returns 1 if the pointer is an errno. Otherwise 0.
ERR_PTR(err) does that void* cast mentioned above so it would be ERR_PTR(-EINVAL).
PTR_ERR(ptr) is the inverse of ERR_PTR(), as it converts a errno-in-pointer to
an errno value. PTR_ERR(ERR_PTR(-EIO)) == -EIO
Here are some usage examples:
int pag_init(void) {
if (...) return -ENOMEM; // Not enough memory
void* paddr = pmm_alloc();
if (IS_ERR(paddr)) return PTR_ERR(paddr); // Pass the error down
return SUCCESS;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef _ERRNO_H
#define _ERRNO_H
#include <kernel.h>
#define ERRNO_MAX 4095
#define IS_ERR(_ptr) ((uintptr_t)(_ptr) >= (uintptr_t)(-ERRNO_MAX))
#define ERR_PTR(_err) ((void*)(_err))
#define PTR_ERR(_ptr) ((int)(intptr_t)(_ptr))
// TODO: Add correct errno.h numbers
enum {
SUCCESS = 0,
ENOMEM, // Cannot allocate memory
EPERM, // Operation not permitted
ENOENT, // No entry (no such file or directory)
EIO, // Input/Output error
ENXIO, // No such device or address
EAGAIN, // Resource temporarly busy
EACCES, // Permission denied
EFAULT, // Bad address
ENODEV, // No such device
EINVAL, // Invalid argument
EDOM, // Numerical argument out of domain
ERANGE, // Numerical result out of range
ENOSYS, // Function not implemented
ENOTSUP, // Not supported
EILLSEQ, // Illegal byte sequence
EOVERFLOW, //
EALIGN, // Not aligned
};
#endif
+1 -1
View File
@@ -32,6 +32,6 @@ struct idt_pointer {
} __packed; } __packed;
int idt_init(void); int idt_init(void);
void idt_set_gate(uint8_t i, void* handler, uint8_t flags); void idt_set_gate(uint8_t i, void* handler, uint8_t flags, uint8_t ist);
#endif #endif
+5 -5
View File
@@ -41,11 +41,11 @@ static inline bool pag_is_user_addr(void* vaddr) { return (uintptr_t)vaddr < 0x0
// NOTE: All uint64_t* are VIRTUAL addresses // NOTE: All uint64_t* are VIRTUAL addresses
int pag_init(void); int pag_init(void);
uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr); uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr);
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);
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);
void pag_unmap(uint64_t* pml4, void* vaddr); int pag_unmap(uint64_t* pml4, void* vaddr);
void pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count); int pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count);
void pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags); int pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags);
void* pag_get_phys(uint64_t* pml4, void* vaddr); void* pag_get_phys(uint64_t* pml4, void* vaddr);
void pag_set_pml4(uint64_t* pml4); void pag_set_pml4(uint64_t* pml4);
uint64_t* pag_get_pml4(void); uint64_t* pag_get_pml4(void);
+1 -1
View File
@@ -5,6 +5,6 @@
int pmm_init(void); int pmm_init(void);
void* pmm_alloc(void); void* pmm_alloc(void);
void pmm_free(void*); int pmm_free(void*);
#endif #endif
+1
View File
@@ -18,6 +18,7 @@ int serial_rcvd(int dev);
char serial_recv(int dev); char serial_recv(int dev);
void serial_write(int dev, char* buf, size_t len); void serial_write(int dev, char* buf, size_t len);
void serial_puts(int dev, char* s); void serial_puts(int dev, char* s);
void serial_cls(int dev);
int debugf(char* fmt, ...); int debugf(char* fmt, ...);
int vdebugf(char* fmt, va_list args); int vdebugf(char* fmt, va_list args);
+1 -1
View File
@@ -18,7 +18,7 @@ $(OUT): $(OBJS_C) $(OBJS_S)
$(BIN)/%.c.o: $(SRC)/%.c $(SSP) $(BIN)/%.c.o: $(SRC)/%.c $(SSP)
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(CC) $(CCFLAGS) -DSTACK_CHK_GUARD=$(shell cat $(SSP)) -I$(INC) -c -o $@ $< $(CC) $(CCFLAGS) -DSTACK_CHK_GUARD="$$(cat $(SSP))" -I$(INC) -c -o $@ $<
$(BIN)/%.s.o: $(SRC)/%.s $(BIN)/%.s.o: $(SRC)/%.s
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
+8 -10
View File
@@ -1,14 +1,12 @@
#include <bootloader.h> #include <bootloader.h>
#include <kernel.h> #include <kernel.h>
#include <limine.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); 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 = static struct limine_paging_mode_request lim_paging_req =
{ .id = LIMINE_PAGING_MODE_REQUEST_ID, .revision = 4, { .id = LIMINE_PAGING_MODE_REQUEST_ID, .revision = 4,
.mode = LIMINE_PAGING_MODE_X86_64_4LVL, }; .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 = static struct limine_executable_file_request lim_exe_req =
{ .id = LIMINE_EXECUTABLE_FILE_REQUEST_ID, .revision = 4 }; { .id = LIMINE_EXECUTABLE_FILE_REQUEST_ID, .revision = 4 };
// Bootloader data struct
struct bootloader bootloader = { 0 };
int boot_init(void) { int boot_init(void) {
if (LIMINE_BASE_REVISION_SUPPORTED(lim_base_revision) == false) panic("Unsupported Limine base revision."); 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_framebuffer_response* lim_fbuf_res = lim_fbuf_req.response;
struct limine_executable_file_response* lim_exe_res = lim_exe_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) { if (lim_paging_res->mode != LIMINE_PAGING_MODE_X86_64_4LVL) panic("Expected 4 level paging.");
debugf("[boot] Expected 4 level paging.\n");
return 1;
}
bootloader.hhdm_offset = lim_hhdm_res->offset; bootloader.hhdm_offset = lim_hhdm_res->offset;
bootloader.kernel_phys_base = lim_kaddr_res->physical_base; bootloader.kernel_phys_base = lim_kaddr_res->physical_base;
bootloader.kernel_virt_base = lim_kaddr_res->virtual_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_entries = lim_fbuf_res->framebuffers;
bootloader.fb_entry_count = lim_fbuf_res->framebuffer_count; 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 <kernel.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <gdt.h> #include <gdt.h>
static struct gdt_entries gdt; static struct gdt_entries gdt;
@@ -105,8 +104,6 @@ int gdt_init(void) {
memset(&tss, 0, sizeof(tss)); memset(&tss, 0, sizeof(tss));
tss_load(&tss); tss_load(&tss);
debugf("[gdt] GDT loaded.\n"); return SUCCESS;
return 0;
} }
+10 -6
View File
@@ -1,5 +1,7 @@
#include <kernel.h> #include <kernel.h>
#include <string.h> #include <string.h>
#include <system.h>
#include <errno.h>
#include <gdt.h> #include <gdt.h>
#include <idt.h> #include <idt.h>
@@ -7,25 +9,27 @@ __align(16) // performace
static struct idt_entry idt[IDT_ENTRIES]; static struct idt_entry idt[IDT_ENTRIES];
static struct idt_pointer idtp; 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; size_t addr = (size_t)handler;
idt[i].offset_low = (uint16_t)addr; idt[i].offset_low = (uint16_t)addr;
idt[i].selector = GDT_KERNEL_CODE; idt[i].selector = GDT_KERNEL_CODE;
idt[i].ist = 0; idt[i].ist = ist & 7;
idt[i].__reserved = 0;
idt[i].attrib = attrib; idt[i].attrib = attrib;
idt[i].offset_mid = (uint16_t)(addr >> 16); idt[i].offset_mid = (uint16_t)(addr >> 16);
idt[i].offset_high = (uint32_t)(addr >> 32); idt[i].offset_high = (uint32_t)(addr >> 32);
idt[i].__reserved = 0;
} }
int idt_init(void) { int idt_init(void) {
memset(idt, 0, sizeof(idt));
idtp.size = sizeof(idt) - 1; idtp.size = sizeof(idt) - 1;
idtp.offset = (size_t)&idt; idtp.offset = (uintptr_t)&idt;
// Load IDT instruction // Load IDT instruction
cli();
__asm__ volatile ("lidt %0" : : "m"(idtp)); __asm__ volatile ("lidt %0" : : "m"(idtp));
debugf("[idt] IDT initalized.\n"); return SUCCESS;
return 0;
} }
+9 -9
View File
@@ -2,6 +2,7 @@
#include <serial.h> #include <serial.h>
#include <string.h> #include <string.h>
#include <system.h> #include <system.h>
#include <errno.h>
#include <idt.h> #include <idt.h>
#include <isr.h> #include <isr.h>
@@ -64,24 +65,23 @@ void pic_remap(void) {
int isr_init(void) { int isr_init(void) {
memset(irq_handlers, 0, sizeof(irq_handlers)); memset(irq_handlers, 0, sizeof(irq_handlers));
if (idt_init() != 0) { idt_init();
debugf("[isr] Could not load IDT.");
return 1;
}
for (int i = 0; i < 48; i++) { for (int i = 0; i < 48; i++) {
// First 32 IRSs are exceptions (traps) and the next 16 are hardware interrupts // 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(); pic_remap();
// TODO: apic_init(); // TODO: apic_init();
sti(); sti();
debugf("[isr] ISR initialized.\n"); return SUCCESS;
return 0;
} }
void isr_register(uint8_t i, isr_handler_ptr handler) { void isr_register(uint8_t i, isr_handler_ptr handler) {
+6 -7
View File
@@ -1,5 +1,4 @@
#include <bootloader.h> #include <bootloader.h>
#include <kmalloc.h>
#include <paging.h> #include <paging.h>
#include <serial.h> #include <serial.h>
#include <splash.h> #include <splash.h>
@@ -13,10 +12,10 @@
__noreturn __noreturn
void _start(void) { void _start(void) {
// Serial console for debugging // 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 // 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. // The most important function in the world.
splash(); splash();
@@ -28,12 +27,12 @@ void _start(void) {
debugf("[kernel] CPUID_GETVENDORID: %s\n", s); debugf("[kernel] CPUID_GETVENDORID: %s\n", s);
// System init // System init
if (gdt_init() != 0) panic("Failed to initalize GDT."); if (gdt_init() < 0) panic("Failed to initalize GDT.");
if (isr_init() != 0) panic("Failed to initalize ISRs."); if (isr_init() < 0) panic("Failed to initalize ISRs.");
// Memory management // Memory management
if (pmm_init() != 0) panic("Failed to initalize Physical Memory Manager."); if (pmm_init() < 0) panic("Failed to initalize Physical Memory Manager.");
if (pag_init() != 0) panic("Failed to initalize Paging."); if (pag_init() < 0) panic("Failed to initalize Paging.");
// Patiently wait for things to do :) // Patiently wait for things to do :)
while (1); while (1);
+54 -65
View File
@@ -3,6 +3,7 @@
#include <limine.h> #include <limine.h>
#include <string.h> #include <string.h>
#include <serial.h> #include <serial.h>
#include <errno.h>
#include <pmm.h> #include <pmm.h>
#include <paging.h> #include <paging.h>
@@ -12,19 +13,17 @@ uint64_t* pag_kernel_pml4 = NULL;
int pag_init(void) { int pag_init(void) {
pag_kernel_pml4 = TO_VIRT(pmm_alloc()); pag_kernel_pml4 = TO_VIRT(pmm_alloc());
if (pag_kernel_pml4 == NULL) { if (IS_ERR(pag_kernel_pml4)) return PTR_ERR(pag_kernel_pml4);
debugf("[pag] Failed to allocate kernel PML4. Not enough memory.\n");
return 1;
}
memset(pag_kernel_pml4, 0, PAGE_SIZE); memset(pag_kernel_pml4, 0, PAGE_SIZE);
pag_map_region( int ret = pag_map_region(
pag_kernel_pml4, pag_kernel_pml4,
(void*)bootloader.kernel_virt_base, (void*)bootloader.kernel_virt_base,
(void*)bootloader.kernel_phys_base, (void*)bootloader.kernel_phys_base,
dceil(bootloader.executable->size, PAGE_SIZE), dceil(bootloader.executable->size, PAGE_SIZE),
PTE_FLAG_WRITE | PTE_FLAG_PRESENT PTE_FLAG_WRITE | PTE_FLAG_PRESENT
); );
if (ret != SUCCESS) return ret;
for (size_t i = 0; i < bootloader.mm_entry_count; i++) { for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
struct limine_memmap_entry* entry = bootloader.mm_entries[i]; struct limine_memmap_entry* entry = bootloader.mm_entries[i];
@@ -48,115 +47,106 @@ int pag_init(void) {
continue; continue;
} }
pag_map_region( ret = pag_map_region(
pag_kernel_pml4, pag_kernel_pml4,
(void*)(entry->base + bootloader.hhdm_offset), (void*)entry->base, (void*)(entry->base + bootloader.hhdm_offset), (void*)entry->base,
dceil(entry->length, PAGE_SIZE), dceil(entry->length, PAGE_SIZE),
flags | PTE_FLAG_PRESENT 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); pag_set_pml4(pag_kernel_pml4);
debugf("[pag] Paging initialized.\n");
return 0; return 0;
} }
uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr) { uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr) {
uintptr_t v = (uintptr_t)vaddr; uintptr_t v = (uintptr_t)vaddr;
if (v % PAGE_SIZE != 0) { if (v % PAGE_SIZE != 0) return ERR_PTR(-EALIGN);
debugf("[pag] Could not get PTE from non-aligned virtual address %p.\n", vaddr);
return NULL;
}
uint64_t* pdpt = pag_get_next_tab(pml4, PML4_IDX(v)); uint64_t* pdpt = pag_get_next_tab(pml4, PML4_IDX(v));
if (pdpt == NULL) { if (IS_ERR(pdpt)) return pdpt;
debugf("[pag] Could not get PTE. %p was not found in PML4.\n");
return NULL;
}
uint64_t* pd = pag_get_next_tab(pdpt, PDPT_IDX(v)); uint64_t* pd = pag_get_next_tab(pdpt, PDPT_IDX(v));
if (pd == NULL) { if (IS_ERR(pd)) return pd;
debugf("[pag] Could not get PTE. %p was not found in PDPT.\n");
return NULL;
}
uint64_t* pt = pag_get_next_tab(pd, PD_IDX(v)); uint64_t* pt = pag_get_next_tab(pd, PD_IDX(v));
if (pt == NULL) { if (IS_ERR(pt)) return pt;
debugf("[pag] Could not get PTE. %p was not found in PD.\n");
return NULL;
}
return &pt[PT_IDX(v)]; return &pt[PT_IDX(v)];
} }
uint64_t* pag_new_pte(uint64_t* pml4, void* vaddr) { uint64_t* pag_new_pte(uint64_t* pml4, void* vaddr) {
uintptr_t v = (uintptr_t)vaddr; uintptr_t v = (uintptr_t)vaddr;
if (v % PAGE_SIZE != 0) { if (v % PAGE_SIZE != 0) return ERR_PTR(-EALIGN);
debugf("[pag] Could not create PTE for non-aligned virtual address %p.\n", vaddr);
return NULL;
}
uint64_t* pdpt = pag_new_next_tab(pml4, PML4_IDX(v)); uint64_t* pdpt = pag_new_next_tab(pml4, PML4_IDX(v));
if (pdpt == NULL) { if (IS_ERR(pdpt)) return pdpt;
debugf("[pag] Failed to create PDPT. Not enough memory.\n");
return NULL;
}
uint64_t* pd = pag_new_next_tab(pdpt, PDPT_IDX(v)); uint64_t* pd = pag_new_next_tab(pdpt, PDPT_IDX(v));
if (pd == NULL) { if (IS_ERR(pd)) return pd;
debugf("[pag] Failed to create PD. Not enough memory.\n");
if (pdpt != NULL) pmm_free(pdpt);
return NULL;
}
uint64_t* pt = pag_new_next_tab(pd, PD_IDX(v)); uint64_t* pt = pag_new_next_tab(pd, PD_IDX(v));
if (pt == NULL) { if (IS_ERR(pt)) return pt;
debugf("[pag] Failed to create PT. Not enough memory.\n");
if (pd != NULL) pmm_free(pd);
if (pdpt != NULL) pmm_free(pdpt);
return NULL;
}
return &pt[PT_IDX(v)]; 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; uintptr_t p = (uintptr_t)paddr;
if (p % PAGE_SIZE != 0) { if (p % PAGE_SIZE != 0) return -EALIGN;
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); uint64_t* pte = pag_new_pte(pml4, vaddr);
*page = PTE_ADDR(p) | flags | PTE_FLAG_PRESENT; if (IS_ERR(pte)) return PTR_ERR(pte);
*pte = PTE_ADDR(p) | flags | PTE_FLAG_PRESENT;
pag_invalidate(vaddr); 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++) { 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 // 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. // 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); uint64_t* pte = pag_get_pte(pml4, vaddr);
if (IS_ERR(pte)) return PTR_ERR(pte);
*pte = 0; *pte = 0;
pag_invalidate(vaddr); 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++) { 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); uint64_t* pte = pag_get_pte(pml4, vaddr);
if (IS_ERR(pte)) return PTR_ERR(pte);
*pte = PTE_ADDR(*pte) | flags | PTE_FLAG_PRESENT; *pte = PTE_ADDR(*pte) | flags | PTE_FLAG_PRESENT;
return SUCCESS;
} }
void* pag_get_phys(uint64_t* pml4, void* vaddr) { void* pag_get_phys(uint64_t* pml4, void* vaddr) {
uint64_t* pte = pag_get_pte(pml4, vaddr); uint64_t* pte = pag_get_pte(pml4, vaddr);
if (IS_ERR(pte)) return pte;
return (void*)PTE_ADDR(*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) { uint64_t* pag_get_next_tab(uint64_t* tab, offset_t index) {
if (index >= 512 || tab == NULL) return NULL; if (tab == NULL || IS_ERR(tab)) return ERR_PTR(-EFAULT);
else if (tab[index] & PTE_FLAG_PRESENT) return TO_VIRT(tab[index] & PTE_ADDR_MASK); if (index >= 512) return ERR_PTR(-EINVAL);
else return NULL;
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) { 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); 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(); void* paddr = pmm_alloc();
if (!paddr) { if (IS_ERR(paddr)) return paddr;
debugf("[pag] Failed to allocate page for new table.\n");
return NULL;
}
vaddr = TO_VIRT(paddr); vaddr = TO_VIRT(paddr);
memset(vaddr, 0, PAGE_SIZE); memset(vaddr, 0, PAGE_SIZE);
+13 -21
View File
@@ -3,6 +3,7 @@
#include <limine.h> #include <limine.h>
#include <paging.h> #include <paging.h>
#include <serial.h> #include <serial.h>
#include <errno.h>
#include <pmm.h> #include <pmm.h>
@@ -10,7 +11,6 @@ uint64_t* pmm_head = NULL;
size_t pmm_total_mem = 0; size_t pmm_total_mem = 0;
int pmm_init(void) { int pmm_init(void) {
debugf("[pmm] Physical memory map:\n"); // We're gonna use the loop to also print the memmap 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++) { for (size_t i = 0; i < bootloader.mm_entry_count; i++) {
struct limine_memmap_entry* entry = bootloader.mm_entries[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); 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() { void* pmm_alloc() {
if (pmm_head == NULL) { if (pmm_head == NULL) return ERR_PTR(-ENOMEM);
debugf("[pmm] Could not allocate page, not enough memory.\n");
return NULL;
}
uint64_t* addr = pmm_head; uint64_t* addr = pmm_head;
if ((uintptr_t)addr % PAGE_SIZE != 0) { if ((uintptr_t)addr % PAGE_SIZE != 0) panic("pmm_head corrupted.");
debugf("[pmm] Tried to allocate non-aligned page.\n");
// It may fix itself if a page gets freed
// panic("pmm_head corrupted.");
return NULL;
}
pmm_head = (uint64_t*)(*addr); pmm_head = (uint64_t*)(*addr);
return TO_PHYS(addr); return TO_PHYS(addr);
} }
void pmm_free(void* page) { int pmm_free(void* page) {
if (page == NULL) { if (page == NULL || IS_ERR(page)) return -EFAULT;
debugf("[pmm] Tried to free NULL.\n"); if ((uintptr_t)page % PAGE_SIZE != 0) return -EALIGN;
return;
}
if ((uintptr_t)page % PAGE_SIZE != 0) {
debugf("[pmm] Tried to free non-aligned page.\n");
return;
}
uint64_t* addr = TO_VIRT(page); uint64_t* addr = TO_VIRT(page);
*addr = (uint64_t)pmm_head; *addr = (uint64_t)pmm_head;
pmm_head = addr; pmm_head = addr;
return SUCCESS;
} }
+9 -2
View File
@@ -1,3 +1,4 @@
#include "errno.h"
#include <vsnprintf.h> #include <vsnprintf.h>
#include <kernel.h> #include <kernel.h>
#include <system.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 + 3, 0x03); // 8 bits, no parity, one stop bit
outb(dev + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold outb(dev + 2, 0xC7); // Enable FIFO, clear them, with 14 byte threshold
outb(dev + 4, 0x0B); // IRQs enabled, RTS/DSR set outb(dev + 4, 0x0B); // IRQs enabled, RTS/DSR set
outb(dev + 4, 0x1E); // Set in loopback mode, test the serial chip 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) outb(dev + 0, 0xAE); // Test serial chip (send byte 0xAE and check if it returns)
if (inb(dev + 0) != 0xAE) return -ENODEV;
if (inb(dev + 0) != 0xAE) return 1;
outb(dev + 4, 0x0F); // non-loopback, IRQs enabled, OUT#1 and OUT#2 bits enabled 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; return 0;
} }
@@ -54,6 +57,10 @@ void serial_puts(int dev, char* s) {
serial_write(dev, s, len); serial_write(dev, s, len);
} }
void serial_cls(int dev) {
serial_write(dev, "\x1b[H\x1b[J", 6);
}
int debugf(char* fmt, ...) { int debugf(char* fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);