當前位置:首頁 » 操作系統 » linux文件內存映射

linux文件內存映射

發布時間: 2022-06-22 21:48:14

linux內存映射問題

Linux的內存模型,一般為:

地址
作用
說明

>=0xc000 0000
內核虛擬存儲
用戶代碼不可見區域

<0xc000 0000
Stack(用戶棧)
ESP指向棧頂





空閑內存

>=0x4000 0000
文件映射區

<0x4000 0000



空閑內存

Heap(運行時堆)
通過brk/sbrk系統調用擴大堆,向上增長。

.data、.bss(讀寫段)
從可執行文件中載入

>=0x0804 8000(0x00008000 for arm linux)
.init、.text、.rodata(只讀段)
從可執行文件中載入

<0x0804 8000(0x00008000 for arm linux)
保留區域

運行一個測試程序,觀察其結果:

#include <stdio.h>

int main(int argc, char* argv[])

{

int first = 0;

int* p0 = malloc(1024);

int* p1 = malloc(1024 * 1024);

int* p2 = malloc(512 * 1024 * 1024 );

int* p3 = malloc(1024 * 1024 * 1024 );

printf("main=%p print=%p\n", main, printf);

printf("first=%p\n", &first);

printf("p0=%p p1=%p p2=%p p3=%p\n", p0, p1, p2, p3);

getchar();

return 0;

}

運行後,輸出結果為:

main=0x8048404 print=0x8048324

first=0xbfcd1264

p0=0x9253008 p1=0xb7ec0008 p2=0x97ebf008 p3=0x57ebe008

my pc (fc5)輸出結果如下:

main=0x80483f4 print=0x8048324
first=0xbf848660
p0=0x9ab2008 p1=0xb7e38008 p2=0x97e37008 p3=(nil)

arm-linux輸出如下結果:

main=0x8528 print=0x8404
first=0xbec9fe10
p0=0x11008 p1=0x4005a008 p2=(nil) p3=(nil)

main和print兩個函數是代碼段(.text)的,其地址符合表一的描述。

first是第一個臨時變數,由於在first之前還有一些環境變數,它的值並非0xbfffffff,而是0xbfcd1264,這是正常的。

p0是在堆中分配的,其地址小於0x4000 0000,這也是正常的。

但p1和p2也是在堆中分配的,而其地址竟大於0x4000 0000,與表一描述不符。

原因在於:運行時堆的位置與內存管理演算法相關,也就是與malloc的實現相關。關於內存管理演算法的問題,我們在後繼文章中有詳細描述,這里只作簡要說明。在glibc實現的內存管理演算法中,Malloc小塊內存是在小於0x4000 0000的內存中分配的,通過brk/sbrk不斷向上擴展,而分配大塊內存,malloc直接通過系統調用mmap實現,分配得到的地址在文件映射區,所以其地址大於0x4000 0000。

⑵ 關於linux系統下的物理內存映射

內存是一種存儲設備,現在一般是ddr
sdram,地址是用來標記內存的數據的。在操作系統中物理內存指實際的ddr
sdram,而虛擬內存指的是在硬碟中的緩存,windows中是頁面文件,linux中是swap分區。cpu產生的地址是虛擬地址也可以稱作有效地址,而在cpu外地址線上的信號稱作實際地址或物理地址。這2類地址有某種對應關系,由操作系統管理。如果是x86架構的話,物理地址和虛擬地址中間還有線性地址的概念。

⑶ 嵌入式 linux基於arm中,其中的 內存映射 是什麼意思具體完成什麼過程一定採納

內存映射主要是在linux底層部分,就是把硬體外設的各種寄存器直接變為可以操作的地址,也就是說,每一個硬體都會有一塊內存來代表它,我們直接操作這塊內存就等於操作了硬體,比方說I2c,它有控制寄存器,數據寄存器,這些寄存器都會被映射到內存里,我們直接操作這塊內存,就操作了寄存器,也就控制了設備

⑷ Linux關於地址空間和MMAP映射有何特點

Linux採用
虛擬
內存技術,系統中的所有進程之間以虛擬方式共享內存。對每個進程來說,它們好像都可以訪問整個系統的所有物理內存。更重要的是,即使單獨一個進程,它擁有的地址空間也可以遠遠大於系統物理內存。
進程地址空間由每個進程中的線性地址區組成,每個進程都有一個32位或64位的平坦(flat)空間,空間的具體大小取決於體系結構。「平坦」指地址空間范圍是一個獨立的連續區間。通常情況下,每個進程都有唯一的這種平坦空間,而且每個進程的地址空間之間彼此互不相干。兩個不同的進程可以在它們各自地址空間的相同地址內存存放不同的數據。但是進程之間也可以選擇共享地址空間,我們稱這樣的進程為線程。
在地址空間中,我們更為關心的是進程有權訪問的虛擬內存地址區間,比如08048000~0804c000。這些可被訪問的合法地址區間被成為內存區域(memory area),通過內核,進程可以給自己的地址空間動態地添加或減少內存區域。
進程只能訪問有效范圍內的內存地址。每個內存區域也具有相應進程必須遵循的特定訪問屬性,如只讀、只寫、可執行等屬性。如果一個進程訪問了不在有效范圍中的地址,或以不正確的方式訪問有效地址,那麼內核就會終止該進程,並返回「段錯誤」信息。
?
內存區域可以包含各種內存對象,如下:
?
可執行文件代碼的內存映射,成為代碼段(text section)。
?
可執行文件的已初始化全局變數的內存映射,成為數據段(data section)。
?
包含未初始化全局變數的零頁(也就是bss段)的內存映射。零頁是指頁面中的數據全部為0。
?
用於進程用戶空間棧的零頁的內存映射。
?
每一個諸如C庫或動態鏈接程序等共享庫的代碼段、數據段和bss也會被載入進程的地址空間。
?
任何內存映射文件。
?
任何共享內存段。
?
任何匿名的內存映射,比如由malloc()分配的內存。
進程地址空間的任何有效地址都只能位於唯一的區域,這些內存區域不能相互覆蓋。可以看到,在執行的進程中,每個不同的內存片斷都對應一個獨立的內存區域:棧、對象代碼、全局變數、被映射的文件等等。
內核使用內存描述符表示進程的地址空間。內存描述符由mm_struct結構體表示,定義在文件中,該結構包含了和進程地址空間有關的全部信息。
VMA
內存區域由vm_area_struct結構體描述,定義在文件中,內存區域在內核中也經常被稱作虛擬內存區域或者VMA。
VMA標志是一種位標志,它定義在vm_area_struct結構中(該結構中的vm_flags子域)。和物理頁的訪問許可權不同,VMA標志反映了內核處理頁面索需要遵守的行為准則,而不是硬體要求。VM_IO標志內存區域中包含對設備I/O空間的映射。該標志通常在設備驅動程序執行 mmap()函數進行I/O空間映射時才被設置,同時該標志也表示該內存區域不能被包含在任何進程的存放轉存(core mp)中。VM_RESERVED標志內存區域不能被換出,它也是在設備驅動程序進行映射時被設置。
vm_area_struct結構體中的vm_ops域指向與指定內存區域相關的操作函數表,內核使用表中的方法操作VMA。
mmap()和do_mmap():創建地址區間
內核使用do_mmap()函數創建一個新的線性地址區間。但是說給函數創建一個新VMA並不非常准確,因為如果創建的地址區間和一個已經存在的地址區間相鄰,並且它們具有相同的訪問許可權的話,那麼兩個區間將合並為一個。如果不能合並,那麼就確實需要創建一個新的VMA了。但無論哪種情況,do_mmap()函數都會將一個地址區間加入到進程的地址空間中——無論是擴展已經存在的內存區域還是創建一個新的區域。
do_mmap()函數聲明在文件中,原型如下:
unsigned long do_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long offset)
在用戶空間可以通過mmap()函數調用獲取內核函數do_mmap()的功能。mmap()系統調用原型如下:
void *mmap2(void *start, size_t length,
int prot, int flags,
int fd, off_t pgoff)
do_munmap()函數從特定的進程地址空間中刪除指定地址區間,該函數在文件中聲明:
int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
系統調用munmap()給用戶空間程序提供了一種從自身地址空間中刪除指定地址區間的方法,它和系統調用mmap()的作用相反:
int munmap(void *start, size_t length)
mmap設備操作
對於驅動程序來說,內存映射可以提供給用戶程序直接訪問設備內存的能力。映射一個設備,意味著使用戶空間的一段地址關聯到設備內存上。無論何時,只要程序在分配的地址范圍內進行讀取或者寫入,實際上就是對設備的訪問。
並不是所有的設備都能進行mmap抽象。例如,串口設備和其他面向流的設備就無法實現這種抽象。mmap的另一個限制是映射都是以 PAGE_SIZE為單位的。內核只能在頁表一級處理虛擬地址;因此,被映射的區域必須是PAGE_SIZE的整數倍,而且必須位於起始於 PAGE_SIZE整數倍地址的物理內存內。如果區域的大小不是頁大小的整數倍,內核就通過生成一個稍微大一些的區域來容納它。
mmap方法是file_operations結構中的一員,並且在執行mmap系統調用時就會調用該方法。在調用實際方法之前,內核會完成很多工作,而且該方法的原型與系統調用的原型由很大區別。關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html
文件操作聲明如下:
int (*mmap) (struct file * filp, struct vm_area_struct *vma);
其中vma參數包含了用於訪問設備的虛擬地址區間的信息。大部分工作已經由內核完成了,要實現mmap,驅動程序只要為這一地址范圍構造合適的頁表即可,如果需要的話,就用一個新的操作集替換vma->vm_ops。
有兩種建立頁表的方法:使用remap_page_range函數可一次建立所有的頁表,或者通過nopage VMA方法每次建立一個頁表。
構造用於映射一段物理地址的新頁表的工作是由remap_page_range完

⑸ Linux I/O內存靜態映射

將Linux移植到目標電路板的過程中,有得會建立外設IO內存物理地址到虛擬地址的靜態映射,這個映射通過在與電路板對應的map_desc結構體數組中添加新的成員來完成。iotable_init()是最終建立頁映射的函數,它通過ACHINE_START、MACHINE_END宏賦值給電路板的map_io())函數。將Linux操作系統移植到特定平台上,MACHINE_START(或者DT_MACHINE_START)、MACHINE_END宏之間的定義針對特定電路板而設計,其中的map_io ()成員函數完成IO內存的靜態映射。在一個已經移植好操作系統的內核中,驅動工程師可以對非常規內存區域的IO內存(外設控制器寄存器、MCU內部集成的外設控制器寄存器等)依照電路板的資源使用情況添加到map_desc數組中,但是目前該方法已經不值得推薦。
Cache和DMA本身似乎是兩個毫不相關的事物。Cache被用作CPU針對內存的緩存,利用程序的空間局部性和時間局部性原理,達到較高的命中率,從而避免CPU每次都必須要與相對慢速的內存交互數據來提高數據的訪問速率。DMA可以作為內存與外設之間傳輸數據的方式,在這種傳輸方式之下,數據並不需要經過CPU中轉。
假設DMA針對內存的目的地址與Cache緩存的對象沒有重疊區域,DMA和Cache之間將相安無事。但是,如果DMA的目的地址與Cache所緩存的內存地址訪問有重疊,經過DMA操作,與Cache緩存對應的內存中的數據已經被修改,而CPU本身並不知道,它仍然認為Cache中的數據就是內存中的數據,那在以後訪問Cache映射的內存時,它仍然使用陳舊的Cache數據。這樣就會發生Cache與內存之間數據「不一致性」的錯誤。

⑹ linux內核中虛擬內存是怎樣映射到物理內存

當程序在運行的時候,會檢測到數據在虛擬內存中,並沒在物理內存中,這時候會產生一個缺頁中斷,
有缺頁中斷來映射。

⑺ Linux ARM內存映射的問題

這個是線性地址的概念:我的理解如下:
進程的角度:32位系統,每一個進程壓入內存,默認認為自己都有4G內存可以用;底端的1G給內核;所以每個進程默認認為都只有自己和內核;所以每個進程是不知道有其他進程存在,所以我們開發的是要通過信號機制來確定其他進程的存在,從而實現進程間通信的;
內核的角度: 當一個進程運行以後,根據進程模擬的頁面一一對應到物理內存中頁框;然後在物理內存中分配頁框,
這塊內容很復雜,當時學了好幾個星期;而且還是很淺的,只是為了應付伺服器端的開發;
當然這塊內容涉及到的東西很多,內存管理,進程通信,中斷,睡眠,虛擬內存等等;

⑻ linux設備驅動物理內存映射

int video_qsb_mmap(struct file *file,struct vm_area_struct *vma)
{
int ret;
u32 size = vma->vm_end - vma->vm_start;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_flags |= VM_RESERVED;
if(frm_num<qsb_dev.mmap_num)
{
ret = remap_pfn_range(vma,vma->vm_start,align_addr>>PAGE_SHIFT,qsb_dev.stride*1944,vma->vm_page_prot); align_addr=PAGE_ALIGN(align_addr+2592*1944);
if(ret != 0)
{ return -EAGAIN; }
frm_num++; }
return 0;
}

這是我自己的函數,我是在UBOOT里規定系統只能用前192M,其它的由應用層調用MMAP函數實現映射,貼過來格式亂了,你參考參考,是可以用的。大概就是申請1張圖片的大小,並進行頁對齊。不懂的問,你查查這幾個函數的作用參數照著寫應該就可以實現你得目的了。

熱點內容
phpphpfpm 發布:2024-11-09 00:27:54 瀏覽:981
機車新手怎麼看配置 發布:2024-11-09 00:12:20 瀏覽:193
關鍵行動安卓如何下載 發布:2024-11-08 23:56:59 瀏覽:59
大便壓縮小 發布:2024-11-08 23:52:37 瀏覽:293
墨刀資料庫 發布:2024-11-08 23:51:10 瀏覽:307
javaget亂碼 發布:2024-11-08 23:41:56 瀏覽:82
空文件python 發布:2024-11-08 23:38:08 瀏覽:488
取消網路訪問密碼 發布:2024-11-08 23:34:09 瀏覽:731
在我的世界伺服器中怎麼設置血月 發布:2024-11-08 23:30:07 瀏覽:631
安卓機如何設置自動錄音 發布:2024-11-08 23:27:56 瀏覽:311