O seguinte arquivo de inicialização (vmlinux64) para o kernel Linux v2.6.21.7 (Distro: 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
Tem estes segmentos e seções:
_______________________________________________________________________________________________
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
_______________________________________________________________________________________________
Observe que este arquivo ELF possui uma seção init.ramfs de 1558kB incorporada contendo arquivos essenciais para o sistema operacional. Esta seção é compactada com gzip e contém um arquivo cpio com 1805 arquivos e diretórios.
De acordo com: Kernel.org e Wikipedia , o extrator cpio do Linux Kernel descompacta esta seção init.ramfs em algum lugar da memória.
Minhas perguntas são:
- O que determina o endereço de memória onde o conteúdo do arquivo cpio é extraído?
- Após a extração, como o kernel encontra os endereços de memória para os dados de um arquivo específico, como o arquivo /sbin/init ?
- O conteúdo do arquivo cpio é extraído em algum tipo de sistema de arquivos que permite que o kernel encontre esses arquivos mais tarde ... ou os endereços de memória desses arquivos são codificados no código do kernel?
Re: Pergunta 1: Eu não acho que a seção .init.ramfs pode ser descompactada para o endereço de memória 0xffffffff804e9000 indicado no cabeçalho da seção do arquivo ELF, porque há apenas 1560kB de espaço disponível antes da próxima seção (". sbss") começa na memória em 0xffffffff8066f000, e o arquivo cpio descompactado ocupa 4035kB.
Em um sistema de arquivos. O tipo de sistema de arquivos usado é ramfs ou tmpfs . Isso é explicado em detalhes, em um dos links que você mencionou.
https://github.com/torvalds/linux/blob/v4.17/Documentation/filesystems/ramfs-rootfs-initramfs.txt
ramfs e tmpfs funcionam de maneira muito semelhante; não faz muita diferença para esta pergunta. O tipo usado para o initramfs pode variar, por exemplo, entre as versões do kernel (se você precisar saber, leia isto ). Fora do initramfs, a regra geral é sempre usar tmpfs. tmpfs limita o uso máximo de espaço, o que protege contra a falta de RAM e travamento do sistema.
A primeira parte de "ramfs-rootfs-initramfs.txt" explica que os dados do arquivo ramfs são alocados no cache da página , a mesma estrutura usada para armazenar em cache os dados do arquivo de sistemas de arquivos físicos. as páginas do arquivo ramfs também podem ser trocadas para um dispositivo de troca, da mesma forma que a memória do processo.
Posso dizer que o cache da página está bem próximo do alocador de nível mais baixo, o alocador de página do kernel . O alocador de páginas recebe todas as regiões físicas de RAM disponíveis no momento da inicialização; estes irão excluir as seções iniciais do kernel. As regiões de RAM físicas disponíveis são passadas ao kernel pelo bootloader/firmware. Você deve ver essas regiões em uma série de linhas no início do log do kernel , conforme mostrado pelo
dmesg
comando.Mais tarde no log do kernel, você pode ver a mensagem quando o alocador de páginas recebe init mem que não é mais necessário, incluindo a seção init.ramfs liberada. (IIRC existe algum alocador muito precoce separado antes do alocador de página, mas esse não é o detalhe mais interessante na inicialização do IMO).
O cache da página é vinculado aos inodes na memória, também conhecidos como vnodes . vnodes são procurados através do cache dentry na memória . dentry = entrada de diretório no cache.
Ele pode ser descompactado em um buffer temporário em qualquer lugar na RAM, por exemplo, usando o alocador de página. Dito isso, presumo que o processo de extração seja transmitido. Ou seja, ele pode usar uma abordagem semelhante ao
gzip -d | cpio --extract
. Essa abordagem evita a necessidade de um buffer para armazenar todo o arquivo cpio descompactado, ao copiar os arquivos do arquivo para o tmpfs.