起動中のinitramfs gzipのcpioアーカイブのアドレス指定方式

起動中のinitramfs gzipのcpioアーカイブのアドレス指定方式

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セクションをメモリ位置に抽出します。

私の質問は次のとおりです

  1. cpio アーカイブコンテンツが抽出されるメモリアドレスはどのように決定されますか?
  2. 解凍後、カーネルは特定のファイル(/ sbin / initファイルなど)のデータのメモリアドレスをどのように検索しますか?
  3. カーネルが後でこれらのファイルを見つけることができるように、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アーカイブを保持する必要はありません。

関連情報