diff options
author | Danny Holman <dholman@gymli.org> | 2023-11-26 18:50:16 -0600 |
---|---|---|
committer | Danny Holman <dholman@gymli.org> | 2023-11-26 18:50:16 -0600 |
commit | 2740284a344209146fdc9b9fd852f277616e1fba (patch) | |
tree | d73babc3cb8e86063cb48456c2d0331fa65c285e | |
parent | e301006c1494674d94e1bcedcd3c3a638af7ec00 (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.h | 52 | ||||
-rw-r--r-- | arch/i386/kernel/paging.c | 88 |
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; +} |