欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    在 MMU 出現之前,操作系統中的內存管理相對簡單很多,開發者所操作的都是看得見摸得著的物理內存,內存的管理工作相對簡單且容易理解,但是直接物理內存的管理總會帶來各種各樣的問題,比如安全問題,而且程序數據和硬盤上的普通文件數據并不一樣,對內存地址有相當的依賴性,這也決定了讓開發者直接操作物理地址是非常不方便,甚至是不合理的。

    不知道你有沒有聽過這名言:

    計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決。

    這句話幾乎概括了計算機軟件體系結構的設計要點.整個體系從上到下都是按照嚴格的層級結構設計的.

    CPU 中的 MMU 就是引入的這個中間層,提供一種新的虛擬地址的概念,開發者面對的是虛擬地址,而 MMU 負責將虛擬地址轉換為對應的物理地址,中間提供一層映射。

    引入虛擬地址最大的意義在于:開發者所操作的地址不再受到任何限制,不需要像使用物理內存那樣考慮該地址上是否存在真實的物理內存,該地址是否已經被占用,只需要對 MMU 負責,而不需要對物理內存負責,這就提供了很大的操作空間。

    一方面,開發者可以很方便地開發出可移植的程序,畢竟 MMU 可以確保程序所占用的虛擬內存的分配,另一方面,由于虛擬內存到物理內存映射的建立是自由的,開發者不能直接訪問真實的物理內存,這也大大提高了安全性。

    arm 中的 MMU

    在 arm 中,MMU 是處理器內部的硬件資源,不像串口、USB 等硬件控制器是 SOC 廠商添加的,因此 MMU 的訪問并不是以外設寄存器的方式,而是由處理器內部集成的 cp15 協處理器進行管理。

    上文中提到,MMU 對外提供虛擬地址,并維護虛擬地址到物理地址的映射,那么 MMU 到底是如何工作的呢?

    (需要注意的是,硬件上,armv7支持多種擴展模式,比如 LPAE 地址擴展, 安全擴展, 安全擴展,不同的擴展模式下對應不同的配置,本文只考慮一般情況,暫時不討論擴展模式下的 MMU 以及頁表設置,有興趣的朋友可以參考 armv7 參考手冊)。

    要了解這個,首先得知道一個概念:頁表,這是內存管理中的核心概念。

    簡單來說:實際的應用中,物理內存通常是比較大的,比如一塊 2G 的內存,也就是一片 2*1024*1024*1024 個字節的內存區域,要把它用起來,自然就需要對它進行管理,通常是以 4K 的粒度來分割內存,每 4K 一個頁面,這時候 2G 的物理內存在系統中就被分成了 1M 個頁面。

    至于為什么操作系統要以 4K 一個頁面來管理內存,而不是使用更大或者更小的粒度進行管理,這是在內存利用效率和管理成本之間做權衡取舍的結果。

    每個頁面都需要在操作系統中進行記錄,畢竟你要使用它,必須得知道它的起始地址、大小、是否已經被分配等信息,而記錄每個頁面的相關信息也需要內存,這就是管理成本。同時,既然操作系統是按照頁面進行記錄的,那么在使用內存時也是以頁面為單位,但是實際的內存使用中并不會剛好用完一個頁面,可能只有 2/3 頁,默認情況下,剩下的 1/3 也就被浪費了,這就是內存的利用率。那么,那剩下的 1/3 是不是可以繼續使用呢,當然也是可以的,但是操作系統又得花一些內存去記錄那 1/3 內存的起始地址以及使用的相關信息,又增加了管理成本,而管理成本越高,管理所浪費的內存越多,所以這很矛盾。

    不難得出,頁面劃分的粒度越小,所浪費的內存是越少,管理成本越高,而劃分粒度越大,每一次使用可能造成的內存浪費越嚴重,管理成本越低。

    頁表

    上面所討論的是物理內存和分頁的概念,回過頭來再看看,頁表到底是什么?

    MMU 提供虛擬地址空間,虛擬地址空間的大小等于 CPU 的線性地址寬度,32 位系統中默認是 4G,頁表其實就是一張映射表,主要記錄了虛擬地址和物理地址之間的映射關系,也就是說,當程序訪問一個虛擬地址時,其對應的物理地址就是通過查找頁表來找到的。

    需要特別注意的是,頁表并不是由 MMU 來建立,而是由操作系統建立,建立一個頁表的流程通常為:

    從這個過程可以看出,MMU 的作用只是維護頁表,畢竟物理內存和虛擬內存空間都還是得由操作系統來管理。同時 MMU 提供頁表的操作接口,將輸入的虛擬地址訪問轉換為物理地址訪問,同時還支持訪問屬性的控制,防止非法訪問,向 CPU 報告異常。

    正如上面所提到的,虛擬地址訪問是需要提交給 MMU 的,如果該虛擬地址沒有建立頁表而去訪問它,也就是 MMU 在尋址時查不到對應的映射表,此時 MMU 會產生一個異常,異常可能被預定義的程序修復,也可能是導致系統崩潰。

    linux 查看文件夾大小_查詢空間大小 linux_linux查詢文件夾大小

    多級頁表

    對于 linux 這種支持多進程的操作系統,進程之間地址隔離的特性讓每個進程看起來都擁有獨立的 4G 地址空間,實際上不能算是 4G,內核部分是共享的查詢空間大小 linux,通常 3G~4G 地址空間是內核空間,因此,一個用戶進程占用了獨立的 0~3G 的內存空間。

    也就是說,對于每個進程而言,虛擬地址對于物理地址的映射都是獨立的,從而每個進程都需要一個獨立的頁表。

    讓我們來計算一下,一個完整的頁表需要多少項,計算過程很簡單:4G / 4K = 1M,也就是一共有 1M 個頁面,這些頁面如何訪問呢?一個最簡單的模型是這樣的:

    將開發者需要訪問的虛擬地址的前 20 位作為頁面偏移,該偏移值上保存的是對應的物理頁面地址,占用 4 字節,20 位剛好對應 1M 空間,后 12 位用于頁內偏移,索引到具體的物理頁面上的內存字節,這樣就根據虛擬地址查找到了對應的物理地址。

    也就是說,每個虛擬地址到物理頁面的映射占用 4 bytes,那么一個完整的頁表就需要 4M 字節,注意,因為每個進程是獨立的,因此系統中每存在一個進程,就需要額外地為每個進程申請 4M 的內存空間,一個系統中存在 50 個進程并不夸張,僅僅是為每個進程分配頁表,就要占用掉 200M 空間,這明顯是非常不劃算的。

    同時,如果剛開始運行時申請 4M 內存不在話下,一旦內存中碎片多了,那么申請連續的 4M 空間是非常吃力的,為什么頁表需要連續的空間呢?上文中有說到,頁表的查找實際上是 MMU 執行的,軟件只是將頁表基地址交給 MMU,MMU 不能接受不連續的地址,這是硬件決定的。

    解決這個問題的辦法是使用多級頁表,處理器是否支持多級頁表以及支持頁表的級數也是由硬件決定的,arm32 硬件上最多支持二級頁表,也就是支持使用一級或者二級頁表,主要使用二級頁表。

    多級頁表有什么好處呢?

    在二級頁表的結構中,第一級的頁表的內容不再指向具體的物理頁面,而是指向第二級頁表的地址,而第二級頁表的內容指向具體的物理頁面,以此索引到具體的物理地址。

    二級頁表虛擬地址到物理地址的映射可以參考下圖:

    通用的二級頁表映射中,每個頁面的 size 依舊是 4K,32 位的虛擬地址被解析為三個部分,首先,一級頁表的基地址被傳遞給 MMU,當程序發起一個虛擬地址的訪問時。

    一級頁表一共 4096 項,MMU 取出虛擬地址的前 12 bits * 4,就可以根據地址索引找到一級頁表中對應的項,該項中保存的是二級頁表的地址。

    二級頁表一共 256 項,MMU 取出虛擬地址的中間 8 bits * 4,就可以根據地址索引找到二級頁表中對應的項,該項中保存的是物理頁面的基地址。

    知道了物理頁面的基地址,MMU 再取出虛擬地址的最后 12 bits,作為物理頁的頁內偏移,尋址到具體的內存地址。

    在上述這種二級頁表的結構中,MMU 并不要求一級頁表和二級頁表存儲在連續的地址上,這兩者可以分開存儲(不過一級頁表和二級頁表本身需要連續),這并不難理解,對于硬件來說,在查表時,只需要提供給 MMU 目標范圍內的數據即可,比如在第一級查完之后,可以確定目標物理面落在了 ~ 地址之間,那么內核只需要進一步提供這個區間的映射表即可。

    因此一級頁表需要占用連續的 4096*4=16K 內存,而二級頁表一共 4096 個,每個占用連續的 1K 字節,MMU 不要求所有二級頁表保存在連續的地址上。

    顯而易見,頁表的存儲不再需要連續且大量的物理地址,這對新進程的創建時比較友好的,畢竟大片內存的申請隨著系統的運行越來越難以得到。

    linux查詢文件夾大小_linux 查看文件夾大小_查詢空間大小 linux

    另一個巨大的好處在于,大部分程序并不會使用所有的虛擬地址,往往只是其中的一小部分,這種情況下,二級頁表完全可以做到按需分配,用到哪一部分的虛擬地址,就創建對應的二級頁表,完全沒必要將所有 4096 個二級頁表一次性創建,二級頁表相比于一級頁表擁有更好的擴展性。

    采用二級頁表的方案極大地解決了內存利用效率的問題,既然多級頁表這么好用,那何不繼而采用三級、四級頁表呢?

    實際上,在 arm32 擴展內存(LPAE)中,可以支持三級頁表,因為隨著物理內存的增大,增加頁表的級數可以節省頁表空間,原理和上述一致,而 arm64 中支持 4 級頁表,linux 因為要支持所有體系架構,軟件上采用 5 級頁表。

    但是,從上文中虛擬地址到物理地址的轉換中應該不難發現,采用多級頁表的副作用是非常明顯的,采用二級頁表將導致訪問一個虛擬地址需要經過兩次內存訪問,第一次訪問到二級頁表,第二次才能訪問到真正的內存,多級頁表的訪問次數也是線性增加,盡管處理器中的緩存器件可以緩解這個問題,但是隨著頁表級數的增加,內存訪問時間延長是必然的。

    在下面針對頁表的討論中,需要統一幾個術語:

    arm 中頁表的硬件特性

    頁表實際上是硬件和軟件合作的產物,虛擬內存和物理內存都是由操作系統管理的,虛擬地址到物理地址的映射也是軟件進行設置,這是軟件層面。

    而硬件層面,MMU 規定了軟件需要將存儲頁表的物理基地址提交給特定的寄存器中,且保證每一級頁表的內容需要占用連續的物理地址,這樣 MMU 才能通過地址偏移找到對應的物理地址。

    頁表相關寄存器TTBR0寄存器

    在 arm 中,TTBR0 寄存器中保存的是頁表基地址,注意這個基地址必須是頁表對應的物理地址而不是虛擬地址,這并不難理解,開啟 MMU 需要先初始化頁表,但是如果不開啟 MMU,就不存在虛擬地址這個概念,頁表自然無法初始化,這就成了悖論。

    armv7 還支持 TTBR1保存頁表基地址,但是 linux 中受限于內核與用戶空間的分配比例,并沒有使用 TTBR1,不管是內核中還是用戶空間,都使用 TTBR0 保存頁表基地址。

    在沒有多核擴展的實現中,TTBR0 寄存器內容為(支持多核擴展的 TTBR0 寄存器請參考 armv7 指令集架構手冊):

    實際上,TTBR0 只是 bits[31:x] 位指定頁表的基地址,其中 x 的值取決于 TTBCR.N bits,x =(14-(TTBCR.N)),為什么 TTBR0 只需要 (31-x+1) 位就可以找到頁表基地址呢?

    TTBCR.N 是 TTBCR 的 bit[2:0],默認會被設置為 0,因此 x=14,也就是 TTBR0 的 bit[31:14] 作為基地址,軟件設置頁表基地址時,只需要保證該基地址是向 16K 對齊,就可以通過 bit[31:14] 找到頁表基地址。這就像內核中一個變量如果向 4 bytes 對齊時,它的 bit[1:0] 是可以挪作它用的。

    NOS:Not Outer bit,該標志位指示頁表相關內存是否是外部可共享內存。

    RGN:同樣是 cache 相關的屬性設置,和 C bit 的區別在于這是設置 outer 的 cache 屬性,而 C bit 針對 inner ,這兩者的區別在于 outer 會存在多 PE 之間的共享行為,因此需要考慮 cache 回寫的策略。

    IMP: ,取決于具體的處理器實現,需要參考 -Ax 處理器手冊。

    S: 標志位,指示與頁表遍歷關聯的內存的 屬性。

    C:cache 標志位,決定頁表的遍歷過程是否支持 Inner 的 cache。

    linux查詢文件夾大小_linux 查看文件夾大小_查詢空間大小 linux

    指令集層面的 模型

    在 TTBR0 中,不難發現其 bit0-bit6 是針對頁表基地址相關的內存訪問屬性,其中包括 inner、outer、 等等這些概念,其實我也并沒有完全理解這部分概念,就照著手冊中寫的翻譯一下吧,有興趣的朋友可以參考 armv7 手冊以及 -Ax 處理器實現手冊:

    首先,在 armv7 中, 被分為三類:

    是最常見的 類型,我們所熟知的 DRAM、DDR,連接在系統總線上的 ROM 也算,也就是我們常說的內存設備。

    對于系統外設來說查詢空間大小 linux,這部分對應的外設內存是有一些特殊性的,表現在:

    類型和 -order 類型的內存就就是上述描述的外設內存,至于 和 -order 的具體區別,手冊中沒有看到,不過從名稱上猜測, 針對外設內存,而 -order 指代上文中所說的 FIFO 緩沖區,必須要求順序訪問,這兩種類型并不沖突,可能是并存的。

    除了被分為三種不同的類型,分別還對應不同的屬性,比如:

    TTBCR 寄存器

    TTBCR 作為頁表相關的控制寄存器,主要包含以下字段:

    如果沒有實現 (不討論),TTBCR 寄存器只包含兩個部分:

    EAE:是否實現了 PAE 地址擴展,arm32 默認是 32 位地址線,可以通過 PAE 擴展到 40 位地址線,以擴展更大的內存。

    N:決定了 TTBR0 中保存的頁表基地址的對齊值,頁表基地址為 TTBR0 bits[31:14-N],當 N 為 0b000 時,向 16K 對齊。

    MMU 使能寄存器

    對于不包含 的系統下,MMU 的開啟和關閉由 SCTLR.M bit 控制,也就是 bit0。

    開啟 MMU,意味著內存訪問從物理世界跳轉到虛擬世界,在 MMU 開啟之前,CPU 發出的內存地址直接對應物理內存,而在 MMU 開啟之后,CPU 發出的內存地址將會被 MMU 作為輸入,查找 TTBR0 寄存器中指定地址的頁表,根據頁表找到相對應的物理地址,然后再是內存訪問。

    因此,在開啟 MMU 之前,頁表就必須準備好,但是并不要求該頁表是完整的,實際上在初始化過程中,可以只建立需要訪問的虛擬地址對應的臨時映射頁表即可,頁表的配置實際上是存在一定的靈活性的。

    arm 硬件對頁表的支持

    盡管上面的示例以及實際操作系統的配置中遇到的分頁都是以 4K 為一個頁面,實際上 armv7 架構支持多種分頁方式:

    當程序將頁表地址設置到 TTBR0 寄存器中時,保存在頁表基地址上的一級頁表項又被稱為 一級描述符(first level ),一級描述符中可能包含以下內容:

    查詢空間大小 linux_linux查詢文件夾大小_linux 查看文件夾大小

    如果軟件配置為 16M 或者 1M 映射,一級描述符(也是一級頁表項)中保存的就是 或 相關信息,而如果是 4K 或者 64K 映射,一級描述符地址上就保存二級頁表的地址,二級頁表中的表項被稱為 二級描述符( level ),二級描述符中保存的是對應的物理頁面基地址以及相應的屬性位,一個完整的二級頁表需要占用連續的 1K 物理內存空間。

    實際上,在 MMU 查詢獲取到一級頁表項之前,MMU 是不知道該虛擬地址對應物理地址的映射采用的是何種 page 大小,當獲取到一級頁表項之后,該頁表項的最后兩位表示頁映射方式:

    一個比較反直覺的事實是,多種頁表的映射方式在一個進程中是可以共存的,這并不沖突。

    比如將內存地址開始的 ~ 采用 映射到物理內存 ~,也就是 1M 的空間,然后將 ~ 這 1M 的空間采用 4K 的 page 映射,映射到物理內存 ~ 。

    對于 映射,因為是 1M 對齊,輸入的虛擬地址的高 12 bits 用于尋址物理頁面基地址,而虛擬地址的后 20 bits 用于索引基地址上的具體字節,因此,只需要在頁表基地址對應頁表項填入 的數據。

    而對于 4K page 的映射,同樣高 12 bits 用于尋址物理頁面基地址,不過這個物理頁面對應的是二級頁表的基地址,因此需要程序額外申請一個 1K 的物理內存來存放二級頁表(不需要與一級頁表連續)。

    參考下圖:

    這個示例可能不大容易理解,等你看完后面的虛擬地址尋址的實現再回過頭來看這部分就應該可以看懂了,頁表本身有些難以理解。

    虛擬地址的尋址 映射

    前面講了那么多,又是 MMU、又是頁表又是內存訪問屬性,實際上只是為了引出最實際的問題:開啟 MMU 之后,程序傳入的虛擬地址訪問是如何被 MMU 轉換成物理地址訪問的,在這期間頁表起到了什么作用?

    既然內核中有使用 1M 的 映射,就從簡單的 映射講起:

    上圖是直接從 armv7 指令集架構手冊中截出的圖,圖中顯示的是兼容了 LPAE 地址擴展實現,但是我們只討論 32 bits 地址的情況,同時 TTBR0 寄存器中的 N 默認為 0。

    1M 的映射相對比較簡單,只有一級映射,它的過程是這樣的:

    4K page 映射

    4K page 的映射是最常用到的,實現的是二級映射,相對來說復雜一點,其實也說不上有多復雜,也就是原本應該指向物理頁面的一級頁表項內容改成了指向二級頁表項地址,二級頁表項指向 4K 物理頁表,增加了一個中間層,至于為什么需要增加一個中間層,可以參考上文的討論。

    4K 頁面的二級映射是這樣的:

    跟 映射不同的是,4K page 的映射自然是 4K 對齊的,因此物理頁面的頁內尋址只需要 12 bits,而多出來的 8bits 作為二級頁表項的索引,它的映射流程是這樣的:

    linux查詢文件夾大小_查詢空間大小 linux_linux 查看文件夾大小

    對于虛擬地址到物理地址的映射,建議各位自行反復推演,加深理解。

    需要再次強調的是,頁表的內容是需要操作系統去設置的,不論是一級頁表還是二級頁表,MMU 只會根據操作系統提供的頁表基地址以及提供的虛擬地址來從頁表中找到對應的物理映射地址。

    對于不同的進程,因為虛擬地址到物理地址的映射各不一樣,從而在切換進程時也要切換頁表,具體的操作就是將進程對應的頁表基地址設置到 TTBR0 中,這樣來看頁表的切換是不是很簡單。

    頁表項屬性

    在上面的描述中,不難發現,不論是一級頁表項(一級描述符)還是二級頁表項(二級描述符),實際上都只使用了部分的 bits,而另一部分 bits 是內存相關的屬性,盡管這不是本章的重點,不過也需要有一定的了解,比如你有沒有想過:我們常說的程序加載器將程序的 .text 段映射到內存的只讀區,這個 "只讀" 屬性是在哪里設置的?

    一級描述符

    對于 映射,高 12 bits 用作物理頁面基地址的索引,因此低 20 bits 都可以用作訪問屬性設置。而 page table 映射只有低 10 bits 可以作為訪問屬性設置。

    : 內存的 域 . 詳情參考 armv7 指令集手冊 B3-1358.

    SBZ : Be Zero 的簡寫,也就是這位沒有意義.

    PXN : 通常實現了 PAE(大物理內存地址擴展) 的架構才需要使用這個 位.如果支持,該位決定了處理器是否可以以 PL1 模式執行該區域的代碼.

    NS : bit,一般的 guest os 代碼不會運行在 模式下.

    二級描述符

    nG: not bit, 在地址翻譯時決定了 TLB 的緩存行為.

    S : bit,決定該地址區域是否是 share 類型的區域.

    AP[2],AP[1:0] : 訪問權限控制位,

    TEX[2:0],B,C :內存訪問屬性

    XN : -never ,表示該位置的數據能不能被當成代碼執行.

    參考

    /forum/-19242-1-1.html

    armv7-A-R 參考手冊

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有