void map_page(uint32_t *page_dir, uint32_t virt_page_num, uint32_t phy_page_num, bool global, bool user, bool read_write) { uint16_t pd_idx = PD_IDX(virt_page_num), pt_idx = PT_IDX(virt_page_num); uint32_t *page_table; if(!(page_dir[pd_idx] & 0x1)) { uint32_t pt_page_num = alloc_phy_page(0, 1023); map_kernel_page(pt_page_num, pt_page_num, true, false, true); memset((void *)(pt_page_num << 12), 0, 4096); page_dir[pd_idx] = make_pde(pt_page_num, user, read_write); } page_table = (uint32_t *)(page_dir[pd_idx] & 0xfffff000); page_table[pt_idx] = make_pte(phy_page_num, global, user, read_write); ++phy_mem_rc[phy_page_num]; __asm__ volatile( ".intel_syntax noprefix;" "mov eax, cr3;" "mov cr3, eax;" ".att_syntax;" :::"eax" ); }
pte_t *mmap_lookup(pml4e_t *pml4, uint64_t va, bool create) { struct page *page4pdp = NULL, *page4pd = NULL, *page4pt = NULL; pdpe_t pml4e = pml4[PML4_IDX(va)]; if ((pml4e & PML4E_P) != 0) goto pml4e_found; if (create == false) return NULL; // Prepare new page directory pointer if ((page4pdp = page_alloc()) == NULL) return NULL; memset(page2kva(page4pdp), 0, PAGE_SIZE); page4pdp->ref = 1; // Insert new pdp into PML4 pml4e = pml4[PML4_IDX(va)] = page2pa(page4pdp) | PML4E_P | PML4E_W | PML4E_U; pml4e_found: assert((pml4e & PML4E_P) != 0); pdpe_t *pdp = VADDR(PML4E_ADDR(pml4e)); pdpe_t pdpe = pdp[PDP_IDX(va)]; if ((pdpe & PDPE_P) != 0) goto pdpe_found; if (create == false) return NULL; // Prepare new page directory if ((page4pd = page_alloc()) == NULL) return NULL; memset(page2kva(page4pd), 0, PAGE_SIZE); page4pd->ref = 1; // Insert new page directory into page directory pointer table pdpe = pdp[PDP_IDX(va)] = page2pa(page4pd) | PDPE_P | PDPE_W | PDPE_U; pdpe_found: assert((pdpe & PDPE_P) != 0); pde_t *pd = VADDR(PDPE_ADDR(pdpe)); pde_t pde = pd[PD_IDX(va)]; if ((pde & PDE_P) != 0) goto pde_found; if (create == false) return NULL; // Prepare new page table if ((page4pt = page_alloc()) == NULL) return NULL; memset(page2kva(page4pt), 0, PAGE_SIZE); page4pt->ref = 1; // Insert new page table into page directory pde = pd[PD_IDX(va)] = page2pa(page4pt) | PDE_P | PTE_W | PDE_U; pde_found: assert((pde & PDE_P) != 0); pte_t *pt = VADDR(PDE_ADDR(pde)); return &pt[PT_IDX(va)]; }
/* * Allocate a number of pages from the OS */ static void * map_pages(size_t pages) { struct pdinfo *pi, *spi; struct pginfo **pd; u_long idx, pidx, lidx; caddr_t result, tail; u_long index, lindex; void *pdregion = NULL; size_t dirs, cnt; pages <<= malloc_pageshift; result = MMAP(pages + malloc_guard); if (result == MAP_FAILED) { #ifdef MALLOC_EXTRA_SANITY wrtwarning("(ES): map_pages fails"); #endif /* MALLOC_EXTRA_SANITY */ errno = ENOMEM; return (NULL); } index = ptr2index(result); tail = result + pages + malloc_guard; lindex = ptr2index(tail) - 1; if (malloc_guard) mprotect(result + pages, malloc_guard, PROT_NONE); pidx = PI_IDX(index); lidx = PI_IDX(lindex); if (tail > malloc_brk) { malloc_brk = tail; last_index = lindex; } dirs = lidx - pidx; /* Insert directory pages, if needed. */ if (pdir_lookup(index, &pi) != 0) dirs++; if (dirs > 0) { pdregion = MMAP(malloc_pagesize * dirs); if (pdregion == MAP_FAILED) { munmap(result, tail - result); #ifdef MALLOC_EXTRA_SANITY wrtwarning("(ES): map_pages fails"); #endif errno = ENOMEM; return (NULL); } } cnt = 0; for (idx = pidx, spi = pi; idx <= lidx; idx++) { if (pi == NULL || PD_IDX(pi->dirnum) != idx) { pd = (struct pginfo **)((char *)pdregion + cnt * malloc_pagesize); cnt++; memset(pd, 0, malloc_pagesize); pi = (struct pdinfo *) ((caddr_t) pd + pdi_off); pi->base = pd; pi->prev = spi; pi->next = spi->next; pi->dirnum = idx * (malloc_pagesize / sizeof(struct pginfo *)); if (spi->next != NULL) spi->next->prev = pi; spi->next = pi; } if (idx > pidx && idx < lidx) { pi->dirnum += pdi_mod; } else if (idx == pidx) { if (pidx == lidx) { pi->dirnum += (u_long)(tail - result) >> malloc_pageshift; } else { pi->dirnum += pdi_mod - PI_OFF(index); } } else {
void malloc_dump(int fd) { char buf[1024]; struct pginfo **pd; struct pgfree *pf; struct pdinfo *pi; u_long j; pd = page_dir; pi = (struct pdinfo *) ((caddr_t) pd + pdi_off); /* print out all the pages */ for (j = 0; j <= last_index;) { snprintf(buf, sizeof buf, "%08lx %5lu ", j << malloc_pageshift, j); write(fd, buf, strlen(buf)); if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) { for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) { if (!PI_OFF(++j)) { if ((pi = pi->next) == NULL || PD_IDX(pi->dirnum) != PI_IDX(j)) break; pd = pi->base; j += pdi_mod; } } j--; snprintf(buf, sizeof buf, ".. %5lu not mine\n", j); write(fd, buf, strlen(buf)); } else if (pd[PI_OFF(j)] == MALLOC_FREE) { for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FREE;) { if (!PI_OFF(++j)) { if ((pi = pi->next) == NULL || PD_IDX(pi->dirnum) != PI_IDX(j)) break; pd = pi->base; j += pdi_mod; } } j--; snprintf(buf, sizeof buf, ".. %5lu free\n", j); write(fd, buf, strlen(buf)); } else if (pd[PI_OFF(j)] == MALLOC_FIRST) { for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) { if (!PI_OFF(++j)) { if ((pi = pi->next) == NULL || PD_IDX(pi->dirnum) != PI_IDX(j)) break; pd = pi->base; j += pdi_mod; } } j--; snprintf(buf, sizeof buf, ".. %5lu in use\n", j); write(fd, buf, strlen(buf)); } else if (pd[PI_OFF(j)] < MALLOC_MAGIC) { snprintf(buf, sizeof buf, "(%p)\n", pd[PI_OFF(j)]); write(fd, buf, strlen(buf)); } else { snprintf(buf, sizeof buf, "%p %d (of %d) x %d @ %p --> %p\n", pd[PI_OFF(j)], pd[PI_OFF(j)]->free, pd[PI_OFF(j)]->total, pd[PI_OFF(j)]->size, pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next); write(fd, buf, strlen(buf)); } if (!PI_OFF(++j)) { if ((pi = pi->next) == NULL) break; pd = pi->base; j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod; } } for (pf = free_list.next; pf; pf = pf->next) { snprintf(buf, sizeof buf, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", pf, pf->page, (char *)pf->page + pf->size, pf->size, pf->prev, pf->next); write(fd, buf, strlen(buf)); if (pf == pf->next) { snprintf(buf, sizeof buf, "Free_list loops\n"); write(fd, buf, strlen(buf)); break; } } /* print out various info */ snprintf(buf, sizeof buf, "Minsize\t%lu\n", malloc_minsize); write(fd, buf, strlen(buf)); snprintf(buf, sizeof buf, "Maxsize\t%lu\n", malloc_maxsize); write(fd, buf, strlen(buf)); snprintf(buf, sizeof buf, "Pagesize\t%lu\n", malloc_pagesize); write(fd, buf, strlen(buf)); snprintf(buf, sizeof buf, "Pageshift\t%u\n", malloc_pageshift); write(fd, buf, strlen(buf)); snprintf(buf, sizeof buf, "In use\t%lu\n", (u_long) malloc_used); write(fd, buf, strlen(buf)); snprintf(buf, sizeof buf, "Guarded\t%lu\n", (u_long) malloc_guarded); write(fd, buf, strlen(buf)); }
/* * Function for page directory lookup. */ static int pdir_lookup(u_long index, struct pdinfo ** pdi) { struct pdinfo *spi; u_long pidx = PI_IDX(index); if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx) *pdi = last_dir; else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx) *pdi = prev_dir; else if (last_dir != NULL && prev_dir != NULL) { if ((PD_IDX(last_dir->dirnum) > pidx) ? (PD_IDX(last_dir->dirnum) - pidx) : (pidx - PD_IDX(last_dir->dirnum)) < (PD_IDX(prev_dir->dirnum) > pidx) ? (PD_IDX(prev_dir->dirnum) - pidx) : (pidx - PD_IDX(prev_dir->dirnum))) *pdi = last_dir; else *pdi = prev_dir; if (PD_IDX((*pdi)->dirnum) > pidx) { for (spi = (*pdi)->prev; spi != NULL && PD_IDX(spi->dirnum) > pidx; spi = spi->prev) *pdi = spi; if (spi != NULL) *pdi = spi; } else for (spi = (*pdi)->next; spi != NULL && PD_IDX(spi->dirnum) <= pidx; spi = spi->next) *pdi = spi; } else { *pdi = (struct pdinfo *) ((caddr_t) page_dir + pdi_off); for (spi = *pdi; spi != NULL && PD_IDX(spi->dirnum) <= pidx; spi = spi->next) *pdi = spi; } return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 : (PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1); }