From 33fdc9b20c12e6c776ed76fc59d848a3ad7f6bca Mon Sep 17 00:00:00 2001 From: Danny Holman Date: Fri, 16 Feb 2024 13:06:43 -0600 Subject: arch: i386: roll physical memory control into VMM The VMM should control the physical memory as well as paging. This allows the VMM to grab frames as it sees fit. Signed-off-by: Danny Holman --- arch/i386/include/kernel/alloc.h | 13 ---- arch/i386/include/kernel/paging.h | 33 ++++----- arch/i386/kernel/alloc.c | 42 ------------ arch/i386/kernel/paging.c | 141 +++++++++++++++++++++++--------------- arch/i386/linker.ld | 6 +- arch/i386/make.config | 4 +- 6 files changed, 107 insertions(+), 132 deletions(-) delete mode 100644 arch/i386/include/kernel/alloc.h delete mode 100644 arch/i386/kernel/alloc.c diff --git a/arch/i386/include/kernel/alloc.h b/arch/i386/include/kernel/alloc.h deleted file mode 100644 index 986bcc5..0000000 --- a/arch/i386/include/kernel/alloc.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef I386_ALLOC_H -#define I386_ALLOC_H - -#include -#include -#include - -int alloc_init(struct mboot_info *info); -void mark_bitmap(uint32_t paddr, int present); -uint32_t pfa_alloc_frame(void); -void pfa_free(uint32_t paddr, int num_frames); - -#endif diff --git a/arch/i386/include/kernel/paging.h b/arch/i386/include/kernel/paging.h index c65718f..bb79d09 100644 --- a/arch/i386/include/kernel/paging.h +++ b/arch/i386/include/kernel/paging.h @@ -2,6 +2,8 @@ #define I386_PAGING_H #include +#include +#include #include #define PD_PRES 0x0001 @@ -21,32 +23,27 @@ #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 PAGE_SIZE 4096 -#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 DMA_BITMAP_SZ 128 +#define BDY_BITMAP_SZ 32640 -#define PAGE_SIZE 4096 - -struct page_frame { - int used; - uint32_t addr; +struct pfa_buddy { + uintptr_t start; + uintptr_t *bitmap; + uint8_t size; + struct list_head list; }; -void load_page_dir(uint32_t pd_addr); +void load_page_dir(uintptr_t pd_addr); void enable_paging(void); -void paging_init(); +void paging_init(void); void page_fault_handler(struct isr_frame *frame); -uint32_t get_paddr(uint32_t vaddr); -uint32_t get_vaddr(uint32_t paddr); +uint32_t get_vaddr(uintptr_t paddr); -void map_page(uint32_t paddr, uint32_t vaddr, uint32_t flags); -void unmap_page(uint32_t vaddr); +void map_page(uint32_t *pd, uintptr_t paddr, uintptr_t vaddr, uint32_t flags); +void unmap_page(uint32_t *pd, uintptr_t vaddr); #endif diff --git a/arch/i386/kernel/alloc.c b/arch/i386/kernel/alloc.c deleted file mode 100644 index 890c2f1..0000000 --- a/arch/i386/kernel/alloc.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include - -extern uint32_t _bitmap_start; -static uint32_t *bm_start = &_bitmap_start; - -static struct mboot_info *info; - -int alloc_init(struct mboot_info *info) { - struct mboot_mmap_entry *mme; - for (uint32_t i = 0; i < info->mmap_length; i += sizeof(struct mboot_mmap_entry)) { - mme = (struct mboot_mmap_entry*)(info->mmap_addr + i); - if (mme->type != MBOOT_MEM_AVAILABLE) - mark_bitmap(mme->addr_low, 1); - } - return 0; -} - -void mark_bitmap(uint32_t paddr, int present) { - uint32_t index = (paddr & 0xFFFFF000) / 4096 / 32; - uint32_t bit = (paddr & 0xFFFFF000) / 4096 % 32; - bm_start[index] |= (present << bit); -} - -uint32_t pfa_alloc_frame(void) { - for (uint32_t i = 0; i < 4096; i++) { - uint32_t index = i / 32; - uint32_t bit = i % 32; - if ((bm_start[index] & (1 << bit)) == 0) { - mark_bitmap(i*4096, 1); - return i * 4096; - } - } - return 0xFFFFFFFF; -} - -void pfa_free(uint32_t paddr, int num_frames) { - for (int i = 0; i < num_frames; i++) - mark_bitmap(paddr + (i*4096), 0); -} diff --git a/arch/i386/kernel/paging.c b/arch/i386/kernel/paging.c index d8f72a3..54539ac 100644 --- a/arch/i386/kernel/paging.c +++ b/arch/i386/kernel/paging.c @@ -2,87 +2,120 @@ #include #include #include -#include -#include -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; +extern uintptr_t _kernel_start; +extern uintptr_t _kernel_end; +static uintptr_t kstart = (uintptr_t)&_kernel_start; +static uintptr_t kend = (uintptr_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 uintptr_t page_directory[1024] __attribute__((aligned(PAGE_SIZE))); +static uintptr_t first_page_table[1024] __attribute__((aligned(PAGE_SIZE))); static int paging_enabled = 0; +static uint32_t dma_zone_bitmap[DMA_BITMAP_SZ]; +static uint32_t buddy_bitmap[BDY_BITMAP_SZ]; +static struct pfa_buddy first_buddy; + +static void _pfa_init(void) { + first_buddy.start = 0x01000000; + first_buddy.bitmap = buddy_bitmap; +} + +static void _pfa_alloc(uintptr_t paddr) { + uintptr_t index = (paddr & 0xFFFFF000) / 4096 / 32; + uintptr_t bit = (paddr & 0xFFFFF000) / 4096 % 32; + uint32_t *bitmap; + if (paddr < 0x01000000) + bitmap = dma_zone_bitmap; + else + bitmap = first_buddy.bitmap; + + bitmap[index] |= (1 << bit); +} + +static void _pfa_free(uintptr_t paddr) { + uintptr_t index = (paddr & 0xFFFFF000) / 4096 / 32; + uintptr_t bit = (paddr & 0xFFFFF000) / 4096 % 32; + uint32_t *bitmap; + if (paddr < 0x01000000) + bitmap = dma_zone_bitmap; + else + bitmap = first_buddy.bitmap; + + bitmap[index] &= ~(1 << bit); +} + void paging_init(void) { + _pfa_init(); 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); + page_directory[1023] = ((uintptr_t)&page_directory - 0xC0000000) | 3; + page_directory[0] = ((uintptr_t)&first_page_table - 0xC0000000) | 3; + page_directory[768] = ((uintptr_t)&first_page_table - 0xC0000000) | 3; + for (uintptr_t i = kstart; i < kend; i += 4096) { + _pfa_alloc(get_vaddr(i)); + map_page(page_directory, i, get_vaddr(i), 0x003); } - map_page(0xB8000, 0xC03FF000, 0x003); - mark_bitmap(0xB8000, 1); - - load_page_dir(((uint32_t)&page_directory) - 0xC0000000); + load_page_dir(((uintptr_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; + uintptr_t errno = frame->errno; - uint32_t fault_addr; + uintptr_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); + int present = errno & ERR_PRESENT; + int rw = errno & ERR_RW; + int user = errno & ERR_USER; + int reserved = errno & ERR_RESERVED; + int ifetch = errno & ERR_INST; + + if (!present) + _pfa_alloc(fault_addr); + map_page(NULL, fault_addr, fault_addr, 0x003); + if (user) + panic("Usermode attempted to read supervisor page"); + if (rw) + panic("Task wrote to read only page"); + if (reserved) + panic("Task overwrote reserved page bits"); + if (ifetch) + panic("Task paging instruction fetch failure"); } -uint32_t get_vaddr(uint32_t paddr) { +uintptr_t get_vaddr(uintptr_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; +void map_page(uint32_t *pd, uintptr_t paddr, uintptr_t vaddr, uint32_t flags) { + if (pd == NULL) + pd = page_directory; + + uintptr_t paddr_aligned = paddr & 0xFFFFF000; + uintptr_t vaddr_aligned = vaddr & 0xFFFFF000; - uint32_t *page_table = (page_directory[pdindex] + 0xC0000000 & 0xFFFFF000); - uint32_t *pte = (uint32_t*)(&page_table[ptindex]); - *pte |= paddr | (flags & 0xFFF) | 0x01; + uintptr_t pdindex = vaddr_aligned >> 22; + uintptr_t ptindex = vaddr_aligned >> 12 & 0x03FF; + + uintptr_t *pt = (pd[pdindex] + 0xC0000000 & 0xFFFFF000); + uintptr_t *pte = (uintptr_t*)(&pt[ptindex]); + *pte |= paddr_aligned | (flags & 0xFFF) | 0x01; } -void unmap_page(uint32_t vaddr) { - uint32_t pdindex = vaddr >> 22; - uint32_t ptindex = vaddr >> 12 & 0x03FF; +void unmap_page(uint32_t *pd, uintptr_t vaddr) { + if (pd == NULL) + pd = page_directory; + + uintptr_t pdindex = vaddr >> 22; + uintptr_t ptindex = vaddr >> 12 & 0x03FF; - uint32_t *page_table = (page_directory[pdindex] + 0xC0000000 & 0xFFFFF000); - uint32_t *pte = (uint32_t*)(&page_table[ptindex]); + uintptr_t *pt = (pd[pdindex] + 0xC0000000 & 0xFFFFF000); + uintptr_t *pte = (uintptr_t*)(&pt[ptindex]); *pte &= 0; } diff --git a/arch/i386/linker.ld b/arch/i386/linker.ld index 61799c7..7eb9d99 100644 --- a/arch/i386/linker.ld +++ b/arch/i386/linker.ld @@ -26,9 +26,9 @@ SECTIONS { *(.bootstrap_stack) } - _bitmap_start = .; - . += 128K; - _bitmap_end = .; + .usertext ALIGN(4K) : AT(ADDR(.usertext) - 0xC0000000) { + *(.usertext) + } _kernel_end = .; } diff --git a/arch/i386/make.config b/arch/i386/make.config index 4729739..2c87912 100644 --- a/arch/i386/make.config +++ b/arch/i386/make.config @@ -7,10 +7,10 @@ KERNEL_ARCH_OBJS=$(ARCHDIR)/boot/boot.o \ $(ARCHDIR)/boot/isr.o \ $(ARCHDIR)/boot/idt.o \ $(ARCHDIR)/boot/gdt.o \ - $(ARCHDIR)/kernel/tty.o \ - $(ARCHDIR)/kernel/alloc.o \ + $(ARCHDIR)/kernel/framebuffer.o \ $(ARCHDIR)/kernel/multiboot.o \ $(ARCHDIR)/kernel/serial.o \ $(ARCHDIR)/kernel/pic.o \ + $(ARCHDIR)/kernel/timer.o \ $(ARCHDIR)/kernel/syscall.o \ $(ARCHDIR)/kernel/paging.o \ -- cgit v1.2.3