PMEM- kernel空间映射到用户进程空间

在android系统需要使用到pmem物理空间及ashmem匿名空间,其实pmem就是一块连续的物理内存空间,可以建立一个设备结点给用户空间进行访问。

1、内核驱动编写:

struct android_pmem_platform_data
{
 const char* name;
 unsigned long start;
 unsigned long size;
 unsigned no_allocator;
 unsigned cached;
 unsigned buffered;
};
/* Structure that declares the usual file  access functions */
struct file_operations memory_fops = {
  open: memory_open,
  mmap: memory_mmap
};
/* alloc pmem space */
struct android_pmem_platform_data android_pmem_data;

   /* Set up a pmem area to match the frame buffer */
  pmem_size = (pmemsize+PAGE_SIZE-1)/PAGE_SIZE;
  FBPart = bpa2_find_part ("bigphysarea");
  android_pmem_device.name = "android_pmem";
  android_pmem_device.id = 0;
  android_pmem_device.dev.platform_data = &android_pmem_data;
  memset(&i->android_pmem_data, 0, sizeof(android_pmem_data));
  android_pmem_data.name = kstrdup(pname, GFP_KERNEL);

  android_pmem_data.start  = bpa2_alloc_pages (FBPart, pmem_size, 0, GFP_KERNEL);
  android_pmem_data.size = i->pmem_size * PAGE_SIZE;
  android_pmem_data.no_allocator = 1;
  android_pmem_data.cached = 0;
  android_pmem_data.buffered = 0;
platform_device_register(&android_pmem_device);

/* Registering device */
register_chrdev(memory_major, NAME_DEVICE , &memory_fops);

实现两个重要的ioctl函数:

int memory_open(struct inode *inode, struct file *filp) {

  /* Success */
  return 0;
}

#define io_remap_page_range(vma, vaddr, pfn, size, prot)    io_remap_pfn_range(vma, vaddr, (pfn) >> PAGE_SHIFT, size, prot)
int memory_mmap(struct file *filp, struct vm_area_struct *vma)
{
    int             ret = 0;
    pgprot_t        pgprot;
    unsigned long   offset;

    /* To avoid warnings */
    filp = 0;
    offset = vma->vm_pgoff << PAGE_SHIFT;
    pgprot = pgprot_noncached(vma->vm_page_prot);

    if ((ret=io_remap_pfn_range(vma, vma->vm_start, offset, vma->vm_end - vma->vm_start, pgprot)) != 0)
    {
        printk("remap_pfn_range error: (0x%.8x - %d)", ret, ret);
        return -EAGAIN;
    }

    return ret;
}




简要说明一下:

在mmap函数里,使用remap_pfn_range函数。代码如下。注意要设置一下vma->vm_pgoff为你要map的io空间的物理地址对应的页。arm  IO/ 内存统一编址  所以#define io_remap_pfn_range(vma,from,pfn,size,prot) /                remap_pfn_range(vma, from, pfn, size, prot)vm_start, vm_end  在系统调用时算好了,使用时找个空闲的空间,然后根据size算出vm_endmap过程:

用户空间map(start,offset, len , fd ,...)   start 映射到的用户空间地址,0就是自己去找,offset 文件的偏移。

static inline unsigned long do_mmap2(unsigned long addr, size_t len,
			unsigned long prot, unsigned long flags,
			unsigned long fd, unsigned long off, int shift)
{
	unsigned long ret = -EINVAL;

	if (!arch_validate_prot(prot))
		goto out;

	if (shift) {
		if (off & ((1 << shift) - 1))
			goto out;
		off >>= shift;
	}
	ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off);
out:
	return ret;
}
unsigned long sys_mmap(unsigned long addr, size_t len,
		       unsigned long prot, unsigned long flags,
		       unsigned long fd, off_t offset)
{
	return do_mmap2(addr, len, prot, flags, fd, offset, PAGE_SHIFT);
}

可能合并VMA,否则新分配一个VMA
然后error = file->f_op->mmap(file, vma);
就调用了驱动里的mmap      
这时候vma->vm_pgoff = pgoff    (这个pgoff就是map(offset, len , fd ,...)  中的 offset ,当然经过处理了,PAGE_SHIFT移来移去)

2、用户空间用法:

int master_fd = open("/dev/pmem", O_RDWR, 0);
if (master_fd >= 0) {
	ioctl(master_fd, PMEM_GET_TOTAL_SIZE, ®ion)
	void* base = mmap(0, size, 
                PROT_READ|PROT_WRITE, MAP_SHARED, master_fd, 0);
        ...  // 访问base地址即可读写数据
}

如此即可将内核空间映射到用户进程空间


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值