ARM32 內核記憶體佈局

来源:https://www.cnblogs.com/linhaostudy/archive/2020/05/09/12857407.html
-Advertisement-
Play Games

Linux內核在啟動時會列印出內核記憶體空間的佈局圖,下麵是ARM Vexpress平臺列印出來的記憶體空間佈局圖: 這部分信息列印是在mem_init()函數中實現的。 編譯器在編譯目標文件並且鏈接完成之後,就可以知道內核映像文件最終的大小,接下來打包成二進位文件,該操作由 控制,其中也劃定了內核的內 ...


Linux內核在啟動時會列印出內核記憶體空間的佈局圖,下麵是ARM Vexpress平臺列印出來的記憶體空間佈局圖:

這部分信息列印是在mem_init()函數中實現的。

[start_kernel->mm_init->mem_init]
	pr_notice("Virtual kernel memory layout:\n"
		  "    vmalloc : 0x%16lx - 0x%16lx   (%6ld GB)\n"
#ifdef CONFIG_SPARSEMEM_VMEMMAP
		  "    vmemmap : 0x%16lx - 0x%16lx   (%6ld GB maximum)\n"
		  "              0x%16lx - 0x%16lx   (%6ld MB actual)\n"
#endif
		  "    fixed   : 0x%16lx - 0x%16lx   (%6ld KB)\n"
		  "    PCI I/O : 0x%16lx - 0x%16lx   (%6ld MB)\n"
		  "    modules : 0x%16lx - 0x%16lx   (%6ld MB)\n"
		  "    memory  : 0x%16lx - 0x%16lx   (%6ld MB)\n"
		  "      .init : 0x%p" " - 0x%p" "   (%6ld KB)\n"
		  "      .text : 0x%p" " - 0x%p" "   (%6ld KB)\n"
		  "      .data : 0x%p" " - 0x%p" "   (%6ld KB)\n",
		  MLG(VMALLOC_START, VMALLOC_END),
#ifdef CONFIG_SPARSEMEM_VMEMMAP
		  MLG((unsigned long)vmemmap,
		      (unsigned long)vmemmap + VMEMMAP_SIZE),
		  MLM((unsigned long)virt_to_page(PAGE_OFFSET),
		      (unsigned long)virt_to_page(high_memory)),
#endif
		  MLK(FIXADDR_START, FIXADDR_TOP),
		  MLM(PCI_IO_START, PCI_IO_END),
		  MLM(MODULES_VADDR, MODULES_END),
		  MLM(PAGE_OFFSET, (unsigned long)high_memory),
		  MLK_ROUNDUP(__init_begin, __init_end),
		  MLK_ROUNDUP(_text, _etext),
		  MLK_ROUNDUP(_sdata, _edata));

編譯器在編譯目標文件並且鏈接完成之後,就可以知道內核映像文件最終的大小,接下來打包成二進位文件,該操作由arch/arm/kernel/vmlinux.ld.S控制,其中也劃定了內核的記憶體佈局。

內核image本身占據的記憶體空間從_text段到 _end段,並且分為如下幾個段:

  • 代碼段:_text和 _etext為代碼段的起始和結束地址,包含了編譯後的內核代碼。
  • init段:__init_begin__init_end為init段的起始和結束地址,包含了大部分的模塊初始化的數據。
  • 數據段:_sdata_edata為數據段的起始和結束地址,包含了大部分內核的變數;
  • BSS段:__bss_start__bss_stop為BSS段的開始和結束地址,包含初始化為0的所有靜態全局變數。

上述幾個段的大小在編譯鏈接時根據內核配置來確定,因為每種配置代碼段和數據段長度都不相同,這取決與要編譯哪些內核模塊,但是起始地址__text總是相同的。內核編譯完成後,會生成一個System.map文件,查詢這個文件可以找到這些地址的具體數值。

內核使用虛擬地址從MODULES_VADDR到MODULES_END這段14MB大小的記憶體區域。

#define MODULES_VADDR		(PAGE_OFFSET - SZ_16M)
#ifdef CONFIG_HIGHMEM
#define MODULES_END		(PAGE_OFFSET - PMD_SIZE)
#else
#define MODULES_END		(PAGE_OFFSET)
#endif

用戶空間和內核空間使用3:1的劃分方法時,內核空間只有1GB大小。這1GB的映射空間,其中有一部分用於直接映射物理地址。這個區域稱為線性映射區。在ARM32平臺上,物理地址[0:760MB]的這一部分記憶體被線性映射到[3GB:3GB+768MB]的虛擬地址上。線性映射區的虛擬地址和物理地址相差PAGE_OFFSET,即3GB。內核中有相關的巨集來實現線性映射區虛擬地址與物理地址的查找過程,例如__pa(x)__va(x)

[arch/arm/include/asm/memory.h]
#define __pa(x)	__virt_to_phys((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt(phys_addr_t)(x))
static inline phys_addr_t __virt_to_phys(unsigned long x)
{
	return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET;
}

static inline unsigned long __phys_to_virt(phys_addr_t x)
{
	return x - PHYS_OFFSET + PAGE_OFFSET;
}

其中,__pa()把線性映射區的虛擬地址轉換為物理地址,轉換公式很簡單,即用虛擬地址減去PAGE_OFFSET(3GB),然後再加上PHYS_OFFSET(這個值在有的ARM平臺上為0,在ARM Vexpress平臺該值為0x6000_0000)。

那麼高端記憶體的起始地址(760MB)如何確定呢?

在內核初始化記憶體時,在santiy_check_meminfo()函數中確定高端記憶體的起始地址,全局變數high_memory來存放高端記憶體的起始地址。

static void * __initdata vmalloc_min =
	(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
void __init sanity_check_meminfo(void)
{
	phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
	arm_lowmem_limit = vmalloc_limit;
	high_memory = __va(arm_lowmem_limit - 1) + 1;
}

vmalloc_min計算出來的結果是0x2F80_0000,即760MB;

為什麼內核只線性映射760MB呢?剩下的264MB的虛擬地址空間用來做什麼呢?

那是保留給vmallc,fixmap和高端向量等使用的。內核許多驅動使用vmalloc來分配連續的虛擬地址的記憶體,因為有的驅動不需要連續的物理地址的記憶體;除此之外,vmalloc還可以用於高端記憶體的臨時映射。一個32bit系統中實際支持的記憶體數量會超過內核線性映射的長度,但是內核具有對所有記憶體的尋找能力。

/*
 * Just any arbitrary offset to the start of the vmalloc VM area: the
 * current 8MB value just means that there will be a 8MB "hole" after the
 * physical memory until the kernel virtual memory starts.  That means that
 * any out-of-bounds memory accesses will hopefully be caught.
 * The vmalloc() routines leaves a hole of 4kB between each vmalloced
 * area for the same reason. ;)
 */
#define VMALLOC_OFFSET		(8*1024*1024)
#define VMALLOC_START		(((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_END		0xff000000UL

vmalloc區域在ARM32內核中,從VMALLOC_START開始到VMALLOC_END結束,即從0xf000_0000到0xff00_0000,大小為240MB。從VMALLOC_START開始之前有一個8MB的洞,用於捕捉越界訪問。

內核通常把物理記憶體低於760MB的稱為線性映射記憶體(Normal Memory),而高於760MB以上的稱為高端記憶體(High Memory)。由於32位系統的定址能力只有4GB,對於物理記憶體高於760MB而低於4GB的情況,我們可以從保留240MB的虛擬地址划出一部分用於動態映射高端記憶體,這樣內核就可以訪問到全部的4GB的記憶體了。如果物理記憶體高於4GB,那麼在ARMv7-A架構中就要使用LPE機制來擴展物理記憶體訪問了。用於映射高端記憶體的虛擬地址空間有限,所以又可以劃分為兩部分,一部分是臨時映射區,另一部分為固定映射區。PKMAP指向的就是固定映射區。如圖2.6所示是ARM Vexpress平臺上畫出內核空間的記憶體佈局圖,詳細可以參考文檔documentation/arm/memory.txt文件。


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

-Advertisement-
Play Games
更多相關文章
  • tune2fs命令允許系統管理員在Linux ext2、ext3或ext4文件系統上調整、設置、查看文件系統參數。tune2fs -l 只會顯示 superblock 上的內容。有時候使用tune2fs命令遇到類似“Couldn't find valid filesystem superblock”... ...
  • 1,目標及展示 首先希望實現文字、圖片、控制項等在觸發後,呈現飄散並消失的效果。在QT常式《Qt Quick Particles Examples》是一個海星點擊滑鼠後呈現打散的效果,這個效果和最終需要的略有不同,所以我們在它的基礎上再加上我需要的一些元素,最終實現如下效果。 圖1(gif) 圖6 2 ...
  • 做為一個過來人,我談談我自己的看法,歡迎大家補充: 首先肯定的一點是:不要一上來就看內核代碼,基本上你會很快被挫敗感打敗。內核正在變得越來越龐大,學習曲線越來越陡峭,當你一無所知的時候冒然進入linux kernel,你會發現處處都是障礙,處處都是大坑,你根本走不下去。最好的方法是把對內核源代碼的熱 ...
  • Linux有非常多的版本,比如世面上常見的有 Ubuntu、RedHat、Fedora、Centos等等,這麼多的版本我們究竟該選哪一個呢?今天我帶大家對各個版本進行一下分析和比較,幫助大家來做出更好的選擇。 (一)Linux 是什麼? 首先瞭解一下Linux是什麼。它是一套類UNIX的操作系統,最 ...
  • 步驟 0 uboot 將 zImage 複製到記憶體之後,跳轉到 zImage 處開始執行,首先執行的代碼是 arch/arm/boot/compressed/head.S 文件,首先是一些涉及不同體繫結構調試相關的彙編巨集定義 ifdef DEBUG if defined(CONFIG_DEBUG_I ...
  • 大家好,我是良許。 不管你用的是什麼操作系統,網速都是你非常關心的一個性能指標,畢竟,誰都不想看個視頻結果網速卡到你懷疑人生。本文介紹三個 Linux 命令行下的網路測速工具,讓你隨時隨地知道你的網路狀況。 fast 是 Netflix 提供的一項服務,它不僅可以通過命令行來使用,而且可以直接在 W ...
  • Linux常用命令大全(非常全!!!) 最近都在和Linux打交道,感覺還不錯。我覺得Linux相比windows比較麻煩的就是很多東西都要用命令來控制,當然,這也是很多人喜歡linux的原因,比較短小但卻功能強大。我將我瞭解到的命令列舉一下,僅供大家參考: 系統信息 arch 顯示機器的處理器架構 ...
  • linux進程,這塊太難了,太多命令,太多新概念.作為初學者戰戰兢兢.同時也在匍匐前進. ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...