免费注册 查看新帖 |

Chinaunix

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

redhat企业版5.5上实现mmap的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-03-31 10:13 |只看该作者 |倒序浏览
我的需求就是:在内核态利用__get_free_pages申请4MB内存,并且申请多个这样的内存,然后需要将申请的内存区利用mmap到用户态,
这样用户态就可以对这些内存进行读写操作。之前我在较低的内核中都是可以mmap /dev/mem内存设备文件直接实现,但是在redhat企业版5.5
中不允许对/dev/mem内存设备文件进行mmap操作,于是我需要通过别的方法将申请的内存映射出来,请大家帮我想想具体的实现方法,谢谢,小弟不胜感激。前提是不能重新编译内核

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
2 [报告]
发表于 2011-03-31 10:27 |只看该作者
共享出来的这块内存是用于只读啊,还是读写

论坛徽章:
0
3 [报告]
发表于 2011-03-31 14:28 |只看该作者
读写

论坛徽章:
0
4 [报告]
发表于 2011-03-31 16:28 |只看该作者
lz 可以参考PACKET MMAP的实现,在net/packet/af_packet.c中

论坛徽章:
0
5 [报告]
发表于 2011-03-31 16:54 |只看该作者
回复 4# linuxxtz

谢谢,我看一下先

论坛徽章:
0
6 [报告]
发表于 2011-03-31 17:02 |只看该作者
int my_mmap(struct file *file, struct vm_area_struct *vma)
{
        struct scullc_dev *dev;
        unsigned long addr;

        if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
                return -EINVAL;

        dev = file->private_data;
        addr = __pa(dev->mem);

        if (addr & (PAGE_SIZE - 1))
                return -ENOSYS;

        vma->vm_flags |= VM_IO;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

        if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,\
                                                        PAGE_SIZE, vma->vm_page_prot)) {
                printk(KERN_ERR "%s: remap_pfn_range failed\n",
                        __func__);
                return -EAGAIN;
        }
        return 0;
}
这是实现的一个mmap驱动函数可以实现mmap,这是在字符设备里面实现的,字符设备struct scullc_dev *dev中的内存区域指针mem是通过scullc_devices->mem = (unsigned char *)__get_free_pages(GFP_KERNEL, 0);来实现的,这样是可以mmap的。
但是我需要申请的应该是多个4M空间,例如__get_free_pages(GFP_KERNEL, 10),然后将这些4M内存的首地址保存在一个unsigned char *mem[64]数组,这样就是4M*64=256MB,这样用户怎么去mmap,驱动的mmap函数应该怎么去写?

论坛徽章:
0
7 [报告]
发表于 2011-03-31 17:15 |只看该作者
在 packet_mmap中, 代码类似如下:
start = vma->vm_start;
    for (i = 0; i <  64 ; i++) {
        struct page *page = virt_to_page(mem[i]);
        int pg_num;

        for (pg_num = 0; pg_num < 4M / PAGE_SIZE; pg_num++, page++) {
            err = vm_insert_page(vma, start, page);
            if (unlikely(err))
                goto out;
            start += PAGE_SIZE;
        }
    }

论坛徽章:
0
8 [报告]
发表于 2011-03-31 17:27 |只看该作者
回复 7# linuxxtz

我在packet_mmap函数中没有找到类似io_remap_pfn_range,remap_pfn_range的函数,那么用户态怎么去mmap这块呢

论坛徽章:
0
9 [报告]
发表于 2011-04-01 08:53 |只看该作者
回复 8# Arm_Linux_boy


    上面的代码就是把它映射到用户态, 用户层也是调用像mmap(0, buffer_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);实现的

论坛徽章:
0
10 [报告]
发表于 2011-04-01 10:03 |只看该作者
回复 9# linuxxtz

我试了一下,应用层出现段错误。
我的底层实现是:
int my_mmap(struct file *file, struct vm_area_struct *vma)
{
        struct scullc_dev *dev;
        struct page *page;
        int tmp_order = 10;
        int tmp_page_num, i;
        unsigned long start;
        int err = -EINVAL;
        tmp_page_num = 1 << tmp_order;
        if (((vma->vm_end - vma->vm_start) != tmp_page_num * PAGE_SIZE) || vma->vm_pgoff)
                return -EINVAL;
       
        dev = file->private_data;
        vma->vm_flags |= VM_IO;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

        start = vma->vm_start;
        page = virt_to_page(dev->mem);
        for (i = 0; i < tmp_page_num; i++) {
                    err = vm_insert_page(vma, start, page);
            if (unlikely(err))
                return -EINVAL;                               
            start += PAGE_SIZE;
            page++;               
                }
        return 0;
}
内存申请如下:
        scullc_devices->mem = (unsigned char *)__get_free_pages(GFP_KERNEL, tmp_order);
        if(scullc_devices->mem == NULL)
        {
                kfree(scullc_devices);
                printk(KERN_ERR "#######vamalloc failed!######\n");
                return -ENOMEM;
        }
        else
        {
                printk(KERN_ERR "#######vmalloc mem success!######\n");
                tmp_page_num = 1 << tmp_order;
                for(i = 0; i < tmp_page_num; i++)
                {
                        SetPageReserved(virt_to_page(scullc_devices->mem + i * PAGE_SIZE));  
                                }
        }

应用层:
buf = (unsigned char *)mmap(NULL, 4096*4096, PROT_READ | PROT_WRITE,\
                MAP_SHARED, mmap_fd, 0);
    if(NULL == buf)
    {
        printf("ERROR:memory map failed. error: %d\n", errno);
        return R_FAIL;
    }
    printf("%s\n", buf);
    printf("%s\n", buf+1024);
执行程序后:
报:Segmentation fault
打印日志:
localhost kernel: netdrv_test[3262]: segfault at ffffffffffffffff rip 000000343e8797c0 rsp 00007fffd21e20c8 error 4
错误4:Interrupted system call

帮我看看是哪里出错了,谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP