title: Linux kernel module mmap function not working correctly
body: <p>I am working on writing a kernel driver for pcie and for this purpose i need to map a buffer of size 4KB from user space to kernel space. Firstly a buffer is allocated at the kernel module initialization using kzalloc() and initialized to 0xff. The pointer of this buffer is then used in the mmap implementation from kernel side. The issue is that after mmap is called from the user space application the buffer is written to a csv file to check if mapping has been done correctly however the file shows certain regions with correct values (0xffffffff) and certain others with garbage values randomly a small portion of this is shown below:</p>
  
  <p>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</p>
  
  <p>Whereas as per my understanding after the mapping all locations should have been printed as 0xffffffff. This is causing issue because I need to fill this buffer with data from the user application and give signal to the driver module so that it can transfer the data over pcie using writel() function. The kernel side code for the mapping is shown below:</p>
  
  <pre class="lang-c prettyprint-override"><code>static int driver_mmap5(struct file *file, struct vm_area_struct *vma)
  {
      int ret;
      vma-&gt;vm_flags  |= VM_LOCKED|VM_SHARED; 
      vma-&gt;vm_page_prot = pgprot_noncached(vma-&gt;vm_page_prot);
      ret = remap_pfn_range(vma, vma-&gt;vm_start,
            virt_to_phys(TEST5) &gt;&gt; PAGE_SHIFT,
            vma-&gt;vm_end-vma-&gt;vm_start, vma-&gt;vm_page_prot);
     if(ret != 0)
     printk("MMAP Failed \n");
  
     SetPageReserved(virt_to_page(TEST5));
  
     #ifdef DEBUG
      printk("MMAP Succeeded \n");
     #endif
  
     return 0;
  }
  </code></pre>
  
  <p>where the TEST5 is pointer to the buffer to be mapped allocated as below:</p>
  
  <pre class="lang-c prettyprint-override"><code> long *TEST5;
   TEST5 = kzalloc(PB_BUFF_SIZE,__GFP_COLD|GFP_DMA);
   memset(TEST5,0xff,PB_BUFF_SIZE)
  </code></pre>
  
  <p>In the user space application another buffer is allocated and mapped as shown below:</p>
  
  <pre class="lang-c prettyprint-override"><code>unsigned long* msg5;
  msg5=(unsigned long*)malloc(PB_BUFF_SIZE);
  </code></pre>
  
  <p>and mmap is called:</p>
  
  <pre class="lang-c prettyprint-override"><code> msg5 = mmap(NULL, PB_BUFF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED , fd, 0);
  </code></pre>
  
  <p>It appears that there is some problem with the mapping as some portions are mapped and some are not, hence the incorrect values. Kindly suggest the causes and solution to this issue. </p>
  
  <p>Regards,</p>
  
  <p>Edit: Adding the related code for both driver and application side below</p>
  
  <p><strong>Driver Side code for buffer mapping</strong>:</p>
  
  <pre class="lang-c prettyprint-override"><code>long *TEST5;
  #define PB_BUFF_SIZE 8192
  
  static int driver_mmap5(struct file *file, struct vm_area_struct *vma)
  
  {
    int ret;
      vma-&gt;vm_flags  |= VM_LOCKED|VM_SHARED; 
      vma-&gt;vm_page_prot = pgprot_noncached(vma-&gt;vm_page_prot);
                  ret = remap_pfn_range(vma, vma-&gt;vm_start,
                        virt_to_phys(TEST5) &gt;&gt; PAGE_SHIFT,
                        vma-&gt;vm_end-vma-&gt;vm_start, vma-&gt;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, &amp;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&lt;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);
  </code></pre>
  
  <p><strong>Application Side Code for buffer mapping and test</strong>:</p>
  
  <pre class="lang-c prettyprint-override"><code>#include&lt;stdio.h&gt;
  #include&lt;stdlib.h&gt;
  #include&lt;fcntl.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;signal.h&gt;
  #include&lt;errno.h&gt;
  #include&lt;sys/mman.h&gt;
  #include&lt;string.h&gt;
  
  
  #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 ))
  
  &lt;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 &lt; 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
      }
  </code></pre>
  
  <p>the values in the csv files are then checked which show the behavior as explained above.</p>