Linuxカーネルv2.6.21.7(vmlinux64)用の次のブートファイル(配布:MIPS64用Cavium-Octeon):
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 そして ウィキペディア、Linuxカーネルcpio Extractorは、このinit.ramfsセクションをメモリ位置に抽出します。
私の質問は次のとおりです
- cpio アーカイブコンテンツが抽出されるメモリアドレスはどのように決定されますか?
- 解凍後、カーネルは特定のファイル(/ sbin / initファイルなど)のデータのメモリアドレスをどのように検索しますか?
- カーネルが後でこれらのファイルを見つけることができるように、cpioアーカイブの内容は一種のファイルシステムに抽出されていますか?それとも、これらのファイルのメモリアドレスはカーネルコードにハードコードされていますか?
A:質問1:.init.ramfsセクションをELFファイルのセクションヘッダーで指定された0xffffffff804e9000メモリアドレスに解凍できないようです。次のセクション(「.sbss)の前に空き容量が1560kBしかないからです」。
答え1
カーネルが後でこれらのファイルを見つけることができるように、cpioアーカイブの内容は一種のファイルシステムに抽出されていますか?それとも、これらのファイルのメモリアドレスはカーネルコードにハードコードされていますか?
ファイルシステムを入力します。使用されるファイルシステムの種類は次のとおりです。メモリファイルシステムまたは一時ファイルシステム。上記のリンクの1つがこれについて詳しく説明しています。
https://github.com/torvalds/linux/blob/v4.17/Documentation/filesystems/ramfs-rootfs-initramfs.txt
ramfsとtmpfsは非常によく似ています。この質問に大きな違いはありません。 initramfsが使用するタイプは、カーネルのバージョンによって異なる場合があります(知りたい場合これを読んでください)。 initramfsの外では、一般的な規則は常にtmpfsを使用することです。 tmpfs は最大スペース使用量を制限し、RAM の枯渇とシステムの競合を防ぎます。
Rootfsは、2.6システムに常に存在するramfs(または有効になっている場合はtmpfs)の特別なインスタンスです。 [...]
initramfsとは何ですか?
すべての2.6 Linuxカーネルには、カーネルの起動時にrootfsで抽出されるgzipで圧縮された「cpio」形式のアーカイブが含まれています。
Kernel.orgとWikipediaによると、Linuxカーネルcpio抽出器はこのinit.ramfsセクションをメモリ位置に抽出します。 [...]
「ramfs-rootfs-initramfs.txt」の最初の部分でこれについて説明します。メモリファイルシステムファイルデータは次の場所に割り当てられます。ページキャッシュは、実際のファイルシステムでファイルデータをキャッシュするために使用されるのと同じ構造です。 ramfsファイルページは、プロセスメモリのようにスワップデバイスにスワップすることもできます。
ページキャッシュは、カーネルである最下位アロケータに非常に近いと言うことができます。ページアロケータ。ページアロケータは、起動時に利用可能なすべての物理RAM領域を取得します。これは初期カーネル部分を除外します。利用可能な物理RAM領域は、ブートローダ/ファームウェアによってカーネルに渡されます。一連の初期ラインでこれらの領域を見ることができます。カーネルログ、コマンドに示すようにdmesg
。
後でカーネルログから解放されたinit.ramfsセクションを含む、不要になったinit memにページアロケータが渡されたときにメッセージを表示できます。 (IIRCにはページアロケータの前に別の初期アロケータがありましたが、これはブートIMOで最も興味深い詳細ではありません。)
2.解凍後、カーネルは特定のファイル(/ sbin / initファイルなど)データのメモリアドレスをどのように検索しますか?
ページキャッシュは、インメモリインデックスノード(またはとも呼ばれる)から接続されます。仮想ノード。 vnodeはメモリを介して取得されます。ディレクトリエントリのキャッシュ。 ディレクトリエントリ=キャッシュのディレクトリエントリ。
ramfsとは何ですか?
Ramfsは、Linuxのディスクキャッシュメカニズム(ページキャッシュとDentryキャッシュ)を動的にサイズ変更可能なRAMベースのファイルシステムにエクスポートする非常に単純なファイルシステムです。
通常、すべてのファイルはLinuxによってメモリにキャッシュされます。バックアップストア(通常はファイルシステムがマウントされているブロックデバイス)から読み取られたデータページは、必要な場合に備えて保持されますが、仮想メモリシステムで他の目的のためにメモリが必要な場合はクリーンアップ(解放可能)として表示されます。同様に、ファイルに書き込まれたデータはバックアップストアに書き込まれるとクリーンであるとマークされますが、仮想マシンがメモリを再割り当てするまでキャッシュの目的のために保持されます。同様のメカニズム(カタログエントリのキャッシュ)を使用すると、ディレクトリへのアクセス速度が大幅に向上します。
ramfs にはバックアップストアはありません。 ramfsに書き込まれたファイルには、通常どおりディレクトリエントリとページキャッシュが割り当てられますが、書き込む場所はありません。これは、これらのページがクリーンアップとしてマークされていないため、仮想マシンがメモリを回復しようとしたときに解放できないことを意味します。
回答:質問1:.init.ramfs部分を抽出できないようです。
たとえば、ページアロケータを使用して、RAMの任意の場所に一時バッファに解凍できます。つまり、抽出プロセスがストリーミングであると仮定します。つまり、同様のアプローチを使用できますgzip -d | cpio --extract
。この方法では、アーカイブからtmpfsにファイルをコピーするときにバッファが圧縮されていない完全なcpioアーカイブを保持する必要はありません。