Portando o Linux para outros requisitos de plataforma [fechado]

28

Eu sei que o Linux está disponível e foi portado para muitas plataformas diferentes, como para X86, ARM, PowerPC etc.

No entanto, em termos de portabilidade, o que é necessário exatamente?

Meu entendimento é que o Linux é um software escrito em C. Portanto, ao portar o Linux originalmente do X86 para o ARM ou outros, por exemplo, não é apenas uma questão de recompilar o código com o compilador para a arquitetura de destino específica?

Pondo de lado os drivers de dispositivo para diferentes periféricos, o que mais seria necessário ao transportar o Linux para uma nova arquitetura. O compilador não cuida de tudo para nós?

Engenheiro999
fonte
11
Podemos assumir que você examinou as fontes do kernel específicas da arquitetura? git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/…
Kusalananda

Respostas:

57

Embora a maior parte do código no kernel do Linux seja escrita em C, ainda existem muitas partes desse código que são muito específicas da plataforma em que está sendo executada e precisam dar conta disso.

Um exemplo específico disso é a memória virtual, que funciona de maneira semelhante na maioria das arquiteturas (hierarquia de tabelas de páginas), mas possui detalhes específicos para cada arquitetura (como o número de níveis em cada arquitetura, e isso tem aumentado mesmo no x86 com introdução de novos chips maiores.) O código do kernel do Linux introduz macros para lidar com a travessia dessas hierarquias que podem ser elididas pelo compilador em arquiteturas que possuem menos níveis de tabelas de páginas (para que o código seja escrito em C, mas inclua detalhes da arquitetura em consideração.)

Muitas outras áreas são muito específicas para cada arquitetura e precisam ser tratadas com código específico do arco. A maioria deles envolve código em linguagem assembly. Exemplos são:

  • Troca de Contexto : A troca de contexto envolve salvar o valor de todos os registros para o processo que está sendo desativado e restaurar os registros do conjunto salvo do processo agendado na CPU. Até o número e o conjunto de registros são muito específicos para cada arquitetura. Esse código geralmente é implementado em assembly, para permitir acesso total aos registros e também para garantir que ele seja executado o mais rápido possível, pois o desempenho da alternância de contexto pode ser crítico para o sistema.

  • Chamadas do sistema : o mecanismo pelo qual o código do espaço do usuário pode acionar uma chamada do sistema geralmente é específico da arquitetura (e algumas vezes até do modelo de CPU específico, por exemplo, Intel e AMD introduziram instruções diferentes para isso, as CPUs mais antigas podem não ter essas instruções, portanto, detalhes para aqueles que ainda serão únicos.)

  • Manipuladores de interrupção : os detalhes de como lidar com interrupções (interrupções de hardware) geralmente são específicos da plataforma e geralmente requerem uma cola no nível do assembly para lidar com as convenções de chamada específicas em uso na plataforma. Além disso, as primitivas para ativar / desativar as interrupções geralmente são específicas da plataforma e também exigem código de montagem.

  • Inicialização : Os detalhes de como a inicialização deve ocorrer também geralmente incluem detalhes específicos da plataforma e geralmente exigem algum código de montagem para lidar com o ponto de entrada no kernel. Nas plataformas que possuem várias CPUs (SMP), os detalhes sobre como colocar outras CPUs online também costumam ser específicos da plataforma.

  • Primitivas de bloqueio : a implementação de primitivas de bloqueio (como spinlocks) geralmente também envolve detalhes específicos da plataforma, pois algumas arquiteturas fornecem (ou preferem) instruções diferentes da CPU para implementá-las com eficiência. Alguns implementarão operações atômicas, outros fornecerão um cmpxchg que pode testar / atualizar atomicamente (mas falhará se outro escritor entrar primeiro), outros incluirão um modificador de "bloqueio" nas instruções da CPU. Isso geralmente envolve escrever código de montagem também.

Provavelmente, existem outras áreas em que o código específico da plataforma ou arquitetura é necessário em um kernel (ou, especificamente, no kernel Linux). Observando a árvore de fontes do kernel, existem subárvores específicas da arquitetura, abaixo arch/e abaixo, nas include/arch/quais você pode encontrar mais exemplos disso.

Algumas são realmente surpreendentes, por exemplo, você verá que o número de chamadas de sistema disponíveis em cada arquitetura é distinto e que algumas chamadas de sistema existirão em algumas arquiteturas e não em outras. (Mesmo no x86, a lista de syscalls difere entre um kernel de 32 e 64 bits.)

Em resumo, há muitos casos em que um kernel precisa estar ciente de que é específico para uma plataforma. O kernel do Linux tenta abstrair a maioria deles, para que algoritmos de nível superior (como o gerenciamento e agendamento de memória funcionem) possam ser implementados em C e funcionem da mesma maneira (ou principalmente da mesma forma) em todas as arquiteturas.

filbranden
fonte
7
Muito bom artigo! A variação no número de syscalls está principalmente relacionada ao histórico: as novas portas incluem os syscalls válidos no momento do porto, eles não se incomodam com a bagagem histórica presente nos portos antigos, portanto, os syscalls obsoletos geralmente não estão presentes nos portos mais recente que a reprovação. (Isso não cobre todos os cenários ...)
Stephen Kitt
10

Além de portar o kernel do Linux, você precisará definir a ABI ( interface binária do aplicativo ) para programas de "espaço do usuário" e portar as camadas mais baixas da pilha de software do espaço do usuário. O Linux é normalmente usado com componentes de espaço de usuário de baixo nível do projeto GNU, dos quais os mais críticos são:

  • O compilador C, montador e vinculador: GCC e GNU Binutils . Para uma arquitetura de CPU totalmente nova, você precisa portar esse software antes mesmo de começar a portar o kernel, pois o próprio kernel é um programa em C e precisa ser compilado. Se já existe suporte de "back-end" para a CPU da sua plataforma, mas não com o Linux como o kernel do sistema operacional, você tem muito menos trabalho a fazer e pode adiar adiar a maior parte do trabalho até que o kernel esteja instalado e corrida.
  • A biblioteca de tempo de execução C: " GNU libc ". Esta biblioteca inclui o código que faz chamadas do sistema e interage diretamente com o kernel.
  • A biblioteca "interface de função externa", libffi , que é um componente essencial de muitos intérpretes de idiomas de alto nível, e executa uma das poucas tarefas restantes que requerem uma pequena quantidade de linguagem assembly escrita à mão.

Muitos outros softwares possuem componentes dependentes da plataforma opcionais; por exemplo, a navegação na Web será substancialmente mais rápida se você escrever primitivas criptográficas otimizadas para mão para NSS e OpenSSL para sua nova arquitetura de CPU e back-ends de compilação just-in-time para IonMonkey e V8 . Mas isso não é essencial para criar uma nova plataforma.

zwol
fonte
1

Você precisa informar o kernel sobre o hardware para o qual está portando. O trabalho do kernel é interagir diretamente com o hardware, para que ele funcione corretamente, o kernel precisa saber sobre a CPU, osciladores (relógios) e quaisquer periféricos, como os vários tipos de portas seriais (SPI, CAN, I2C, etc.).

Antigamente, você fazia isso escrevendo código específico da plataforma que os drivers usariam para funcionar. Hoje em dia, isso é feito escrevendo uma definição da Árvore de Dispositivos .

Pato de borracha
fonte