<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > gdb+gdbserver調(diào)試arm-linux程序

          gdb+gdbserver調(diào)試arm-linux程序

          作者: 時(shí)間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
          mmap作為struct file_operations的重要一個(gè)元素,mmap主要是實(shí)現(xiàn)物理內(nèi)存到虛擬內(nèi)存的映射關(guān)系,這樣可以實(shí)現(xiàn)直接訪問虛擬內(nèi)存,而不用使用設(shè)備相關(guān)的read、write操作,mmap的基本過程是將文件映射到虛擬內(nèi)存中。在之前的一篇博客中談到了mmap實(shí)現(xiàn)文件復(fù)制的操作。
          關(guān)于linux中的mmap調(diào)用如下,最好的辦法查看命令,man mmap:
          必要的頭文件
          #include
          函數(shù)聲明
          void * mmap(void *addr,size_t length,int prot,
          int flags,int fd,off_t offset);
          關(guān)于各個(gè)參數(shù)的意義如下:
          1、返回值是一個(gè)通用型指針,這樣就保證了各種類型的申請(qǐng)方式。
          2、void *addr 是程序員所希望的虛擬地址作為起始映射地址,通常為NULL,內(nèi)核自動(dòng)分配。
          3、size_t length當(dāng)然是指需要映射的區(qū)域大小。
          4、int flags是指對(duì)這段區(qū)域的保護(hù)方式。具體的可以參看內(nèi)核源碼的linux/mm.h。常用的是PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE。
          5、int flags主要是指對(duì)這段區(qū)域的映射方式,主要分為兩種方式MAP_SHARE,MAP_PRIVATE.其中的MAP_SHARE是指對(duì)映射區(qū)域的寫操作會(huì)更新到文件中,這樣就相當(dāng)于直接操作文件。而MAP_PRIVATE通常采用一種稱為"寫時(shí)保護(hù)的機(jī)制"實(shí)現(xiàn)映射,對(duì)映射區(qū)的寫操作不會(huì)更新到文件中,實(shí)現(xiàn)方法是將需要被寫操作的頁(yè)復(fù)制到重新分配的新頁(yè)中,然后再對(duì)新的頁(yè)進(jìn)行寫操作。原來的映射并沒有改變,但是讀操作并不會(huì)重新分配物理內(nèi)存空間。具體的參考深入理解計(jì)算機(jī)系統(tǒng)。
          6、int fd是指將被映射的文件描述符,映射需要保證文件描述符的正確性。
          7、off_t offset是指從文件的具體位置開始映射,通常情況下可以設(shè)置為0,即從開頭映射。
          基本的映射關(guān)系如下圖:
          設(shè)備驅(qū)動(dòng)的mmap實(shí)現(xiàn)主要是將一個(gè)物理設(shè)備的可操作區(qū)域(設(shè)備空間)映射到一個(gè)進(jìn)程的虛擬地址空間。這樣就可以直接采用指針的方式像訪問內(nèi)存的方式訪問設(shè)備。在驅(qū)動(dòng)中的mmap實(shí)現(xiàn)主要是完成一件事,就是實(shí)際物理設(shè)備的操作區(qū)域到進(jìn)程虛擬空間地址的映射過程。同時(shí)也需要保證這段映射的虛擬存儲(chǔ)器區(qū)域不會(huì)被進(jìn)程當(dāng)做一般的空間使用,因此需要添加一系列的保護(hù)方式。
          具體的實(shí)現(xiàn)過程如下:
          /*主要是建立虛擬地址到物理地址的頁(yè)表關(guān)系,其他的過程又內(nèi)核自己完成*/
          static int mem_mmap(struct file* filp,struct vm_area_struct *vma)
          {
          /*間接的控制設(shè)備*/
          struct mem_dev *dev = filp->private_data;
          /*標(biāo)記這段虛擬內(nèi)存映射為IO區(qū)域,并阻止系統(tǒng)將該區(qū)域包含在進(jìn)程的存放轉(zhuǎn)存中*/
          vma->vm_flags |= VM_IO;
          /*標(biāo)記這段區(qū)域不能被換出*/
          vma->vm_flags |= VM_RESERVED;
          /**/
          if(remap_pfn_range(vma,/*虛擬內(nèi)存區(qū)域*/
          vma->vm_start, /*虛擬地址的起始地址*/
          virt_to_phys(dev->data)>>PAGE_SHIFT, /*物理存儲(chǔ)區(qū)的物理頁(yè)號(hào)*/
          dev->size, /*映射區(qū)域大小*/
          vma->vm_page_prot /*虛擬區(qū)域保護(hù)屬性*/
          ))
          return -EAGAIN;
          return 0;
          }
          具體的實(shí)現(xiàn)分析如下:
          vma->vm_flags |= VM_IO;
          vma->vm_flags |= VM_RESERVED;
          上面的兩個(gè)保護(hù)機(jī)制就說明了被映射的這段區(qū)域具有映射IO的相似性,同時(shí)保證這段區(qū)域不能隨便的換出。就是建立一個(gè)物理頁(yè)與虛擬頁(yè)之間的關(guān)聯(lián)性。具體原理是虛擬頁(yè)和物理頁(yè)之間是以頁(yè)表的方式關(guān)聯(lián)起來,虛擬內(nèi)存通常大于物理內(nèi)存,在使用過程中虛擬頁(yè)通過頁(yè)表關(guān)聯(lián)一切對(duì)應(yīng)的物理頁(yè),當(dāng)物理頁(yè)不夠時(shí),會(huì)選擇性的犧牲一些頁(yè),也就是將物理頁(yè)與虛擬頁(yè)之間切斷,重現(xiàn)關(guān)聯(lián)其他的虛擬頁(yè),保證物理內(nèi)存夠用。在設(shè)備驅(qū)動(dòng)中應(yīng)該具體的虛擬頁(yè)和物理頁(yè)之間的關(guān)系應(yīng)該是長(zhǎng)期的,應(yīng)該保護(hù)起來,不能隨便被別的虛擬頁(yè)所替換。具體也可參看關(guān)于虛擬存儲(chǔ)器的文章。
          接下來就是建立物理頁(yè)與虛擬頁(yè)之間的關(guān)系,即采用函數(shù)remap_pfn_range(),具體的參數(shù)如下:
          int remap_pfn_range(structvm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot)
          1、struct vm_area_struct是一個(gè)虛擬內(nèi)存區(qū)域結(jié)構(gòu)體,表示虛擬存儲(chǔ)器中的一個(gè)內(nèi)存區(qū)域。其中的元素vm_start是指虛擬存儲(chǔ)器中的起始地址。
          2、addr也就是虛擬存儲(chǔ)器中的起始地址,通??梢赃x擇addr = vma->vm_start。
          3、pfn是指物理存儲(chǔ)器的具體頁(yè)號(hào),通常通過物理地址得到對(duì)應(yīng)的物理頁(yè)號(hào),具體采用virt_to_phys(dev->data)>>PAGE_SHIFT.首先將虛擬內(nèi)存轉(zhuǎn)換到物理內(nèi)存,然后得到頁(yè)號(hào)。>>PAGE_SHIFT通常為12,這是因?yàn)槊恳豁?yè)的大小剛好是4K,這樣右移12相當(dāng)于除以4096,得到頁(yè)號(hào)。
          4、size區(qū)域大小
          5、區(qū)域保護(hù)機(jī)制。
          返回值,如果成功返回0,否則正數(shù)。
          測(cè)試代碼可以直接通過對(duì)虛擬內(nèi)存區(qū)域操作,實(shí)現(xiàn)不同的操作,如下:
          #include
          #include
          #include
          #include
          #include
          #include
          #include
          #include
          int main()
          {
          int fd;
          char *start;
          char buf[2048];
          strcpy(buf,"This is a test!!!!");
          fd = open("/dev/memdev0",O_RDWR);
          if(fd == -1)
          {
          printf("Error!!");
          exit(-1);
          }
          /*創(chuàng)建映射*/
          start = mmap(NULL,2048,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
          /*必須檢測(cè)是否成功*/
          if(start == -1)
          {
          printf("mmap error!!!");
          exit(-1);
          }
          strcpy(start,buf);
          printf("start = %s,buf = %s",start,buf);
          strcpy(start,"Test is Test!!!");
          printf("start = %s,buf = %s",start,buf);
          /**/
          strcpy(buf,start);
          printf("start = %s,buf=%s",start,buf);
          /*取消映射關(guān)系*/
          munmap(start,2048);
          /*關(guān)閉文件*/
          close(fd);
          exit(0);
          }
          經(jīng)過測(cè)試,成功得到了驅(qū)動(dòng)。


          關(guān)鍵詞: gdbgdbserverarmlinux程

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();