首頁 > 運維 > linux運維 > 詳解Linux的使用者空間與核心空間

詳解Linux的使用者空間與核心空間

藏色散人
發布: 2020-12-08 17:01:31
轉載
4553 人瀏覽過

推薦:《linux影片教學

  • #Linux 作業系統和驅動程式運行在核心空間,應用程式運行在用戶空間。
  • 兩者不能簡單地使用指標傳遞數據,因為Linux使用的虛擬記憶體機制,使用者空間的資料可能被換出,當核心空間使用使用者空間指標時,對應的資料可能不在記憶體中。使用者空間的記憶體映射採用段頁式,而核心空間有自己的規則;本文旨在探討核心空間的位址映射。
  • os分配給每個進程一個獨立的、連續的、虛擬的位址記憶體空間,該大小一般是4G(32位元作業系統,即2的32次方),其中將高位址值的記憶體空間分配給os佔用,linux os佔用1G,window os佔用2G;其餘記憶體位址空間分配給進程使用。
  • 通常32位元Linux核心虛擬位址空間劃分0~3G為用戶空間,3~4G為核心空間(注意,核心可以使用的線性位址只有1G)。注意這裡是32位元核心位址空間劃分,64位元核心位址空間劃分是不同的。

 

 
  • #程式尋址空間0~4G
  • 程式在使用者狀態只能存取0~3G,只有進入核心態才能存取3G~4G  
  • 程式透過系統呼叫進入核心態
  • 每個行程虛擬空間的3G~4G部分是相同的 
  • 進程從使用者狀態進入核心狀態不會造成CR3的改變但會造成堆疊的改變

二. Linux核心高階記憶體

# 1. 由來當核心模組程式碼或執行緒存取記憶體時,程式碼中的記憶體位址都是邏輯位址,而對應到真正的實體記憶體位址,需要位址一對一的映射,如邏輯位址0xc0000003對應的實體位址為0×3,0xc0000004對應的實體位址為0×4,… …,邏輯位址與實體位址對應的關係為實體位址= 邏輯位址– 0xC0000000 :這是核心位址空間的位址轉換關係,注意核心的虛擬位址在“高端”,但是ta映射的實體記憶體位址在低端。 邏輯位址#實體記憶體位址 0xc00000000×0
#########0xc0000001######0×1#############0xc0000002################0xc0000002##### #0×2############0xc0000003#######0×3###########…#####…######################################################################################################### ########0xe0000000######0×20000000############…######…###################################################################### ###0xffffffff############0×40000000 ??###############

假 設依照上述簡單的位址映射關係,那麼核心邏輯位址空間存取為0xc0000000 ~ 0xffffffff,那麼對應的物理記憶體範圍就為0×0 ~ 0×40000000,即只能存取1G物理記憶體。若機器中安裝8G物理內存,那麼核心就只能訪問前1G物理內存,後面7G物理內存將會無法訪問,因為內核 的地址空間已經全部映射到物理內存地址範圍0×0 ~ 0×40000000。即使安裝了8G物理內存,那麼物理位址為0×40000001的內存,核心該怎麼去存取呢?程式碼中必須要有記憶體邏輯位址 的,0xc0000000 ~ 0xffffffff的位址空間已經被用完了,所以無法存取實體位址0×40000000以後的記憶體。

顯 然不能將核心位址空間0xc0000000 ~ 0xfffffff全部用來簡單的位址對映。因此x86架構中將核心位址空間分割三個部分:ZONE_DMA、ZONE_NORMAL和 ZONE_HIGHMEM。 ZONE_HIGHMEM即為高階內存,這就是記憶體高階記憶體概念的由來。


在x86結構中,三種類型的區域(從3G開始計算)如下:

ZONE_DMA        記憶體開始的16MB

ZONE_NORMAL       16MB~896MB

ZONE_HIGHMEM       896MB ~ 結束(1G)

 

2. 理解

前面我們解釋了高階記憶體的由來。 Linux將核心位址空間分割為三部分ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM,高階記憶體HIGH_MEM位址空間範圍為 0xF8000000 ~ 0xFFFFFFFF(896MB~1024MB)。那麼如核心是如何借助128MB高階記憶體位址空間是如何實現存取可以所有實體記憶體

當核心想存取高於896MB實體位址記憶體時,從0xF8000000 ~ 0xFFFFFFFF位址空間範圍內找一段對應大小空閒的邏輯位址空間,借用一會。借用這段邏輯位址空間,建立映射到想存取的那段實體記憶體(即填滿核心PTE頁面表),暫時用一會,用完後歸還。這樣別人也可以藉用這段位址空間來存取其他實體內存,實現了使用有限的位址空間,存取所有所有實體記憶體。如下圖。

範例 如核心想存取2G開始的一段大小為1MB的物理內存,即物理位址範圍為0×80000000 ~ 0x800FFFFF。造訪前先找到一段1MB大小的空閒位址空間,假設找到的空閒位址空間為0xF8700000 ~ 0xF87FFFFF,用這1MB的邏輯位址空間對應到物理位址空間0×80000000 ~ 0x800FFFFF的記憶體。映射關係如下:

##0×800000000xF8700001#0×800000010xF8700020×80000002…0x800FFFFF
邏輯位址 #物理記憶體位址
0xF8700000
0xF870002
0xF87FFFFF
######

當核心存取完0×80000000 ~ 0x800FFFFF實體記憶體後,就將0xF8700000 ~ 0xF87FFFFF核心線性空間釋放。這樣其他進程或程式碼也可以使用0xF8700000 ~ 0xF87FFFFF這段位址存取其他實體記憶體。

從上面的描述,我們可以知道高階記憶體的最基本想法:借一段位址空間,建立臨時位址映射,用完後釋放,達到這段位址空間可以循環使用,存取所有實體記憶體。

看到這裡,不禁有人會問:萬一有核心行程或模組一直佔用某段邏輯位址空間不釋放,怎麼辦?若真的出現的這種情況,則核心的高端記憶體位址空間越來越緊張,若都被佔用不釋放,則沒有建立映射到實體記憶體都無法存取了。

 

3. 分割

核心將高階記憶體劃分為3部分:VMALLOC_START~VMALLOC_END、KMAP_BASE~FIXADDR_START和FIXADDR_START~4G。


對於高階內存,可以透過alloc_page() 或其它函數取得對應的page,但是要存取實際實體內存,還得把page 轉為線性位址才行(為什麼?想想MMU 是如何存取實體記憶體的),也就是說,我們需要為高階記憶體對應的page 找一個線性空間,這個過程稱為高階記憶體映射。

對應高階記憶體的3部分,高階記憶體映射有三種方式:
對應到」內核動態映射空間」(noncontiguous memory allocation)
這種方式很簡單,因為透過vmalloc() ,在」內核動態映射空間」申請記憶體的時候,就可能從高階記憶體獲得頁面(參考vmalloc 的實作),因此說高階記憶體有可能映射到」內核動態映射空間」。

持久內核映射(permanent kernel mapping)
如果是透過 alloc_page() 獲得了高階記憶體對應的 page,如何給它找個線性空間?
核心專門為此留出一塊線性空間,從 PKMAP_BASE 到 FIXADDR_START ,用於映射高階記憶體。在 2.6核心上,這個位址範圍是 4G-8M 到 4G-4M 之間。這個空間起叫」內核永久映射空間」或」永久內核映射空間」。這個空間和其它空間使用同樣的頁目錄表,對於核心來說,就是 swapper_pg_dir,對普通進程來說,透過 CR3 暫存器指向。通常情況下,這個空間是 4M 大小,因此只需要一個頁表即可,核心會透過來 pkmap_page_table 尋找這個頁表。透過 kmap(),可以把一個 page 映射到這個空間來。由於這個空間是 4M 大小,最多能同時對應 1024 個 page。因此,對於不使用的的 page,及應該時從這個空間釋放掉(也就是解除映射關係),透過 kunmap() ,可以把一個 page 對應的線性位址從這個空間釋放出來。

暫時映射(temporary kernel mapping)
核心在 FIXADDR_START 到 FIXADDR_TOP 之間保留了一些線性空間用於特殊需求。這個空間稱為”固定映射空間」在這個空間中,有一部分用於高端記憶體的臨時映射。

這塊空間有以下特點:
(1)每個CPU 佔用一塊空間
(2)在每個CPU 佔用的那塊空間中,又分成多個小空間,每個小空間大小是1 個page,每個小空間用於一個目的,這些目的定義在kmap_types.h 中的km_type 中。

當要進行一次暫時映射的時候,需要指定映射的目的,根據映射目的,可以找到對應的小空間,然後把這個空間的位址當作映射位址。這意味著一次臨時映射會導致先前的映射被覆蓋。透過 kmap_atomic() 可實現臨時映射。

 

三. 其他

1、使用者空間(進程)是否有高階記憶體概念?

使用者進程沒有高階記憶體概念。只有在核心空間才存在高端記憶體。使用者進程最多只可以存取3G物理內存,而內核進程可以存取所有實體內存。

2、64位元核心中有高階記憶體嗎?

目前現實中,64位元Linux核心不存在高階內存,因為64位元核心可以支援超過512GB記憶體。若機器安裝的實體記憶體超過核心位址空間範圍,就會存在高階記憶體。

3、使用者行程能存取多少實體記憶體?內核程式碼能存取多少實體記憶體?

32位元系統使用者行程最大可以存取3GB,核心程式碼可以存取所有實體記憶體。

64位元系統使用者進程最大可以存取超過512GB,核心程式碼可以存取所有實體記憶體。

4、高階記憶體和實體位址、邏輯位址、線性位址的關係?

高階記憶體只和邏輯位址有關係,和邏輯位址、實體位址沒有直接關係。

以上是詳解Linux的使用者空間與核心空間的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
centos7 - git的linux版本沒有centos的?
來自於 1970-01-01 08:00:00
0
0
0
學習Linux的先行知識
來自於 1970-01-01 08:00:00
0
0
0
Linux下連接資料庫
來自於 1970-01-01 08:00:00
0
0
0
Linux 批次修改檔名
來自於 1970-01-01 08:00:00
0
0
0
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板