Linux内核模块mmap功能无法正常工作

时间:2016-05-31 13:20:51

标签: c linux linux-kernel kernel linux-device-driver

我正在为pcie编写内核驱动程序,为此我需要将大小为4KB的缓冲区从用户空间映射到内核空间。首先,在内核模块初始化时使用kzalloc()分配缓冲区并初始化为0xff。然后在内核端的mmap实现中使用该缓冲区的指针。问题是从用户空间应用程序调用mmap后,缓冲区被写入csv文件以检查映射是否已正确完成,但文件显示某些区域的值正确(0xffffffff),而某些其他区域的垃圾值随机变小部分内容如下所示:

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 006bafdf 00000008 006c9fdf 00000008 00000000 00000000 006c1fdf

根据我在映射后的理解,所有位置都应该打印为0xffffffff。这引起了问题,因为我需要用来自用户应用程序的数据填充此缓冲区并向驱动程序模块发送信号,以便它可以使用writel()函数通过pcie传输数据。映射的内核端代码如下所示:

static int driver_mmap5(struct file *file, struct vm_area_struct *vma)
{
    int ret;
    vma->vm_flags  |= VM_LOCKED|VM_SHARED; 
    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    ret = remap_pfn_range(vma, vma->vm_start,
          virt_to_phys(TEST5) >> PAGE_SHIFT,
          vma->vm_end-vma->vm_start, vma->vm_page_prot);
   if(ret != 0)
   printk("MMAP Failed \n");

   SetPageReserved(virt_to_page(TEST5));

   #ifdef DEBUG
    printk("MMAP Succeeded \n");
   #endif

   return 0;
}

其中TEST5是指向要映射的缓冲区的指针,如下所示:

 long *TEST5;
 TEST5 = kzalloc(PB_BUFF_SIZE,__GFP_COLD|GFP_DMA);
 memset(TEST5,0xff,PB_BUFF_SIZE)

在用户空间应用程序中,分配并映射另一个缓冲区,如下所示:

unsigned long* msg5;
msg5=(unsigned long*)malloc(PB_BUFF_SIZE);

和mmap被称为:

 msg5 = mmap(NULL, PB_BUFF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED , fd, 0);

似乎映射存在一些问题,因为某些部分已映射而某些部分未映射,因此值不正确。请提出这个问题的原因和解决方案。

此致

编辑:在

下添加驱动程序和应用程序端的相关代码

缓冲区映射的驱动程序端代码

long *TEST5;
#define PB_BUFF_SIZE 8192

static int driver_mmap5(struct file *file, struct vm_area_struct *vma)

{
  int ret;
    vma->vm_flags  |= VM_LOCKED|VM_SHARED; 
    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                ret = remap_pfn_range(vma, vma->vm_start,
                      virt_to_phys(TEST5) >> PAGE_SHIFT,
                      vma->vm_end-vma->vm_start, vma->vm_page_prot);
  if(ret != 0)
   printk("MMAP Failed \n");

  SetPageReserved(virt_to_page(TEST5));

 #ifdef DEBUG
   printk("MMAP Succeeded \n");
 #endif

 return 0;

}

struct file_operations proc_fops5 = 
   {
     //.read  = read_proc,
     .write = write_proc5, 
     .mmap  = driver_mmap5,
   }; 


static void create_new_proc_entries(void) 
   {


    proc_create ("PCI_PICOZED_Param5",0,NULL, &proc_fops5);

    printk(KERN_DEBUG "Proc entries created successfully\n"); 

   } 

  static void Delete_proc_entries(void) 
   {

    remove_proc_entry ("PCI_PICOZED_Param5", NULL);

    printk(KERN_DEBUG "Proc entries removed successfully\n");
   } 

static int __init pci_skel_init(void)
  {

   TEST5 = kzalloc(PB_BUFF_SIZE,__GFP_COLD|GFP_DMA);
   memset(TEST5,0xff,PB_BUFF_SIZE);//test with mem
   printk("memset array ok\n");

   //adding print of few buffer values
   int i=0;
   for(i=0;i<20;i++)
    printk("alloc TEST5[%d]=%.8lx, add=%.lx\n",i,TEST5[i],TEST5+i);//should be 0xff

   return 1;   
  }



  static void __exit pci_skel_exit(void)
   {

    Delete_proc_entries();  
    kfree(TEST5);

   }


module_init(pci_skel_init);
module_exit(pci_skel_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Malik");
MODULE_DEVICE_TABLE(pci, PCI_ID_K);

缓冲区映射和测试的应用程序端代码

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


#define PB_BUFF_SIZE 8192
unsigned long *msg5 = NULL;

int main(int argc,char *argv[])//adding cmd line arguments to control the operating mode 
{
    int mode=0; //mode 1 for VDM, mode 2 for playback
    if(argc==2)
    {

        mode=atoi(argv[1]);
        printf("The operating mode is %d\n",mode);
    }
    else
    {
        mode=1;//default mode VDM
    }
    int fd,i;
    char str [10];
    //msg5=(unsigned long*)malloc(PB_BUFF_SIZE); //now commented as mmap returns allocated memory

    //buffer mapping
    if((fd=open("/proc/PCI_PICOZED_Param5", O_RDWR ))

<0)//open("/proc/PCI_PICOZED_Param", O_RDONLY )
        {
         printf("File not opened ");
        }

        printf("fd PCI_PICOZED_Param5 opened\n");

        msg5 = mmap(NULL, PB_BUFF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED , fd, 0);
        if(msg5==MAP_FAILED)
        {
         printf("MAP failed and error is %s", strerror(errno));
         return 0;
        }
        close(fd);
       fd=open("Init_check_msg5.csv", O_CREAT | O_RDWR );
       for(i=0;i < PB_BUFF_SIZE/4 ;i++)
         {
            //fprintf(bf,"%.8lx\n",msg5[i]);
            sprintf(stri, "%.8lx\n",msg5[i]);
            write(fd,stri,20);
         }
       close(fd);
       return 0
    }

然后检查csv文件中的值,这些值显示上述行为。

0 个答案:

没有答案