【问题标题】:Getting empty output when reading from file using "mmap"使用“mmap”从文件读取时得到空输出
【发布时间】:2017-12-12 08:56:23
【问题描述】:

我在考虑使用 mmap 时遇到问题。我正在尝试将 pci 设备映射到虚拟地址并读取其内容。以后我也打算给它写值。

问题是我(似乎)成功地将设备映射到虚拟内存空间。但是,当我读取该虚拟地址的内容时,所有值都为零,尽管文件不是空的。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "../include/types.h"
#include "../include/pci.h"

#define PRINT_ERROR \
    do { \
        fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
        __LINE__, __FILE__, errno, strerror(errno)); exit(1);\
     } while(0)

#define MAP_SIZE 4069
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char *argv[])
{
    int pci_dev;
    int *mmap_base;
    int *content;
    char file[] = {"/sys/bus/pci/devices/0000:04:00.0/resource"};
    int i;

    printf("File to be read from: %s\n", file);

    pci_dev = open(file, O_RDONLY);
    if (pci_dev < 0)
    {
        PRINT_ERROR;
    }

    mmap_base = mmap(NULL, MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANON, pci_dev, 0);
    if (mmap_base == (void *)-1 || mmap_base == NULL)
    {
        PRINT_ERROR;
    }
    printf("Mapped on address %p of size %d Byte\n", mmap_base, (int)MAP_SIZE);
    content = (int *)mmap_base;

    for(i = 0; i < 1024; i++)
    {
        printf("%x", content[i]);
    }


    return 0;
}

这是我试图访问的文件"/sys/bus/pci/devices/0000:04:00.0/resource" 第一行的内容:

0x00000000cd000000 0x00000000cd07ffff 0x0000000000040200

但是我得到的输出是:

File to be read from: /sys/bus/pci/devices/0000:04:00.0/resource
Mapped on address 0xb7705000 of size 4096 Byte
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...

我做错了吗?感谢您的每一次帮助!

【问题讨论】:

  • 在与您的问题无关的注释上,您真的是指4069MAP_SIZE 吗?不是4096 通常的二次幂值吗?是实际代码中的拼写错误,还是您为问题重写了代码?如果是后者,那就不要那样做。 复制粘贴 Minimal, Complete, and Verifiable Example。这样您就不会引入不相关的错误,甚至可能(不经意间)解决问题。
  • 不,那是我文件的实际代码。当我只写 4096 时,我收到一条警告,指出 int 是错误的数据类型。在那种情况下有关系吗?编辑:我将值更改为 (int) 4096,现在我不再收到警告...当我仍在努力从 mmap 获取指针而不是错误代码时收到警告。
  • 那么它将无法构建 (#include ...),并且您显示的输出与代码不匹配(代码显示 MAP_SIZE4069 但您的输出显示为 4096 )。因此,您显示的代码不是您构建和运行的实际代码。像这样的小事情让我们更难以信任其余的代码,所以很多可以帮助你的人都不会这样做。
  • 我发誓我唯一改变的是删除包含。我编辑了我的帖子并附上了屏幕截图。
  • "MAP_PRIVATE | MAP_ANON" ,将其替换为 "MAP_SHARED" ,然后它可以打印文件。我更改了参数来模拟一个旧的mmap演示程序,但我不确定你的参数有什么问题,我稍后会检查它

标签: c linux mmap pci virtual-address-space


【解决方案1】:

其实你有两个错误:

  1. 为文件系统上的真实文件创建映射时不要使用 MAP_ANON,它适用于 IPC,需要操作系统提供额外的内存,例如而 malloc()。
  2. 当您删除该标志时,mmap() 可能会返回 ENODEV,因为 linux sysfs 不支持 mmaping;所以你必须在这里使用 read()。

【讨论】:

  • 哦,我明白了。另一篇文章中有人这么说,我很高兴不再出现错误。是的,我在不使用 MAP_ANON 时确实收到了错误“没有这样的设备”。是否有可能访问 pci 设备并将值写入 BAR 0?我以为 mmap 会解决我的问题,但似乎我错了。
  • @A.Z.如果您尝试访问 BAR 0,则应该映射 resource0 文件,而不是 resource 文件。 resource 文件仅提供有关 BAR 的信息。
  • @IanAbbott 哦,我明白了。不知道,谢谢!由于 resource0 是一个二进制文件,我想访问资源,以便首先检查我的 mmap 是否正常工作,然后查看在哪里可以找到 BAR0。我可以使用 mmap 访问 resource0 文件吗?如果是,我该如何正确地做到这一点?
  • @A.Z.是的,您可以将其映射为 MAP_SHARED。如果 PCI BAR 设置了“prefechable”位,则可能还有一个“resourceN_wc”文件。 “wc”代表“写结合”。
  • 注意,有一个工具做的几乎一样:github.com/billfarrow/pcimem。此外,就内核模块使用设备而言,resourceX 似乎不可用。
猜你喜欢
  • 2013-12-25
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
  • 2014-02-21
  • 1970-01-01
  • 2021-09-14
  • 1970-01-01
  • 2022-12-09
相关资源
最近更新 更多