3.1 – Considerações Iniciais

Para explicarmos como o Linux gerência processos, faremos considerações iniciais sobre o código fonte do kernel do Linux (onde encontramos a implementação da Gerência de Processos) e a inicialização “boot” do sistema.


Neste tópico tentaremos explicar, de uma maneira ordenada o código fonte do Linux, tentando conseguir um bom entendimento sobre como o código fonte está situado e como as características mais relevantes do UNIX foram implementadas.

O objetivo é ajuda-lo a se familiarizar com o projeto geral do Linux. Então, vamos começar por onde o Linux começa: seu sistema de boot.

Um bom entendimento da linguagem C é necessário para entender este material, assim como familiaridade com conceitos de UNIX e arquitetura dos PCs. Porém, nenhum código C aparecerá neste material, mas referencias de onde podem ser encontrados.

Qualquer referencia "pathname" à arquivos tem como ponto de partida a arvore principal de fontes, usualmente /usr/src/linux. A maioria das informações reportadas aqui tem como referencia o código fonte do Linux versão

1.0. Referencias a versões posteriores conterão o símbolo novo. Caso o símbolo não estiver presente, significa que não houveram modificações após as versões 1.0.9-1.1.76. mais Ocasionalmente um parágrafo como este ocorrerá no texto. Indicando onde poderam ser obtidas mais informações sobre o assunto corrente (geralmente o código fonte).

3.1.1 – Inicialização ("boot" do sistema)

Quando o PC é ligado, o processador 80×86 encontra-se em modo real e executa o código contido no endereço 0xFFFF0, que corresponde a um endereço ROM-BIOS.

A BIOS do PC realiza alguns testes no sistema e inicializa o vetor de interrupções no endereço físico 0. Depois disto ele carrega o primeiro setor do device bootavel em 0x7C00, e passa a execução para este endereço.

O dispositivo é, usualmente, o disquete ou o disco rígido. A descrição anterior é um tanto simplificada, mas é tudo que se necessita para entender o trabalho inicial do kernel.

A primeiríssima parte do kernel Linux está escrito em linguagem assembly 8086 (boot/bootsect.S). Quando é executado, ele se move para o endereço absoluto 0x90000, carrega os próximos 2 kBytes de código do device de boot até o endereço 0x90200, e o resto do kernel para o endereço 0x10000. A mensagem "Loading…" é apresentada durante o carregamento do sistema.

O controle é, então passado para o código contido em boot/Setup.S, outro código assembly de modo real.

A parte de "setup" identifica algumas características do sistema (hardware) e o tipo da placa VGA. Se requerido, pede ao usuário para escolher o modo do vídeo da console.

E, então, move todo o sistema do endereço 0x10000 para o endereço 0x1000, passa para o modo protegido e passa o controle para o resto do sistema (endereço 0x1000).

O próximo passo é a descompressão do kernel. O código em 0x1000 vem de zBoot/head.S que inicializa os registradores e invoca decompress_kernel(), o qual é composto por zBoot/inflate.c, zBoot/unzip.c e zBoot/misc.c.

O dado "descompresso" vai para o endereço 0x100000 (1 Mega), e esta é a principal razão do por que o Linux não pode rodar com menos de 2 Megas de RAM. mais O encapsulamento do kernel em um arquivo gzip é realizado por Makefile e utilitários no diretório zBoot.

São arquivos interessantes para se dar uma olhada. novo A versão 1.1.75 moveu os diretórios boot e zBoot para arch/i386/boot. Esta modificação pretendeu possibilitar a construção de "kernel verdadeiro" para diferentes arquiteturas.

O código "descompresso" é executado a partir do endereço 0x1010000 , onde todo o setup 32-bit esta lotado: IDT, GDT e LDT são carregados, o processador e o co-processador são identificados, a rotina start_kernel é invocada.
Os arquivos fonte das operações acima estão em boot/head.S.

Este, talvez, seja o código mais difícil em todo o kernel do Linux. Note que se algum erro ocorrer durante alguns dos passos precedentes, o computador irá travar.

O sistema operacional não pode manipular erros enquanto não estiver totalmente operante. start_kernel() reside em init/main.c. Tode de agora em diante esta codificado em linguagem C, exceto gerência de interrupções e chamadas de sistemas (Bem, a maior parte das macros possuem códigos assembly embutidos, também).

Depois dos procedimentos com todas as questões iniciais, start_kernel() inicializa todas as partes do kernel, especificamente:

• Inicializa a memória e chama paging_init().
• Inicializa os traps, canais IRQ e scheduling.
• Se requerido, aloja um profiling buffer.
• Inicializa todos device drives e buffers de discos, bem como outras partes menores.
• Regula o delay loop (calcula o numero "BogoMips").
• Checa se a interrupção 16 está trabalhando com o co-processador.

Finalmente, o kernel está pronto para move_to_user_mode(), em seguida fork (bifurca) o processo de inicialização, cujos códigos estão no mesmo arquivo fonte. E o processo número 0, também chamado idle task (tarefa preguiçosa), se mantém rodando em um loop infinito.
O processo de inicialização tenta executar /etc/init, ou /bin/init, ou /sbin/init.

Se nenhum deles tem sucesso, o código se desvia para "/bin/sh /etc/rc" e cria um root shell no primeiro terminal (console). Este código é remanescente do Linux 0.01, quando o S.O. era feito para um kernel standalone, e não havia processo de login.

Depois de exec() o programa de inicialização de um dos lugares padrão (deve haver um deles), o kernel não tem controle direto sobre o fluxo do programa.

Sua função, de agora em diante, é prover processos através de chamadas ao sistema (system calls), assim como prover eventos para serviços assíncronos (como uma interrupção do hardware).


A multitarefa está inicializada, e inicializará o gerenciamento de acesso a multiusuários, através do fork() e processos de login. Estando o kernel carregado e provendo serviço, vamos prosseguir dando uma olhada nesses serviços ("system calls").

3.2 – Gerência de processo pelo kernel

Páginas: 1 2 3

Páginas ( 1 de 3 ): 1 23Next »