Como o Linux carrega a imagem 'initrd'?

13

Eu tenho tentado entender o processo de inicialização, mas há apenas uma coisa que está passando pela minha cabeça ..

Assim que o kernel do Linux for inicializado e o sistema de arquivos raiz (/) montado, os programas poderão ser executados e outros módulos do kernel poderão ser integrados para fornecer funções adicionais. Para montar o sistema de arquivos raiz, certas condições devem ser atendidas. O kernel precisa dos drivers correspondentes para acessar o dispositivo no qual o sistema de arquivos raiz está localizado (especialmente os drivers SCSI). O kernel também deve conter o código necessário para ler o sistema de arquivos (ext2, reiserfs, romfs, etc.). Também é concebível que o sistema de arquivos raiz já esteja criptografado. Nesse caso, é necessária uma senha para montar o sistema de arquivos.

O ramdisk inicial (também chamado initdisk ou initrd) resolve precisamente os problemas descritos acima. O kernel do Linux oferece uma opção de carregar um pequeno sistema de arquivos em um disco RAM e executar programas antes que o sistema de arquivos raiz real seja montado. O carregamento do initrd é tratado pelo gerenciador de inicialização (GRUB, LILO, etc.). Os carregadores de inicialização precisam apenas de rotinas de BIOS para carregar dados da mídia de inicialização. Se o carregador de inicialização conseguir carregar o kernel, ele também poderá carregar o ramdisk inicial. Drivers especiais não são necessários.

Se / boot não é uma partição diferente, mas está presente na partição /, o carregador de inicialização não deve exigir os drivers SCSI, para acessar a imagem 'initrd' e a imagem do kernel? Se você pode acessar as imagens diretamente, por que exatamente precisamos dos drivers SCSI?

rpthms
fonte

Respostas:

20

Próximo, tentarei responder à sua pergunta, mas para uma descrição mais abrangente do processo de inicialização, tente o artigo da IBM .

Ok, suponho que você esteja usando o GRUB ou GRUB2 como seu carregador de inicialização para obter explicações. Primeiro, quando o BIOS acessa seu disco para carregar o carregador de inicialização, ele usa suas rotinas internas para acesso ao disco, que são armazenadas na famosa interrupção de 13h. O gerenciador de inicialização (e o kernel na fase de configuração) fazem uso dessas rotinas quando acessam o disco. Observe que o BIOS é executado no modo real (16 bits) do processador, portanto, não pode endereçar mais de 2 ^ 20 bytes de RAM (2 ^ 20 e não 2 ^ 16 porque cada endereço no modo real é composto por segmento_address * 16 + deslocamento , onde o endereço do segmento e o deslocamento são de 16 bits, consulte http://en.wikipedia.org/wiki/X86_memory_segmentation ). Portanto, essas rotinas não podem acessar mais de 1 MiB de RAM, o que é uma limitação estrita e um grande inconveniente.

O BIOS carrega o código do carregador de inicialização diretamente do MBR - os primeiros 512 bytes do seu disco e o executa. Se você estiver usando o GRUB, esse código será o estágio 1. do GRUB. Esse código carregará o estágio 1.5 do GRUB, localizado nos primeiros 32 KiB de espaço em disco, chamado região de compatibilidade do DOS ou em um endereço fixo do sistema de arquivos. Ele não precisa entender o sistema de arquivos para fazer isso, porque o estágio 1.5 está no sistema de arquivos, é um código "bruto" e pode ser carregado diretamente na RAM e executado: http://www.pixelbeat.org/ docs / disk / . A carga do stage1.5 do disco para a RAM faz uso das rotinas de acesso ao disco do BIOS.

insira a descrição da imagem aqui

O Stage1.5 contém os utilitários do sistema de arquivos, para que ele possa ler o stage2 do sistema de arquivos (bem, ele ainda usa o BIOS 13h para ler do disco para a RAM, mas agora pode decifrar as informações do sistema de arquivos sobre inodes etc. e obter o código bruto do disco). Os BIOS mais antigos podem não conseguir acessar todo o HD devido a limitações no modo de endereçamento de disco - eles podem usar o sistema Cylinder-Head-Sector, incapaz de endereçar mais de 8 GiB de espaço em disco: http: //en.wikipedia. org / wiki / Setor de cabeçotes .

O Stage2 carrega o kernel na RAM (novamente, usando os utilitários de disco do BIOS). Se for 2.6+ ou mais, ele também possui o initramfs compilado, portanto, não é necessário carregá-lo. Se for um kernel mais antigo, o carregador de inicialização também carrega imagem initrd independente na memória, para que o kernel possa montá-lo e obter drivers para montar o sistema de arquivos real a partir do disco.

O problema é que o kernel (e ramdisk) pesa mais de 1 MiB; portanto, para carregá-los na RAM, você precisa carregar o kernel no primeiro 1 MiB, depois pular para o modo protegido (32 bits) e mover o kernel carregado para a memória alta (livre o primeiro 1 MiB para o modo real), depois retorne ao modo real (16 bits) novamente, instale o ramdisk do disco para o primeiro 1 MiB (se for um initrd separado e um kernel mais antigo), possivelmente mude para o modo protegido (32 bits) novamente, coloque-o onde ele pertence, possivelmente volte ao modo real (ou não: /programming/4821911/does-grub-switch-to-protected-mode ) e execute o código do kernel. Aviso: não tenho certeza absoluta sobre o rigor e a precisão desta parte da descrição.

Agora, quando você finalmente executa o kernel, já o possui e o ramdisk foi carregado na RAM pelo gerenciador de inicialização , para que o kernel possa usar os utilitários de disco do ramdisk para montar seu sistema de arquivos raiz real e fazer a rotação do root. Os drivers ramfs estão presentes no kernel, para que ele possa entender o conteúdo do initramfs, é claro.

Boris Burkov
fonte
O bootlader não pode simplesmente carregar o kernel em pedaços, em vez de entrar no modo protegido? E o que é a necessidade de libertar que 1 MB .. (Desculpe .. não conseguia entender que ..)
rpthms
A necessidade de liberar o primeiro 1MiB é a seguinte: o gerenciador de inicialização pode acessar seu disco rígido apenas no modo real, porque o acessa com os utilitários da BIOS, que são em modo real (eles operam com argumentos de 16 bits e usam operações de 16 bits). O modo real apenas não vê nenhuma RAM, exceto no primeiro 1 MiB. Mas você precisa carregar o kernel + initramfs na RAM e eles ocupam ~ 5 MiB de espaço na RAM. Esses utilitários do BIOS simplesmente não serão capazes de espremer 5 MiB no primeiro 1 MiB. Portanto, o carregador de inicialização precisa copiá-los do disco para o primeiro 1 MiB, depois ir para o modo protegido e movê-los da primeira RAM de 1Mb para a RAM maior. Está mais claro agora? :)
Boris Burkov 09/09
1
Todo o material do estágio 1 / 1.5 / 2 é legado do grub.
Psusi 09/09/13
1
@CMCDragonkai Sim, o carregador de inicialização stage2 está no sistema de arquivos (ou seja, na /bootpartição). O kernel não está carregado neste momento - é o stage1.5 do grub, que está acessando o stage2 no /bootsistema de arquivos (por exemplo, no /boot/grubarquivo) através de seus drivers minimalistas do sistema de arquivos. O kernel também poderá ler da /bootpartição, mas isso acontecerá mais tarde, após a execução do código grub2 e o carregamento do kernel, e depois que o kernel ler o initramfs. Você está falando do init.shinitramfs? Ele reside na /bootpartição do seu disco rígido, então o stage2 do grub o coloca na RAM e o Kernel lê a partir da RAM.
Boris Burkov
1
O Initrd tinha que ser um arquivo separado. O initramfs mais recente pode ser vinculado ao kernel, mas não precisa ser - ele também pode ser carregado como um arquivo separado pelo gerenciador de inicialização. Como o arquivo initramfs é definido como uma sequência de arquivos cpio, alguns gerenciadores de inicialização (por exemplo, o iPXE) até permitem vários arquivos initramfs, que serão carregados na memória um após o outro. Além disso, algumas distribuições Linux usam nomes de arquivos no estilo initrd para compatibilidade com versões anteriores, embora a tecnologia usada atualmente seja o initramfs.
Telcom
1

Eu acredito que tudo se resume ao que suporta determinados gerenciadores de inicialização. Por exemplo. ele não precisa conhecer o sistema de arquivos específico da sua partição combinada (inicialização + raiz). Nesse caso, você apenas cria uma partição de inicialização separada, na condição de que ela funcione com o seu carregador de inicialização, e qualquer outra complexidade de como montar sua partição raiz é deixada no kernel e na imagem initrd inicializada na partição de inicialização. O carregador de inicialização sabe como acessar os dispositivos SCSI (e outros dispositivos também, dependendo de qual carregador de inicialização é usado), usando seus próprios drivers ou utilizando as rotinas do BIOS. Além disso, ele sabe ler alguns sistemas de arquivos, etc.

Considere, por exemplo. A maneira UEFI de inicializar, onde o firmware UEFI já sabe como acessar a partição EFI, lê-la e carregar o kernel Linux a partir daí, sem a necessidade de um gerenciador de inicialização intermediário. Nesse caso, a imagem do linux vive separada da partição raiz e o firmware UEFI não precisa conhecer todos os sistemas de arquivos exóticos para acessá-la. Eu acredito que a separação das imagens "boot" da partição "root" faz muito sentido. Caso contrário, isso é necessário ao configurar a criptografia do sistema de arquivos raiz.

Miroslav Koškár
fonte
0

Apenas para constar, se um gerenciador de inicialização não carregar o initrd, vale a pena testar outro gerenciador de inicialização; Acabei de enfrentar uma situação como essa quando o LILO ignorou silenciosamente um initrd corretamente especificado de tamanho médio (<4Mb; rootfs ext4 únicos em um SSD SATA; GPT) e o GRUB 2.00 foi bem-sucedido.

O processo de inicialização terminou rapidamente com um típico

RAMDISK: Couldn't find valid RAM disk image starting at 0.
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(8,3)
Michael Shigorin
fonte