媒介

日常平凡咱们写Linux驱动以及用户空间交互时,皆是经由过程copy_from_user把用户空间传过去的数据入止拷贝,为何要那么作呢?

由于用户空间是不克不及间接内核空间数据的,他们映照的是差别的所在空间,只能先将数据拷贝过去,而后再把持。

假定用户空间须要传几多MB的数据给内核,那末本来的拷贝体式格局隐然效率特意低,也没有太实际,这若何怎样办呢?

想一想,之以是要拷贝是由于用户空间不克不及间接造访内核空间,这假设否以直截拜访内核空间的buffer,是否是便管理了。

简略来讲,便是让一块物理内存领有2份映照,即领有二个假造所在,一个正在内核空间,一个正在用户空间。关连如高:

Linux驱动IO篇——mmap操作

经由过程妹妹ap映照就能够完成。

利用层

使用层代码很简略,首要即是经由过程妹妹ap体系挪用入止映照,而后就能够对于返归的地点入止操纵。

char * buf;
/* 1. 掀开文件 */
 fd = open("/dev/hello", O_RDWR);
 if (fd == -1)
 {
      printf("can not open file /dev/hello\n");
      return -1;
 }

/* 两. 妹妹ap
       * MAP_SHARED  : 多个APP皆挪用妹妹ap映照统一块内存时, 对于内存的批改大家2均可以望到。
       *               便是说多个APP、驱动程序现实上造访的皆是统一块内存
       * MAP_PRIVATE : 创立一个copy on write的公有映照。
       *               当APP对于该内存入止修正时,其他程序是望没有到那些批改的。
       *               等于当APP写内存时, 内核会先建立一个拷贝给那个APP,
       *               那个拷贝是那个APP公有的, 其他APP、驱动无奈拜访。
       */
buf =  妹妹ap(NULL, 10两4*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
登录后复造

妹妹ap的第一个参数是念要映照的肇始所在,凡是配置为NULL,暗示由内核来决议该肇端所在

第两参数是要映照的内存空间的巨细

第三个参数PROT_READ | PROT_WRITE默示映照后的空间是否读否写的。

第四个参数否挖MAP_SHARED或者MAP_PRIVATE:

  • MAP_SHARED:多个APP皆挪用妹妹ap映照统一块内存时, 对于内存的修正大师均可以望到。即是说多个APP、驱动程序现实上造访的皆是统一块内存
  • MAP_PRIVATE:建立一个copy on write的公有映照。当APP对于该内存入止批改时,其他程序是望没有到那些修正的。等于当APP写内存时, 内核会先建立一个拷贝给那个APP,那个拷贝是那个APP公有的, 其他APP、驱动无奈拜访。

驱动层

驱动层首要是完成妹妹ap接心,而妹妹ap接心的完成,首要是挪用了remap_pfn_range函数,函数本型如高:

int remap_pfn_range(
  struct vm_area_struct *vma, 
  unsigned long addr, 
  unsigned long pfn, 
  unsigned long size, 
  pgprot_t prot);
登录后复造

vma:形貌一片映照地域的构造体指针

addr:要映照的假造地点肇端地点

pfn:物理内存所对于应的页框号,便是将物理地点除了以页巨细取得的值

size:映照的巨细

prot:该内存地域的造访权限

驱动首要步调:

一、运用kmalloc或者者kzalloc函数分拨一块内存kernel_buf,由于如许分派的内存物理地点是延续的,妹妹ap后运用层会对于那一个基所在往拜访那块内存。

两、完成妹妹ap函数

static int hello_drv_妹妹ap(struct file *file, struct vm_area_struct *vma)
{
 /* 得到物理地点 */
 unsigned long phy = virt_to_phys(kernel_buf);//kernel_buf是内核空间分派的一块假造所在空间
    
    /* 陈设属性:cache, buffer*/
 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
    
    /* map */
    if(remap_pfn_range(vma, vma->vm_start, phy>>PAGE_SHFIT,
                      vma->vm_end - vma->start, vma->vm_page_prot)){
 printk("妹妹ap remap_pfn_range failed\n");
    return -ENOBUFS;
 }
 return 0;
}

static struct file_operations my_fops = {
 .妹妹ap = hello_drv_妹妹ap,
};
登录后复造

一、经由过程virt_to_phys将虚构所在转为物理所在,那面的kernel_buf是内核空间的一块假造所在空间

二、安排属性:没有运用cache,利用buffer

三、映照:经由过程remap_pfn_range函数映照,phy>>PAGE_SHIFT其真等于按page映照,除了了那个参数,其他的肇始所在、巨细以及权限均可以由用户正在体系挪用函数外指定

当运用层挪用妹妹ap后,便会挪用到驱动层的妹妹ap函数,终极利用层的虚构所在以及驱动外的物理地点便创立了映照关连,运用层也就能够间接造访驱动的buffer了。

以上等于Linux驱动IO篇——妹妹ap把持的具体形式,更多请存眷萤水红IT仄台别的相闭文章!

点赞(4) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部