Rev 1264 | Rev 1411 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 1264 | Rev 1409 | ||
|---|---|---|---|
| Line 39... | Line 39... | ||
| 39 | #include <mm/frame.h> |
39 | #include <mm/frame.h> |
| 40 | #include <mm/slab.h> |
40 | #include <mm/slab.h> |
| 41 | #include <align.h> |
41 | #include <align.h> |
| 42 | #include <memstr.h> |
42 | #include <memstr.h> |
| 43 | #include <macros.h> |
43 | #include <macros.h> |
| - | 44 | #include <arch.h> |
|
| 44 | 45 | ||
| 45 | static char *error_codes[] = { |
46 | static char *error_codes[] = { |
| 46 | "no error", |
47 | "no error", |
| 47 | "invalid image", |
48 | "invalid image", |
| 48 | "address space error", |
49 | "address space error", |
| Line 53... | Line 54... | ||
| 53 | 54 | ||
| 54 | static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as); |
55 | static int segment_header(elf_segment_header_t *entry, elf_header_t *elf, as_t *as); |
| 55 | static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as); |
56 | static int section_header(elf_section_header_t *entry, elf_header_t *elf, as_t *as); |
| 56 | static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as); |
57 | static int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as); |
| 57 | 58 | ||
| - | 59 | static int elf_page_fault(as_area_t *area, __address addr); |
|
| - | 60 | static void elf_frame_free(as_area_t *area, __address page, __address frame); |
|
| - | 61 | ||
| - | 62 | mem_backend_t elf_backend = { |
|
| - | 63 | .backend_page_fault = elf_page_fault, |
|
| - | 64 | .backend_frame_free = elf_frame_free |
|
| - | 65 | }; |
|
| - | 66 | ||
| 58 | /** ELF loader |
67 | /** ELF loader |
| 59 | * |
68 | * |
| 60 | * @param header Pointer to ELF header in memory |
69 | * @param header Pointer to ELF header in memory |
| 61 | * @param as Created and properly mapped address space |
70 | * @param as Created and properly mapped address space |
| 62 | * @return EE_OK on success |
71 | * @return EE_OK on success |
| Line 157... | Line 166... | ||
| 157 | * @return EE_OK on success, error code otherwise. |
166 | * @return EE_OK on success, error code otherwise. |
| 158 | */ |
167 | */ |
| 159 | int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as) |
168 | int load_segment(elf_segment_header_t *entry, elf_header_t *elf, as_t *as) |
| 160 | { |
169 | { |
| 161 | as_area_t *a; |
170 | as_area_t *a; |
| 162 | int i, flags = 0; |
171 | int flags = 0; |
| 163 | size_t segment_size; |
172 | void *backend_data[2] = { elf, entry }; |
| 164 | __u8 *segment; |
- | |
| 165 | 173 | ||
| 166 | if (entry->p_align > 1) { |
174 | if (entry->p_align > 1) { |
| 167 | if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) { |
175 | if ((entry->p_offset % entry->p_align) != (entry->p_vaddr % entry->p_align)) { |
| 168 | return EE_INVALID; |
176 | return EE_INVALID; |
| 169 | } |
177 | } |
| Line 180... | Line 188... | ||
| 180 | * Check if the virtual address starts on page boundary. |
188 | * Check if the virtual address starts on page boundary. |
| 181 | */ |
189 | */ |
| 182 | if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) |
190 | if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) |
| 183 | return EE_UNSUPPORTED; |
191 | return EE_UNSUPPORTED; |
| 184 | 192 | ||
| 185 | segment_size = ALIGN_UP(max(entry->p_filesz, entry->p_memsz), PAGE_SIZE); |
- | |
| 186 | if ((entry->p_flags & PF_W)) { |
- | |
| 187 | /* If writable, copy data (should be COW in the future) */ |
- | |
| 188 | segment = malloc(segment_size, 0); |
- | |
| 189 | memsetb((__address) (segment + entry->p_filesz), segment_size - entry->p_filesz, 0); |
- | |
| 190 | memcpy(segment, (void *) (((__address) elf) + entry->p_offset), entry->p_filesz); |
- | |
| 191 | } else /* Map identically original data */ |
- | |
| 192 | segment = ((void *) elf) + entry->p_offset; |
- | |
| 193 | - | ||
| 194 | a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE); |
193 | a = as_area_create(as, flags, entry->p_memsz, entry->p_vaddr, AS_AREA_ATTR_NONE, &elf_backend, backend_data); |
| 195 | if (!a) |
194 | if (!a) |
| 196 | return EE_MEMORY; |
195 | return EE_MEMORY; |
| 197 | 196 | ||
| - | 197 | /* |
|
| 198 | for (i = 0; i < SIZE2FRAMES(entry->p_filesz); i++) { |
198 | * The segment will be mapped on demand by elf_page_fault(). |
| 199 | as_set_mapping(as, entry->p_vaddr + i*PAGE_SIZE, KA2PA(((__address) segment) + i*PAGE_SIZE)); |
- | |
| 200 | } |
199 | */ |
| 201 | 200 | ||
| 202 | return EE_OK; |
201 | return EE_OK; |
| 203 | } |
202 | } |
| 204 | 203 | ||
| 205 | /** Process section header. |
204 | /** Process section header. |
| 206 | * |
205 | * |
| Line 217... | Line 216... | ||
| 217 | break; |
216 | break; |
| 218 | } |
217 | } |
| 219 | 218 | ||
| 220 | return EE_OK; |
219 | return EE_OK; |
| 221 | } |
220 | } |
| - | 221 | ||
| - | 222 | /** Service a page fault in the ELF backend address space area. |
|
| - | 223 | * |
|
| - | 224 | * The address space area and page tables must be already locked. |
|
| - | 225 | * |
|
| - | 226 | * @param area Pointer to the address space area. |
|
| - | 227 | * @param addr Faulting virtual address. |
|
| - | 228 | * |
|
| - | 229 | * @return AS_PF_FAULT on failure (i.e. page fault) or AS_PF_OK on success (i.e. serviced). |
|
| - | 230 | */ |
|
| - | 231 | int elf_page_fault(as_area_t *area, __address addr) |
|
| - | 232 | { |
|
| - | 233 | elf_header_t *elf = (elf_header_t *) area->backend_data[0]; |
|
| - | 234 | elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1]; |
|
| - | 235 | __address base, frame; |
|
| - | 236 | index_t i; |
|
| - | 237 | ||
| - | 238 | ASSERT((addr >= entry->p_vaddr) && (addr < entry->p_vaddr + entry->p_memsz)); |
|
| - | 239 | i = (addr - entry->p_vaddr) >> PAGE_WIDTH; |
|
| - | 240 | base = (__address) (((void *) elf) + entry->p_offset); |
|
| - | 241 | ASSERT(ALIGN_UP(base, FRAME_SIZE) == base); |
|
| - | 242 | ||
| - | 243 | if (ALIGN_DOWN(addr, PAGE_SIZE) + PAGE_SIZE < entry->p_vaddr + entry->p_filesz) { |
|
| - | 244 | /* |
|
| - | 245 | * Initialized portion of the segment. The memory is backed |
|
| - | 246 | * directly by the content of the ELF image. Pages are |
|
| - | 247 | * only copied if the segment is writable so that there |
|
| - | 248 | * can be more instantions of the same memory ELF image |
|
| - | 249 | * used at a time. Note that this could be later done |
|
| - | 250 | * as COW. |
|
| - | 251 | */ |
|
| - | 252 | if (entry->p_flags & PF_W) { |
|
| - | 253 | frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0)); |
|
| - | 254 | memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), FRAME_SIZE); |
|
| - | 255 | } else { |
|
| - | 256 | frame = KA2PA(base + i*FRAME_SIZE); |
|
| - | 257 | } |
|
| - | 258 | } else if (ALIGN_DOWN(addr, PAGE_SIZE) >= ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) { |
|
| - | 259 | /* |
|
| - | 260 | * This is the uninitialized portion of the segment. |
|
| - | 261 | * It is not physically present in the ELF image. |
|
| - | 262 | * To resolve the situation, a frame must be allocated |
|
| - | 263 | * and cleared. |
|
| - | 264 | */ |
|
| - | 265 | frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0)); |
|
| - | 266 | memsetb(PA2KA(frame), FRAME_SIZE, 0); |
|
| - | 267 | } else { |
|
| - | 268 | size_t size; |
|
| - | 269 | /* |
|
| - | 270 | * The mixed case. |
|
| - | 271 | * The lower part is backed by the ELF image and |
|
| - | 272 | * the upper part is anonymous memory. |
|
| - | 273 | */ |
|
| - | 274 | size = entry->p_filesz - (i<<PAGE_WIDTH); |
|
| - | 275 | frame = PFN2ADDR(frame_alloc(ONE_FRAME, 0)); |
|
| - | 276 | memsetb(PA2KA(frame) + size, FRAME_SIZE - size, 0); |
|
| - | 277 | memcpy((void *) PA2KA(frame), (void *) (base + i*FRAME_SIZE), size); |
|
| - | 278 | } |
|
| - | 279 | ||
| - | 280 | page_mapping_insert(AS, addr, frame, as_area_get_flags(area)); |
|
| - | 281 | if (!used_space_insert(area, ALIGN_DOWN(addr, PAGE_SIZE), 1)) |
|
| - | 282 | panic("Could not insert used space.\n"); |
|
| - | 283 | ||
| - | 284 | return AS_PF_OK; |
|
| - | 285 | } |
|
| - | 286 | ||
| - | 287 | /** Free a frame that is backed by the ELF backend. |
|
| - | 288 | * |
|
| - | 289 | * The address space area and page tables must be already locked. |
|
| - | 290 | * |
|
| - | 291 | * @param area Pointer to the address space area. |
|
| - | 292 | * @param page Page that is mapped to frame. Must be aligned to PAGE_SIZE. |
|
| - | 293 | * @param frame Frame to be released. |
|
| - | 294 | * |
|
| - | 295 | */ |
|
| - | 296 | void elf_frame_free(as_area_t *area, __address page, __address frame) |
|
| - | 297 | { |
|
| - | 298 | elf_header_t *elf = (elf_header_t *) area->backend_data[0]; |
|
| - | 299 | elf_segment_header_t *entry = (elf_segment_header_t *) area->backend_data[1]; |
|
| - | 300 | __address base; |
|
| - | 301 | index_t i; |
|
| - | 302 | ||
| - | 303 | ASSERT((page >= entry->p_vaddr) && (page < entry->p_vaddr + entry->p_memsz)); |
|
| - | 304 | i = (page - entry->p_vaddr) >> PAGE_WIDTH; |
|
| - | 305 | base = (__address) (((void *) elf) + entry->p_offset); |
|
| - | 306 | ASSERT(ALIGN_UP(base, FRAME_SIZE) == base); |
|
| - | 307 | ||
| - | 308 | if (page + PAGE_SIZE < ALIGN_UP(entry->p_vaddr + entry->p_filesz, PAGE_SIZE)) { |
|
| - | 309 | if (entry->p_flags & PF_W) { |
|
| - | 310 | /* |
|
| - | 311 | * Free the frame with the copy of writable segment data. |
|
| - | 312 | */ |
|
| - | 313 | frame_free(ADDR2PFN(frame)); |
|
| - | 314 | } |
|
| - | 315 | } else { |
|
| - | 316 | /* |
|
| - | 317 | * The frame is either anonymous memory or the mixed case (i.e. lower |
|
| - | 318 | * part is backed by the ELF image and the upper is anonymous). |
|
| - | 319 | * In any case, a frame needs to be freed. |
|
| - | 320 | */ |
|
| - | 321 | frame_free(ADDR2PFN(frame)); |
|
| - | 322 | } |
|
| - | 323 | } |
|