nuclear@17: #include nuclear@17: #include nuclear@17: #include nuclear@17: #include "vm.h" nuclear@17: #include nuclear@17: #include "intr.h" nuclear@17: #include "mem.h" nuclear@17: #include "panic.h" nuclear@17: nuclear@17: nuclear@17: /* defined in vm-asm.S */ nuclear@17: void enable_paging(void); nuclear@17: void set_pgdir_addr(uint32_t addr); nuclear@17: uint32_t get_fault_addr(void); nuclear@17: nuclear@17: static void pgfault(int inum, uint32_t err); nuclear@17: nuclear@17: /* page directory */ nuclear@18: static uint32_t *pgdir; nuclear@17: nuclear@17: #define KMEM_START 0xc0000000 nuclear@17: #define IDMAP_START 0xa0000 nuclear@17: nuclear@17: #define ATTR_PGDIR_MASK 0x3f nuclear@17: #define ATTR_PGTBL_MASK 0x1ff nuclear@17: #define ADDR_PGENT_MASK 0xfffff000 nuclear@17: nuclear@17: #define PAGEFAULT 14 nuclear@17: nuclear@17: void init_vm(struct mboot_info *mb) nuclear@17: { nuclear@17: init_mem(mb); nuclear@17: nuclear@18: pgdir = (uint32_t*)alloc_phys_page(); nuclear@17: memset(pgdir, 0, sizeof pgdir); nuclear@17: nuclear@17: /* map the video memory and kernel code 1-1 */ nuclear@17: map_mem_range(IDMAP_START, MAX_BRK - IDMAP_START, IDMAP_START, 0); nuclear@17: nuclear@17: interrupt(PAGEFAULT, pgfault); nuclear@17: nuclear@17: set_pgdir_addr((int32_t)pgdir); nuclear@17: enable_paging(); nuclear@17: } nuclear@17: nuclear@17: void map_page(int vpage, int ppage, unsigned int attr) nuclear@17: { nuclear@17: uint32_t *pgtbl; nuclear@17: int diridx = PAGE_TO_PGTBL(vpage); nuclear@17: int pgidx = PAGE_TO_PGTBL_PG(vpage); nuclear@17: nuclear@17: if(!(pgdir[diridx] & PG_PRESENT)) { nuclear@17: uint32_t addr = alloc_phys_page(); nuclear@17: pgtbl = (uint32_t*)addr; nuclear@18: memset(pgtbl, 0, PGSIZE); nuclear@18: nuclear@17: pgdir[diridx] = addr | (attr & ATTR_PGDIR_MASK) | PG_PRESENT; nuclear@17: } else { nuclear@17: pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK); nuclear@17: } nuclear@17: nuclear@17: pgtbl[pgidx] = PAGE_TO_ADDR(ppage) | (attr & ATTR_PGTBL_MASK) | PG_PRESENT; nuclear@17: } nuclear@17: nuclear@17: void unmap_page(int vpage) nuclear@17: { nuclear@17: uint32_t *pgtbl; nuclear@17: int diridx = PAGE_TO_PGTBL(vpage); nuclear@17: int pgidx = PAGE_TO_PGTBL_PG(vpage); nuclear@17: nuclear@17: if(!(pgdir[diridx] & PG_PRESENT)) { nuclear@17: goto err; nuclear@17: } nuclear@17: pgtbl = (uint32_t*)(pgdir[diridx] & ADDR_PGENT_MASK); nuclear@17: nuclear@17: if(!(pgtbl[pgidx] & PG_PRESENT)) { nuclear@17: goto err; nuclear@17: } nuclear@17: pgtbl[pgidx] = 0; nuclear@17: nuclear@17: return; nuclear@17: err: nuclear@17: printf("unmap_page(%d): page already not mapped\n", vpage); nuclear@17: } nuclear@17: nuclear@17: void map_page_range(int vpg_start, int pgcount, int ppg_start, unsigned int attr) nuclear@17: { nuclear@17: int i; nuclear@17: nuclear@17: for(i=0; iflags & MB_MMAP) { nuclear@17: struct mboot_mmap *mem, *mmap_end; nuclear@17: nuclear@17: mem = mb->mmap; nuclear@17: mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len); nuclear@17: nuclear@17: printf("memory map:\n"); nuclear@17: while(mem < mmap_end) { nuclear@17: unsigned int end = mem->base_low + mem->length_low; nuclear@17: char *type = mem->type == MB_MEM_VALID ? "free:" : "hole:"; nuclear@17: nuclear@17: printf(" %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low); nuclear@17: mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip); nuclear@17: } nuclear@17: } nuclear@17: nuclear@17: if(mb->flags & MB_MEM) { nuclear@17: printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper); nuclear@17: } nuclear@17: */ nuclear@17: nuclear@18: uint32_t virt_to_phys(uint32_t vaddr) nuclear@18: { nuclear@18: uint32_t pgaddr, *pgtbl; nuclear@18: int diridx = ADDR_TO_PGTBL(vaddr); nuclear@18: int pgidx = ADDR_TO_PGTBL_PG(vaddr); nuclear@18: nuclear@18: if(!(pgdir[diridx] & PG_PRESENT)) { nuclear@18: panic("virt_to_phys(%x): page table %d not present\n", vaddr, diridx); nuclear@18: } nuclear@18: pgtbl = (uint32_t*)(pgdir[diridx] & PGENT_ADDR_MASK); nuclear@18: nuclear@18: if(!(pgtbl[pgidx] & PG_PRESENT)) { nuclear@18: panic("virt_to_phys(%x): page %d not present\n", vaddr, ADDR_TO_PAGE(vaddr)); nuclear@18: } nuclear@18: pgaddr = pgtbl[pgidx] & PGENT_ADDR_MASK; nuclear@18: nuclear@18: return pgaddr | ADDR_TO_PGOFFS(vaddr); nuclear@18: } nuclear@18: nuclear@17: static void pgfault(int inum, uint32_t err) nuclear@17: { nuclear@17: printf("~~~~ PAGE FAULT ~~~~\n"); nuclear@17: nuclear@17: printf("fault address: %x\n", get_fault_addr()); nuclear@17: nuclear@17: if(err & PG_PRESENT) { nuclear@17: if(err & 8) { nuclear@17: printf("reserved bit set in some paging structure\n"); nuclear@17: } else { nuclear@17: printf("%s protection violation ", (err & PG_WRITABLE) ? "write" : "read"); nuclear@17: printf("in %s mode\n", err & PG_USER ? "user" : "kernel"); nuclear@17: } nuclear@17: } else { nuclear@17: printf("page not present\n"); nuclear@17: } nuclear@17: }