pcie设备bar地址空间映射到用户空间的方式

该程序通过指定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;
}

你可能感兴趣的:(linux开发,linux驱动,linux)