forked from PoliEcho-holding-org/kern
Added <errno.h> and made kernel use it
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -32,6 +32,6 @@ struct idt_pointer {
|
||||
} __packed;
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
int pag_init(void);
|
||||
uint64_t* pag_get_pte(uint64_t* pml4, void* vaddr);
|
||||
void 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);
|
||||
void pag_unmap(uint64_t* pml4, void* vaddr);
|
||||
void pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count);
|
||||
void pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags);
|
||||
int pag_map(uint64_t* pml4, void* vaddr, void* paddr, uint64_t flags);
|
||||
int pag_map_region(uint64_t* pml4, void* vaddr, void* paddr, size_t count, uint64_t flags);
|
||||
int pag_unmap(uint64_t* pml4, void* vaddr);
|
||||
int pag_unmap_region(uint64_t* pml4, void* vaddr, size_t count);
|
||||
int pag_protect(uint64_t* pml4, void* vaddr, uint64_t flags);
|
||||
void* pag_get_phys(uint64_t* pml4, void* vaddr);
|
||||
void pag_set_pml4(uint64_t* pml4);
|
||||
uint64_t* pag_get_pml4(void);
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
|
||||
int pmm_init(void);
|
||||
void* pmm_alloc(void);
|
||||
void pmm_free(void*);
|
||||
int pmm_free(void*);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,7 @@ int serial_rcvd(int dev);
|
||||
char serial_recv(int dev);
|
||||
void serial_write(int dev, char* buf, size_t len);
|
||||
void serial_puts(int dev, char* s);
|
||||
void serial_cls(int dev);
|
||||
|
||||
int debugf(char* fmt, ...);
|
||||
int vdebugf(char* fmt, va_list args);
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ $(OUT): $(OBJS_C) $(OBJS_S)
|
||||
|
||||
$(BIN)/%.c.o: $(SRC)/%.c $(SSP)
|
||||
@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
|
||||
@mkdir -p $(dir $@)
|
||||
|
||||
+8
-10
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user