<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Chapter-1 Memory Management (section 1.1-1.5)

      參考了 《打通 Linux 操作系統(tǒng)和芯片開發(fā)》 書籍的內(nèi)容,實(shí)際也可以說是完全參照加上了個(gè)人的拙見或者是讀書記錄。
      和我上一篇說的一樣,我依然還是一個(gè)初學(xué)者,記錄這些是自己梳理,以及想讓文字發(fā)揮一些作用和意義。

      涉及到代碼的部分實(shí)在是非常非常的枯燥無(wú)味和無(wú)聊,并且由于 Linux 中函數(shù)的分層很多,call stack 特別深,函數(shù)名稱特別相似,
      非常容易頭暈眼花了,所以還是應(yīng)該采取從宏觀角度的,抓住關(guān)鍵的函數(shù)調(diào)用鏈來(lái)進(jìn)行分析和理解,不應(yīng)該要求細(xì)節(jié)到某一行代碼的程度,
      否則陷入難解的困境了。

      操作系統(tǒng)為什么需要內(nèi)存管理?

      這應(yīng)該是一個(gè)很經(jīng)典的問題,內(nèi)存池 (Memory Pool) 也可以認(rèn)為是一種內(nèi)存管理的方式,所以關(guān)于內(nèi)存管理四個(gè)字有點(diǎn)像謎底就在謎面上,更多的只是你如何管理的方式。
      比如 FreeRTOS 中的好幾種分配方式,常用的只是 heap_4.c 的方式,這種用在 MCU 上的方式可以比較簡(jiǎn)單,而對(duì)于現(xiàn)代的 2025 年的 MCU 可能依然還是比較小的內(nèi)存,
      至少?zèng)]有上升到 4GB ,至少我還沒接觸到。并且芯片性能可能不強(qiáng),無(wú)法負(fù)責(zé)和管理這么多的內(nèi)存(后面出現(xiàn)了一個(gè)東西專門輔助此工作),所以操作系統(tǒng)采取了其他的方式來(lái)管理。

      MCU 跑的都是在很小的內(nèi)存中,大部分直接都是訪問了物理地址,
      所以簡(jiǎn)單的說為什么的原因,就是為了更好的利用和使用內(nèi)存 這個(gè)相對(duì)比較快速的可以存數(shù)據(jù)的東西,才出現(xiàn)了內(nèi)存管理的各種方式,一般在操作系統(tǒng)課程中都會(huì)提到在演進(jìn)中出現(xiàn)的:

      • 分段機(jī)制(Segmentation)
      • 分頁(yè)機(jī)制(Paging)

      兩種經(jīng)典的方式,也可能聽到 段頁(yè)式 就是兩種合并在一起說的。

      Linux 采取的是分頁(yè)的機(jī)制,同時(shí)根據(jù)書中描述是 四級(jí)頁(yè)表 的形式,關(guān)于分段、分頁(yè)的一些說明和概述及原理性這里就不詳細(xì)說明,可以詢問 ChatGPT 或是查看其他的文章,
      這里僅添加一些可能重要的名詞:

      名詞 翻譯
      換入 Swapping In
      換出 Swapping Out
      頁(yè)面 Page
      物理頁(yè)面 Physical Page
      頁(yè)幀 Page Frame
      頁(yè)幀號(hào) Page Frame Number (PFN)
      虛擬頁(yè)幀號(hào) Virtual Page Frame Number (VPN)
      物理頁(yè)幀號(hào) Physical Page Frame Number (PFN)
      虛擬頁(yè)面 Virtual Page
      頁(yè)表 Page Table (PT)
      頁(yè)表項(xiàng) Page Table Entry (PTE)
      內(nèi)存管理單元 Memory Management Unit (MMU)
      虛擬地址 Virtual Address
      物理地址 Physical Address
      轉(zhuǎn)譯后備緩沖器(快表) Translation Lookaside Buffer (TLB)
      頁(yè)全局目錄 Page Global Direcotry (PGD)
      頁(yè)上級(jí)目錄 Page Upper Directory (PUD)
      頁(yè)中間目錄 Page Middle Direcotry (PMD)
      頁(yè)表 Page Table (PTE)
      上面出現(xiàn)了但含義不一樣
      這里主要指Linux中多級(jí)頁(yè)表的
      頁(yè)內(nèi)偏移 Page offset

      上面提到了一個(gè)專門輔助 Linux 做內(nèi)存管理的東西就是 MMU 了(用來(lái)將虛擬地址轉(zhuǎn)換成物理地址),現(xiàn)代的芯片一般都是將 MMU 內(nèi)置在芯片中了,這是 Linux 運(yùn)行的必備條件,所以 區(qū)別一個(gè)芯片能不能運(yùn)行 Linux 系統(tǒng),就是芯片有沒有 MMU 這個(gè)模塊了。 (當(dāng)然現(xiàn)在也可以不用 MMU 也能運(yùn)行 Linux 了只不過是功能受限

      關(guān)于 MMU 如何尋址,如何管理,以及頁(yè)表的映射和使用的過程,這里不多贅述,感興趣的可以找操作系統(tǒng)相關(guān)課程學(xué)習(xí),或者找 408 相關(guān)的學(xué)習(xí)視頻參考。
      另外重點(diǎn)是 Linux 一個(gè)頁(yè)面的大小為 4KB 至于為什么是 4KB 的大小,AI 給出的答案是歷史原因;還有就是想要運(yùn)行 Linux 就需要 MMU 這個(gè)模塊;

      Linux 內(nèi)存架構(gòu)和模型略過,對(duì)理解關(guān)系不大不太重要

      一級(jí)、二級(jí)頁(yè)表映射過程

      感覺實(shí)在是有必要的畫一個(gè)一級(jí)、二級(jí)的頁(yè)表映射的過程

      二級(jí)頁(yè)表只是在一級(jí)的基礎(chǔ)上做了修改,添加了一個(gè)對(duì)一級(jí)頁(yè)表的索引表,這樣能對(duì)應(yīng)的一級(jí)頁(yè)表項(xiàng)就會(huì)更多了,而 Linux 用了四級(jí)來(lái)管理,數(shù)量就不計(jì)算了,同時(shí)這只是大致的示意,不代表就是這樣的尋址。

      對(duì)于 Linux 的多級(jí)頁(yè)表管理不準(zhǔn)備畫圖了,只不過是更多級(jí),更復(fù)雜,更多控制位,更長(zhǎng)的地址長(zhǎng)度,但基本的方式是一樣的。
      簡(jiǎn)單說明就是首先將一個(gè)包含了虛擬頁(yè)幀號(hào)的虛擬地址(線性地址)通過一系列查表的方式(查表的這個(gè)動(dòng)作也可以是 MMU 在執(zhí)行)轉(zhuǎn)換成一個(gè)包含了物理頁(yè)幀號(hào)的物理地址,(這里假設(shè)用到了 TLB ) 然后 MMU 通過查 TLB 快速的知道了物理頁(yè)幀號(hào)與內(nèi)存的某一塊位置的對(duì)應(yīng)關(guān)系,
      然后就使用一下偏移量,在這一頁(yè)中的偏移多少,就知道了這個(gè)虛擬地址的數(shù)據(jù)內(nèi)容是多少了。
      另外在這個(gè)過程中可能會(huì)產(chǎn)生一個(gè) 缺頁(yè)中斷 (Page Fault) ,簡(jiǎn)單說明即是在代碼中使用 malloc 申請(qǐng)內(nèi)存空間是在虛擬地址空間中,此時(shí)隨便申請(qǐng),實(shí)際上物理的內(nèi)存條上對(duì)應(yīng)映射的空間并不存在,或者說并沒有數(shù)據(jù)內(nèi)容,
      或者當(dāng)訪問的頁(yè)不在任何一個(gè)頁(yè)表中,這個(gè)時(shí)候出現(xiàn)了缺頁(yè)中斷,此時(shí)才會(huì)從存儲(chǔ)中加載到內(nèi)存中,或者是正式的分配內(nèi)存,這時(shí)候內(nèi)存條上就有了空間和數(shù)據(jù)內(nèi)容了,那么這正好也有頁(yè)的換入(Swaping In)和換出(Swaping Out)兩個(gè)動(dòng)作。

      memblock 物理內(nèi)存的初始化

      這部分有比較多的圖和代碼,太麻煩了,嘗試通過文字來(lái)簡(jiǎn)單的敘述看看

      memblock 的作用

      Linux 中通過 Buddy 伙伴系統(tǒng)和 slab 分配器來(lái)分配和管理內(nèi)存的,但是在此之前不可用的階段,就由 memblock 來(lái)承擔(dān)了初始化和管理的工作,所以自然的就想到這個(gè)階段的 memblock 直接就是訪問和管理的物理地址,
      memblock 是唯一能做早期啟動(dòng)階段管理內(nèi)存的內(nèi)存分配器,由此出現(xiàn)了 early boot memory 階段的名稱,是系統(tǒng)啟動(dòng)中間階段的內(nèi)存管理,這里涉及的內(nèi)存模型不多贅述。

      memblock 的數(shù)據(jù)結(jié)構(gòu)及代碼分析

      書籍解析了代碼的結(jié)構(gòu),只是簡(jiǎn)單解析了各部分的字段含義,詳細(xì)可以直接讓 AI 生成,注釋內(nèi)容 Gemini 2.5 Flash 生成:

      include/linux/memblock.h
      
      struct memblock {
      	bool bottom_up;					/* 是否是自底向上? */
      	phys_addr_t current_limit;		/* 當(dāng)前限制地址 */
      	struct memblock_type memory;	/* 可用內(nèi)存區(qū)域 */
      	struct memblock_type reserved;	/* 保留內(nèi)存區(qū)域 */
      };
      
      struct memblock_type {
      	unsigned long cnt; 				 /* 區(qū)域計(jì)數(shù) */
      	unsigned long max; 				 /* 最大區(qū)域數(shù) */
      	phys_addr_t total_size; 		 /* 總大小 */
      	struct memblock_region *regions; /* 區(qū)域數(shù)組 */
      	char *name;						 /* 類型名稱 */
      };
      
      struct memblock_region {
      	phys_addr_t base;		 	/* 區(qū)域基地址 */
      	phys_addr_t size; 			/* 區(qū)域大小 */
      	enum memblock_flags flags; 	/* 區(qū)域標(biāo)志 */
      #ifdef CONFIG_NUMA
      	int nid; /* NUMA節(jié)點(diǎn)ID */
      #endif
      };
      
      enum memblock_flags {
      	MEMBLOCK_NONE			= 0x0,	/* 無(wú)特殊請(qǐng)求 */
      	MEMBLOCK_HOTPLUG		= 0x1,	/* 可熱插拔區(qū)域 */
      	MEMBLOCK_MIRROR			= 0x2,	/* 鏡像區(qū)域 */
      	MEMBLOCK_NOMAP			= 0x4,	/* 不添加到內(nèi)核直接映射 */
      	MEMBLOCK_DRIVER_MANAGED = 0x8,	/* 總是通過驅(qū)動(dòng)檢測(cè) */
      	MEMBLOCK_RSRV_NOINIT	= 0x10,	/* 不初始化struct pages */
      };
      
      

      接著從 stark_kernel 入手,主要關(guān)注了 setup_arch 函數(shù),參數(shù)是 command_line,貼出函數(shù):

      // 只給出相對(duì)重要的函數(shù)調(diào)用
      arch/arm64/kernel/setup.c
      
      void __init __no_sanitize_address setup_arch(char **cmdline_p)
      {
      	setup_initial_init_mm(_stext, _etext, _edata, _end);
      
      	*cmdline_p = boot_command_line;
      
      	... ...
      	early_fixmap_init();
      	early_ioremap_init();
      
      	setup_machine_fdt(__fdt_pointer);
      	... ...
      
      	arm64_memblock_init();
      
      	paging_init();
          ... ...
      	bootmem_init();
      
      	... ...
      }
      

      Gemini 2.5 Flash:

      1. setup_initial_init_mm

        • 初始化內(nèi)核的第一個(gè)內(nèi)存描述符 init_mm
        • 主要用于設(shè)置內(nèi)核代碼 (_stext, _etext) 和數(shù)據(jù)段 (_edata, _end) 的內(nèi)存范圍。
      2. *cmdline_p = boot_command_line

        • 將系統(tǒng)啟動(dòng)時(shí)傳遞的命令行參數(shù) (boot_command_line) 賦值給 cmdline_p 指針。
        • 這使得后續(xù)的內(nèi)核組件能夠訪問和解析啟動(dòng)參數(shù)。
      3. early_fixmap_init

        • 初始化早期固定映射(fixmap)區(qū)域。
        • 用于在啟動(dòng)初期為特定的、固定地址的內(nèi)存區(qū)域建立虛擬地址映射,通常用于訪問一些關(guān)鍵的硬件寄存器或數(shù)據(jù)結(jié)構(gòu)。
      4. early_ioremap_init

        • 初始化早期 I/O 內(nèi)存重映射機(jī)制。
        • 允許內(nèi)核在啟動(dòng)初期安全地訪問和映射設(shè)備 I/O 空間,例如外設(shè)控制器的寄存器。
      5. setup_machine_fdt(__fdt_pointer)

        • 根據(jù)設(shè)備樹(Flattened Device Tree, FDT)設(shè)置機(jī)器相關(guān)的參數(shù)和配置。
        • 解析由 __fdt_pointer 指向的設(shè)備樹,從中獲取硬件信息、設(shè)備配置等,以初始化系統(tǒng)。
      6. arm64_memblock_init

        • 初始化 ARM64 架構(gòu)的內(nèi)存塊(memblock)管理機(jī)制。
        • 用于在內(nèi)核啟動(dòng)早期跟蹤和管理物理內(nèi)存區(qū)域,包括可用內(nèi)存和保留內(nèi)存。
      7. paging_init

        • 初始化頁(yè)表和內(nèi)存分頁(yè)機(jī)制。
        • 建立將物理內(nèi)存映射到虛擬地址空間的頁(yè)表結(jié)構(gòu),這是現(xiàn)代操作系統(tǒng)內(nèi)存管理的基礎(chǔ)。
      8. bootmem_init

        • 初始化 bootmem 分配器。
        • 這是一個(gè)簡(jiǎn)單的物理內(nèi)存分配器,在內(nèi)核啟動(dòng)的早期階段(分頁(yè)機(jī)制剛建立,但更復(fù)雜的內(nèi)存管理系統(tǒng)尚未完全初始化時(shí))用于分配物理內(nèi)存。

      接著繼續(xù)分析了 setup_machine_fdt 函數(shù):

      static void __init setup_machine_fdt(phys_addr_t dt_phys)
      {
      	int size;
      	void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
      	const char *name;
      
      	if (dt_virt)
      		memblock_reserve(dt_phys, size);
      
      	if (!early_init_dt_scan(dt_virt, dt_phys)) {
      		pr_crit("\n"
      			"Error: invalid device tree blob at physical address %pa (virtual address 0x%px)\n"
      			"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
      			"\nPlease check your bootloader.",
      			&dt_phys, dt_virt);
      
      		while (true)
      			cpu_relax();
      	}
      
      	/* Early fixups are done, map the FDT as read-only now */
      	fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
      
      	name = of_flat_dt_get_machine_name();
      	if (!name)
      		return;
      
      	pr_info("Machine model: %s\n", name);
      	dump_stack_set_arch_desc("%s (DT)", name);
      }
      

      該函數(shù)主要功能是:

      • 拿到 DTB 的物理地址后,會(huì)通過 fixmap_remap_fdt() 進(jìn)行映射,其中包括 pgdpudpte 等映射(書中這部分是否漏了 pmd ?),當(dāng)映射完成后會(huì)返回 dt_virt,并通過 memblock_reserve() 添加到 memblock.reserved 中。
      • early_init_dt_scan() 通過解析 DTB 文件的 memory 節(jié)點(diǎn)獲得可用物理內(nèi)存的起始地址和大小,并通過類 memblock_add 的 API 向 memory.regions 數(shù)組添加一個(gè) memblock.region 實(shí)例,用于管理這個(gè)物理內(nèi)存的區(qū)域。

      接著是 arm64_memblock_init 函數(shù),其主要工作是將物理內(nèi)存進(jìn)行整理,將一些特殊區(qū)域添加到 reserved 內(nèi)存中,主要是設(shè)備樹中的:chosenchosen(cma)reserved-memory/memreservechosen(initrd) 節(jié)點(diǎn)。

      這部分的代碼工作大體將物理內(nèi)存進(jìn)行了分區(qū)和簡(jiǎn)單的管理,后續(xù)需要進(jìn)行重要的 內(nèi)存頁(yè)表映射 完成物理地址到虛擬地址的映射,書中說系統(tǒng)完成初始化之后,所有的工作會(huì)移交給 Buddy 系統(tǒng)來(lái)進(jìn)行內(nèi)存管理。

      —— juezhong 乙巳年丙戌月戊辰日 戌時(shí)

      posted @ 2025-10-26 20:29  縱然似夢(mèng)  閱讀(109)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产资源精品中文字幕| 色欲av亚洲一区无码少妇| 日韩av中文字幕有码| 亚洲产在线精品亚洲第一站一| 国产精品鲁鲁鲁| 国产在线一区二区不卡| 国产精品国产精品偷麻豆| 滨州市| 国产成人无码av大片大片在线观看| 色狠狠色婷婷丁香五月| 亚洲 自拍 另类小说综合图区| 最新亚洲精品国偷自产在线| 久久午夜无码鲁丝片直播午夜精品| 国产成人综合亚洲第一区| 国产精品国产三级国产专业| 国产av中文字幕精品| 亚洲中文一区二区av| 国产精品国产亚洲区久久| 日韩av中文字幕有码| 欧美自拍嘿咻内射在线观看| 久久亚洲国产精品五月天| 最新国产精品好看的精品| 香港| 日韩精品av一区二区三区| 国产福利精品一区二区 | 亚洲精品一区二区三区蜜臀| 正在播放酒店约少妇高潮| 少妇人妻av毛片在线看| √新版天堂资源在线资源| 男女性高爱潮免费网站| 国产高清在线a视频大全| 免费久久人人爽人人爽AV| 亚洲永久精品日韩成人av| 国产v亚洲v天堂a无码| 天堂www在线中文| 亚洲AV无码秘?蜜桃蘑菇| 亚洲精品日韩久久精品| 男女性高爱潮免费网站| 亚洲国产av无码综合原创国产| 亚洲a免费| 国产精品店无码一区二区三区|