示例#1
0
文件: mmap.c 项目: rrohit25/Avengers
/*
 * This function implements the mmap(2) syscall, but only
 * supports the MAP_SHARED, MAP_PRIVATE, MAP_FIXED, and
 * MAP_ANON flags.
 *
 * Add a mapping to the current process's address space.
 * You need to do some error checking; see the ERRORS section
 * of the manpage for the problems you should anticipate.
 * After error checking most of the work of this function is
 * done by vmmap_map(), but remember to clear the TLB.
 */
int
do_mmap(void *addr, size_t len, int prot, int flags,int fd, off_t off, void **ret)
{
	/*NOT_YET_IMPLEMENTED("VM: do_mmap");*/

	int address = (uintptr_t) addr;

	tlb_flush(address);

	KASSERT(NULL != curproc->p_pagedir);
	dbg(DBG_PRINT, "(GRADING3A 2.a)curproc->p_pagedir; first ten bits of the virtual address is NOT NULL\n ");

	vmmap_map(curproc->p_vmmap, curproc->p_files[fd]->f_vnode, 0, 0, prot, flags, off, NULL, (vmarea_t**) ret);
	return 0;


}
示例#2
0
文件: mmap.c 项目: ketapate/kernel_3
/*
 * This function implements the mmap(2) syscall, but only
 * supports the MAP_SHARED, MAP_PRIVATE, MAP_FIXED, and
 * MAP_ANON flags.
 *
 * Add a mapping to the current process's address space.
 * You need to do some error checking; see the ERRORS section
 * of the manpage for the problems you should anticipate.
 * After error checking most of the work of this function is
 * done by vmmap_map(), but remember to clear the TLB.
 */
int
do_mmap(void *addr, size_t len, int prot, int flags,
        int fd, off_t off, void **ret)
{
    /*NOT_YET_IMPLEMENTED("VM: do_mmap");*/
    
    if(((flags & MAP_FIXED) == MAP_FIXED) && ((size_t)addr < USER_MEM_LOW || (size_t)addr >= USER_MEM_HIGH)){
        return (int)MAP_FAILED;
    }
    
    
    if(!PAGE_ALIGNED(addr) || /*!PAGE_ALIGNED(len) ||*/ !PAGE_ALIGNED(off)){
        dbg(DBG_PRINT,"Error: do_mmap failed due to addr or len or off is not page aligned!\n");
        return (int)MAP_FAILED;
    }
    
    if((len <= 0) || (len >= USER_MEM_HIGH - USER_MEM_LOW)){
        dbg(DBG_PRINT,"Error: do_mmap failed due to len is <= 0!\n");
        return (int)MAP_FAILED;
    }
    
    if (!(((flags & MAP_PRIVATE) == MAP_PRIVATE) || ((flags & MAP_SHARED) == MAP_SHARED))) {
        return (int)MAP_FAILED;
    }
    
    if (((fd >= NFILES) || ( fd < 0)) && ((flags & MAP_ANON) != MAP_ANON)) {
        dbg(DBG_PRINT,"ERROR!!! fd = %d is out of range\n", fd);
        return (int)MAP_FAILED;
    }
   
    file_t *file = NULL;
    if ((flags & MAP_ANON) != MAP_ANON) {
        file = fget(fd);
    
    
        if (file == NULL) {
            return (int)MAP_FAILED;
        }
        if (((flags & MAP_PRIVATE) == MAP_PRIVATE) && ((file->f_mode & FMODE_READ) != FMODE_READ)) {
            fput(file);
            return (int)MAP_FAILED;
        }
        if (((flags & MAP_SHARED)==MAP_SHARED) && ((prot & PROT_WRITE) == PROT_WRITE) && /*(((file->f_mode & FMODE_READ )!=FMODE_READ)&&*/((file->f_mode &FMODE_WRITE)!=FMODE_WRITE)) {
            fput(file);
            return (int)MAP_FAILED;
        }
        if (((prot & PROT_WRITE)==PROT_WRITE)&&(file->f_mode==FMODE_APPEND)) {
            fput(file);
            return (int)MAP_FAILED;
        }
        if(file->f_vnode->vn_flags == VN_BUSY){
            fput(file);
            return (int)MAP_FAILED;
        }

    }

    *ret = NULL;
    vmmap_t *map = curproc->p_vmmap;
    uint32_t lopage;
    uint32_t npages;
    vmarea_t *vma;
    
    lopage = ADDR_TO_PN(addr);
    
    uint32_t hipage = ADDR_TO_PN((size_t)addr + len - 1) + 1; 
    /*uint32_t hipage = ADDR_TO_PN((size_t)addr + len) + 1;*/
    npages = hipage - lopage;
    int dir = VMMAP_DIR_HILO; /* see elf32.c */
    
    int retval;
    if ((flags & MAP_ANON) != MAP_ANON) {
        retval = vmmap_map(map, file->f_vnode, lopage, npages, prot, flags, off, dir, &vma);
    } else {
        retval = vmmap_map(map, NULL, lopage, npages, prot, flags, off, dir, &vma);
    }

    if(retval < 0){
        if ((flags & MAP_ANON) != MAP_ANON) {
            fput(file);
        }
        dbg(DBG_PRINT,"Error: The mapping of the vmarea was unsuccessful\n");
        return (int)MAP_FAILED;
    }

    *ret = PN_TO_ADDR (vma->vma_start);
    /* clear TLB for this vaddr*/
    tlb_flush_range((uintptr_t)(*ret), npages);
    
    if ((flags & MAP_ANON) != MAP_ANON) {
        fput(file);
    }
    
    return 0;
}
示例#3
0
/*
 * This function implements the mmap(2) syscall, but only
 * supports the MAP_SHARED, MAP_PRIVATE, MAP_FIXED, and
 * MAP_ANON flags.
 *
 * Add a mapping to the current process's address space.
 * You need to do some error checking; see the ERRORS section
 * of the manpage for the problems you should anticipate.
 * After error checking most of the work of this function is
 * done by vmmap_map(), but remember to clear the TLB.
 */
int
do_mmap(void *addr, size_t len, int prot, int flags,
        int fd, off_t off, void **ret)
{
    if (len == 0){
        return -EINVAL;
    }

    if (!valid_map_type(flags)){
        return -EINVAL;
    }

    if (!PAGE_ALIGNED(off)){
        return -EINVAL;
    }

    if (!(flags & MAP_ANON) && (flags & MAP_FIXED) && !PAGE_ALIGNED(addr)){
        return -EINVAL;
    }

    if (addr != NULL && (uint32_t) addr < USER_MEM_LOW){
        return -EINVAL;
    }

    if (len > USER_MEM_HIGH){
        return -EINVAL;
    }

    if (addr != NULL && len > USER_MEM_HIGH - (uint32_t) addr){
        return -EINVAL;
    }

    if (addr == 0 && (flags & MAP_FIXED)){
        return -EINVAL;
    }

/*    if ((!(flags & MAP_PRIVATE) && !(flags & MAP_SHARED))*/
            /*|| ((flags & MAP_PRIVATE) && (flags & MAP_SHARED)))*/
    /*{*/
        /*return -EINVAL;*/
    /*}*/

    vnode_t *vnode;
      
    if (!(flags & MAP_ANON)){
    
        if (!valid_fd(fd) || curproc->p_files[fd] == NULL){
            return -EBADF;
        }

        file_t *f = curproc->p_files[fd];
        vnode = f->f_vnode;

        if ((flags & MAP_PRIVATE) && !(f->f_mode & FMODE_READ)){
            return -EACCES;
        }

        if ((flags & MAP_SHARED) && (prot & PROT_WRITE) &&
                !((f->f_mode & FMODE_READ) && (f->f_mode & FMODE_WRITE)))
        {
            return -EACCES;
        }

        /*if ((prot & PROT_WRITE) && (f->f_mode & FMODE_APPEND)){*/
            /*return -EACCES;*/
        /*}*/
    } else {
        vnode = NULL;
    }

    vmarea_t *vma;

    int retval = vmmap_map(curproc->p_vmmap, vnode, ADDR_TO_PN(addr),
            (uint32_t) PAGE_ALIGN_UP(len) / PAGE_SIZE, prot, flags, off,
            VMMAP_DIR_HILO, &vma);

    KASSERT(retval == 0 || retval == -ENOMEM);

    if (ret != NULL && retval >= 0){
        *ret = PN_TO_ADDR(vma->vma_start);
    
        pt_unmap_range(curproc->p_pagedir, (uintptr_t) PN_TO_ADDR(vma->vma_start),
               (uintptr_t) PN_TO_ADDR(vma->vma_start)
               + (uintptr_t) PAGE_ALIGN_UP(len));
    
        tlb_flush_range((uintptr_t) PN_TO_ADDR(vma->vma_start),
                (uint32_t) PAGE_ALIGN_UP(len) / PAGE_SIZE);
    }
    


    return retval;
}
示例#4
0
/*
 * This function implements the mmap(2) syscall, but only
 * supports the MAP_SHARED, MAP_PRIVATE, MAP_FIXED, and
 * MAP_ANON flags.
 *
 * Add a mapping to the current process's address space.
 * You need to do some error checking; see the ERRORS section
 * of the manpage for the problems you should anticipate.
 * After error checking most of the work of this function is
 * done by vmmap_map(), but remember to clear the TLB.
 */
int
do_mmap(void *addr, size_t len, int prot, int flags,
        int fd, off_t off, void **ret)
{
	  	dbg(DBG_PRINT,"go into do_mmap\n");
		file_t* file = NULL;

    	if(!PAGE_ALIGNED(off))
		{
			dbg(DBG_PRINT,"(GRADING3C)\n");
        	return -EINVAL;
		}

		if(len <= 0||len > 0xc0000000)
	    {
			dbg(DBG_PRINT,"(GRADING3C)\n");
	    	return -EINVAL;
	   	}

    	if (((uint32_t)addr < USER_MEM_LOW || (uint32_t)addr > USER_MEM_HIGH) && flags& MAP_FIXED)
		{      
			dbg(DBG_PRINT,"(GRADING3C)\n");  
			return -1;
		}

    if(!(flags & MAP_SHARED || flags & MAP_PRIVATE))
{			
	dbg(DBG_PRINT,"(GRADING3C)\n");
        return -EINVAL;
}
   	file = NULL;
    vnode_t *vn = NULL;
    int status = 0;
    uint32_t lopages = 0;
    size_t npages = (len - 1)/PAGE_SIZE  + 1;
    vmarea_t *newvma = NULL;
    if(flags & MAP_FIXED)
    {
			dbg(DBG_PRINT,"(GRADING3C)\n");
            lopages = ADDR_TO_PN( addr );
    }
    if(!(flags & MAP_ANON))
	{
			dbg(DBG_PRINT,"(GRADING3B)\n");
        if(fd < 0 || fd > NFILES)
		{
			dbg(DBG_PRINT,"(GRADING3C)\n");
            return -1;
        }
        file = fget(fd);
        if((prot & PROT_WRITE && MAP_SHARED & flags) && (file->f_mode == FMODE_READ))
		{
			dbg(DBG_PRINT,"(GRADING3C)\n");
            fput(file);
            return -1;
        }
        if(file == NULL) 
		{			
			dbg(DBG_PRINT,"(GRADING3C)\n");
			return -1;
		}
        vn = file->f_vnode;
    }




    status = vmmap_map(curproc->p_vmmap, vn, lopages, npages, prot, flags, off, VMMAP_DIR_HILO, &newvma);
    if(file != NULL) 
	{
		dbg(DBG_PRINT,"(GRADING3B)\n");
		fput(file);
	}
    if(newvma != NULL)
	{
			dbg(DBG_PRINT,"(GRADING3B)\n");
    *ret = PN_TO_ADDR(newvma->vma_start);
	}    
	if(status < 0)
	{
		dbg(DBG_PRINT,"(GRADING3C)\n");
		KASSERT(file == NULL);
        return status;
    }

    tlb_flush_all();
    KASSERT(curproc->p_pagedir != NULL);
    dbg(DBG_VM, "(GRADING3A 2.a)\n");
    return 0;

}
示例#5
0
/*
 * This function implements the brk(2) system call.
 *
 * This routine manages the calling process's "break" -- the ending address
 * of the process's "dynamic" region (often also referred to as the "heap").
 * The current value of a process's break is maintained in the 'p_brk' member
 * of the proc_t structure that represents the process in question.
 *
 * The 'p_brk' and 'p_start_brk' members of a proc_t struct are initialized
 * by the loader. 'p_start_brk' is subsequently never modified; it always
 * holds the initial value of the break. Note that the starting break is
 * not necessarily page aligned!
 *
 * 'p_start_brk' is the lower limit of 'p_brk' (that is, setting the break
 * to any value less than 'p_start_brk' should be disallowed).
 *
 * The upper limit of 'p_brk' is defined by the minimum of (1) the
 * starting address of the next occuring mapping or (2) USER_MEM_HIGH.
 * That is, growth of the process break is limited only in that it cannot
 * overlap with/expand into an existing mapping or beyond the region of
 * the address space allocated for use by userland. (note the presence of
 * the 'vmmap_is_range_empty' function).
 *
 * The dynamic region should always be represented by at most ONE vmarea.
 * Note that vmareas only have page granularity, you will need to take this
 * into account when deciding how to set the mappings if p_brk or p_start_brk
 * is not page aligned.
 *
 * You are guaranteed that the process data/bss region is non-empty.
 * That is, if the starting brk is not page-aligned, its page has
 * read/write permissions.
 *
 * If addr is NULL, you should NOT fail as the man page says. Instead,
 * "return" the current break. We use this to implement sbrk(0) without writing
 * a separate syscall. Look in user/libc/syscall.c if you're curious.
 *
 * Also, despite the statement on the manpage, you MUST support combined use
 * of brk and mmap in the same process.
 *
 * Note that this function "returns" the new break through the "ret" argument.
 * Return 0 on success, -errno on failure.
 */
int do_brk(void *addr, void **ret) {
	/*NOT_YET_IMPLEMENTED("VM: do_brk");*/
	vmarea_t *vmarea;
	/*If addr is NULL, "return" the current break.*/
	dbg(DBG_PRINT, "(GRADING3D 3)\n");
	if (addr == NULL || addr == curproc->p_brk) {
		dbg(DBG_PRINT, "(GRADING3D 3)\n");
		*ret = curproc->p_brk;
		return 0;
	}

	/*check for the address range*/
	if (((uint32_t) addr > USER_MEM_HIGH) || (curproc->p_start_brk > addr)) {
		dbg(DBG_PRINT, "(GRADING3D 3)\n");
		return -ENOMEM;
	}

	/*if p_brk and addr are not page aligned*/
	if (ADDR_TO_PN(
			PAGE_ALIGN_UP(curproc->p_brk)) != ADDR_TO_PN(PAGE_ALIGN_UP(addr))) {
		dbg(DBG_PRINT, "(GRADING3D 3)\n");
		if (addr > curproc->p_brk) {
			dbg(DBG_PRINT, "(GRADING3D 3)\n");
			if (!vmmap_is_range_empty(curproc->p_vmmap,
					ADDR_TO_PN(PAGE_ALIGN_UP(curproc->p_brk)),
					ADDR_TO_PN(
							PAGE_ALIGN_UP(addr)) -ADDR_TO_PN(PAGE_ALIGN_UP(curproc->p_brk)))) {
				dbg(DBG_PRINT, "(GRADING3D 3)\n");
				return -ENOMEM;
			}
			vmarea = vmmap_lookup(curproc->p_vmmap,
					ADDR_TO_PN(PAGE_ALIGN_UP(curproc->p_start_brk)));
			if (vmarea != NULL) {
				dbg(DBG_PRINT, "(GRADING3D 3)\n");
				vmarea->vma_end = ADDR_TO_PN(PAGE_ALIGN_UP(addr));
			} else {
				dbg(DBG_PRINT, "(GRADING3D 3)\n");
				vmmap_map(curproc->p_vmmap,
				NULL, ADDR_TO_PN(PAGE_ALIGN_UP(curproc->p_start_brk)),
						ADDR_TO_PN(
								PAGE_ALIGN_UP(addr)) - ADDR_TO_PN(PAGE_ALIGN_UP(curproc->p_start_brk)),
						PROT_READ | PROT_WRITE, MAP_PRIVATE, 0, VMMAP_DIR_LOHI,
						&vmarea);
			}
		} else {
			dbg(DBG_PRINT, "(GRADING3D 3)\n");
			vmmap_remove(curproc->p_vmmap, ADDR_TO_PN(PAGE_ALIGN_UP(addr)),
					ADDR_TO_PN(
							PAGE_ALIGN_UP(curproc->p_brk)) -ADDR_TO_PN(PAGE_ALIGN_UP(addr)));
		}

		curproc->p_brk = addr;
		*ret = addr;
	} else {
		dbg(DBG_PRINT, "(GRADING3D 3)\n");
		curproc->p_brk = addr;
		*ret = addr;
		return 0;
	}
	return 0;
}
示例#6
0
文件: elf32.c 项目: Aliced3645/os
static int _elf32_load(const char *filename, int fd, char *const argv[],
                       char *const envp[], uint32_t *eip, uint32_t *esp)
{
        int err = 0;
        Elf32_Ehdr header;
        Elf32_Ehdr interpheader;

        /* variables to clean up on failure */
        vmmap_t *map = NULL;
        file_t *file = NULL;
        char *pht = NULL;
        char *interpname = NULL;
        int interpfd = -1;
        file_t *interpfile = NULL;
        char *interppht = NULL;
        Elf32_auxv_t *auxv = NULL;
        char *argbuf = NULL;

        uintptr_t entry;

        file = fget(fd);
        KASSERT(NULL != file);

        /* Load and verify the ELF header */
        if (0 > (err = _elf32_load_ehdr(fd, &header, 0))) {
                goto done;
        }

        if (NULL == (map = vmmap_create())) {
                err = -ENOMEM;
                goto done;
        }

        size_t phtsize = header.e_phentsize * header.e_phnum;
        if (NULL == (pht = kmalloc(phtsize))) {
                err = -ENOMEM;
                goto done;
        }
        /* Read in the program header table */
        if (0 > (err = _elf32_load_phtable(fd, &header, pht, phtsize))) {
                goto done;
        }
        /* Load the segments in the program header table */
        if (0 > (err = _elf32_map_progsegs(file->f_vnode, map, &header, pht, 0))) {
                goto done;
        }

        Elf32_Phdr *phinterp = NULL;
        /* Check if program requires an interpreter */
        if (0 > (err = _elf32_find_phinterp(&header, pht, &phinterp))) {
                goto done;
        }

        /* Calculate program bounds for future reference */
        void *proglow;
        void *proghigh;
        _elf32_calc_progbounds(&header, pht, &proglow, &proghigh);

        entry = (uintptr_t) header.e_entry;

        /* if an interpreter was requested load it */
        if (NULL != phinterp) {
                /* read the file name of the interpreter from the binary */
                if (0 > (err = do_lseek(fd, phinterp->p_offset, SEEK_SET))) {
                        goto done;
                } else if (NULL == (interpname = kmalloc(phinterp->p_filesz))) {
                        err = -ENOMEM;
                        goto done;
                } else if (0 > (err = do_read(fd, interpname, phinterp->p_filesz))) {
                        goto done;
                }
                if (err != (int)phinterp->p_filesz) {
                        err = -ENOEXEC;
                        goto done;
                }

                /* open the interpreter */
                dbgq(DBG_ELF, "ELF Interpreter: %*s\n", phinterp->p_filesz, interpname);
                if (0 > (interpfd = do_open(interpname, O_RDONLY))) {
                        err = interpfd;
                        goto done;
                }
                kfree(interpname);
                interpname = NULL;

                interpfile = fget(interpfd);
                KASSERT(NULL != interpfile);

                /* Load and verify the interpreter ELF header */
                if (0 > (err = _elf32_load_ehdr(interpfd, &interpheader, 1))) {
                        goto done;
                }
                size_t interpphtsize = interpheader.e_phentsize * interpheader.e_phnum;
                if (NULL == (interppht = kmalloc(interpphtsize))) {
                        err = -ENOMEM;
                        goto done;
                }
                /* Read in the program header table */
                if (0 > (err = _elf32_load_phtable(interpfd, &interpheader, interppht, interpphtsize))) {
                        goto done;
                }

                /* Interpreter shouldn't itself need an interpreter */
                Elf32_Phdr *interpphinterp;
                if (0 > (err = _elf32_find_phinterp(&interpheader, interppht, &interpphinterp))) {
                        goto done;
                }
                if (NULL != interpphinterp) {
                        err = -EINVAL;
                        goto done;
                }

                /* Calculate the interpreter program size */
                void *interplow;
                void *interphigh;
                _elf32_calc_progbounds(&interpheader, interppht, &interplow, &interphigh);
                uint32_t interpnpages = ADDR_TO_PN(PAGE_ALIGN_UP(interphigh)) - ADDR_TO_PN(interplow);

                /* Find space for the interpreter */
                /* This is the first pn at which the interpreter will be mapped */
                uint32_t interppagebase = (uint32_t) vmmap_find_range(map, interpnpages, VMMAP_DIR_HILO);
                if ((uint32_t) - 1 == interppagebase) {
                        err = -ENOMEM;
                        goto done;
                }

                /* Base address at which the interpreter begins on that page */
                void *interpbase = (void *)((uintptr_t)PN_TO_ADDR(interppagebase) + PAGE_OFFSET(interplow));

                /* Offset from "expected base" in number of pages */
                int32_t interpoff = (int32_t) interppagebase - (int32_t) ADDR_TO_PN(interplow);

                entry = (uintptr_t) interpbase + ((uintptr_t) interpheader.e_entry - (uintptr_t) interplow);

                /* Load the interpreter program header and map in its segments */
                if (0 > (err = _elf32_map_progsegs(interpfile->f_vnode, map, &interpheader, interppht, interpoff))) {
                        goto done;
                }

                /* Build the ELF aux table */
                /* Need to hold AT_PHDR, AT_PHENT, AT_PHNUM, AT_ENTRY, AT_BASE,
                 * AT_PAGESZ, AT_NULL */
                if (NULL == (auxv = (Elf32_auxv_t *) kmalloc(7 * sizeof(Elf32_auxv_t)))) {
                        err = -ENOMEM;
                        goto done;
                }
                Elf32_auxv_t *auxvent = auxv;

                /* Add all the necessary entries */
                auxvent->a_type = AT_PHDR;
                auxvent->a_un.a_ptr = pht;
                auxvent++;

                auxvent->a_type = AT_PHENT;
                auxvent->a_un.a_val = header.e_phentsize;
                auxvent++;

                auxvent->a_type = AT_PHNUM;
                auxvent->a_un.a_val = header.e_phnum;
                auxvent++;

                auxvent->a_type = AT_ENTRY;
                auxvent->a_un.a_ptr = (void *) header.e_entry;
                auxvent++;

                auxvent->a_type = AT_BASE;
                auxvent->a_un.a_ptr = interpbase;
                auxvent++;

                auxvent->a_type = AT_PAGESZ;
                auxvent->a_un.a_val = PAGE_SIZE;
                auxvent++;

                auxvent->a_type = AT_NULL;

        } else {
                /* Just put AT_NULL (we don't really need this at all) */
                if (NULL == (auxv = (Elf32_auxv_t *) kmalloc(sizeof(Elf32_auxv_t)))) {
                        err = -ENOMEM;
                        goto done;
                }
                auxv->a_type = AT_NULL;
        }

        /* Allocate a stack. We put the stack immediately below the program text.
         * (in the Intel x86 ELF supplement pp 59 "example stack", that is where the
         * stack is located). I suppose we can add this "extra page for magic data" too */
        uint32_t stack_lopage = ADDR_TO_PN(proglow) - (DEFAULT_STACK_SIZE / PAGE_SIZE) - 1;
        err = vmmap_map(map, NULL, stack_lopage, (DEFAULT_STACK_SIZE / PAGE_SIZE) + 1,
                        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 0, 0, NULL);
        KASSERT(0 == err);
        dbg(DBG_ELF, "Mapped stack at low addr 0x%p, size %#x\n",
            PN_TO_ADDR(stack_lopage), DEFAULT_STACK_SIZE + PAGE_SIZE);


        /* Copy out arguments onto the user stack */
        int argc, envc, auxc;
        size_t argsize = _elf32_calc_argsize(argv, envp, auxv, phtsize, &argc, &envc, &auxc);
        /* Make sure it fits on the stack */
        if (argsize >= DEFAULT_STACK_SIZE) {
                err = -E2BIG;
                goto done;
        }
        /* Copy arguments into kernel buffer */
        if (NULL == (argbuf = (char *) kmalloc(argsize))) {
                err = -ENOMEM;
                goto done;
        }
        /* Calculate where in user space we start putting the args. */
        void *arglow = (void *)((uintptr_t)(((char *) proglow) - argsize) & ~PTR_MASK);
        /* Copy everything into the user address space, modifying addresses in
         * argv, envp, and auxv to be user addresses as we go. */
        _elf32_load_args(map, arglow, argsize, argbuf, argv, envp, auxv, argc, envc, auxc, phtsize);

        dbg(DBG_ELF, "Past the point of no return. Swapping to map at 0x%p, setting brk to 0x%p\n", map, proghigh);
        /* the final threshold / What warm unspoken secrets will we learn? / Beyond
         * the point of no return ... */

        /* Give the process the new mappings. */
        vmmap_t *tempmap = curproc->p_vmmap;
        curproc->p_vmmap = map;
        map = tempmap; /* So the old maps are cleaned up */
        curproc->p_vmmap->vmm_proc = curproc;
        map->vmm_proc = NULL;

        /* Flush the process pagetables and TLB */
        pt_unmap_range(curproc->p_pagedir, USER_MEM_LOW, USER_MEM_HIGH);
        tlb_flush_all();

        /* Set the process break and starting break (immediately after the mapped-in
         * text/data/bss from the executable) */
        curproc->p_brk = proghigh;
        curproc->p_start_brk = proghigh;

        strncpy(curproc->p_comm, filename, PROC_NAME_LEN);

        /* Tell the caller the correct stack pointer and instruction
         * pointer to begin execution in user space */
        *eip = (uint32_t) entry;
        *esp = ((uint32_t) arglow) - 4; /* Space on the user stack for the (garbage) return address */
        /* Note that the return address will be fixed by the userland entry code,
         * whether in static or dynamic */

        /* And we're done */
        err = 0;

done:
        if (NULL != map) {
                vmmap_destroy(map);
        }
        if (NULL != file) {
                fput(file);
        }
        if (NULL != pht) {
                kfree(pht);
        }
        if (NULL != interpname) {
                kfree(interpname);
        }
        if (0 <= interpfd) {
                do_close(interpfd);
        }
        if (NULL != interpfile) {
                fput(interpfile);
        }
        if (NULL != interppht) {
                kfree(interppht);
        }
        if (NULL != auxv) {
                kfree(auxv);
        }
        if (NULL != argbuf) {
                kfree(argbuf);
        }
        return err;
}
示例#7
0
文件: elf32.c 项目: Aliced3645/os
/* Helper function for the ELF loader. Maps the specified segment
 * of the program header from the given file in to the given address
 * space with the given memory offset (in pages). On success returns 0, otherwise
 * returns a negative error code for the ELF loader to return.
 * Note that since any error returned by this function should
 * cause the ELF loader to give up, it is acceptable for the
 * address space to be modified after returning an error.
 * Note that memoff can be negative */
static int _elf32_map_segment(vmmap_t *map, vnode_t *file, int32_t memoff, const Elf32_Phdr *segment)
{
        uintptr_t addr;
        if (memoff < 0) {
                KASSERT(ADDR_TO_PN(segment->p_vaddr) > (uint32_t) -memoff);
                addr = (uintptr_t)segment->p_vaddr - (uintptr_t)PN_TO_ADDR(-memoff);
        } else {
                addr = (uintptr_t)segment->p_vaddr + (uintptr_t)PN_TO_ADDR(memoff);
        }
        uint32_t off = segment->p_offset;
        uint32_t memsz = segment->p_memsz;
        uint32_t filesz = segment->p_filesz;

        dbg(DBG_ELF, "Mapping program segment: type %#x, offset %#08x,"
            " vaddr %#08x, filesz %#x, memsz %#x, flags %#x, align %#x\n",
            segment->p_type, segment->p_offset, segment->p_vaddr,
            segment->p_filesz, segment->p_memsz, segment->p_flags,
            segment->p_align);

        /* check for bad data in the segment header */
        if (PAGE_SIZE != segment->p_align) {
                dbg(DBG_ELF, "ERROR: segment does not have correct alignment\n");
                return -ENOEXEC;
        } else if (filesz > memsz) {
                dbg(DBG_ELF, "ERROR: segment file size is greater than memory size\n");
                return -ENOEXEC;
        } else if (PAGE_OFFSET(addr) != PAGE_OFFSET(off)) {
                dbg(DBG_ELF, "ERROR: segment address and offset are not aligned correctly\n");
                return -ENOEXEC;
        }

        int perms = 0;
        if (PF_R & segment->p_flags) {
                perms |= PROT_READ;
        }
        if (PF_W & segment->p_flags) {
                perms |= PROT_WRITE;
        }
        if (PF_X & segment->p_flags) {
                perms |= PROT_EXEC;
        }

        if (0 < filesz) {
                /* something needs to be mapped from the file */
                /* start from the starting address and include enough pages to
                 * map all filesz bytes of the file */
                uint32_t lopage = ADDR_TO_PN(addr);
                uint32_t npages = ADDR_TO_PN(addr + filesz - 1) - lopage + 1;
                off_t fileoff = (off_t)PAGE_ALIGN_DOWN(off);

                int ret;
                if (!vmmap_is_range_empty(map, lopage, npages)) {
                        dbg(DBG_ELF, "ERROR: ELF file contains overlapping segments\n");
                        return -ENOEXEC;
                } else if (0 > (ret = vmmap_map(map, file, lopage, npages, perms,
                                                MAP_PRIVATE | MAP_FIXED, fileoff,
                                                0, NULL))) {
                        return ret;
                }
        }

        if (memsz > filesz) {
                /* there is left over memory in the segment which must
                 * be initialized to 0 (anonymously mapped) */
                uint32_t lopage = ADDR_TO_PN(addr + filesz);
                uint32_t npages = ADDR_TO_PN(PAGE_ALIGN_UP(addr + memsz)) - lopage;

                int ret;
                if (npages > 1 && !vmmap_is_range_empty(map, lopage + 1, npages - 1)) {
                        dbg(DBG_ELF, "ERROR: ELF file contains overlapping segments\n");
                        return -ENOEXEC;
                } else if (0 > (ret = vmmap_map(map, NULL, lopage, npages, perms,
                                                MAP_PRIVATE | MAP_FIXED, 0, 0, NULL))) {
                        return ret;
                } else if (!PAGE_ALIGNED(addr + filesz) && filesz > 0) {
                        /* In this case, we have accidentally zeroed too much of memory, as
                         * we zeroed all memory in the page containing addr + filesz.
                         * However, the remaining part of the data is not a full page, so we
                         * should not just map in another page (as there could be garbage
                         * after addr+filesz). For instance, consider the data-bss boundary
                         * (c.f. Intel x86 ELF supplement pp. 82).
                         * To fix this, we need to read in the contents of the file manually
                         * and put them at that user space addr in the anon map we just
                         * added. */
                        void *buf;
                        if (NULL == (buf = page_alloc()))
                                return -ENOMEM;
                        if (!(0 > (ret = file->vn_ops->read(file, (off_t) PAGE_ALIGN_DOWN(off + filesz),
                                                            buf, PAGE_OFFSET(addr + filesz))))) {
                                ret = vmmap_write(map, PAGE_ALIGN_DOWN(addr + filesz),
                                                  buf, PAGE_OFFSET(addr + filesz));
                        }
                        page_free(buf);
                        return ret;
                }
        }
        return 0;
}