mmap函数映射物理地址失败指针全F问题解决

1、mmap 的优点

1)实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。

2)提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。

2、问题现象

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

内核申请物理地址,用户态获取并做mmap映射后虚拟地址指针全F,地址映射失败。

3、定位过程

已知:映射成功时,mmap() 返回被映射区的指针。映射失败时,mmap() 返回 MAP_FAILED((void *)-1)即全F,error 被设为以下的某个值:

返回值	    含义
EACCES	    访问出错
EAGAIN	    文件已被锁定,或者太多的内存已被锁定
EBADF	    fd 不是有效的文件描述词
EINVAL	    一个或者多个参数无效
ENFILE	    已达到系统对打开文件的限制
ENODEV	    指定文件所在的文件系统不支持内存映射
ENOMEM	    内存不足,或者进程已超出最大内存映射数量
EPERM	    权能不足,操作不允许
ETXTBSY	    已写的方式打开文件,同时指定 MAP_DENYWRITE 标志
SIGSEGV	    试着向只读区写入
SIGBUS	    试着访问不属于进程的内存区

在mmap失败下面增加如下打印:

printf(“mmap error : %d-%s.,errno,strerror(errno));

重新运行程序得到失败原因前后有两种:

#define EPERM   1  /* Operation not permitted */
mmap error :1-Operation not permitted. 

#define EINVAL  22  /* Invalid argument */
mmap error :22-Invalid argument. 

4、问题原因

内存设备节点 /dev/mem 作为可随机读写的字符设备,在内核源码的 drivers/char/mem.c 中初始化(/dev/kmem, /dev/null, /dev/zero, /dev/random, /dev/urandom 等设备节点也都在这个文件中定义),对 /dev/mem 的 mmap 操作定义为 mmap_mem()。在 mmap_mem() 中返回 -EPERM 的代码片段如下:

if (!range_is_allowed(vma->vm_pgoff, size))
    return -EPERM;

当定义了 CONFIG_STRICT_DEVMEM 时,在 range_is_allowed() 中会逐页调用 devmem_is_allowed() 检查是否可访问:

static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{
    u64 from = ((u64)pfn) << PAGE_SHIFT;
    u64 to = from + size;
    u64 cursor = from;
    while (cursor < to) {
        if (!devmem_is_allowed(pfn)) {
            printk(KERN_INFO
                "Program %s tried to access /dev/mem between %Lx->%Lx.\n",
                current->comm, from, to);
            return 0;
        }
        cursor += PAGE_SIZE;
        pfn++;
    }
    return 1;
}

devmem_is_allowed() 返回 1 表示允许访问,0 表示不允许访问。

5、修改方法

1)关闭内核 CONFIG_STRICT_DEVMEM 配置选项即可。

从前面的说明中可以看出,几个检查函数都是在定义了 CONFIG_STRICT_DEVMEM 才生效的,因此最简单的方法,就是将内核配置中 CONFIG_STRICT_DEVMEM 选项关闭并重新编译内核,这也是我们的应用系统所采用的方法。

2)修改内核为CONFIG_ARM64_4K_PAGES 4K页大小

有的内核对CONFIG_ARCH_MMAP_RND_BITS 基地址位数有限制,此选项在arch/arm64/Kconfig里定义并和page页大小设置有关联,mmap在64K页下会失败。

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值