新聞中心

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

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

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


關(guān)鍵詞: gdbgdbserverarmlinux程

評論


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

關(guān)閉