该程序通过指定pcie设备的vendor id和device id能够将设备的bar空间映射到用户空间,用户空间可以通过映射后的地址对bar进行读写操作,方便驱动调试。
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef unsigned long long __u64;
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)
#define SEARCH_ROOT_DIR "/sys/devices"///pci0000:00/0000:00:03.0/0000:04:00.0/0000:05:01.0/0000:06:00.0"
#define MAIN_DEV_ID_FILE "vendor"
#define SUB_DEV_ID_FILE "device"
#define VIRADDR_FILE "resource"
#define MAX_FILE_NAME_LONG 255
#define MAX_DIR_PATH_LONG 255
int pci_get_attrvalue_by_file(__u64 *pValue, char *fileName, __u64 region)
{
FILE * fp = NULL;
char buf[1024] = {0};
if(0 != access(fileName,F_OK))
return -1;
fp = fopen(fileName, "rb");
if(fp)
{
while(fgets(buf,1024,fp))
{
if (region == 0)
{
fclose(fp);
__u64 tmpVal = (__u64)strtoll(buf, NULL, 16);
*pValue = tmpVal;
return 0;
}
region--;
}
fclose(fp);
}
return -1;
}
int pci_get_bar_phyaddr_by_id(__u64 *pValue, __u64 mainDevId, __u64 subDevId, __u64 region, char *pDirPath)
{
__u64 value = 0;
char fileName[MAX_FILE_NAME_LONG+1] = {0};
memset(fileName, 0, MAX_FILE_NAME_LONG);
snprintf(fileName,MAX_FILE_NAME_LONG,"%s/%s", pDirPath ,MAIN_DEV_ID_FILE);
if(pci_get_attrvalue_by_file(&value, fileName, 0) || value != mainDevId)
return -1;
memset(fileName, 0, MAX_FILE_NAME_LONG);
snprintf(fileName,MAX_FILE_NAME_LONG,"%s/%s", pDirPath ,SUB_DEV_ID_FILE);
if(pci_get_attrvalue_by_file(&value, fileName, 0) || value != subDevId)
return -1;
memset(fileName, 0, MAX_FILE_NAME_LONG);
snprintf(fileName,MAX_FILE_NAME_LONG,"%s/%s", pDirPath ,VIRADDR_FILE);
if(0 == pci_get_attrvalue_by_file(&value, fileName, region))
{
*pValue = value;
return 0;
}
return -1;
}
int pci_get_bar_by_traversal_dir( __u64 *pOutValue, char *dirName, __u64 mainDevId, __u64 subDevId, __u64 region)
{
DIR *pDir = NULL;
struct dirent *pDirent = NULL;
__u64 addr = 0;
int ret = -1;
if( 0 == pci_get_bar_phyaddr_by_id(&addr, mainDevId, subDevId, region, dirName ))
{
*pOutValue = addr;
return 0;
}
else
{
if( (pDir =opendir(dirName))==NULL )
return -1;
while( NULL != (pDirent = readdir(pDir)) )
{
if(4 == pDirent->d_type)//dir
{
char subDirName[MAX_FILE_NAME_LONG+1] = {0};
if(0 == strcmp(pDirent->d_name,".") || 0 == strcmp(pDirent->d_name,".."))
continue;
snprintf(subDirName,MAX_FILE_NAME_LONG,"%s/%s", dirName, pDirent->d_name);
if(0 == pci_get_bar_by_traversal_dir( pOutValue, subDirName, mainDevId, subDevId, region))
{
ret = 0;
break;
}
}
}
closedir(pDir);
}
return ret;
}
int pci_get_bar_phyaddr( __u64 *pOutValue, __u64 mainDevId, __u64 subDevId, __u64 region)
{
return pci_get_bar_by_traversal_dir(pOutValue, SEARCH_ROOT_DIR, mainDevId, subDevId, region);
}
int main(int argc, char **argv)
{
void *membase=NULL;
__u64 target=0;
int mmap_fd;
void *map_base;
__u64 mainDevId;
__u64 subDevId;
if(argc != 3)
{
printf("param error\n");
return -1;
}
mainDevId = strtoll(argv[1],NULL,16);
subDevId = strtoll(argv[2],NULL,16);
if(pci_get_bar_phyaddr(&target, mainDevId,subDevId, 0))
{
fprintf(stderr, "pci_get_attrvalue_by_file mainDevId:0x%llx subDevId:0x%llx err\n", mainDevId,subDevId);
return -1;
}
printf("bar phyaddr:0x%llx\n",target);
if((mmap_fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
fflush(stdout);
/* Map one page */ //将内核空间映射到用户空间
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, target & ~MAP_MASK);
if(map_base == (void *) -1) FATAL;
printf("Memory mapped at address %p.\n", map_base);
fflush(stdout);
membase = map_base + (target & MAP_MASK);
printf("bar map virtual address %p.\n", map_base);
close(mmap_fd);
return 0;
}