void *miomap(unsigned long addr, int size, int protect) { char *vaddr; int i; unsigned long flags = pte_flags_from_protect(protect); int pages = PAGES(size); vaddr = (char *) PTOB(rmap_alloc(vmap, pages)); if (vaddr == NULL) return NULL; for (i = 0; i < pages; i++) { map_page(vaddr + PTOB(i), BTOP(addr) + i, flags | PT_PRESENT); } return vaddr; }
void miounmap(void *addr, int size) { int i; int pages = PAGES(size); for (i = 0; i < pages; i++) unmap_page((char *) addr + PTOB(i)); rmap_free(vmap, BTOP(addr), pages); }
void *vmmap(void *addr, unsigned long size, int protect, struct file *filp, off64_t offset, int *rc) { int pages = PAGES(size); unsigned long flags = pte_flags_from_protect(protect); struct filemap *fm; int i; char *vaddr; if (rc) *rc = 0; if (size == 0 || flags == 0xFFFFFFFF) { if (rc) *rc = -EINVAL; return NULL; } addr = (void *) PAGEADDR(addr); if (addr == NULL) { addr = (void *) PTOB(rmap_alloc(vmap, pages)); if (addr == NULL) { if (rc) *rc = -ENOMEM; return NULL; } } else { if (rmap_reserve(vmap, BTOP(addr), pages)) { if (rc) *rc = -ENOMEM; return NULL; } } fm = (struct filemap *) kmalloc(sizeof(struct filemap)); if (!fm) { rmap_free(vmap, BTOP(addr), pages); if (rc) *rc = -ENOMEM; return NULL; } init_object(&fm->object, OBJECT_FILEMAP); fm->self = halloc(&fm->object); fm->file = halloc(&filp->iob.object); if (fm->self < 0 || fm->file < 0) { if (rc) *rc = -ENFILE; return NULL; } hprotect(fm->self); hprotect(fm->file); fm->offset = offset; fm->pages = pages; fm->object.signaled = 1; fm->addr = addr; fm->size = size; fm->protect = flags | PT_FILE; vaddr = (char *) addr; flags = (flags & ~PT_USER) | PT_FILE; for (i = 0; i < pages; i++) { map_page(vaddr, fm->self, flags); vaddr += PAGESIZE; } return addr; }
void map_page(void *vaddr, unsigned long pfn, unsigned long flags) { // Allocate page table if not already done if ((GET_PDE(vaddr) & PT_PRESENT) == 0) { unsigned long pdfn; pdfn = alloc_pageframe('PTAB'); if (USERSPACE(vaddr)) { SET_PDE(vaddr, PTOB(pdfn) | PT_PRESENT | PT_WRITABLE | PT_USER); } else { SET_PDE(vaddr, PTOB(pdfn) | PT_PRESENT | PT_WRITABLE); } memset(ptab + PDEIDX(vaddr) * PTES_PER_PAGE, 0, PAGESIZE); register_page_table(pdfn); } // Map page frame into address space SET_PTE(vaddr, PTOB(pfn) | flags); }
void init_pdir() { unsigned long i; // Clear identity mapping of the first 4 MB made by the os loader for (i = 0; i < PTES_PER_PAGE; i++) SET_PTE(PTOB(i), 0); }
void *vmalloc(void *addr, unsigned long size, int type, int protect, unsigned long tag, int *rc) { int pages = PAGES(size); unsigned long flags = pte_flags_from_protect(protect); int i; if (rc) *rc = 0; if (size == 0) { if (rc) *rc = -EINVAL; return NULL; } if ((type & MEM_COMMIT) != 0 && flags == 0xFFFFFFFF) { if (rc) *rc = -EINVAL; return NULL; } addr = (void *) PAGEADDR(addr); if (!addr && (type & MEM_COMMIT) != 0) type |= MEM_RESERVE; if (!tag) tag = 'VM'; if (type & MEM_RESERVE) { if (addr == NULL) { if (type & MEM_ALIGN64K) { addr = (void *) PTOB(rmap_alloc_align(vmap, pages, 64 * 1024 / PAGESIZE)); } else { addr = (void *) PTOB(rmap_alloc(vmap, pages)); } if (addr == NULL) { if (rc) *rc = -ENOMEM; return NULL; } } else { if (rmap_reserve(vmap, BTOP(addr), pages)) { if (rc) *rc = -ENOMEM; return NULL; } } } else { if (!valid_range(addr, size)) { if (rc) *rc = -EFAULT; return NULL; } } if (type & MEM_COMMIT) { char *vaddr; unsigned long pfn; vaddr = (char *) addr; for (i = 0; i < pages; i++) { if (page_mapped(vaddr)) { set_page_flags(vaddr, flags | PT_PRESENT); } else { pfn = alloc_pageframe(tag); if (pfn == 0xFFFFFFFF) { if (rc) *rc = -ENOMEM; return NULL; } map_page(vaddr, pfn, flags | PT_PRESENT); memset(vaddr, 0, PAGESIZE); } vaddr += PAGESIZE; } } return addr; }