/* * Copy binary's section into a given mem_area. * @mma -- memory area to hold the section * @inode -- inode containing the binary * @off -- offset of the section in the file * @len -- length of the section * Note1: section has to be created beforehand. * Note2: it is assumed that all the file's pages are loaded in * inode's buffers. */ void aout_copy_section(struct mem_area *mma, struct inode *inode, off_t off, size_t len) { struct page *page; struct klist0_node *tmp; struct page *destpg; void *to = NULL; u32 pgnum, pgoff; size_t left, tocopy; /* where we start */ pgnum = (off & NOPAGE_MASK) >> PAGE_SHIFT; pgoff = off & PAGE_MASK; tmp = mma->m_plist.next; left = len; while (left > 0) { page = inode->i_map.i_pages[pgnum]; if (!((u32)to & PAGE_MASK)) { destpg = klist0_entry(tmp, struct page, area_list); to = page_to_addr(destpg); } if (pgoff) tocopy = MIN(left, (size_t)PAGE_SIZE - pgoff); else tocopy = MIN(left, (size_t)(PAGE_SIZE - ((u32)to & PAGE_MASK))); /*DPRINT("### copy: %x[%x] to %x[%x], %d bytes\n", page_to_addr(page) + pgoff, page->virt, to, destpg->virt, tocopy);*/ memory_copy(to, page_to_addr(page) + pgoff, tocopy); /* switch to next source page */ if (pgoff + tocopy == PAGE_SIZE) pgnum++; else pgoff = tocopy; left -= tocopy; to += tocopy; if (!((u32)to & PAGE_MASK)) tmp = tmp->next; else pgoff = 0; }
static void phy_pages_init(e820map_t *e820map) { uint32_t phy_mem_length = 0; for (uint32_t i = 0; i < e820map->count; ++i){ if (e820map->map[i].addr_low > ZONE_HIGHMEM_ADDR) { break; } if (e820map->map[i].addr_low + e820map->map[i].length_low > ZONE_HIGHMEM_ADDR) { phy_mem_length = ZONE_HIGHMEM_ADDR; break; } phy_mem_length = e820map->map[i].length_low; } uint32_t pages_mem_length = sizeof(page_t) * (phy_mem_length / PMM_PAGE_SIZE); bzero(phy_pages, pages_mem_length); // 物理内存页管理起始地址 pmm_addr_start = ((uint32_t)phy_pages - KERNBASE + pages_mem_length + PMM_PAGE_SIZE) & PMM_PAGE_MASK; for (uint32_t i = 0; i < e820map->count; ++i){ uint32_t start_addr = e820map->map[i].addr_low; uint32_t end_addr = e820map->map[i].addr_low + e820map->map[i].length_low; if (start_addr < pmm_addr_start) { start_addr = pmm_addr_start; } if (end_addr > ZONE_HIGHMEM_ADDR) { end_addr = ZONE_HIGHMEM_ADDR; } for (uint32_t addr = start_addr; addr < end_addr; addr += PMM_PAGE_SIZE) { phy_pages_count++; } pmm_addr_end = end_addr; } assert(pmm_addr_start == page_to_addr(&phy_pages[0]), "phy_pages_init error pmm_start != &page[0]"); assert(pmm_addr_end - PMM_PAGE_SIZE == page_to_addr(&phy_pages[phy_pages_count-1]), "phy_pages_init error pmm_end != &page[n-1]"); assert(&phy_pages[0] == addr_to_page(page_to_addr(&phy_pages[0])), "phy_pages_init error addr_to_page error"); assert(&phy_pages[1] == addr_to_page(page_to_addr(&phy_pages[1])), "phy_pages_init error addr_to_page error"); }
/* Sets the specified page's permission value. This involves two steps: * First, mprotect() is used to set the actual permissions on the page's * virtual address range. After this is completed successfully, the page's * Page Table Entry is updated with the new permission value. (The other bits * in the PTE are left unmodified.) */ void set_page_permission(page_t page, int perm) { assert(page < NUM_PAGES); assert(perm == PAGEPERM_NONE || perm == PAGEPERM_READ || perm == PAGEPERM_RDWR); /* Call mprotect() to set the memory region's protections. */ if (mprotect(page_to_addr(page), PAGE_SIZE, pageperm_to_mmap(perm)) == -1) { perror("mprotect"); abort(); } /* Replace old permission with new permission. */ page_table[page] = (page_table[page] & ~PAGEPERM_MASK) | perm; }
/* This function unmaps the specified page from the virtual address space, * making sure to write the contents of dirty pages back into the swap file. */ void unmap_page(page_t page) { int ret; assert(page < NUM_PAGES); assert(num_resident > 0); assert(is_page_resident(page)); /* * Step 1: * If the page is dirty, seek to the start of the corresponding slot in the * swap file and save the page’s contents to the slot. */ /* Only if dirty. */ if (is_page_dirty(page)) { /* Seek. */ ret = lseek(fd_swapfile, page * PAGE_SIZE, SEEK_SET); /* Check that it worked. */ if (ret == -1) { perror("lseek"); abort(); } /* Save to slot, need to be able to read from page to write to slot. */ set_page_permission(page, PAGEPERM_READ); ret = write(fd_swapfile, page_to_addr(page), PAGE_SIZE); /* Check that it worked. */ if (ret == -1) { perror("write"); abort(); } if (ret != PAGE_SIZE) { fprintf(stderr, "write: only wrote %d bytes (%d expected)\n", ret, PAGE_SIZE); abort(); } } /* * Step 2: * Remove the page’s address-range from the process’ virtual address space. */ ret = munmap(page_to_addr(page), PAGE_SIZE); /* Check that it worked. */ if (ret == -1) { perror("munmap"); abort(); } /* * Step 3: * Update the page table entry for the page to be “not resident”. */ clear_page_entry(page); assert(!is_page_resident(page)); num_resident--; /* Inform the paging policy that the page was unmapped. */ policy_page_unmapped(page); }
/* This function maps the specified page from the swap file into the virtual * address space, and sets up the page permissions so that accesses and writes * to the page can be detected. */ void map_page(page_t page, unsigned initial_perm) { int ret; assert(page < NUM_PAGES); assert(initial_perm == PAGEPERM_NONE || initial_perm == PAGEPERM_READ || initial_perm == PAGEPERM_RDWR); assert(!is_page_resident(page)); /* Shouldn't already be mapped */ #if VERBOSE fprintf(stderr, "Mapping in page %u. Resident (before mapping) = %u, " "max resident = %u.\n", page, num_resident, max_resident); #endif /* Make sure we don't exceed the physical memory constraint. */ num_resident++; if (num_resident > max_resident) { fprintf(stderr, "map_page: exceeded physical memory, resident pages " "= %u, max resident = %u\n", num_resident, max_resident); abort(); } /* * Step 1: * Add the page’s address-range to the process’ virtual memory. * Use the flags MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS to force mmap() to * use the specified address, and to use the anonymous file so that the * page will initially be filled with zeros. */ /* Use mmap to add to virtual memory. */ void * vm_address = mmap(page_to_addr(page), PAGE_SIZE, pageperm_to_mmap(PAGEPERM_RDWR), MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS, -1, 0); /* Check that it worked. */ if (vm_address == (void *) -1) { perror("mmap"); abort(); } if (vm_address != page_to_addr(page)) { fprintf(stderr, "mmap: address changed\n"); abort(); } /* * Step 2: * Seek to the start of the corresponding slot in the swap file, read the * contents into the page. */ /* Seek. */ ret = lseek(fd_swapfile, page * PAGE_SIZE, (size_t) SEEK_SET); /* Check that it worked. */ if (ret == -1) { perror("lseek"); abort(); } /* Read contents. */ ret = read(fd_swapfile, page_to_addr(page), (size_t) PAGE_SIZE); /* Check that it worked. */ if (ret == -1) { perror("read"); abort(); } if (ret != PAGE_SIZE) { fprintf(stderr, "read: only read %d bytes (%d expected)\n", ret, PAGE_SIZE); abort(); } /* * Step 3: * Update the page table entry for the page to be resident, and set the * appropriate permissions on the page. */ set_page_resident(page); set_page_permission(page, initial_perm); assert(is_page_resident(page)); /* Now it should be mapped! */ num_loads++; /* Inform the paging policy that the page was mapped. */ policy_page_mapped(page); #if VERBOSE fprintf(stderr, "Successfully mapped in page %u with initial " "permission %u.\n Resident (after mapping) = %u.\n", page, initial_perm, num_resident); #endif }