应用层通过mmap进行地址映射,读写pcie bar

如何在应用层通过进行地址映射,读写pcie bar

mmap函数说明
mmap 函数是 Unix 和 Linux 操作系统中的一个重要系统调用,用于将文件或者其它对象映射到进程的地址空间中。映射完成后,进程可以通过指针直接访问这些映射区域,就像访问普通的内存一样。这种方式可以提高文件 I/O 的效率,并支持内存映射文件的共享。
函数原型
mmap 的函数原型通常如下:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数说明
• addr: 指定映射区域的起始地址。如果设置为 NULL,则由系统自动选择一个合适的地址。
• length: 映射区域的长度(以字节为单位)。
• prot: 映射区域的保护标志,可以是以下标志的组合:
• PROT_READ: 区域可读。
• PROT_WRITE: 区域可写。
• PROT_EXEC: 区域可执行。
• PROT_NONE: 区域不可访问。
• flags: 映射区域的标志,可以是以下标志的组合:
• MAP_SHARED: 与文件共享映射,对映射区域的更改会被写回文件。
• MAP_PRIVATE: 私有映射,对映射区域的更改不会写回文件,而是创建一个写时复制(copy-on-write)的副本。
• MAP_ANONYMOUS 或 MAP_ANON: 匿名映射,映射不与任何文件关联。
• MAP_FIXED: 必须将映射区域映射到 addr 指定的地址,否则失败。
• MAP_POPULATE: 立即读取文件数据,而不是延迟加载。
• 其他系统特定的标志。
• fd: 文件描述符,通常是从 open 获得的。如果使用匿名映射,则设为 -1。
• offset: 文件映射的偏移量(以字节为单位)。
返回值
mmap 函数成功时返回映射区域的起始地址,如果失败则返回 MAP_FAILED(通常定义为 (void *) -1),并通过 errno 设置错误代码。
示例
假设有一个文件描述符 fd,我们想映射文件的一部分到内存中,可以这样做:

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>

int main() {
    int fd;
    char *mapped_addr;

    // 打开文件
    fd = open("example.txt", O_RDWR);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 映射文件
    mapped_addr = (char *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (mapped_addr == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }

    // 使用映射的内存
    printf("Mapped data at address: %p\n", mapped_addr);
    // 可以直接修改或读取mapped_addr指向的内容

    // 取消映射
    munmap(mapped_addr, 4096);

    // 关闭文件描述符
    close(fd);

    return 0;
}

注意事项
• 当使用 mmap 进行文件映射时,文件必须是可寻址的,即文件大小必须小于或等于映射区域的大小。
• 对于私有映射(MAP_PRIVATE),映射区域的更改不会直接写回到文件中,而是创建一个副本。如果需要将更改写回文件,可以使用 msync 函数。
• 使用完毕后,需要调用 munmap 函数来取消映射,释放资源。
mmap 是一种高效的数据访问方式,特别是在处理大型文件或共享内存时非常有用。

接下来贴一个通过mmap读写pcie bar的小程序,仅供参考:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

#include <libgen.h>

#include <sys/mman.h>

#define MEM_DEBUG	0
#if MEM_DEBUG==1
#define open(f, o, m)			1
#define close(fd)				0
#define lseek(fd, off, opt)		1
#define read(fd, buf, size)		strncpy((void *)buf,"0123456789abcdef", size)
#endif

#define ALIGN(p, n)      (((p) & ~(n-1)))
#define ISPRINT(c)      ((c) >= 0x20 && (c) < 0x7f)

typedef struct {
	void *addr;
	size_t length;
} my_mmap_t;

static void *
my_mmap(my_mmap_t *m, void *addr, size_t length, int prot, int flags,
	int fd, off_t org_offset)
{
	off_t offset;
	off_t diff;
	size_t pgsize;
	void *p;

	pgsize = sysconf(_SC_PAGE_SIZE);
	offset = ALIGN(org_offset, pgsize);
	diff = org_offset - offset;

	if ((p = mmap(addr, length + diff, prot, flags, fd, offset)) == MAP_FAILED)
		return p;
	m->addr = p;
	m->length = length + diff;
	return (char *)p + diff;
}

static int
my_munmap(my_mmap_t *m)
{
	return munmap(m->addr, m->length);
}


static void
memdump(u_int8_t *buf, int offset, size_t bytes, int width)
{
	int last = (offset&0xf)+bytes;
	int i, j, total=ALIGN(last+0xf, 16);
	u_int8_t *bp;

	for (i=0; i<total; i+=16) {
		printf("%08x: ", ALIGN(offset+i, 16));
		bp = buf + i - (offset&0xf);
		for (j=0; j<16; j+=width) {
			if (i+j<(offset&0xf) || i+j>=last) {
				printf("%*s ", width*2, "");
				continue;
			}
			switch (width) {
			case 1:
				printf("%02x", *(u_int8_t *) (bp + j));
				break;
			case 2:
				printf("%04x", *(u_int16_t *) (bp + j));
				break;
			case 4:
				printf("%08x", *(u_int32_t *) (bp + j));
				break;
			}
			printf(" ");
		}

		printf("|");

		for (j=0; j<16; j++) {
			if (i+j<(offset&0xf) || i+j>=last) {
				printf(" ");
				continue;
			}
			printf("%c", ISPRINT(bp[j]) ? bp[j] : '.');
		}

		printf("\n");
	}
}

static void
read_memory(int fd, u_int64_t s_addr, int len, int size)
{
	my_mmap_t m;
	void *addr;


	addr = my_mmap(&m, 0, len, PROT_READ, MAP_FILE|MAP_SHARED, fd, s_addr);
	if (addr==MAP_FAILED){
		perror("mmap");
		return;
	}
	memdump(addr, s_addr, len, size);
	my_munmap(&m);

	return;
}

static 
read_memory_result(int fd, u_int64_t s_addr, int len, int size)
{
	my_mmap_t m;
	void *addr;


	addr = my_mmap(&m, 0, len, PROT_READ, MAP_FILE|MAP_SHARED, fd, s_addr);
	if (addr==MAP_FAILED){
		perror("mmap");
		return;
	}
	memdump(addr, s_addr, len, size);
	my_munmap(&m);

	return;
}

static void
write_memory(int fd, u_int64_t s_addr, u_int32_t val, int size, int total)
{
	my_mmap_t m;
	int i;
	void *addr;
	u_int8_t val_8 = val;
	u_int16_t val_16 = val;
	u_int32_t val_32 = val;

	if (s_addr!=ALIGN(s_addr, size)){
		printf("miss align %d %d\n", s_addr, size);
		return;
	}

	printf("Write 0x%llx-0x%llx 0x%x %d\n",
		s_addr, ALIGN(s_addr+total+size-1, size), val, size);

	addr = my_mmap(&m, 0, total, PROT_READ|PROT_WRITE, MAP_SHARED, fd, s_addr);
	if (addr==MAP_FAILED){
		perror("mmap");
		return;
	}

	for (i=0; i<total; i+=size) {
		switch (size) {
		case 1:
			*(u_int8_t *)((u_int64_t)addr+i) = val_8;
			break;
		case 2:
			*(u_int16_t *)((u_int64_t)addr+i) = val_16;
			break;
		case 4:
			*(u_int32_t *)((u_int64_t)addr+i) = val_32;
			break;
		}
	}

	my_munmap(&m);
}

static void
and_memory(int fd, u_int64_t s_addr, u_int32_t val, int size)
{
	my_mmap_t m;
	void *addr;

	if (s_addr!=ALIGN(s_addr, size)){
		printf("miss align %d %d\n", s_addr, size);
		return;
	}

	printf("AND 0x%x ", s_addr);
	addr = my_mmap(&m, 0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, s_addr);
	if (addr==MAP_FAILED){
		perror("mmap");
		return;
	}

	switch (size) {
	case 1:
		printf("0x%02x->0x%02x\n",
			*(u_int8_t *)addr, *(u_int8_t *)addr&(u_int8_t)val );
		*(u_int8_t *)addr &= (u_int8_t)val;
		break;
	case 2:
		printf("0x%04x->0x%04x\n",
			*(u_int16_t *)addr, *(u_int16_t *)addr&(u_int16_t)val );
		*(u_int16_t *)addr &= (u_int16_t)val;
		break;
	case 4:
		printf("0x%08x->0x%08x\n",
			*(u_int32_t *)addr, *(u_int32_t *)addr&(u_int32_t)val );
		*(u_int32_t *)addr &= (u_int32_t)val;
		break;
	}

	my_munmap(&m);
}

static void
or_memory(int fd, u_int64_t s_addr, u_int32_t val, int size)
{
	my_mmap_t m;
	void *addr;

	if (s_addr!=ALIGN(s_addr, size)){
		printf("miss align %d %d\n", s_addr, size);
		return;
	}

	printf("OR 0x%x ", s_addr);
	addr = my_mmap(&m, 0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, s_addr);
	if (addr==MAP_FAILED){
		perror("mmap");
		return;
	}

	switch (size) {
	case 1:
		printf("0x%02x->0x%02x\n",
			*(u_int8_t *)addr, *(u_int8_t *)addr|(u_int8_t)val );
		*(u_int8_t *)addr |= (u_int8_t)val;
		break;
	case 2:
		printf("0x%04x->0x%04x\n",
			*(u_int16_t *)addr, *(u_int16_t *)addr|(u_int16_t)val );
		*(u_int16_t *)addr |= (u_int16_t)val;
		break;
	case 4:
		printf("0x%08x->0x%08x\n",
			*(u_int32_t *)addr, *(u_int32_t *)addr|(u_int32_t)val );
		*(u_int32_t *)addr |= (u_int32_t)val;
		break;
	}

	my_munmap(&m);
}
#undef ALIGN

static int count=0;
static u_int32_t pattern[] =
		{0x00000000, 0xaaaaaaaa, 0x55555555,
		0xa5a5a5a5, 0x5a5a5a5a, 0xffffffff};

static void
signal_handler_usr1(int sig)
{
	printf("Signal %d catched\n", sig);
	printf("Current count %d pattern %x\n",
		count, pattern[count%(sizeof(pattern)/sizeof(u_int32_t))]);
}

static void
test_memory(int fd, u_int32_t size)
{
	u_int32_t *addr;
	int i;

	if ((addr = malloc(size))==NULL) {
		perror("malloc:");
		return;
	}
	while (1) {
		for (i=0; i<sizeof(u_int32_t); i++) {
			*(addr+i) = pattern[count%(sizeof(pattern)/sizeof(u_int32_t))];
		}
		count++;
	}
}

static void
verify_memory(int fd, u_int32_t s_addr, int val, int size)
{
	my_mmap_t m;
	u_int8_t *addr;
	int i;

	addr = my_mmap(&m, 0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, s_addr);
	if (addr==MAP_FAILED){
		perror("mmap");
		return;
	}
	for (i=0; i<size; i++) {
		if (*(addr+i)!=val) {
			printf("Addr %p %x!=%x\n", addr+i, *(addr+i), val);
		}
	}
	my_munmap(&m);
}

static void
usage(char *com)
{
	fprintf(stderr, "%s: read <addr> <length> [<1,2 or 4>]\n", com);
	fprintf(stderr, "%*s  write <addr> <val> [<1,2 or 4> [<repeat>]]\n",
		strlen(com), " ");
	fprintf(stderr, "%*s  and <addr> <val> [<1,2 or 4>]\n", strlen(com), " ");
	fprintf(stderr, "%*s  or <addr> <val> [<1,2 or 4>]\n", strlen(com), " ");
	fprintf(stderr, "%*s  test <size>\n", strlen(com), " ");
	fprintf(stderr, "%*s  verify <addr> <val> <size>\n", strlen(com), " ");
}

int
main(int argc, char *argv[])
{
	int fd;
	int len;
	u_int64_t addr;
	u_int32_t val;
	int size=1;
	int total=1;

	if (argc<3) {
		usage(basename(argv[0]));
		return 1;
	}
	if ((fd=open("/dev/mem", O_RDWR, 0))<0) {
		perror("open");
		return 1;
	}

	addr = strtoul(argv[2], NULL, 0);

	if (argc>4) {
		size = strtol(argv[4], NULL, 0);
		if (size!=1 && size!=2 && size!=4 && strncmp(argv[1], "verify", strlen(argv[1])!=0)) {
			size = 1;
		}
	}

	if (strncmp(argv[1], "read", strlen(argv[1]))==0) {
		len = strtoul(argv[3], NULL, 10);
		read_memory(fd, addr, len, size);
	}
	else if (strncmp(argv[1], "write", strlen(argv[1]))==0) {
		val = strtoul(argv[3], NULL, 0);
		if (argc>5) {
			total = strtoul(argv[5], NULL, 0);
		}
		else {
			total = 1;
		}
		write_memory(fd, addr, val, size, total);
	}
	else if (strncmp(argv[1], "and", strlen(argv[1]))==0) {
		val = strtoul(argv[3], NULL, 0);
		and_memory(fd, addr, val, size);
	}
	else if (strncmp(argv[1], "or", strlen(argv[1]))==0) {
		val = strtoul(argv[3], NULL, 0);
		or_memory(fd, addr, val, size);
	}
	else if (strncmp(argv[1], "test", strlen(argv[1]))==0) {
		signal(SIGUSR1, signal_handler_usr1);
		addr = (addr/4)*4;
		test_memory(fd, addr);
	}
	else if (strncmp(argv[1], "verify", strlen(argv[1]))==0) {
		val = strtoul(argv[3], NULL, 0);
		size = strtoul(argv[4], NULL, 0);
		verify_memory(fd, addr, val, size);
	}

	close(fd);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值