引導期間 initramfs gzip’ed cpio 歸檔的定址方案
以下引導文件 (vmlinux64) 適用於 Linux 核心 v2.6.21.7(發行版:Cavium-Octeon for MIPS64):
ELF HEADER: ------------------------------------------ Magic: 0x7f 0x45 0x4c 0x46 ("ELF") Class: 64-bit Encoding: Big-Endian ELF version: 1 OS ABI: System V ABI Version: 0 Type: ET_EXEC Machine: MIPS Version: 1 Entry Point: 0xffffffff804b0000 Program Headers Offset: 0x40 Section Headers Offset: 0x572C70 Flags: 0x808b0001 ELF Header Size: 0x40 Program Header Entry Size: 0x38 Program Header Entries: 1 Section Header Entry Size: 0x40 Section Header Entries: 0x21 .shstrtab Index: 0x20
有這些段和部分:
_______________________________________________________________________________________________ PROGRAM HEADERS: _______________________________________________________________________________________________ Index Type Flags SizeInMem MemVirtAddress FileOffs SizeInFile ----------------------------------------------------------------------------------------------- 0 PT_LOAD Write+Read+Exec 0x5AB200 0xffffffff80100000 0x4000 0x56EAC7 _______________________________________________________________________________________________ SECTION HEADERS: _______________________________________________________________________________________________ Index Name Type Flags MemVirtAddress FileOffs SizeInFile ----------------------------------------------------------------------------------------------- 0 K_NULL 0x0 0x0 0x0 1 .text K_PROGBITS Alloc+Exec 0xffffffff80100000 0x4000 0x30DFE8 2 __ex_table K_PROGBITS Alloc+ 0xffffffff8040dff0 0x311FF0 0x5EA0 3 __dbe_table K_PROGBITS Alloc+ 0xffffffff80413e90 0x317E90 0x0 4 .rodata K_PROGBITS Alloc+ 0xffffffff80414000 0x318000 0x48B68 5 .pci_fixup K_PROGBITS Alloc+ 0xffffffff8045cb68 0x360B68 0xB20 7 __ksymtab K_PROGBITS Alloc+ 0xffffffff8045d688 0x361688 0x8EA0 8 __ksymtab_gpl K_PROGBITS Alloc+ 0xffffffff80466528 0x36A528 0x2580 17 __ksymtab_strings K_PROGBITS Alloc+ 0xffffffff80468aa8 0x36CAA8 0xEBA8 18 __param K_PROGBITS Alloc+ 0xffffffff80477650 0x37B650 0x6E0 19 .data K_PROGBITS Alloc+Write 0xffffffff80478000 0x37C000 0x2FD20 20 .data.cacheline_aligned K_PROGBITS Alloc+Write 0xffffffff804a8000 0x3AC000 0x7280 21 .init.text K_PROGBITS Alloc+Exec 0xffffffff804b0000 0x3B4000 0x31270 22 .init.data K_PROGBITS Alloc+Write 0xffffffff804e1270 0x3E5270 0x3708 23 .init.setup K_PROGBITS Alloc+Write 0xffffffff804e4980 0x3E8980 0x5B8 24 .initcall.init K_PROGBITS Alloc+Write 0xffffffff804e4f38 0x3E8F38 0x6D8 25 .con_initcall.init K_PROGBITS Alloc+Write 0xffffffff804e5610 0x3E9610 0x10 27 .exit.text K_PROGBITS Alloc+Exec 0xffffffff804e5620 0x3E9620 0x30C0 28 .init.ramfs K_PROGBITS Alloc+ 0xffffffff804e9000 0x3ED000 0x185AC7 32 .shstrtab K_STRTAB 0x0 0x572AC7 0x1A7 6 .rio_route K_PROGBITS Write 0xffffffff8045d688 0x572AC7 0x0 9 __ksymtab_unused K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 10 __ksymtab_unused_gpl K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 11 __ksymtab_gpl_future K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 12 __kcrctab K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 13 __kcrctab_gpl K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 14 __kcrctab_unused K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 15 __kcrctab_unused_gpl K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 16 __kcrctab_gpl_future K_PROGBITS Write 0xffffffff80468aa8 0x572AC7 0x0 26 .security_initcall.init K_PROGBITS Write 0xffffffff804e5620 0x572AC7 0x0 29 .sbss K_PROGBITS Alloc+Write 0xffffffff8066f000 0x572AC7 0x0 30 .bss K_NOBITS Alloc+Write 0xffffffff80670000 0x572AC7 0x3AEF0 31 .cvmx_shared_bss K_NOBITS Alloc+Write 0xffffffff806aaef0 0x572AC7 0x310 _______________________________________________________________________________________________
請注意,此 ELF 文件有一個嵌入的 1558kB init.ramfs 部分,其中包含對作業系統至關重要的文件。這部分是 gzip 的,包含一個包含 1805 個文件和目錄的 cpio 存檔。
根據: Kernel.org 和 Wikipedia,Linux Kernel cpio 提取器將這個 init.ramfs 部分解壓縮到記憶體中的某個位置。
我的問題是:
- 是什麼決定了提取 cpio 存檔內容的記憶體地址?
- 提取後,核心如何找到特定文件的數據的記憶體地址,…例如 /sbin/init 文件?
- cpio 存檔的內容是否被提取到某種文件系統中,允許核心稍後找到這些文件……或者這些文件的記憶體地址是否在核心程式碼中硬編碼?
回复:問題 1:我不認為 .init.ramfs 部分可以解壓縮到 ELF 文件的部分標題中所述的 0xffffffff804e9000 記憶體地址,因為在下一部分之前只有 1560kB 可用空間(“. sbss") 從記憶體中的 0xffffffff8066f000 開始,而 ungzip 的 cpio 存檔佔用 4035kB。
cpio 存檔的內容是否被提取到某種文件系統中,允許核心稍後找到這些文件……或者這些文件的記憶體地址是否在核心程式碼中硬編碼?
進入文件系統。使用的文件系統類型是ramfs或tmpfs。在您提到的連結之一中對此進行了詳細說明。
https://github.com/torvalds/linux/blob/v4.17/Documentation/filesystems/ramfs-rootfs-initramfs.txt
ramfs 和 tmpfs 的工作方式非常相似;這個問題沒有太大區別。initramfs 使用哪種類型可能會有所不同,例如在核心版本之間(如果您需要知道,請閱讀此內容)。在 initramfs 之外,一般規則是始終使用 tmpfs。tmpfs 限制最大空間使用量,以防止記憶體不足和系統崩潰。
Rootfs 是 ramfs(或 tmpfs,如果已啟用)的特殊實例,它始終存在於 2.6 系統中
$$ … $$ 什麼是initramfs?
所有 2.6 Linux 核心都包含一個 gzip 壓縮的“cpio”格式存檔,當核心啟動時,它會被提取到 rootfs 中。
根據:Kernel.org 和 Wikipedia,Linux Kernel cpio 提取器將這個 init.ramfs 部分解壓在記憶體中的某個位置
$$ … $$
“ramfs-rootfs-initramfs.txt”的第一部分解釋了ramfs文件數據是在**頁面記憶體中分配的,這與用於記憶體來自物理文件系統的文件數據的結構相同。ramfs 文件頁面也可以換出到交換設備,就像程序記憶體一樣。
我可以告訴你,頁面記憶體非常接近最低級別的分配器,即核心頁面分配器。頁面分配器在啟動時被交給所有可用的物理 RAM 區域;這些將排除初始核心部分。可用的物理記憶體區域由引導載入程序/韌體傳遞給核心。如命令所示,您應該在核心日誌早期的一系列行中看到這些區域
dmesg
。稍後在核心日誌中,當頁面分配器被交給不再需要的 init mem 時,您可以看到該消息,包括已釋放的 init.ramfs 部分。(IIRC 在頁面分配器之前有一些單獨的非常早期的分配器,但這不是引導 IMO 中最令人興奮的細節)。
- 解壓後,核心如何找到特定文件的數據的記憶體地址,…例如 /sbin/init 文件?
頁面記憶體從記憶體中的 inode 連結,也就是vnodes。通過記憶體中的dentry 記憶體查找vnode 。 dentry = 記憶體中的目錄條目。
什麼是ramfs?
Ramfs 是一個非常簡單的文件系統,它將 Linux 的磁碟記憶體機制(頁面記憶體和目錄記憶體)導出為基於 RAM 的可動態調整大小的文件系統。
通常所有文件都被 Linux 記憶體在記憶體中。從備份儲存(通常是掛載文件系統的塊設備)讀取的數據頁面會保留下來,以防再次需要它,但如果虛擬記憶體系統需要記憶體用於其他用途,則將其標記為乾淨(可釋放)。類似地,寫入文件的數據在寫入備份儲存後立即標記為乾淨,但出於記憶體目的而保留,直到 VM 重新分配記憶體。類似的機制(dentry 記憶體)極大地加快了對目錄的訪問。
使用 ramfs,沒有備份儲存。寫入 ramfs 的文件照常分配目錄和頁面記憶體,但無處可寫入。這意味著這些頁面永遠不會被標記為乾淨,因此當 VM 尋求回收記憶體時,它們不能被釋放。
回复:問題 1:我不認為 .init.ramfs 部分可以解壓縮到
它可以解壓縮到 RAM 中任何地方的臨時緩衝區,例如使用頁面分配器。也就是說,我假設提取過程是流式傳輸的。也就是說,它可以使用與
gzip -d | cpio --extract
. 在將文件從存檔複製到 tmpfs 時,這種方法避免了需要一個緩衝區來保存整個未壓縮的 cpio 存檔。