Exemple #1
0
/*
 * This function implements the munmap(2) syscall.
 *
 * As with do_mmap() it should perform the required error checking,
 * before calling upon vmmap_remove() to do most of the work.
 * Remember to clear the TLB.
 */
int
do_munmap(void *addr, size_t len)
{
    /*NOT_YET_IMPLEMENTED("VM: do_munmap");*/

    if ((size_t)addr < USER_MEM_LOW || (size_t)addr >= USER_MEM_HIGH) {
        return -EINVAL;
    }

    if(len == PAGE_SIZE * 15)
    {
        dbg(DBG_PRINT, "BREAK\n");
    }


    if(!PAGE_ALIGNED(addr)){
        dbg(DBG_PRINT,"Error: do_munmap failed due to addr or len is not page aligned!\n");
        return -EINVAL;
    }

    if((len <= 0) || (len >= USER_MEM_HIGH - USER_MEM_LOW)){
        dbg(DBG_PRINT,"Error: do_munmap failed due to len is <= 0!\n");
        return -EINVAL;
    }

    vmmap_t *map = curproc->p_vmmap;
    uint32_t lopage;
    uint32_t npages;
    lopage = ADDR_TO_PN(addr);
    
    /* updated */
    /* TODO: Check later: may change to: uint32_t hipage = ADDR_TO_PN((size_t)addr + len - 1) + 1; */
    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 retval = vmmap_remove(map, lopage, npages);
    if(retval < 0){
        dbg(DBG_PRINT,"Error: The unmapping of the vmarea was unsuccessful\n");
        return retval;
    }
    /* clear TLB for this vaddr*/
    /* Corrected */
    tlb_flush_range((uintptr_t)addr, npages);
    
    return 0;
}
Exemple #2
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)
{
    /*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;
}
Exemple #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;
}
Exemple #4
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)
{
	dbg(DBG_VM, "\n");

	void *cur_sbrk = curproc->p_start_brk;
	vmarea_t *vma;
	vmarea_t *nvma = NULL;

	if (addr == NULL) {
		*ret = curproc->p_brk;
		return 0;
	}

	KASSERT((uintptr_t)curproc->p_brk >= (uintptr_t)curproc->p_start_brk);

	if ((uintptr_t)cur_sbrk > (uintptr_t)addr) {
		return -ENOMEM;
	}

	/* check for upper limits */
	if ((uintptr_t)addr >= USER_MEM_HIGH)
		return -ENOMEM;

	uintptr_t pbrk_pg = ADDR_TO_PN(curproc->p_brk);
	uintptr_t addr_pg = ADDR_TO_PN(addr);
	(PAGE_ALIGNED(addr))? (addr_pg) : (addr_pg++);
	(PAGE_ALIGNED(curproc->p_brk))? (pbrk_pg) : (pbrk_pg++);

	/* if they resides in the same page, just update p_brk */
	if (pbrk_pg == addr_pg) {
		curproc->p_brk = addr;
		*ret = addr;
		return 0;
	}

	/* Get dynamic region's vmarea */
	vma = vmmap_lookup(curproc->p_vmmap, ADDR_TO_PN(cur_sbrk));
	KASSERT(vma && "vmarea for the dynamic region is not found!");

	/* check to see if vma has a next vma */
	if (vma->vma_plink.l_next != &curproc->p_vmmap->vmm_list) {
		nvma = list_item(vma->vma_plink.l_next, vmarea_t, vma_plink);
		KASSERT(nvma &&
			"next vmarea should exist but could not be found!");
	}

	/* check for upper limits */
	if (nvma && addr_pg > nvma->vma_start)
		return -ENOMEM;

	/* Now, update the vma, and curpor->p_brk */
	if (pbrk_pg > addr_pg) {
		vmmap_remove(curproc->p_vmmap, addr_pg, (pbrk_pg - addr_pg));
		tlb_flush_range((uintptr_t)PN_TO_ADDR(addr_pg), pbrk_pg - addr_pg);
	} else {
		vma->vma_end = addr_pg;
	}

	curproc->p_brk = addr;
	*ret = addr;

	return 0;
}