kern

annotate src/vm.c @ 19:8be069e6bb05

I think I'm done with the physical memory page allocator
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 30 Mar 2011 22:42:16 +0300
parents 096807345aa2
children 7ece008f09c5
rev   line source
nuclear@17 1 #include <stdio.h>
nuclear@17 2 #include <string.h>
nuclear@17 3 #include <inttypes.h>
nuclear@17 4 #include "vm.h"
nuclear@17 5 #include <stdio.h>
nuclear@17 6 #include "intr.h"
nuclear@17 7 #include "mem.h"
nuclear@17 8 #include "panic.h"
nuclear@17 9
nuclear@17 10
nuclear@17 11 /* defined in vm-asm.S */
nuclear@17 12 void enable_paging(void);
nuclear@17 13 void set_pgdir_addr(uint32_t addr);
nuclear@17 14 uint32_t get_fault_addr(void);
nuclear@17 15
nuclear@17 16 static void pgfault(int inum, uint32_t err);
nuclear@17 17
nuclear@17 18 /* page directory */
nuclear@18 19 static uint32_t *pgdir;
nuclear@17 20
nuclear@17 21 #define KMEM_START 0xc0000000
nuclear@17 22 #define IDMAP_START 0xa0000
nuclear@17 23
nuclear@17 24 #define ATTR_PGDIR_MASK 0x3f
nuclear@17 25 #define ATTR_PGTBL_MASK 0x1ff
nuclear@17 26 #define ADDR_PGENT_MASK 0xfffff000
nuclear@17 27
nuclear@17 28 #define PAGEFAULT 14
nuclear@17 29
nuclear@17 30 void init_vm(struct mboot_info *mb)
nuclear@17 31 {
nuclear@19 32 uint32_t idmap_end;
nuclear@19 33
nuclear@17 34 init_mem(mb);
nuclear@17 35
nuclear@18 36 pgdir = (uint32_t*)alloc_phys_page();
nuclear@17 37 memset(pgdir, 0, sizeof pgdir);
nuclear@17 38
nuclear@17 39 /* map the video memory and kernel code 1-1 */
nuclear@19 40 get_kernel_mem_range(0, &idmap_end);
nuclear@19 41 map_mem_range(IDMAP_START, idmap_end - IDMAP_START, IDMAP_START, 0);
nuclear@17 42
nuclear@17 43 interrupt(PAGEFAULT, pgfault);
nuclear@17 44
nuclear@17 45 set_pgdir_addr((int32_t)pgdir);
nuclear@17 46 enable_paging();
nuclear@17 47 }
nuclear@17 48
nuclear@17 49 void map_page(int vpage, int ppage, unsigned int attr)
nuclear@17 50 {
nuclear@17 51 uint32_t *pgtbl;
nuclear@17 52 int diridx = PAGE_TO_PGTBL(vpage);
nuclear@17 53 int pgidx = PAGE_TO_PGTBL_PG(vpage);
nuclear@17 54
nuclear@17 55 if(!(pgdir[diridx] & PG_PRESENT)) {
nuclear@17 56 uint32_t addr = alloc_phys_page();
nuclear@17 57 pgtbl = (uint32_t*)addr;
nuclear@18 58 memset(pgtbl, 0, PGSIZE);
nuclear@18 59
nuclear@17 60 pgdir[diridx] = addr | (attr & ATTR_PGDIR_MASK) | PG_PRESENT;
nuclear@17 61 } else {
nuclear@17 62 pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK);
nuclear@17 63 }
nuclear@17 64
nuclear@17 65 pgtbl[pgidx] = PAGE_TO_ADDR(ppage) | (attr & ATTR_PGTBL_MASK) | PG_PRESENT;
nuclear@17 66 }
nuclear@17 67
nuclear@17 68 void unmap_page(int vpage)
nuclear@17 69 {
nuclear@17 70 uint32_t *pgtbl;
nuclear@17 71 int diridx = PAGE_TO_PGTBL(vpage);
nuclear@17 72 int pgidx = PAGE_TO_PGTBL_PG(vpage);
nuclear@17 73
nuclear@17 74 if(!(pgdir[diridx] & PG_PRESENT)) {
nuclear@17 75 goto err;
nuclear@17 76 }
nuclear@17 77 pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK);
nuclear@17 78
nuclear@17 79 if(!(pgtbl[pgidx] & PG_PRESENT)) {
nuclear@17 80 goto err;
nuclear@17 81 }
nuclear@17 82 pgtbl[pgidx] = 0;
nuclear@17 83
nuclear@17 84 return;
nuclear@17 85 err:
nuclear@17 86 printf("unmap_page(%d): page already not mapped\n", vpage);
nuclear@17 87 }
nuclear@17 88
nuclear@17 89 void map_page_range(int vpg_start, int pgcount, int ppg_start, unsigned int attr)
nuclear@17 90 {
nuclear@17 91 int i;
nuclear@17 92
nuclear@17 93 for(i=0; i<pgcount; i++) {
nuclear@17 94 map_page(vpg_start + i, ppg_start + i, attr);
nuclear@17 95 }
nuclear@17 96 }
nuclear@17 97
nuclear@17 98 void map_mem_range(uint32_t vaddr, size_t sz, uint32_t paddr, unsigned int attr)
nuclear@17 99 {
nuclear@17 100 int vpg_start, ppg_start, num_pages;
nuclear@17 101
nuclear@17 102 if(!sz) return;
nuclear@17 103
nuclear@17 104 if(ADDR_TO_PGOFFS(paddr)) {
nuclear@17 105 panic("map_mem_range called with unaligned physical address: %x\n", paddr);
nuclear@17 106 }
nuclear@17 107
nuclear@17 108 vpg_start = ADDR_TO_PAGE(vaddr);
nuclear@17 109 ppg_start = ADDR_TO_PAGE(paddr);
nuclear@17 110 num_pages = ADDR_TO_PAGE(sz) + 1;
nuclear@17 111
nuclear@17 112 map_page_range(vpg_start, num_pages, ppg_start, attr);
nuclear@17 113 }
nuclear@17 114
nuclear@18 115 uint32_t virt_to_phys(uint32_t vaddr)
nuclear@18 116 {
nuclear@18 117 uint32_t pgaddr, *pgtbl;
nuclear@18 118 int diridx = ADDR_TO_PGTBL(vaddr);
nuclear@18 119 int pgidx = ADDR_TO_PGTBL_PG(vaddr);
nuclear@18 120
nuclear@18 121 if(!(pgdir[diridx] & PG_PRESENT)) {
nuclear@18 122 panic("virt_to_phys(%x): page table %d not present\n", vaddr, diridx);
nuclear@18 123 }
nuclear@18 124 pgtbl = (uint32_t*)(pgdir[diridx] & PGENT_ADDR_MASK);
nuclear@18 125
nuclear@18 126 if(!(pgtbl[pgidx] & PG_PRESENT)) {
nuclear@18 127 panic("virt_to_phys(%x): page %d not present\n", vaddr, ADDR_TO_PAGE(vaddr));
nuclear@18 128 }
nuclear@18 129 pgaddr = pgtbl[pgidx] & PGENT_ADDR_MASK;
nuclear@18 130
nuclear@18 131 return pgaddr | ADDR_TO_PGOFFS(vaddr);
nuclear@18 132 }
nuclear@18 133
nuclear@17 134 static void pgfault(int inum, uint32_t err)
nuclear@17 135 {
nuclear@17 136 printf("~~~~ PAGE FAULT ~~~~\n");
nuclear@17 137
nuclear@17 138 printf("fault address: %x\n", get_fault_addr());
nuclear@17 139
nuclear@17 140 if(err & PG_PRESENT) {
nuclear@17 141 if(err & 8) {
nuclear@17 142 printf("reserved bit set in some paging structure\n");
nuclear@17 143 } else {
nuclear@17 144 printf("%s protection violation ", (err & PG_WRITABLE) ? "write" : "read");
nuclear@17 145 printf("in %s mode\n", err & PG_USER ? "user" : "kernel");
nuclear@17 146 }
nuclear@17 147 } else {
nuclear@17 148 printf("page not present\n");
nuclear@17 149 }
nuclear@19 150
nuclear@19 151 panic("unhandled page fault\n");
nuclear@17 152 }