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;
|
} __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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||||
|
|||||||
+55
-66
@@ -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* pte = pag_new_pte(pml4, vaddr);
|
||||||
}
|
if (IS_ERR(pte)) return PTR_ERR(pte);
|
||||||
|
|
||||||
uint64_t* page = pag_new_pte(pml4, vaddr);
|
*pte = PTE_ADDR(p) | flags | PTE_FLAG_PRESENT;
|
||||||
*page = 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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-3
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user