我正在尝试通过open
、mmap
/dev/mem 1阅读系统上的PCI CSR(配置空间寄存器)。
使用8字节长度阅读时遇到一些问题
下面是我的代码的最小工作示例
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define FATAL \
do { \
fprintf(stderr, \
"Error at line %d, file %s (%d) [%s]\n", \
__LINE__, \
__FILE__, \
errno, \
strerror(errno)); \
exit(1); \
} while(0)
#define PAGE_SIZE 4096UL
#define PAGE_MASK (PAGE_SIZE - 1)
typedef struct rw_config rw_config;
struct rw_config {
uint64_t address;
uint64_t data;
};
static uint64_t _mmio_read_worker(uint64_t address) {
int fd;
void *map_base = NULL;
void *map_address = NULL;
uint64_t result = 0UL;
if((fd = open("/dev/mem", O_RDONLY | O_SYNC)) < 0) FATAL;
// PAGE_SIZE = 4096UL
// PAGE_MASK = (PAGE_SIZE - 1) = 4095UL
if((map_base = mmap(NULL,
PAGE_SIZE,
PROT_READ,
MAP_SHARED,
fd,
(address & ~PAGE_MASK)))
== MAP_FAILED)
FATAL;
map_address = map_base + (address & PAGE_MASK);
result = *(uint64_t *)map_address;
printf("uint32_t 0x%016x, uint64_t 0x%016lx\n",
(*(uint32_t *)map_address),
(*(uint64_t *)map_address));
close(fd);
return result;
}
void rw_worker(rw_config *cfg) {
cfg->data = _mmio_read_worker(cfg->address);
return;
}
int main(int argc, char *argv[]) {
rw_config *cfg = malloc(sizeof(rw_config));
cfg->address = 0x80000000;
cfg->data = 0x0;
rw_worker(cfg);
return 0;
}
正在阅读address = 0x80000000
,它是pci mmio基址。
我的代码的输出如下所示:
uint32_t 0x0000000009a28086, uint64_t 0xffffffffffffffff
我试着用gdb来获取一些信息。
(gdb) printf "0x%llx\n",(*(uint64_t *)map_address)
0x10000009a28086
# before assigning 'result'
(gdb) printf "0x%llx\n",result
0x0
(gdb) next
# after assigning 'result'
(gdb) printf "0x%llx\n",result
0xffffffffffffffff
(gdb) print map_address
$2 = (void *) 0x7ffff7ffb000
(gdb) x/1xg 0x7ffff7ffb000
0x7ffff7ffb000: 0x0010000009a28086
我想我没有把(void*)
转换成*(uint64_t *)
,但是为什么呢?
map_address中的值存储是正确的,我是否使用了错误的方法来获取值?
2条答案
按热度按时间pdtvr36n1#
阅读了其他成员的回复后,我阅读了一些可能与此bug有关的文档,以下是我的一些见解:
5vf7fwbs2#
必须使用1、2或4字节访问读取PCIe配置空间。不允许8字节访问。我的经验是8字节访问总是在所有字节中返回FF。这是PCIe规范要求配置空间访问不能跨越4字节对齐边界(第7.2.2节)的结果。