将物理设备映射到用户空间中的指针 [英] Mapping a physical device to a pointer in User space

查看:98
本文介绍了将物理设备映射到用户空间中的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个嵌入式系统,其中连接了内存映射的设备,而ARM CPU运行Linux.该设备位于地址0x40400000上并占用了一个兆字节(其中大部分没有实际内存支持,但是地址空间始终映射到该设备).我们目前没有具有该设备的设备驱动程序.

We have an embedded system where a memory mapped device is connected, and an ARM CPU runs Linux. The device is located at address 0x40400000 and occupies a megabyte (most of it is not backed by an actual memory, but the address space is mapped to the device anyway). We currently don't have a device driver for this device.

在设备中,地址0x404f0704上有一个特殊的只读寄存器(称为CID).该寄存器包含值CID = 0x404.我正在尝试从ARM上运行的程序读取此寄存器.

In the device there is a special read-only register (called CID) at address 0x404f0704. This register contains the value CID = 0x404. I am trying to read this register from a program running on the ARM.

搜索网络时,我了解了mmap()函数,该函数应该可以让我从用户空间访问物理地址.因此,尝试遵循我发现的几个示例,我编写了以下测试:

Searching the net I learned about the mmap() function that supposedly lets me access a physical address from userspace. So, trying to follow a couple of examples I found, I wrote the following test:



#include <sys/mman.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    void          *pdev = (void *) 0x40400000;
    size_t         ldev = (1024*1024);
    int           *pu;
    int  volatile *pcid;
    int  volatile  cid;

    pu = mmap(pdev, ldev, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
    if (pu == MAP_FAILED)
        errx(1, "mmap failure");

    pcid = (int *) (((void *) pu) + 0xf0704);

    printf("pu    = %08p\n", pu);
    printf("pcid  = %08p\n", pcid);

    cid = *pcid;
    printf("CID   = %x\n", cid);

    munmap(pu, ldev);

    return (EXIT_SUCCESS);
}

使用ARM交叉编译器进行编译:

Compiling with the ARM cross-compiler:

a-gcc -O0 -g3 -o mmap-test.elf mmap-test.c

我无法获得预期的结果.我看到的是:

I can't get the expected result. What I see is that:

pu   = 0x40400000
pcid = 0x404f0704
CID  = 0

而不是预期的

CID  = 404

我在这里想念什么/做错什么了吗?

What am I missing / doing wrong here?

更新:

我找到了另一个演示程序,并按照其代码运行了我的代码:

I found another demo program and following its code I was able to get my code working:



int main(void)
{
    off_t          dev_base = 0x40400000;
    size_t         ldev = (1024 * 1024);
    unsigned long  mask = (1024 * 1024)-1;
    int           *pu;
    void          *mapped_base;
    void          *mapped_dev_base;
    int  volatile *pcid;
    int  volatile  cid;
    int            memfd;

    memfd = open("/dev/mem", O_RDWR | O_SYNC);
    mapped_base = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, dev_base & ~MAP_MASK);
    if (mapped_base == MAP_FAILED)
        errx(1, "mmap failure");
    mapped_dev_base = mapped_base + (dev_base & MAP_MASK);
    pu = mapped_dev_base;

    pcid = (int *) (((void *) pu) + 0xf0704);

    printf("pu    = %08p\n", pu);
    printf("pcid  = %08p\n", pcid);

    cid = *pcid;
    printf("CID   = %x\n", cid);

    munmap(mapped_base, ldev);
    close(memfd);

    return (EXIT_SUCCESS);
}

仍然,我不确定为什么第一个版本不起作用.我的理解是,一旦使用MAP_ANONYMOUS,就不需要用于映射的文件句柄.另外,我显然将 addr 参数(在我的第一个版本中为pepi)误认为是物理地址.如果我现在在话,那么这实际上是虚拟地址.

Still, I am not so sure why the 1st version did not work. My understanding was that once you use MAP_ANONYMOUS you do not need a file handle for the mapping. Also, I obviously mistaken the addr argument (pepi in my 1st version) to be the physical address. If I am right now, then this is actually the virtual address.

推荐答案

Mmap是通常与虚拟地址一起使用的功能.当您调用mmap(... MAP_ANONYMOUS)(或/dev/zero文件的mmap)时,它将为您提供一定数量的新虚拟内存,填充为零.返回的地址将是虚拟内存的地址.

Mmap is the function which usually works with virtual addresses. When you call mmap(... MAP_ANONYMOUS) (or mmap of /dev/zero file) it will give you some amount of new virtual memory, filled with zero. Address returned will be address of virtual memory.

您可以映射某些文件(不使用MAP_ANONYMOUS),然后mmap会将文件内容映射到某个虚拟内存范围.

You can mmap some file (without MAP_ANONYMOUS) and then mmap will map file contents into some virtual memory range.

该设备位于地址0x40400000

The device is located at address 0x40400000

设备MMIO位于物理内存中;任何进程都可以使用虚拟地址0x40400000;但是它们会被MMU(内存管理单元)映射(翻译)到一些免费的物理页面上.您不能只要求OS提供一些虚拟内存,而期望它会被映射到设备范围(这将是地狱的变种).

Device MMIO is located in Physical memory; any process can use virtual address 0x40400000; but they will be mapped (translated) to some free physical page by MMU (memory management unit). You can't just ask OS for some virtual memory and expect that is will be mmaped to device range (it will be variant of hell).

但是有一个特殊的设备,/dev/mem,可以用作包含所有物理内存的文件. 当您mmap的/dev/mem时,您实际上是在要求OS创建一些虚拟内存到要求的物理范围的新映射.

But there is a special device, /dev/mem, which can be used as File containing all physical memory. When you mmaps /dev/mem you are actually asking OS to create new mapping of some virtual memory into asked physical range.

在调用mmap时:

 mapped_base = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, 
   MAP_SHARED, memfd, dev_base & ~MAP_MASK);

您要求将物理内存范围[0x40400000 .. 0x4050000-1](一个兆字节;不包括字节0x40500000)映射到某个兆字节的虚拟内存(其起始地址由mmap返回).

you ask to map physical memory range [0x40400000 .. 0x4050000-1] (one megabyte; not including byte 0x40500000) into some megabyte of virtual memory (its starting address is returned by mmap).

这篇关于将物理设备映射到用户空间中的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆