예제 #1
0
unsigned long
pisces_map_xpmem_pfn_range(struct xpmem_pfn * pfns,
			   u64                num_pfns)
{
	struct aspace * aspace      = current->aspace;
	unsigned long   addr        = 0;
	unsigned long   attach_addr = 0;
	unsigned long   size        = 0;
	int status = 0;
	u64 i      = 0;

	size = num_pfns * PAGE_SIZE;

	spin_lock(&(aspace->lock));
	{
		status = __aspace_find_hole(aspace, 0, size, PAGE_SIZE, &attach_addr);
		
		if (status) {
			spin_unlock(&(aspace->lock));
			printk(KERN_ERR "Cannot map xpmem pfn range - out of memory\n");
			return -ENOMEM;
		}
		
		status = __aspace_add_region(aspace, attach_addr, size, VM_READ | VM_WRITE | VM_USER,
					     PAGE_SIZE, "pisces_ppe");
		if (status) {
			spin_unlock(&(aspace->lock));
			printk(KERN_ERR "Cannot map xpmem pfn range - cannot add memory to aspace\n");
			return -ENOMEM;
		}
	}
	spin_unlock(&(aspace->lock));

	for (i = 0; i < num_pfns; i++) {
		addr = attach_addr + (i * PAGE_SIZE);

		printk("Mapping vaddr = %p, pfn = %llu, (paddr = %p)\n", 
		       (void *)addr,
		       pfns[i].pfn,
		       (void *)(pfns[i].pfn << PAGE_SHIFT)
		       );

		status = map_pfn_range(addr, pfns[i].pfn, PAGE_SIZE);

		if (status) {
			return -ENOMEM;
		}
	}   

	return attach_addr;
}
예제 #2
0
파일: mmap.c 프로젝트: jamesyc/kitten
long
sys_mmap(
	unsigned long addr,
	unsigned long len,
	unsigned long prot,
	unsigned long flags,
	unsigned long fd,
	unsigned long off
)
{
	struct aspace *as = current->aspace;
	struct file *file;
	struct vm_area_struct vma;
	unsigned long mmap_brk;
	int rv;

	if (len != round_up(len, PAGE_SIZE))
		return -EINVAL;

	/* we only support anonymous private mapping; file-backed
	   private mapping has copy-on-write semantics, which we don't
	   want due to complete lack of any pagefaulting resolution */

	if((flags & MAP_PRIVATE) && !(flags & MAP_ANONYMOUS))
		return -EINVAL;

	/* anonymous mappings (not backed by a file) are handled specially */
	if(flags & MAP_ANONYMOUS) {
		/* anonymous mmap()ed memory is put at the top of the
		   heap region, and grows from high to low addresses,
		   i.e. down towards the current heap end. */
		spin_lock(&as->lock);
		mmap_brk = round_down(as->mmap_brk - len, PAGE_SIZE);

		/* Protect against extending into the UNIX data segment,
		   or becoming negative (which wraps around to large addr) */
		if ((mmap_brk <= as->brk) || (mmap_brk >= as->mmap_brk)) {
			spin_unlock(&as->lock);
			return -ENOMEM;
		}

		as->mmap_brk = mmap_brk;
		spin_unlock(&as->lock);

		paddr_t phys;
		if ( __aspace_virt_to_phys( as, mmap_brk, & phys ) ) {
			panic("sys_mmap() failed to get physical address\n");
		}
		memset( __va(phys), 0, len );
		return mmap_brk;
	}

	/* file-backed mappings */

	/* TODO: add a million checks here that we'll simply ignore now */

	file = get_current_file(fd);
	if(NULL == file)
		return -EBADF;

	if(NULL == file->f_op ||
	   NULL == file->f_op->mmap)
		return -ENODEV;

	spin_lock(&as->lock);
	if ((rv = __aspace_find_hole(as, addr, len, PAGE_SIZE, &addr))) {
		spin_unlock(&as->lock);
		return -ENOMEM;
	}

	if ((rv = __aspace_add_region(as, addr, len,
				      VM_READ|VM_WRITE|VM_USER,
				      PAGE_SIZE, "mmap"))) {
		/* assuming there is no race between find_hole and
		   add_region, as we're holding the as->lock, this
		   failure can't be due to someone adding our region
		   in between */
		spin_unlock(&as->lock);
		return -ENOMEM;
	}
	spin_unlock(&as->lock);

	/* fill the vm_area_struct to keep compatible with linux layer */
	vma.vm_start = addr;
	vma.vm_end = addr + len;
	vma.vm_page_prot = __pgprot(VM_READ|VM_WRITE);
	vma.vm_pgoff = 0;

	rv = file->f_op->mmap(file, &vma);
	if(rv) {
		spin_lock(&as->lock);
		__aspace_del_region(as, addr, len);
		spin_unlock(&as->lock);
		return rv;
	}
	return vma.vm_start;
}