Changes in kernel/generic/src/mm/backend_elf.c [8f80c77:55b77d9] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/mm/backend_elf.c
r8f80c77 r55b77d9 43 43 #include <mm/slab.h> 44 44 #include <mm/page.h> 45 #include <mm/reserve.h> 45 46 #include <genarch/mm/page_pt.h> 46 47 #include <genarch/mm/page_ht.h> … … 51 52 #include <arch/barrier.h> 52 53 53 #ifdef CONFIG_VIRT_IDX_DCACHE 54 #include <arch/mm/cache.h> 55 #endif 56 57 static int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access); 58 static void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame);59 static void elf_ share(as_area_t *area);54 static bool elf_create(as_area_t *); 55 static bool elf_resize(as_area_t *, size_t); 56 static void elf_share(as_area_t *); 57 static void elf_destroy(as_area_t *); 58 59 static int elf_page_fault(as_area_t *, uintptr_t, pf_access_t); 60 static void elf_frame_free(as_area_t *, uintptr_t, uintptr_t); 60 61 61 62 mem_backend_t elf_backend = { 63 .create = elf_create, 64 .resize = elf_resize, 65 .share = elf_share, 66 .destroy = elf_destroy, 67 62 68 .page_fault = elf_page_fault, 63 69 .frame_free = elf_frame_free, 64 .share = elf_share65 70 }; 71 72 static size_t elf_nonanon_pages_get(as_area_t *area) 73 { 74 elf_segment_header_t *entry = area->backend_data.segment; 75 uintptr_t first = ALIGN_UP(entry->p_vaddr, PAGE_SIZE); 76 uintptr_t last = ALIGN_DOWN(entry->p_vaddr + entry->p_filesz, 77 PAGE_SIZE); 78 79 if (entry->p_flags & PF_W) 80 return 0; 81 82 if (last < first) 83 return 0; 84 85 return last - first; 86 } 87 88 bool elf_create(as_area_t *area) 89 { 90 size_t nonanon_pages = elf_nonanon_pages_get(area); 91 92 if (area->pages <= nonanon_pages) 93 return true; 94 95 return reserve_try_alloc(area->pages - nonanon_pages); 96 } 97 98 bool elf_resize(as_area_t *area, size_t new_pages) 99 { 100 size_t nonanon_pages = elf_nonanon_pages_get(area); 101 102 if (new_pages > area->pages) { 103 /* The area is growing. */ 104 if (area->pages >= nonanon_pages) 105 return reserve_try_alloc(new_pages - area->pages); 106 else if (new_pages > nonanon_pages) 107 return reserve_try_alloc(new_pages - nonanon_pages); 108 } else if (new_pages < area->pages) { 109 /* The area is shrinking. */ 110 if (new_pages >= nonanon_pages) 111 reserve_free(area->pages - new_pages); 112 else if (area->pages > nonanon_pages) 113 reserve_free(nonanon_pages - new_pages); 114 } 115 116 return true; 117 } 118 119 /** Share ELF image backed address space area. 120 * 121 * If the area is writable, then all mapped pages are duplicated in the pagemap. 122 * Otherwise only portions of the area that are not backed by the ELF image 123 * are put into the pagemap. 124 * 125 * @param area Address space area. 126 */ 127 void elf_share(as_area_t *area) 128 { 129 elf_segment_header_t *entry = area->backend_data.segment; 130 link_t *cur; 131 btree_node_t *leaf, *node; 132 uintptr_t start_anon = entry->p_vaddr + entry->p_filesz; 133 134 ASSERT(mutex_locked(&area->as->lock)); 135 ASSERT(mutex_locked(&area->lock)); 136 137 /* 138 * Find the node in which to start linear search. 139 */ 140 if (area->flags & AS_AREA_WRITE) { 141 node = list_get_instance(list_first(&area->used_space.leaf_list), 142 btree_node_t, leaf_link); 143 } else { 144 (void) btree_search(&area->sh_info->pagemap, start_anon, &leaf); 145 node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap, 146 leaf); 147 if (!node) 148 node = leaf; 149 } 150 151 /* 152 * Copy used anonymous portions of the area to sh_info's page map. 153 */ 154 mutex_lock(&area->sh_info->lock); 155 for (cur = &node->leaf_link; cur != &area->used_space.leaf_list.head; 156 cur = cur->next) { 157 unsigned int i; 158 159 node = list_get_instance(cur, btree_node_t, leaf_link); 160 161 for (i = 0; i < node->keys; i++) { 162 uintptr_t base = node->key[i]; 163 size_t count = (size_t) node->value[i]; 164 unsigned int j; 165 166 /* 167 * Skip read-only areas of used space that are backed 168 * by the ELF image. 169 */ 170 if (!(area->flags & AS_AREA_WRITE)) 171 if (base >= entry->p_vaddr && 172 base + P2SZ(count) <= start_anon) 173 continue; 174 175 for (j = 0; j < count; j++) { 176 pte_t *pte; 177 178 /* 179 * Skip read-only pages that are backed by the 180 * ELF image. 181 */ 182 if (!(area->flags & AS_AREA_WRITE)) 183 if (base >= entry->p_vaddr && 184 base + P2SZ(j + 1) <= start_anon) 185 continue; 186 187 page_table_lock(area->as, false); 188 pte = page_mapping_find(area->as, 189 base + P2SZ(j), false); 190 ASSERT(pte && PTE_VALID(pte) && 191 PTE_PRESENT(pte)); 192 btree_insert(&area->sh_info->pagemap, 193 (base + P2SZ(j)) - area->base, 194 (void *) PTE_GET_FRAME(pte), NULL); 195 page_table_unlock(area->as, false); 196 197 pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(pte)); 198 frame_reference_add(pfn); 199 } 200 201 } 202 } 203 mutex_unlock(&area->sh_info->lock); 204 } 205 206 void elf_destroy(as_area_t *area) 207 { 208 size_t nonanon_pages = elf_nonanon_pages_get(area); 209 210 if (area->pages > nonanon_pages) 211 reserve_free(area->pages - nonanon_pages); 212 } 66 213 67 214 /** Service a page fault in the ELF backend address space area. … … 91 238 if (!as_area_check_access(area, access)) 92 239 return AS_PF_FAULT; 93 94 ASSERT((addr >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) && 95 (addr < entry->p_vaddr + entry->p_memsz)); 240 241 if (addr < ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) 242 return AS_PF_FAULT; 243 244 if (addr >= entry->p_vaddr + entry->p_memsz) 245 return AS_PF_FAULT; 246 96 247 i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH; 97 248 base = (uintptr_t) … … 153 304 */ 154 305 if (entry->p_flags & PF_W) { 155 frame = (uintptr_t)frame_alloc (ONE_FRAME, 0);306 frame = (uintptr_t)frame_alloc_noreserve(ONE_FRAME, 0); 156 307 memcpy((void *) PA2KA(frame), 157 308 (void *) (base + i * FRAME_SIZE), FRAME_SIZE); … … 171 322 * and cleared. 172 323 */ 173 frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);324 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0); 174 325 memsetb((void *) PA2KA(frame), FRAME_SIZE, 0); 175 326 dirty = true; … … 193 344 pad_hi = 0; 194 345 195 frame = (uintptr_t) frame_alloc(ONE_FRAME, 0);346 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0); 196 347 memcpy((void *) (PA2KA(frame) + pad_lo), 197 348 (void *) (base + i * FRAME_SIZE + pad_lo), … … 252 403 * data. 253 404 */ 254 frame_free (frame);405 frame_free_noreserve(frame); 255 406 } 256 407 } else { … … 260 411 * anonymous). In any case, a frame needs to be freed. 261 412 */ 262 frame_free(frame); 263 } 264 } 265 266 /** Share ELF image backed address space area. 267 * 268 * If the area is writable, then all mapped pages are duplicated in the pagemap. 269 * Otherwise only portions of the area that are not backed by the ELF image 270 * are put into the pagemap. 271 * 272 * @param area Address space area. 273 */ 274 void elf_share(as_area_t *area) 275 { 276 elf_segment_header_t *entry = area->backend_data.segment; 277 link_t *cur; 278 btree_node_t *leaf, *node; 279 uintptr_t start_anon = entry->p_vaddr + entry->p_filesz; 280 281 ASSERT(mutex_locked(&area->as->lock)); 282 ASSERT(mutex_locked(&area->lock)); 283 284 /* 285 * Find the node in which to start linear search. 286 */ 287 if (area->flags & AS_AREA_WRITE) { 288 node = list_get_instance(area->used_space.leaf_head.next, 289 btree_node_t, leaf_link); 290 } else { 291 (void) btree_search(&area->sh_info->pagemap, start_anon, &leaf); 292 node = btree_leaf_node_left_neighbour(&area->sh_info->pagemap, 293 leaf); 294 if (!node) 295 node = leaf; 296 } 297 298 /* 299 * Copy used anonymous portions of the area to sh_info's page map. 300 */ 301 mutex_lock(&area->sh_info->lock); 302 for (cur = &node->leaf_link; cur != &area->used_space.leaf_head; 303 cur = cur->next) { 304 unsigned int i; 305 306 node = list_get_instance(cur, btree_node_t, leaf_link); 307 308 for (i = 0; i < node->keys; i++) { 309 uintptr_t base = node->key[i]; 310 size_t count = (size_t) node->value[i]; 311 unsigned int j; 312 313 /* 314 * Skip read-only areas of used space that are backed 315 * by the ELF image. 316 */ 317 if (!(area->flags & AS_AREA_WRITE)) 318 if (base >= entry->p_vaddr && 319 base + count * PAGE_SIZE <= start_anon) 320 continue; 321 322 for (j = 0; j < count; j++) { 323 pte_t *pte; 324 325 /* 326 * Skip read-only pages that are backed by the 327 * ELF image. 328 */ 329 if (!(area->flags & AS_AREA_WRITE)) 330 if (base >= entry->p_vaddr && 331 base + (j + 1) * PAGE_SIZE <= 332 start_anon) 333 continue; 334 335 page_table_lock(area->as, false); 336 pte = page_mapping_find(area->as, 337 base + j * PAGE_SIZE); 338 ASSERT(pte && PTE_VALID(pte) && 339 PTE_PRESENT(pte)); 340 btree_insert(&area->sh_info->pagemap, 341 (base + j * PAGE_SIZE) - area->base, 342 (void *) PTE_GET_FRAME(pte), NULL); 343 page_table_unlock(area->as, false); 344 345 pfn_t pfn = ADDR2PFN(PTE_GET_FRAME(pte)); 346 frame_reference_add(pfn); 347 } 348 349 } 350 } 351 mutex_unlock(&area->sh_info->lock); 413 frame_free_noreserve(frame); 414 } 352 415 } 353 416
Note:
See TracChangeset
for help on using the changeset viewer.