Pesquisa de site

Portar sistemas operacionais para novas arquiteturas de chips


O que os mantenedores do RT-Thread aprenderam ao portar o sistema operacional de sistemas embarcados para diferentes arquiteturas de chip.

Certa vez me perguntaram por que os computadores são chamados de “computadores” quando fazem muito mais do que calcular números. Um PC moderno navega na Internet, reproduz áudio e vídeo, gera belos gráficos para videogames e filmes, simula e prevê padrões climáticos complexos e riscos epidemiológicos, dá vida a projetos arquitetônicos e de engenharia e muito mais.

A razão pela qual os computadores podem fazer tudo isso é que todos esses problemas podem ser expressos como equações numéricas, e a CPU do computador – sua unidade central de processamento – é na verdade pouco mais que uma simples calculadora.

Para fazer com que uma CPU envie sinais a um disco rígido para gravar dados ou a um monitor para mostrar uma imagem, ela deve receber instruções. Essas instruções vêm na forma de “código”, que é uma forma concisa de dizer que alguém deve escrever um programa que “fale” a mesma linguagem da CPU. Uma CPU entende a linguagem de máquina, um conjunto de bits incompreensível que a maioria dos humanos não se preocupa em escrever manualmente. Em vez disso, usamos linguagens de programação como C, C++, Java, Python e assim por diante. Essas linguagens são analisadas e compiladas em linguagem de máquina, que é entregue à CPU.

Se você tentar instruir uma CPU em uma linguagem que ela não entende, a CPU não saberá o que fazer. Você pode experimentar os resultados nada espetaculares de tal tentativa de falha de comunicação tentando inicializar um Raspberry Pi a partir de uma imagem RHEL x86_64. Seria bom se pudesse funcionar, mas não funciona.

Portando um sistema operacional para uma nova arquitetura

O projeto RT-Thread oferece um sistema operacional (SO) de código aberto para programadores de sistemas embarcados. O espaço incorporado é extremamente diversificado, com muitos dispositivos de Internet das Coisas (IoT), industriais personalizados e dispositivos amadores. O objetivo do RT-Thread é facilitar a programação embarcada para todos, independentemente do dispositivo que você estiver usando. Às vezes, isso significa portar um sistema operacional para uma nova arquitetura, seja para um chip da mesma arquitetura, mas com conjuntos de instruções ligeiramente diferentes ou para arquiteturas totalmente novas.

Abordar esse problema pode ser um pouco intimidante no início – você pode não saber por onde ou como começar. Este artigo coleta as lições que os mantenedores do RT-Thread aprenderam quando portamos o RTOS para novas arquiteturas de chip.

O que você precisa saber antes de começar

Aqui está uma visão de alto nível de um processo aparentemente intransponível. Isso pode ser diferente para o seu projeto, mas conceitualmente é relativamente universal, mesmo que algumas especificidades sejam diferentes:

  1. Prepare um ambiente de execução em linguagem C
  2. Confirme se os caracteres podem ser enviados e recebidos por uma porta serial
  3. Confirme se o código de troca de contexto funciona
  4. Obtenha suporte para temporizadores de hardware
  5. Confirme se a rotina de interrupção pode receber e analisar dados pela porta serial

O modelo de execução

Para a maioria das arquiteturas avançadas, o sistema operacional e os aplicativos do usuário são executados em diferentes níveis de privilégio. Isso evita que códigos com defeito afetem a integração e a segurança do sistema operacional. Por exemplo, na arquitetura ARMv7-A, o sistema operacional geralmente é executado no modo Sistema, enquanto no ARMv8-A, um sistema operacional pode ser executado no nível de privilégio EL2 ou EL3.

Normalmente, um chip executa o código de inicialização no nível de privilégio mais alto quando está ligado. Depois disso, porém, o sistema operacional muda o nível de privilégio para o modo de destino.

1. Execute o código C

A ação principal nesta etapa é definir a seção do símbolo inicial do bloco (.bss) como zero e configurar os ponteiros da pilha.

Nas implementações da linguagem C, as variáveis globais não inicializadas e as variáveis estáticas são geralmente armazenadas na seção .bss, que não ocupa nenhum espaço no dispositivo de armazenamento. Quando o programa é carregado, o espaço correspondente é alocado na memória e inicializado em zero. Quando o sistema operacional é inicializado, ele precisa fazer esse trabalho sozinho.

Por outro lado, o sistema operacional precisa inicializar o espaço da pilha e configurar o ponteiro da pilha. Como os programas em linguagem C salvam e restauram variáveis locais na pilha ao entrar e sair de uma função, o ponteiro da pilha deve ser definido antes de invocar qualquer função C. O RT-Thread deve executar esta etapa para cada thread recém-criado.

2. Use pelo menos uma unidade serial

O RT-Thread gera informações e logs por meio da porta serial, o que também ajuda a depurar o código durante o processo de transplante. Nesta fase, não é necessário receber dados através de portas seriais. Sabíamos que estávamos no caminho certo quando vimos pela primeira vez nosso amigável e familiar logotipo RT-Thread na porta serial!

3. Confirme a lógica de troca de contexto

O contexto de uma tarefa é todo o seu ambiente de execução, que contém registros genéricos, o contador do programa, a localização do quadro de pilha e assim por diante. Quando um novo thread é criado, o RT-Thread precisa alocar e configurar seu contexto manualmente para que o escalonador possa mudar para o novo thread, como faz com outros.

Há três coisas para prestar atenção:

  • Primeiro, quando o RT-Thread é inicializado, as interrupções são desabilitadas por padrão. Eles são habilitados quando o agendador de tarefas é habilitado pela primeira vez; esse processo é implementado em linguagem assembly durante o período de mudança de contexto.
  • Em segundo lugar, o próximo agendamento será iniciado quando um thread terminar, que é quando os recursos pertencentes forem recuperados pelo thread inativo.
  • Terceiro, a ordem em que os dados são colocados na pilha deve ser consistente com a ordem em que os dados são retirados da pilha.

Geralmente, você deseja entrar na função principal e no console msh normalmente. Entretanto, o controle de entrada não pode ser alcançado neste estágio porque as interrupções de entrada serial não são implementadas. Quando interrupções seriais são implementadas, entradas msh podem ser feitas.

4. Defina o cronômetro

O RT-Thread requer um temporizador para gerar interrupções periodicamente; isso é usado para contar os ticks decorridos desde a inicialização do sistema. O número do tick é usado para fornecer funções de interrupção de software e instruir o kernel quando iniciar o agendamento de uma tarefa.

Definir o valor de um intervalo de tempo pode ser uma tarefa complicada. Geralmente é de 10ms a 1ms. Se você escolher um intervalo de tempo pequeno em uma CPU lenta, a maior parte do tempo será gasta na alternância de tarefas – em detrimento de realizar qualquer outra tarefa.

5. Confirme se a porta serial funciona corretamente

Nesta etapa, interagimos com RT-Thread msh pela porta serial. Enviamos comandos, pressionamos Enter e observamos msh executar o comando e exibir os resultados.

Este processo geralmente não é difícil de implementar. Porém, um aviso: não se esqueça de limpar o sinalizador de interrupção em algumas plataformas depois que a interrupção da porta serial for tratada.

Assim que a porta serial funcionar corretamente, o processo de portabilidade estará essencialmente concluído!

Ficar ocupado

Para portar seu projeto para diferentes arquiteturas de chip, você precisa ser muito claro sobre a arquitetura do chip que está almejando. Familiarize-se com o código subjacente nos pontos mais críticos do seu projeto. Ao cruzar o manual do chip combinado com muita experiência prática de trabalho, você aprenderá o modo de privilégio do chip, registro e método de compilação.

Se você não tem um projeto que precisa migrar para um novo chip, junte-se a nós; o projeto RT-Thread sempre pode precisar de ajuda para portar RTOS para novos chips! Como um projeto de código aberto, o RT-Thread está mudando o cenário da programação embarcada de código aberto. Por favor, apresente-se e peça ajuda no RT-Thread Club!

Este artigo é baseado em Como portar o sistema operacional para diferentes arquiteturas de chip? na comunidade DEV e é republicado com permissão.