內存與IO訪問

IO空間是相對於內存空間而言的,
x86一般使用IO空間
arm等嵌入式cpu一般不提供IO空間,只存在內存空間

詳看宋寶華第三版第11章:內存與IO訪問
1.內存空間可以直接通過地址,指針來訪問,程序即在程序運行中使用的變量和其他數據都有存在於內存空間中,所以變量有一個地址,這個地址一定是MMU映射過的一個va,
我們在程序中操作的寄存器的地址也是一個va(虛擬地址),只是這兩個地址的映射來源不一樣而已。
2.如果外設掛接在內存空間中(這個說法是不準確的),那麼我們就可以像訪問一個內存單元一樣去訪問這些寄存器的地址(或者IO端口)

總結:物理地址到虛擬地址的映射,內存空間與IO空間的概念很亂也不好理清,這裏總結一下:
1.我們的程序都是運行在內存之中包括那些變量和其他數據,而又因爲需要擴大進程所需要的尋址地址範圍,我們發明了虛擬地址(這裏所謂的地址僅僅是虛擬的內存地址),
這裏就需要用到物理地址到虛擬地址的映射這個概念。如果沒有用到虛擬地址,那麼我們尋址變量所需要的地址就實實在在的物理地址。
2.一定要樹立一個概念,我們在內存中操作的地址都是MMU映射後的虛擬地址,這個虛擬地址的來源分爲兩種:一種是將DDR的物理地址映射,一種是將非DDR的其他總線地址進行映射。
由1可只,程序中使用的地址都是虛擬地址,這個虛擬地址由MMU來進行映射轉換,mmu轉換的都是總線上的地址,他不會知道這個地址是留給ram還是其他模塊上用的。我們倒着來,
我們需要在程序中定義一個變量int a = 1,此時我們是找到a的虛擬地址,然後賦值爲1,這個地址由編譯器在編譯的時候指定?(這句話還沒有驗證),此時指定映射這個
虛擬地址的總線地址就是總線上的物理地址,所以這個操作是內存的物理地址上進行的。

如果我們這樣ioremap(0x18xxxx) = 0xxxxxx;此時我們調用ioremap得到0x18xxx的虛擬地址,並給該地址賦值爲0xxxx,此時,是指定ioremap這個操作所得到的虛擬地址是由總線上的
其他非預留給RAM的物理地址映射而來的。如果這個0x18xxx地址躍進了內存物理地址,也是一樣的,對他而言,他只是將總線上的地址映射到內核空間中劃分爲IO內存空間的虛擬地址,
所以這個函數實際上可以映射總線上的任何地址)

所以上面這句話應該更正爲:
如果我們這樣ioremap(0x18xxxx) = 0xxxxxx;此時我們調用ioremap得到0x18xxx的虛擬地址,並給該地址賦值爲0xxxx,此時,是指定ioremap這個操作所得到的虛擬地址是由總線上的
物理地址映射而來。如果這個(0x18xxxx是預留給ddr的物理地址,那麼你得到的就是一個由內存物理地址映射而來的va,如果這個(0x18xxxx是總線上的其他地址,而這個地址上剛好
掛載着一個ip,那麼我們得到的就是一個總線上的寄存器地址映射而來的va。但是通常我們不會去指定的去讀寫由內存物理地址映射而來的虛擬地址空間,這樣會導致程序出錯(你
清除掉一個你不知道存放什麼數據的內存地址是一個危險操作)。那麼我們要去操作非預留給DDR的物理地址空間,我們就要使用ioremap這個函數去映射了。但是一定不要地址越界(和內存地 址)。
也就是說同樣是虛擬地址,但是他們的來源不同,非RAM空間的地址總線尋址就需要這些特殊的接口來訪問纔可以。
這樣物理地址到虛擬地址的映射,內存空間與IO空間的概念就可以清楚些

高端內存的使用:
在32位系統中,線性地址空間是4G,其中規定3~4G的範圍是內核空間(1G),0~3G是用戶空間(3G)。如果把這1G的內核線性地址空間全部拿來直接一一映射物理內存 的話,在內核態的所有進程(線程)能使用的物理內存總共最多隻有1G,很顯然,如果你有4G內存,3G都不能用來做內核空間,太浪費了!爲了能使在內核態的所有進程 能使用更多的物理內存,linux採取了一種變通的形式:它將1G內核線性地址空間分爲2部分,第一部分爲1G的前896M,這部分內核線性空間與物理內存的0~896M一一映 射,第二部分爲1G的後128M的線性空間,拿來動態映射剩下的所有物理內存(即高端內存)。

用戶進程沒有高端內存概念。只有在內核空間才存在高端內存。用戶進程最多只可以訪問3G物理內存,而內核進程可以訪問所有物理內存(如果ddr小於896M,
虛擬地址一一對應物理地址,若大於896M,則會出現一個高端內存的概念,多餘的物理內存則由1G虛擬內存剩餘的(1G-896 = )128M虛擬地址空間動態的去訪問剩餘的所有物理內存)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章