I211学习笔记
查看PCIE设备的BAR
通过cpu spc查看PCIE配置寄存器存放信息,可以看到在**0x80000000L偏移10h处便是映射的内存地址**:
这个地址有多种方法查看,在RU下可以通过F6直接打开对应设备的寄存器基地址查看,也可以通过编程IO方式查看,主要是要知道base address + bus + dev +fun。再根据addr = Ox80000000 L | (bus<<16) | (dev<<11) | (fun<<8)|offset 计算。
RU下查看
通过打印pci的配置空间查看
在ubuntu下可以通过命令查看pcie设备内存映射的地址
lspci -vv
访问I211的控制寄存器、状态寄存器等
读取某一个PCIe设备(比如网卡)的控制寄存器、状态寄存器。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#define I211_BAR0_ADDR 0xf7500000
#define I211_BAR0_SIZE (128 * 1024) // 128KB
// I211寄存器偏移
#define I211_REG_CTRL 0x0000 // Device Control
#define I211_REG_STATUS 0x0008 // Device Status
#define I211_REG_EERD 0x0014 // EEPROM Read
#define I211_REG_ICR 0x00C0 // Interrupt Cause Read
#define I211_REG_MAC_L 0x5400 // MAC地址低32位
#define I211_REG_MAC_H 0x5404 // MAC地址高16位
// 寄存器访问
uint32_t read_reg32(volatile void *base, uint32_t offset) {
return *(volatile uint32_t*)((uint8_t*)base + offset);
}
void write_reg32(volatile void *base, uint32_t offset, uint32_t value) {
*(volatile uint32_t*)((uint8_t*)base + offset) = value;
}
int main() {
int fd;
void *base_addr;
// 打开物理内存
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
printf("Error opening /dev/mem: %s\n", strerror(errno));
return -1;
}
// 映射BAR0地址空间
base_addr = mmap(NULL, I211_BAR0_SIZE, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, I211_BAR0_ADDR);
if (base_addr == MAP_FAILED) {
printf("Error mapping memory: %s\n", strerror(errno));
close(fd);
return -1;
}
// 读取控制寄存器
uint32_t ctrl = read_reg32(base_addr, I211_REG_CTRL);
printf("Control Register (0x%04X): 0x%08X\n", I211_REG_CTRL, ctrl);
// 读取状态寄存器
uint32_t status = read_reg32(base_addr, I211_REG_STATUS);
printf("Status Register (0x%04X): 0x%08X\n", I211_REG_STATUS, status);
// 读取MAC地址
uint32_t mac_l = read_reg32(base_addr, I211_REG_MAC_L);
uint32_t mac_h = read_reg32(base_addr, I211_REG_MAC_H);
printf("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
(uint8_t)(mac_l),
(uint8_t)(mac_l >> 8),
(uint8_t)(mac_l >> 16),
(uint8_t)(mac_l >> 24),
(uint8_t)(mac_h),
(uint8_t)(mac_h >> 8));
// 清理
munmap(base_addr, I211_BAR0_SIZE);
close(fd);
return 0;
}
编译运行
gcc -o GetNetInfo GetNetInfo.c
./GetNetInfo