免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 7107 | 回复: 10
打印 上一主题 下一主题

[请教]驱动程序中IO内存的mmap问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-26 23:31 |只看该作者 |倒序浏览
10可用积分
一个很简单的驱动,我打算用mmap的方式将它的IO内存映射到用户进程空间。已知感兴趣的设备IO内存地址是从0x50100000开始的几十个寄存器。以下是驱动中的mmap程序:

unsigned int phy_addr = 0x50100000;
int dev_mmap(struct file * filp, struct vm_area_struct * vma)
{
        int ret;
        ret = remap_pfn_range(vma,
               vma->vm_start,
               phy_addr >> PAGE_SHIFT,
               vma->vm_end-vma->vm_start,
               PAGE_SHARED);
        if(ret != 0)
                return -EAGAIN;
        vma->vm_ops = &dev_vma_ops;
        dev_vma_open(vma);
        return 0;
}

用户空间调用mmap,映射256个字节:
p = mmap(0, 0xff, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);       

结果程序不work,gdb 一下,输出如下:

(gdb) p p
$2 = 0xafdfb000 <Address 0xafdfb000 out of bounds>

请问这是什么原因造成的啊?

[ 本帖最后由 idolspawn 于 2009-10-27 09:53 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-10-27 09:51 |只看该作者

回复 #1 idolspawn 的帖子

试试 io_remap_page_range

论坛徽章:
0
3 [报告]
发表于 2009-10-27 09:56 |只看该作者
io_remap_page_range不是对IO端口用的么?我提到的这个设备是被映射为IO内存的。
另外,抛开IO端口/内存不提,为什么上述程序会mmap出一个out of bounds的地址?

论坛徽章:
0
4 [报告]
发表于 2009-10-27 11:58 |只看该作者
你这种用法不对,ldd3上已经给出了示例代码:

  1. remap_pfn_range(vma, vma->start, vm->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot);
复制代码

注意第三个参数不是你所理解的phy_addr >> PAGE_SHIFT,要映射的io端口地址应该在用户空间的mmap()指定
比如:p = mmap(0x50100000, 0xff, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);  

你试试看。

论坛徽章:
0
5 [报告]
发表于 2009-10-27 14:06 |只看该作者
ls说的不对吧?mmap()的arg1是“要映射到用户空间的地址”,是虚拟地址,如果它不是NULL,则mmap()成功后的返回值就是它。可是我这里0x50010000是一个设备的物理地址啊。

论坛徽章:
0
6 [报告]
发表于 2009-10-27 14:19 |只看该作者

回复 #5 idolspawn 的帖子

兄弟,man手册上可没说第一个参数是虚拟地址:
mmap, munmap - map or unmap files or devices into memory

论坛徽章:
0
7 [报告]
发表于 2010-04-06 16:24 |只看该作者
回复 1# idolspawn


    楼主,你好,我现在做视频采集也碰到这种错误提示,下面是我的代码:
//map the buffers between driver and approcation
unsigned int i;
for (i = 0; i < reqbuf.count; i++)
{
        struct v4l2_buffer buffer;
        CLEAR(buffer);
        buffer.type = reqbuf.type;
        buffer.memory = V4L2_MEMORY_MMAP;
        buffer.index = i;
//        buffer.length =  img_width*img_height*2;        

      if (ioctl (fd, VIDIOC_QUERYBUF, &buffer)==-1)
           printf (" querybuf failed\n");
       else printf ("Querybuf successlly!\n");
         
//          map_start_buf = calloc(1,sizeof(buffer.length));
//          if(!map_start_buf) printf("Calloc map_start_buf error\n");
         buffers.length = buffer.length; /* remember for munmap() */
         buffers.start = mmap (NULL, buffer.length+100,PROT_READ | PROT_WRITE,MAP_PRIVATE,fd, buffer.m.offset);
//         printf("%d\n",errno);
        if (MAP_FAILED == buffers.start)
//            printf ( " Mmap failed\n");
               printf("%s,%s\n",   errno , strerror(errno));
//                exit(errno);
        else printf ("Mmap it successlly!\n");

  }//end of for

我单步调试后出现
(gdb) p buffers[0]
$1 = {start = 0xb7f45000 <Address 0xb7f45000 out of bounds>, length = 153600}
请问楼主,你是怎样解决这个问题的?

论坛徽章:
0
8 [报告]
发表于 2010-04-06 18:32 |只看该作者
CONFIG_STRICT_DEVMEM把这个选项关掉试试.

论坛徽章:
0
9 [报告]
发表于 2010-04-06 22:26 |只看该作者
phy_addr  &= PAGE_MASK
另len也要用PAGE_ALIGN进行page对齐
如2l所说用io_remap_page_range,vma->vm_flags |= VM_IO | VM_RESERVED;
实际上这些东西随便都内核的驱动里拿过来改下就好了

论坛徽章:
0
10 [报告]
发表于 2010-04-07 16:56 |只看该作者
用gdb来看mmap出来的虚拟地址都是out bound。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP