[英]Failed to read pci csr via mmap using uint64_t pointer
我正在尝试通过open
、 mmap
/dev/mem 在我的系统上读取 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 基地址。
我的代码output如下:
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 中的值存储是正确的,我使用错误的方式获取值吗?
看了其他会员的回复,看了一些可能和这个bug相关的文档,以下是自己的一些感悟:
我尝试用另一个不在 PCI CSR(配置空间寄存器)中的地址进行测试,并得到了正确的值。 所以我认为这个错误与硬件寄存器有关,而不是软件实现
在EDK II UEFI Writer Guide 链接中,使用64bits read on PCI BAR(Base Address Register, PCI CSR的一部分)可能会导致alignment错误,你应该使用2x of 32bits read来实现64bits read。 虽然在示例中并没有强制要求整个 CSR 都有这个限制,但我认为这个错误已经有了很好的理由。
必须使用 1、2 或 4 字节访问来读取 PCIe 配置空间。 不允许进行 8 字节访问。 我的经验是 8 字节访问总是在所有字节中返回 FF。 这是 PCIe 规范要求的结果,即配置空间访问不能跨越 4 字节对齐的边界(第 7.2.2 节)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.