#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/io.h>
#define PCI_DEVICE "/sys/bus/pci/devices"
#define PCI_DEVICE_SOMEONE "/sys/bus/pci/devices/%s"
#define PCI_DEVICE_SOMEONE_RES "/sys/bus/pci/devices/%s/resource"
#define RES_BAR3 "%*x%*x%*x\n%*x%*x%*x\n%*x%*x%*x\n%lx"
#define RES_BAR2 "%*x%*x%*x\n%*x%*x%*x\n%lx"
vector<uint64_t> m_Bar3PhyAddVec;
vector<void*> m_Bar3VirAddVec;
vector<uint64_t> m_Bar2PhyAddVec;
vector<void*> m_Bar2VirAddVec;
// Function to find the Base Address Register (BAR3) of a device with matching vendor and device IDs
int CanFwDownload::findBAR(uint32_t vendorID, uint32_t deviceID, int barX)
{
DIR *dir;
struct dirent *entry;
char path[PATH_MAX];
// Open the PCI devices directory
dir = opendir(PCI_DEVICE);
if (dir == NULL) {
perror("Failed to open PCI devices directory");
return -1;
}
// Iterate through each directory entry in the PCI devices directory
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_LNK) {
// Generate the path to the current device directory
snprintf(path, sizeof(path), PCI_DEVICE_SOMEONE, entry->d_name);
// Check if the current device matches the vendor and device IDs
if (isMatchingDevice(path, vendorID, deviceID)) {
// Generate the path to the device's BAR3 file
snprintf(path, sizeof(path), PCI_DEVICE_SOMEONE_RES, entry->d_name);
printf("dev name:%s\n",entry->d_name);
// Open the device's BAR3 file
FILE *file = fopen(path, "r");
if (file == NULL) {
perror("Failed to open resource file");
continue;
}
if (barX == BAR3) {
// Read the BAR3 value from the file
uint64_t bar3 = 0;
int n = fscanf(file, RES_BAR3, &bar3);//"%*x" is read and skip a hex value,"%\n" is read and skip a line break
if (n != 1) {
perror("Can not get BAR3\n");
fclose(file);
return -1;
}
printf("vend id:0x%0x,deice id:0x%04x,Bar3:0x%lx,d_name:%s\n",vendorID,deviceID,bar3,entry->d_name);
m_Bar3PhyAddVec.push_back(bar3);
}
if (barX == BAR2) {
// Read the BAR3 value from the file
uint64_t bar2 = 0;
int n = fscanf(file, RES_BAR2, &bar2);//"%*x" is read and skip a hex value,"%\n" is read and skip a line break
if (n != 1) {
perror("Can not get BAR2\n");
fclose(file);
return -1;
}
printf("vend id:0x%0x,deice id:0x%04x,Bar2:0x%lx\n",vendorID,deviceID,bar2);
m_Bar2PhyAddVec.push_back(bar2);
}
fclose(file);
}
}
}
closedir(dir);
return Success;
}
int CanFwDownload::mapVirtualAddr(vector<uint64_t> &barXPhyAddVec,vector<void*> &barXVirAddr,int barX)
{
void *map_base, *virt_addr;
unsigned page_size, mapped_size, offset_in_page;
off_t target;
unsigned width = 8 * sizeof(int);
int fd = open("/dev/mem", (O_RDWR | O_SYNC),0666);
if (fd < 0) {
printf("Can't open /dev/mem\n");
return fd;
}
page_size = getpagesize();
mapped_size = page_size;
printf("---pageSize:%d\n",page_size);
//mapped_size = MAP_SIZE;
for (auto iter = barXPhyAddVec.begin();iter < barXPhyAddVec.end();++iter) {
target = *iter;
//target = barXPhyAddVec[0];
offset_in_page = (unsigned)target & (page_size - 1);
off_t off = target & ~(off_t)(page_size - 1);
printf("=====offset_in_page:%u,PhtAddr:0x%0lx,offset:0x%0lx\n",offset_in_page,target,off);
if (offset_in_page + width > page_size) {
/* This access spans pages.
* Must map two pages to make it possible: */
mapped_size *= 2;
}
//map_base = mmap(NULL,mapped_size,(PROT_READ | PROT_WRITE),MAP_SHARED,fd,target & ~(off_t)(page_size - 1));
//map_base = mmap(NULL, getpagesize() + 8192, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 1024 * 1024);
if (barX == BAR3) {
map_base = mmap(NULL, FLASH_MAP_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, target & ~(off_t)(page_size - 1));
}else if (barX == BAR2) {
map_base = mmap(NULL, page_size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, target & ~(off_t)(page_size - 1));
}
if (map_base == MAP_FAILED){
printf("mmap failed.errno:0x%0x\n",errno);
return -1;
}
virt_addr = (char*)map_base + offset_in_page;
barXVirAddr.push_back(virt_addr);
}
return 0;
}
//FwDownload deviceID FwPath
int main(int argc, char* argv[])
{
uint32_t devId = strtoul(argv[1],NULL,16);
printf("devid:0x%04x\n",devId);
int ret = findBAR(VENDOR_ID, devId, BAR3);
if (ret != Success) {
printf("findBAR3,Some error occured!\n");
return ret;
}
ret = mapVirtualAddr(m_Bar3PhyAddVec,m_Bar3VirAddVec,BAR3);
if (ret != Success) {
printf("mapVirtualAddr bar3,Some error occured!,errno:0x%0x\n",errno);
return ret;
}
ret = findBAR(VENDOR_ID, devId, BAR2);
if (ret != Success) {
printf("findBAR2,Some error occured!\n");
return ret;
}
ret = mapVirtualAddr(m_Bar2PhyAddVec,m_Bar2VirAddVec,BAR2);
if (ret != Success) {
printf("mapVirtualAddr Bar2,Some error occured!,errno:0x%0x\n",errno);
return ret;
}
}
注意的知识点:
机器上插了两张卡,①和②是不同地方打印的两张卡的BAR3地址,实际上是—样的,注意观察③的地址,实际上正好和①和②相同,也就是此种情况下,mmap函数映射物理地址到操作系统虚拟地址空间时,最后一个参数offset的地址,正好是两张卡各自BAR3的物理地址。