O kernel possui uma função main ()? [fechadas]

52

Estou aprendendo drivers de dispositivo e programação do Kernel. De acordo com o livro de Jonathan Corbet, não há main()função nos drivers de dispositivo.

Então, eu duas perguntas:

  • Por que não precisamos de uma main()função nos drivers de dispositivo?
  • O próprio kernel tem uma main()função?

Alguém pode me explicar isso?

alguém
fonte
11
Também solicitado pelo mesmo usuário aqui: stackoverflow.com/q/18266063/827263 #
Keith Thompson
@KeithThompson ... Sim ... Só porque não consegui responder o que quero, então pedi aqui.
alguém
@Shadur ... de qualquer forma agora ele está prestes a fechada ... E eu não tenho o privilégio de migrar que ...
alguém
Isto deveria ter sido fechado o contrário, este tem muito mais vistas :-)
Ciro Santilli新疆改造中心法轮功六四事件

Respostas:

82

Nos programas de espaço do usuário, main()é o ponto de entrada para o programa chamado pelo código de inicialização libc quando o binário é executado. O código do kernel não tem o luxo de confiar na libc, pois a própria libc depende da interface syscall do kernel para alocação de memória, E / S, gerenciamento de processos etc.

Dito isto, o equivalente main()no código do kernel é start_kernel(), chamado pelo gerenciador de inicialização após carregar a imagem do kernel, descompactada na memória e configurando hardware e paginação de memória essenciais. start_kernel()executa a maior parte da configuração do sistema e, eventualmente, gera o processo de inicialização.

O ponto de entrada para os módulos do kernel do Linux é uma função init registrada no kernel chamando a module_init()macro. A função init do módulo registrado é chamada pelo código do kernel através da do_initcalls()função durante a inicialização do kernel.

Thomas Nyman
fonte
11
Obrigado por reconhecer o real objetivo do mainmétodo em C. (É um equívoco muito comum que o SO faz uma chamada direta main, o que não é o caso e ainda menos em, por exemplo, C ++.) Eu daria a você outro voto positivo, se eu pudesse apenas por isso.
um CVn 16/08/13
11
@ Thomas ... Obrigado por esta excelente resposta ....
alguém
17

O kernel não tem uma mainfunção. mainé um conceito da linguagem C. O kernel é escrito em C e assembly. O código de entrada do kernel é escrito por assembly.

A sequência de inicialização está organizada da seguinte maneira:

  1. O BIOS geralmente carrega um carregador de inicialização de um dispositivo de bloco de inicialização. Um gerenciador de inicialização popular agora é o grub.
  2. O Grub carrega uma imagem do kernel no ram, possível com um dispositivo raiz inicial ( initrd). Em seguida, o código em algum endereço é executado.
  3. A imagem do kernel possui alguns módulos do kernel, por exemplo: módulos do sistema de arquivos, drivers de dispositivo. A imagem do kernel usa o módulo do sistema de arquivos para montar o sistema de arquivos raiz. Agora o kernel pode carregar e executar todos os módulos do kernel a partir do disco.
  4. O kernel executa tarefas de inicialização. Por exemplo: atravesse o barramento PCI e encontre todos os dispositivos PCI, inicialize todos os drivers de dispositivo.
  5. Finalmente, o kernel cria o processo 0 e o processo 1 (o initprocesso), alterna o contexto da CPU do anel 0 para o anel 3 e inicia o processo init (a identificação do processo é 1). Agora a inicialização do kernel está concluída!
  6. O initprograma executa todos os scripts de inicialização. Todos os serviços são iniciados. Shell é chamado. Os usuários podem fazer login.

A mainfunção é uma função C. Na verdade, o método principal não é o ponto de entrada dos programas C. O tempo de execução C chama muitas funções antes main. O GCC possui um recurso de extensão: construtores. As funções declaradas "construtor" são chamadas antes main.

Por exemplo:

/* This should not be used directly. Use block_init etc. instead. */ 
#define module_init(function, type) \
    static void _attribute__((constructor)) do_qemu_init ## function(void) { \
    register_module_init(function, type); \
} 

Essa macro é do projeto qemu.

Edward Shen
fonte
O método principal é o método ac. O método principal não é a entrada do programa c. O tempo de execução chamou muitos métodos antes do método principal.
Edward Shen
bem, o BIOS geralmente carrega um carregador de inicialização, e esse carregador de inicialização carrega uma imagem do kernel (e possivelmente um initrd). O código do kernel é na imagem do kernel, não initrd
Stéphane Chazelas
O GCC possui um recurso de extensão: construtor. A declaração do método "construtor" é chamada antes do método principal. Por exemplo: / * Isso não deve ser usado diretamente. Use block_init etc. em vez disso. * / #define module_init (função, tipo) \ static void _attribute __ ((construtor)) do_qemu_init ## function (void) {\ register_module_init (função, tipo); \}
Edward Shen
11
initrd.img NÃO é a imagem do kernel. É um conjunto de módulos carregados pelo kernel na inicialização. As imagens do kernel geralmente têm nomes começando com "vmlinuz", mas diferem de distribuição para distribuição.
Goldilocks
3
Esta resposta está repleta de "tudo é um PC / Linux / i86" e é inicializado dessa maneira e o kernel é assim ... Por que todo mundo acha que esse é o único caminho possível no mundo?
Jens
9

Existe, por exemplo, uma função main () em arch / x86 / boot / main.c para preparar o sistema para mudar do modo real para o modo protegido, mas outras arquiteturas não possuem esse código. Há uma boa visão geral de como funciona a inicialização do kernel Linux 2.6.x na plataforma x86. Realmente vale a pena ler.

De acordo com o documento COMO FAZER o desenvolvimento do kernel Linux , o kernel Linux é

um ambiente C independente, sem depender da biblioteca C padrão, portanto, algumas partes do padrão C não são suportadas.

o que de acordo com o padrão C BTW significa que

É definido pela implementação se um programa em um ambiente independente é necessário para definir uma função 'principal'.

dsmsk80
fonte