// buf: buffer returned by mmap_file() // size: same size as supplied to the mmap_file() void unmap(void* buf, size_t size) { assert(buf); uintptr_t end = page_ceil((uintptr_t)buf + size); uintptr_t start = page_floor((uintptr_t)buf); assert(end > (uintptr_t)buf); size_t len = end - start; if (munmap((void*)start, len) < 0) err(1, "munmap failed"); }
// mmap file content at given offset // use unmap to release the mapping void* mmap_file(int fd, off_t offset, size_t size) { off_t offset_end = offset + size; assert(offset >= 0); assert(offset_end >= offset); // No overflow uintptr_t end = page_ceil(offset_end); uintptr_t start = page_floor(offset); uintptr_t len = end - start; void* buf = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, start); if (buf == MAP_FAILED) err(1, "mmap failed"); return ((void *)((uintptr_t)buf + (offset - start))); }
void elflink_parse_load( elfinfo_t *elf, Elf32_Phdr *hdr ) { Elf32_Addr rstart, rend; Elf32_Addr fstart, fend, frend; Elf32_Addr caddr, cend, cmaddr; physaddr_t cphys, pstart, fphys, cdstart, cfstart, csz, psz; int flags; /* Determine base address */ if ( elf->base == 0xFFFFFFFF ) { elf->base = page_floor( hdr->p_vaddr ); elf->mbase = platldr_start_image( elf->id ); } /* Setup page flags */ flags = PAGE_FLAG_GLOBAL; if ( hdr->p_flags & PF_R ) flags |= PAGE_PERM_R; if ( hdr->p_flags & PF_W ) flags |= PAGE_PERM_W; if ( hdr->p_flags & PF_X ) flags |= PAGE_PERM_X; //Note: Assume page size power of 2 /* Calculate the page boundaries of the LOAD */ rstart = page_floor( hdr->p_vaddr ); rend = page_ceil( hdr->p_vaddr + hdr->p_memsz ); fstart = hdr->p_vaddr; fend = hdr->p_vaddr + hdr->p_filesz; /* pstart contains the physical offset of the segment data */ pstart = (physaddr_t) elf->pstart; pstart += page_floor(hdr->p_offset); /* Calculate the page boundary of the last filled page */ frend = page_ceil(fend); /* Determine image end address */ if ( rend > elf->end ) elf->end = rend; /* Map all pages containing file data */ for ( caddr = rstart; caddr < frend; caddr = cend ) { cend = caddr + ARCH_PAGE_SIZE; cmaddr = (caddr - elf->base) + elf->mbase; cphys = fphys = caddr - rstart + pstart; if ( caddr < fstart ) { /* This page does not fully contain the file */ /* Allocate a fresh frame for this page */ cphys = physmm_alloc_frame(); /* Calculate the padding size */ psz = fstart - caddr; /* Clear the padded start */ memset( (void *) cphys, 0, psz ); /* Calculate the offsets */ cdstart = cphys + psz; cfstart = fphys + psz; csz = cend - fstart; // printf("Copy over: 0x%x to 0x%x\n", cfstart, cdstart ); /* Copy in the data */ memcpy( (void *) cdstart, (void *) cfstart, csz ); } else if ( cend > fend ) { /* This page does not fully contain the file */ /* Allocate a fresh frame for this page */ cphys = physmm_alloc_frame(); /* Calculate the padding size */ psz = cend - fend; /* Calculate the data size and padding start */ csz = fend - caddr; cdstart = cphys + csz; /* Clear the padded end */ memset( (void *) cdstart, 0, psz ); // printf("Copy over: 0x%x to 0x%x %x bytes\n", fphys, cphys, // csz); /* Copy in the data */ memcpy( (void *) cphys, (void *) fphys, csz ); } /* If the page fully contains the file, map it */ // else printf("Nocopy\n"); platldr_map( elf->id, cmaddr, cphys, flags ); } /* Map all pages which should not contain file data */ for ( caddr = frend; caddr < rend; caddr = cend ) { cend = caddr + ARCH_PAGE_SIZE; cphys = physmm_alloc_frame(); cmaddr = (caddr - elf->base) + elf->mbase; memset( (void *) cphys, 0, ARCH_PAGE_SIZE ); platldr_map( elf->id, cmaddr, cphys, flags ); } }