Changes in kernel/generic/src/mm/backend_elf.c [55b77d9:8f80c77] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/mm/backend_elf.c
r55b77d9 r8f80c77 43 43 #include <mm/slab.h> 44 44 #include <mm/page.h> 45 #include <mm/reserve.h>46 45 #include <genarch/mm/page_pt.h> 47 46 #include <genarch/mm/page_ht.h> … … 52 51 #include <arch/barrier.h> 53 52 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);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); 61 60 62 61 mem_backend_t elf_backend = { 63 .create = elf_create,64 .resize = elf_resize,65 .share = elf_share,66 .destroy = elf_destroy,67 68 62 .page_fault = elf_page_fault, 69 63 .frame_free = elf_frame_free, 64 .share = elf_share 70 65 }; 71 66 72 static size_t elf_nonanon_pages_get(as_area_t *area) 67 /** Service a page fault in the ELF backend address space area. 68 * 69 * The address space area and page tables must be already locked. 70 * 71 * @param area Pointer to the address space area. 72 * @param addr Faulting virtual address. 73 * @param access Access mode that caused the fault (i.e. 74 * read/write/exec). 75 * 76 * @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK 77 * on success (i.e. serviced). 78 */ 79 int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access) 80 { 81 elf_header_t *elf = area->backend_data.elf; 82 elf_segment_header_t *entry = area->backend_data.segment; 83 btree_node_t *leaf; 84 uintptr_t base, frame, page, start_anon; 85 size_t i; 86 bool dirty = false; 87 88 ASSERT(page_table_locked(AS)); 89 ASSERT(mutex_locked(&area->lock)); 90 91 if (!as_area_check_access(area, access)) 92 return AS_PF_FAULT; 93 94 ASSERT((addr >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) && 95 (addr < entry->p_vaddr + entry->p_memsz)); 96 i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH; 97 base = (uintptr_t) 98 (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE)); 99 100 /* Virtual address of faulting page*/ 101 page = ALIGN_DOWN(addr, PAGE_SIZE); 102 103 /* Virtual address of the end of initialized part of segment */ 104 start_anon = entry->p_vaddr + entry->p_filesz; 105 106 if (area->sh_info) { 107 bool found = false; 108 109 /* 110 * The address space area is shared. 111 */ 112 113 mutex_lock(&area->sh_info->lock); 114 frame = (uintptr_t) btree_search(&area->sh_info->pagemap, 115 page - area->base, &leaf); 116 if (!frame) { 117 unsigned int i; 118 119 /* 120 * Workaround for valid NULL address. 121 */ 122 123 for (i = 0; i < leaf->keys; i++) { 124 if (leaf->key[i] == page - area->base) { 125 found = true; 126 break; 127 } 128 } 129 } 130 if (frame || found) { 131 frame_reference_add(ADDR2PFN(frame)); 132 page_mapping_insert(AS, addr, frame, 133 as_area_get_flags(area)); 134 if (!used_space_insert(area, page, 1)) 135 panic("Cannot insert used space."); 136 mutex_unlock(&area->sh_info->lock); 137 return AS_PF_OK; 138 } 139 } 140 141 /* 142 * The area is either not shared or the pagemap does not contain the 143 * mapping. 144 */ 145 if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) { 146 /* 147 * Initialized portion of the segment. The memory is backed 148 * directly by the content of the ELF image. Pages are 149 * only copied if the segment is writable so that there 150 * can be more instantions of the same memory ELF image 151 * used at a time. Note that this could be later done 152 * as COW. 153 */ 154 if (entry->p_flags & PF_W) { 155 frame = (uintptr_t)frame_alloc(ONE_FRAME, 0); 156 memcpy((void *) PA2KA(frame), 157 (void *) (base + i * FRAME_SIZE), FRAME_SIZE); 158 if (entry->p_flags & PF_X) { 159 smc_coherence_block((void *) PA2KA(frame), 160 FRAME_SIZE); 161 } 162 dirty = true; 163 } else { 164 frame = KA2PA(base + i * FRAME_SIZE); 165 } 166 } else if (page >= start_anon) { 167 /* 168 * This is the uninitialized portion of the segment. 169 * It is not physically present in the ELF image. 170 * To resolve the situation, a frame must be allocated 171 * and cleared. 172 */ 173 frame = (uintptr_t)frame_alloc(ONE_FRAME, 0); 174 memsetb((void *) PA2KA(frame), FRAME_SIZE, 0); 175 dirty = true; 176 } else { 177 size_t pad_lo, pad_hi; 178 /* 179 * The mixed case. 180 * 181 * The middle part is backed by the ELF image and 182 * the lower and upper parts are anonymous memory. 183 * (The segment can be and often is shorter than 1 page). 184 */ 185 if (page < entry->p_vaddr) 186 pad_lo = entry->p_vaddr - page; 187 else 188 pad_lo = 0; 189 190 if (start_anon < page + PAGE_SIZE) 191 pad_hi = page + PAGE_SIZE - start_anon; 192 else 193 pad_hi = 0; 194 195 frame = (uintptr_t)frame_alloc(ONE_FRAME, 0); 196 memcpy((void *) (PA2KA(frame) + pad_lo), 197 (void *) (base + i * FRAME_SIZE + pad_lo), 198 FRAME_SIZE - pad_lo - pad_hi); 199 if (entry->p_flags & PF_X) { 200 smc_coherence_block((void *) (PA2KA(frame) + pad_lo), 201 FRAME_SIZE - pad_lo - pad_hi); 202 } 203 memsetb((void *) PA2KA(frame), pad_lo, 0); 204 memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi, 205 0); 206 dirty = true; 207 } 208 209 if (dirty && area->sh_info) { 210 frame_reference_add(ADDR2PFN(frame)); 211 btree_insert(&area->sh_info->pagemap, page - area->base, 212 (void *) frame, leaf); 213 } 214 215 if (area->sh_info) 216 mutex_unlock(&area->sh_info->lock); 217 218 page_mapping_insert(AS, addr, frame, as_area_get_flags(area)); 219 if (!used_space_insert(area, page, 1)) 220 panic("Cannot insert used space."); 221 222 return AS_PF_OK; 223 } 224 225 /** Free a frame that is backed by the ELF backend. 226 * 227 * The address space area and page tables must be already locked. 228 * 229 * @param area Pointer to the address space area. 230 * @param page Page that is mapped to frame. Must be aligned to 231 * PAGE_SIZE. 232 * @param frame Frame to be released. 233 * 234 */ 235 void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame) 73 236 { 74 237 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; 238 uintptr_t start_anon; 239 240 ASSERT(page_table_locked(area->as)); 241 ASSERT(mutex_locked(&area->lock)); 242 243 ASSERT(page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)); 244 ASSERT(page < entry->p_vaddr + entry->p_memsz); 245 246 start_anon = entry->p_vaddr + entry->p_filesz; 247 248 if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) { 249 if (entry->p_flags & PF_W) { 250 /* 251 * Free the frame with the copy of writable segment 252 * data. 253 */ 254 frame_free(frame); 255 } 256 } else { 257 /* 258 * The frame is either anonymous memory or the mixed case (i.e. 259 * lower part is backed by the ELF image and the upper is 260 * anonymous). In any case, a frame needs to be freed. 261 */ 262 frame_free(frame); 263 } 117 264 } 118 265 … … 139 286 */ 140 287 if (area->flags & AS_AREA_WRITE) { 141 node = list_get_instance( list_first(&area->used_space.leaf_list),288 node = list_get_instance(area->used_space.leaf_head.next, 142 289 btree_node_t, leaf_link); 143 290 } else { … … 153 300 */ 154 301 mutex_lock(&area->sh_info->lock); 155 for (cur = &node->leaf_link; cur != &area->used_space.leaf_ list.head;302 for (cur = &node->leaf_link; cur != &area->used_space.leaf_head; 156 303 cur = cur->next) { 157 304 unsigned int i; … … 170 317 if (!(area->flags & AS_AREA_WRITE)) 171 318 if (base >= entry->p_vaddr && 172 base + P2SZ(count)<= start_anon)319 base + count * PAGE_SIZE <= start_anon) 173 320 continue; 174 321 … … 182 329 if (!(area->flags & AS_AREA_WRITE)) 183 330 if (base >= entry->p_vaddr && 184 base + P2SZ(j + 1) <= start_anon) 331 base + (j + 1) * PAGE_SIZE <= 332 start_anon) 185 333 continue; 186 334 187 335 page_table_lock(area->as, false); 188 336 pte = page_mapping_find(area->as, 189 base + P2SZ(j), false);337 base + j * PAGE_SIZE); 190 338 ASSERT(pte && PTE_VALID(pte) && 191 339 PTE_PRESENT(pte)); 192 340 btree_insert(&area->sh_info->pagemap, 193 (base + P2SZ(j)) - area->base,341 (base + j * PAGE_SIZE) - area->base, 194 342 (void *) PTE_GET_FRAME(pte), NULL); 195 343 page_table_unlock(area->as, false); … … 204 352 } 205 353 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 }213 214 /** Service a page fault in the ELF backend address space area.215 *216 * The address space area and page tables must be already locked.217 *218 * @param area Pointer to the address space area.219 * @param addr Faulting virtual address.220 * @param access Access mode that caused the fault (i.e.221 * read/write/exec).222 *223 * @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK224 * on success (i.e. serviced).225 */226 int elf_page_fault(as_area_t *area, uintptr_t addr, pf_access_t access)227 {228 elf_header_t *elf = area->backend_data.elf;229 elf_segment_header_t *entry = area->backend_data.segment;230 btree_node_t *leaf;231 uintptr_t base, frame, page, start_anon;232 size_t i;233 bool dirty = false;234 235 ASSERT(page_table_locked(AS));236 ASSERT(mutex_locked(&area->lock));237 238 if (!as_area_check_access(area, access))239 return AS_PF_FAULT;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 247 i = (addr - ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE)) >> PAGE_WIDTH;248 base = (uintptr_t)249 (((void *) elf) + ALIGN_DOWN(entry->p_offset, PAGE_SIZE));250 251 /* Virtual address of faulting page*/252 page = ALIGN_DOWN(addr, PAGE_SIZE);253 254 /* Virtual address of the end of initialized part of segment */255 start_anon = entry->p_vaddr + entry->p_filesz;256 257 if (area->sh_info) {258 bool found = false;259 260 /*261 * The address space area is shared.262 */263 264 mutex_lock(&area->sh_info->lock);265 frame = (uintptr_t) btree_search(&area->sh_info->pagemap,266 page - area->base, &leaf);267 if (!frame) {268 unsigned int i;269 270 /*271 * Workaround for valid NULL address.272 */273 274 for (i = 0; i < leaf->keys; i++) {275 if (leaf->key[i] == page - area->base) {276 found = true;277 break;278 }279 }280 }281 if (frame || found) {282 frame_reference_add(ADDR2PFN(frame));283 page_mapping_insert(AS, addr, frame,284 as_area_get_flags(area));285 if (!used_space_insert(area, page, 1))286 panic("Cannot insert used space.");287 mutex_unlock(&area->sh_info->lock);288 return AS_PF_OK;289 }290 }291 292 /*293 * The area is either not shared or the pagemap does not contain the294 * mapping.295 */296 if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {297 /*298 * Initialized portion of the segment. The memory is backed299 * directly by the content of the ELF image. Pages are300 * only copied if the segment is writable so that there301 * can be more instantions of the same memory ELF image302 * used at a time. Note that this could be later done303 * as COW.304 */305 if (entry->p_flags & PF_W) {306 frame = (uintptr_t)frame_alloc_noreserve(ONE_FRAME, 0);307 memcpy((void *) PA2KA(frame),308 (void *) (base + i * FRAME_SIZE), FRAME_SIZE);309 if (entry->p_flags & PF_X) {310 smc_coherence_block((void *) PA2KA(frame),311 FRAME_SIZE);312 }313 dirty = true;314 } else {315 frame = KA2PA(base + i * FRAME_SIZE);316 }317 } else if (page >= start_anon) {318 /*319 * This is the uninitialized portion of the segment.320 * It is not physically present in the ELF image.321 * To resolve the situation, a frame must be allocated322 * and cleared.323 */324 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);325 memsetb((void *) PA2KA(frame), FRAME_SIZE, 0);326 dirty = true;327 } else {328 size_t pad_lo, pad_hi;329 /*330 * The mixed case.331 *332 * The middle part is backed by the ELF image and333 * the lower and upper parts are anonymous memory.334 * (The segment can be and often is shorter than 1 page).335 */336 if (page < entry->p_vaddr)337 pad_lo = entry->p_vaddr - page;338 else339 pad_lo = 0;340 341 if (start_anon < page + PAGE_SIZE)342 pad_hi = page + PAGE_SIZE - start_anon;343 else344 pad_hi = 0;345 346 frame = (uintptr_t) frame_alloc_noreserve(ONE_FRAME, 0);347 memcpy((void *) (PA2KA(frame) + pad_lo),348 (void *) (base + i * FRAME_SIZE + pad_lo),349 FRAME_SIZE - pad_lo - pad_hi);350 if (entry->p_flags & PF_X) {351 smc_coherence_block((void *) (PA2KA(frame) + pad_lo),352 FRAME_SIZE - pad_lo - pad_hi);353 }354 memsetb((void *) PA2KA(frame), pad_lo, 0);355 memsetb((void *) (PA2KA(frame) + FRAME_SIZE - pad_hi), pad_hi,356 0);357 dirty = true;358 }359 360 if (dirty && area->sh_info) {361 frame_reference_add(ADDR2PFN(frame));362 btree_insert(&area->sh_info->pagemap, page - area->base,363 (void *) frame, leaf);364 }365 366 if (area->sh_info)367 mutex_unlock(&area->sh_info->lock);368 369 page_mapping_insert(AS, addr, frame, as_area_get_flags(area));370 if (!used_space_insert(area, page, 1))371 panic("Cannot insert used space.");372 373 return AS_PF_OK;374 }375 376 /** Free a frame that is backed by the ELF backend.377 *378 * The address space area and page tables must be already locked.379 *380 * @param area Pointer to the address space area.381 * @param page Page that is mapped to frame. Must be aligned to382 * PAGE_SIZE.383 * @param frame Frame to be released.384 *385 */386 void elf_frame_free(as_area_t *area, uintptr_t page, uintptr_t frame)387 {388 elf_segment_header_t *entry = area->backend_data.segment;389 uintptr_t start_anon;390 391 ASSERT(page_table_locked(area->as));392 ASSERT(mutex_locked(&area->lock));393 394 ASSERT(page >= ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE));395 ASSERT(page < entry->p_vaddr + entry->p_memsz);396 397 start_anon = entry->p_vaddr + entry->p_filesz;398 399 if (page >= entry->p_vaddr && page + PAGE_SIZE <= start_anon) {400 if (entry->p_flags & PF_W) {401 /*402 * Free the frame with the copy of writable segment403 * data.404 */405 frame_free_noreserve(frame);406 }407 } else {408 /*409 * The frame is either anonymous memory or the mixed case (i.e.410 * lower part is backed by the ELF image and the upper is411 * anonymous). In any case, a frame needs to be freed.412 */413 frame_free_noreserve(frame);414 }415 }416 417 354 /** @} 418 355 */
Note:
See TracChangeset
for help on using the changeset viewer.