【原創】(三)Linux paging_init解析

来源:https://www.cnblogs.com/LoyenWang/archive/2019/09/07/11483948.html
-Advertisement-
Play Games

背景 By 魯迅 By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex A53,雙核 3. 使用工具:Source Insight 3.5, Visio 1. 介紹 從 中,可知在 調用之前,存放 和`DTB memblock_add memblock_all ...


背景

  • Read the fucking source code! --By 魯迅
  • A picture is worth a thousand words. --By 高爾基

說明:

  1. Kernel版本:4.14
  2. ARM64處理器,Contex-A53,雙核
  3. 使用工具:Source Insight 3.5, Visio

1. 介紹

(二)Linux物理記憶體初始化中,可知在paging_init調用之前,存放Kernel ImageDTB的兩段物理記憶體區域可以訪問了(相應的頁表已經建立好)。儘管物理記憶體已經通過memblock_add添加進系統,但是這部分的物理記憶體到虛擬記憶體的映射還沒有建立,可以通過memblock_alloc分配一段物理記憶體,但是還不能訪問,一切還需要等待paging_init的執行。最終頁表建立好後,可以通過虛擬地址去訪問最終的物理地址了。

按照慣例,先上圖,來一張ARM64內核的記憶體佈局圖片吧,最終的佈局如下所示:

開啟探索之旅吧!

2. paging_init

paging_init源代碼短小精悍,直接貼上來,分模塊來介紹吧。

/*
 * paging_init() sets up the page tables, initialises the zone memory
 * maps and sets up the zero page.
 */
void __init paging_init(void)
{
    phys_addr_t pgd_phys = early_pgtable_alloc();   /********(mark 1)*******/
    pgd_t *pgd = pgd_set_fixmap(pgd_phys);

    map_kernel(pgd);                                        /********(mark 2)*******/
    map_mem(pgd);                                         /********(mark 3)*******/

    /*
     * We want to reuse the original swapper_pg_dir so we don't have to
     * communicate the new address to non-coherent secondaries in
     * secondary_entry, and so cpu_switch_mm can generate the address with
     * adrp+add rather than a load from some global variable.
     *
     * To do this we need to go via a temporary pgd.
     */
    cpu_replace_ttbr1(__va(pgd_phys));                 /********(mark 4)*******/
    memcpy(swapper_pg_dir, pgd, PGD_SIZE);
    cpu_replace_ttbr1(lm_alias(swapper_pg_dir));

    pgd_clear_fixmap();
    memblock_free(pgd_phys, PAGE_SIZE);

    /*
     * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
     * allocated with it.
     */
    memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
              SWAPPER_DIR_SIZE - PAGE_SIZE);
}
  • mark 1:分配一頁大小的物理記憶體存放pgd
  • mark 2:將內核的各個段進行映射;
  • mark 3:將memblock子系統添加的物理記憶體進行映射;
  • mark 4:切換頁表,並將新建立的頁表內容替換swappper_pg_dir頁表內容;

代碼看起來費勁?圖來了:

下邊將對各個子模塊進一步的分析。

3. early_pgtable_alloc

這個模塊與FIX MAP映射區域相關,建議先閱讀前文(二)Linux物理記憶體初始化
先上圖:

FIX MAP的區域劃分從圖中可以看出來
本函數會先分配物理記憶體,然後借用之前的全局頁表bm_pte,建立物理地址到虛擬地址的映射,這次映射的作用是為了去訪問物理記憶體,把記憶體清零,所以它只是一個臨時操作,操作完畢後,會調用pte_clear_fixmap()來清除映射。

early_pgtable_alloc之後,我們看到paging_init調用了pgd_set_fixmap函數,這個函數調用完後,通過memblock_alloc分配的物理記憶體,最終就會用來存放pgd table了,這片區域的內容最後也會拷貝到swapper_pg_dir中去。

4. map_kernel

map_kernel的主要工作是完成內核中各個段的映射,此外還包括了FIXADDR_START虛擬地址的映射,如下圖:

映射完成之後,可以看一下具體各個段的區域,以我自己使用的平臺為例:

這些地址信息也能從System.map文件中找到。

aarch64-linux-gnu-objdump -x vmlinux能查看更詳細的地址信息。

5. map_mem

從函數名字中可以看出,map_mem主要完成的是物理記憶體的映射,這部分的物理記憶體是通過memblock_add添加到系統中的,當對應的memblock設置了MEMBLOCK_NOMAP的標誌時,則不對其進行地址映射。
map_mem函數中,會遍歷memblock中的各個塊,然後調用__map_memblock來完成實際的映射操作。先來一張效果圖:

map_mem都是將物理地址映射到線性區域中,我們也發現了Kernel Image中的text, rodata段映射了兩次,原因是其他的子系統,比如hibernate,會映射到線性區域中,可能需要線性區域的地址來引用內核的text, rodata,映射的時候也會限製成了只讀/不可執行,防止意外修改或執行。

map_kernelmap_mem函數中的頁表映射,最終都是調用__create_pgd_mapping函數實現的:

總體來說,就是逐級頁表建立映射關係,同時中間會進行許可權的控制等。
細節不再贅述,代碼結合圖片閱讀,效果會更佳噢。

6. 頁表替換及記憶體釋放

這部分代碼不多,不上圖了,看代碼吧:

    /*
     * We want to reuse the original swapper_pg_dir so we don't have to
     * communicate the new address to non-coherent secondaries in
     * secondary_entry, and so cpu_switch_mm can generate the address with
     * adrp+add rather than a load from some global variable.
     *
     * To do this we need to go via a temporary pgd.
     */
    cpu_replace_ttbr1(__va(pgd_phys));
    memcpy(swapper_pg_dir, pgd, PGD_SIZE);
    cpu_replace_ttbr1(lm_alias(swapper_pg_dir));

    pgd_clear_fixmap();
    memblock_free(pgd_phys, PAGE_SIZE);

    /*
     * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
     * allocated with it.
     */
    memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
              SWAPPER_DIR_SIZE - PAGE_SIZE);

簡單來說,將新建立好的pgd頁表內容,拷貝到swapper_pg_dir中,也就是覆蓋掉之前的臨時頁表了。當拷貝完成後,顯而易見的是,我們可以把paging_init一開始分配的物理記憶體給釋放掉。
此外,在之前的文章也分析過swapper_pg_dir頁表存放的時候,是連續存放的pgd, pud, pmd等,現在只需要復用swapper_pg_dir,其餘的當然也是可以釋放的了。

好了,點到為止,前路漫漫,離Buddy System,Slab,Malloc以及各種記憶體的騷操作好像還有很遠的樣子,待續吧。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 錯誤提示如圖: 檢查C:\Windows\System32\inetsrv\config目錄下的applicationHost.config文件,備份一份。 可使用IIS提供的AppCmd.exe的restore功能恢復applicationHost.config文件 運行CMD 輸入 cd %wi ...
  • 上是效果圖我這裡使用的是兩張表作為父子節點的分配,網上很多demo是一張表的那張一般作為導航欄用。 1 public void Bind(DataTable dt) 2 { 3 this.equiplist.ClearNodes(); 4 if (dt.Rows.Count > 0) 5 { 6 7... ...
  • 場景 點擊按鈕使窗體以Dialog的方式顯示,即彈窗。 然後設置彈窗的位置居中顯示。 關註公眾號霸道的程式猿獲取編程相關電子書、教程推送與免費下載。 實現 以上設置顯示在屏幕中間,其他選項如下: ...
  • 1、==、!=、、= 運算符為比較運算符(comparison operator)。C 語言規範5.0中文版中比較運算符的描述如下: 2、通用類型系統 3、值類型Equal函數 and 運算符'==' 3.1、常見類型 int、float、double、decimal等雖然繼承自ValueType, ...
  • 前言 前段時間使用了net.json保存對象數據。添加完成後,測試發現300多實例數據保存載入json文件,速度比原方式(BinaryFormatter)慢。但是功能加上後也懶再刪掉代碼了,索性就採用兩種方式。怎麼說兩種方式也比一種多不是?^_^ net.json "詳細介紹" 1 測試之前需要引用 ...
  • 十一長假就要過去了,今年假期沒有回家,一個人閑著無聊就在看C 語言規範5.0中文版。昨天看了 is運算符和 as運算符,平時項目中也有用到這兩種符號,對於其效率也沒有進行比較過,趁著假期有空,先看下效率。 is 常用法: 先判斷obj是不是T類型,如果是再進行轉換。 as 常用法: 如果obj不是T ...
  • ps:原諒我的書法出自魯迅的《野草》 《Linux就該這麼學》書本介紹: 本書是由全國多名紅帽架構師(RHCA)基於最新Linux系統共同編寫的高質量Linux技術自學教程,極其適合用於Linux技術入門教程或講課輔助教材,目前是國內最值得去讀的Linux教材,也是最有價值的Linux實驗手冊。章節 ...
  • 工欲善其事,必先利其器 虛擬機安裝(鏈接中有詳細的操作方法,這裡就不再詳細說明瞭,但有註意事項,會在下文中截圖標註) https://www.linuxprobe.com/ 註:為了避免是許可權問題導致的命令執行失敗,請在學習中使用root賬號進行登錄操作 一.YUM倉庫 源代碼->RPM->YUMR ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...