summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Holman <dholman@gymli.org>2023-11-26 18:50:16 -0600
committerDanny Holman <dholman@gymli.org>2023-11-26 18:50:16 -0600
commit2740284a344209146fdc9b9fd852f277616e1fba (patch)
treed73babc3cb8e86063cb48456c2d0331fa65c285e
parente301006c1494674d94e1bcedcd3c3a638af7ec00 (diff)
arch: i386: paging: add a proper paging API
Add a proper page control API. These functions allow the kernel to directly map and unmap pages in the logical address space. Signed-off-by: Danny Holman <dholman@gymli.org>
-rw-r--r--arch/i386/include/kernel/paging.h52
-rw-r--r--arch/i386/kernel/paging.c88
2 files changed, 140 insertions, 0 deletions
diff --git a/arch/i386/include/kernel/paging.h b/arch/i386/include/kernel/paging.h
new file mode 100644
index 0000000..c65718f
--- /dev/null
+++ b/arch/i386/include/kernel/paging.h
@@ -0,0 +1,52 @@
+#ifndef I386_PAGING_H
+#define I386_PAGING_H
+
+#include <kernel/isr.h>
+#include <stdint.h>
+
+#define PD_PRES 0x0001
+#define PD_RW 0x0002
+#define PD_USR 0x0004
+#define PD_PWT 0x0008
+#define PD_PCD 0x0010
+#define PD_ACC 0x0020
+#define PD_DIRTY 0x0040
+#define PD_PS 0x0080
+#define PD_GLOB 0x0100
+#define PD_PAT 0x1000
+
+#define ERR_PRESENT 0x1
+#define ERR_RW 0x2
+#define ERR_USER 0x4
+#define ERR_RESERVED 0x8
+#define ERR_INST 0x10
+
+#define BLOCK_SIZE 4096
+#define BLOCKS_PER_BUCKET 8
+#define BLOCK_ALIGN(addr) (((addr) & 0xFFFFF000) + 0x1000)
+
+#define SETBIT(x,i) x[i/BLOCKS_PER_BUCKET] = x[i/BLOCKS_PER_BUCKET] | (1 << (i % BLOCKS_PER_BUCKET))
+#define CLEARBIT(x,i) x[i/BLOCKS_PER_BUCKET] = x[i/BLOCKS_PER_BUCKET] & (~(1 << (i % BLOCKS_PER_BUCKET)))
+#define ISSET(x,i) ((x[i/BLOCKS_PER_BUCKET] >> (i % BLOCKS_PER_BUCKET)) & 0x1)
+#define GETBUCKET(x,i) (*((uint32_t*)&x[i/32]))
+
+#define PAGE_SIZE 4096
+
+struct page_frame {
+ int used;
+ uint32_t addr;
+};
+
+void load_page_dir(uint32_t pd_addr);
+void enable_paging(void);
+
+void paging_init();
+void page_fault_handler(struct isr_frame *frame);
+
+uint32_t get_paddr(uint32_t vaddr);
+uint32_t get_vaddr(uint32_t paddr);
+
+void map_page(uint32_t paddr, uint32_t vaddr, uint32_t flags);
+void unmap_page(uint32_t vaddr);
+
+#endif
diff --git a/arch/i386/kernel/paging.c b/arch/i386/kernel/paging.c
new file mode 100644
index 0000000..d8f72a3
--- /dev/null
+++ b/arch/i386/kernel/paging.c
@@ -0,0 +1,88 @@
+#include <kernel/paging.h>
+#include <kernel/io.h>
+#include <kernel/syscall.h>
+#include <kernel/string.h>
+#include <kernel/alloc.h>
+#include <stddef.h>
+
+extern int halt_catch_fire();
+extern uint32_t _kernel_start;
+extern uint32_t _kernel_end;
+static uint32_t *kstart = &_kernel_start;
+static uint32_t *kend = (uint32_t)(&_kernel_end) - 0xC0000000;
+
+static uint32_t page_directory[1024] __attribute__((aligned(PAGE_SIZE)));
+static uint32_t first_page_table[1024] __attribute__((aligned(PAGE_SIZE)));
+
+static int paging_enabled = 0;
+
+void paging_init(void) {
+ for (int i = 0; i < 1024; i++)
+ page_directory[i] = 0x00000002;
+
+ page_directory[1023] = ((uint32_t)&page_directory - 0xC0000000) | 3;
+ page_directory[0] = ((uint32_t)&first_page_table - 0xC0000000) | 3;
+ page_directory[768] = ((uint32_t)&first_page_table - 0xC0000000) | 3;
+ for (uint32_t i = kstart; i < kend; i += 4096) {
+ map_page(i, get_vaddr(i), 0x003);
+ mark_bitmap(i, 1);
+ }
+
+ map_page(0xB8000, 0xC03FF000, 0x003);
+ mark_bitmap(0xB8000, 1);
+
+ load_page_dir(((uint32_t)&page_directory) - 0xC0000000);
+ enable_paging();
+ paging_enabled = 1;
+ return;
+}
+
+void page_fault_handler(struct isr_frame *frame) {
+ kprintf("Page fault detected\n");
+ uint32_t errno = frame->errno;
+
+ uint32_t fault_addr;
+ __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr));
+ kprintf("Fault occured at address %x\n", fault_addr);
+ uint32_t present = errno & ERR_PRESENT;
+ uint32_t rw = errno & ERR_RW;
+ uint32_t user = errno & ERR_USER;
+ uint32_t reserved = errno & ERR_RESERVED;
+ uint32_t ifetch = errno & ERR_INST;
+ kprintf("Possible causes:\n");
+ if (!present) kprintf("\tPage not present\n");
+ if (rw || user) kprintf("\tPage is read only\n");
+ if (reserved) kprintf("\tOverwrote reserved bits\n");
+ if (ifetch) kprintf("\tInstruction fetch\n");
+ halt_catch_fire(frame);
+}
+
+uint32_t get_paddr(uint32_t vaddr) {
+ uint32_t pdindex = vaddr >> 22;
+ uint32_t ptindex = vaddr >> 12 & 0x03FF;
+
+ uint32_t *page_table = (page_directory[pdindex] + 0xC0000000 & 0xFFFFF000);
+ return (page_table[ptindex] & 0xFFFFF000) | (vaddr & 0x00000FFF);
+}
+
+uint32_t get_vaddr(uint32_t paddr) {
+ return paddr + 0xC0000000;
+}
+
+void map_page(uint32_t paddr, uint32_t vaddr, uint32_t flags) {
+ uint32_t pdindex = vaddr >> 22;
+ uint32_t ptindex = vaddr >> 12 & 0x03FF;
+
+ uint32_t *page_table = (page_directory[pdindex] + 0xC0000000 & 0xFFFFF000);
+ uint32_t *pte = (uint32_t*)(&page_table[ptindex]);
+ *pte |= paddr | (flags & 0xFFF) | 0x01;
+}
+
+void unmap_page(uint32_t vaddr) {
+ uint32_t pdindex = vaddr >> 22;
+ uint32_t ptindex = vaddr >> 12 & 0x03FF;
+
+ uint32_t *page_table = (page_directory[pdindex] + 0xC0000000 & 0xFFFFF000);
+ uint32_t *pte = (uint32_t*)(&page_table[ptindex]);
+ *pte &= 0;
+}