FAVORITAR
FecharPlease login

Firmware update utilizando MCUboot no ESP32

Este post faz parte da série MCUboot no ESP32. Leia também os outros posts da série:

Continuando a série MCUboot no ESP32, onde anteriormente explicamos as características, o funcionamento geral deste bootloader e também realizamos algumas etapas práticas para a preparação de ambiente de desenvolvimento, compilação e execução no ESP32. 

Este presente artigo abordará o processo de atualização de firmware realizado pelo MCUboot e também incluirá a realização de um exemplo OTA (Over-the-air) deste processo no ESP32. 
Para ilustrar as etapas do processo de atualização o exemplo prático utiliza o RTOS NuttX. Para quem não tem conhecimento sobre este RTOS, sugiro a leitura do artigo Primeiros Passos com o ESP32 e o NuttX. A placa ESP32-DevKitC será novamente utilizada e assume-se como premissa de que os passos para a preparação de ambiente do artigo anterior, Primeiros passos com ESP32 utilizando MCUboot como bootloader, também já foram realizados.

O processo de atualização de firmware

O processo de atualização padrão no MCUboot está diretamente ligado a organização da flash do dispositivo, pois ocorre através da permuta (“swap”) de regiões e para cada imagem de firmware executável existem dois “slots”: o Primário, onde reside a imagem a ser executada e o Secundário, onde residirá sua imagem de atualização (ou de rollback no momento após a atualização). Há também a região de “scratch”, que auxilia no swap dos slots.

Deste modo o MCUboot consegue integrar importantes características ao processo: 

No dia 25 de Junho de 2024, ocorrerá o “Seminário de Sistemas Embarcados e IoT 2024“, no Holiday Inn Anhembi — Parque Anhembi, São Paulo–SP.

Garanta seu ingresso

  • Segurança: 
    • Integridade da imagem através da verificação de hash (SHA256).
    • Autenticidade da fonte através da validação de assinatura de chaves assimétricas, como RSA 2048 e 3072, ECDSA e ed25519.
    • Confidencialidade de dados da imagem (encriptação/decriptação) durante o transporte e/ou durante o armazenamento da mesma em flash externa. O MCUboot possui suporte para encriptação/decriptação on-the-fly durante o processo de atualização e utiliza algoritmos AES ou ECIES para isso.

Nota: o slot primário sempre é armazenado sem encriptação, a premissa original do MCUboot é de que o slot primário da imagem principal resida em flash interna, o que resguarda seu acesso por via física. Contudo, no port MCUboot da Espressif é possível ativar a criptografia de flash nativa de suas placas ESP32-XX e manter a confidencialidade do processo. Mais informações na documentação do port. 

  • Tolerância a falhas: o mecanismo de swap permite a recuperação/reversão de imagens caso um problema durante o processo ocorra, como um reset no meio de um swap durante uma atualização. Além disso, se por alguma razão uma nova imagem tenha sido atualizada e inicializada, mas não se sinalizou como “ok”, o MCUboot possui um mecanismo de rollback para reverter à imagem anterior, uma vez que ela é mantida após o swap.

As etapas gerais do processo de atualização, considerando um dispositivo já executando um firmware normalmente, são:

  1. Sinalização de atualização: agente atualizador (update agent) presente no firmware atual recebe ou busca a sinalização de que há uma atualização. Esta etapa não diz respeito ao MCUboot, sendo responsabilidade do firmware principal conter e executar este agente.

Nota: Há frameworks/plataformas como, por exemplo, Golioth, Hawkbit ou UpdateHub que são compatíveis com a estrutura e organização do MCUboot.

  1. Download do novo firmware: o agente atualizador faz o download do novo firmware e o grava no slot secundário referente à imagem a ser atualizada.
  2. Reset do dispositivo: a consolidação do novo firmware só será efetivada no próximo boot, sendo assim, é necessário o reiniciar o dispositivo.
  3. Verificação do novo firmware: o MCUboot neste novo ciclo de boot realizará a checagem de hash e assinatura (se houver) da nova imagem.
  4. Permuta do slot secundário para o slot primário.
  5. Boot do novo firmware que agora reside no slot primário.
  6. O firmware atualizado se verificará, pois é necessário que ele indique ao MCUboot que a imagem está ok (a bliblioteca utilizada é a bootutil do MCUboot, que deve ser integrada ao firmware).

Veja o resumo no diagrama de sequência:

Atualização de firmware utilizando MCUboot
Figura 1: Processo de update utilizando MCUboot

Update OTA utilizando MCUboot no NuttX

Vamos agora demonstrar o processo, explicado na prática. Como já dito no início do artigo, para executar todos os passos deste exemplo é necessário ter os ambientes do NuttX e do MCUboot preparados.

Primeiramente é necessário compilar e gravar o bootloader, para isso siga os passos do artigo anterior . Ainda estamos lidando com as features mais básicas do bootloader, então caso já tenha o bootloader gravado, não será necessário realizar essa etapa novamente.

Compilando o agente atualizador no NuttX

Vamos configurar a aplicação de exemplo do agente atualizador existente no NuttX apps. 

Primeiro vamos ao diretório raiz do NuttX (por exemplo “~/nuttxspace/nuttx”) e fazer a pré-configuração indicando a placa (target/de desenvolvimento) e as aplicações que farão parte do firmware. Neste caso a pré-configuração inicial que faremos será da aplicação Wireless API para utilizarmos os comandos para a conexão Wi-Fi necessária para a atualização OTA.

Agora vamos terminar a configuração adicionando a aplicação do agente atualizador compatível com o MCUboot.

No menu gráfico vamos realizar as seguintes configurações:

– Habilitar [Build Setup → Prompt for development and/or incomplete code/drivers]:

Atualização de firmware utilizando MCUboot

– Alterar [System Type → Application Image Configuration → Application Image Format] para MCUboot-bootable format:

Atualização de firmware utilizando MCUboot


Uma coisa interessante a se observar neste menu, é que estamos compilando a “primeira versão” do firmware principal, então naturalmente ela deve ser colocada no slot primário:

Atualização de firmware utilizando MCUboot

– Verificar e alterar se necessário os endereços e tamanhos dos slots de acordo com o que foi configurado no MCUboot [System Type → SPI Flash configuration]:

– Desabilitar a persistência de parâmetros do Wi-Fi [System Type → Wi-Fi configuration → Save Wi-Fi Parameters]:

– Habilitar o comando de reset [Board Selection → Enable reset interfaces]:

– Habilitar o exemplo de agente de atualização do MCUboot [Application Configuration → Bootloader Utilities → MCUboot] e [Application Configuration → Bootloader Utilities → MCUboot → MCUboot update agent example]:


– Alterar [Application Configuration → Bootloader Utilities → MCUboot → Download buffer size in bytes] para 4096.

– Habilitar o web client que será necessário para fazer o download da atualização via HTTP [Application Configuration → Network Utilities → uIP web client]:

– Para facilitar a diferenciação deste firmware principal de sua atualização, vamos colocar uma mensagem de inicialização no NuttX shell [Application Configuration → NSH Library → Message of the Day (MOTD)], Welcome to NuttX from MCUboot, this is the FIRST firmware!:

Salve as configurações e saia do menu. Vamos agora compilar:

Note que o sistema de build já fez a adição do cabeçalho MCUboot à imagem e indicou que ela está confirmada:

Atualização de firmware utilizando MCUboot

Finalmente faremos o flash desta imagem no dispositivo. Ajuste <PORT> de acordo com a porta em que o dispositivo está conectado (exemplo: /dev/ttyUSB0), <BAUD> de acordo com o baud rate compatível e <FLASH_SIZE> de acordo com o tamanho da flash do dispositivo:

Reinicie o dispositivo. Observe a nossa mensagem de inicialização configurada anteriormente:

Atualização de firmware utilizando MCUboot

Compilando o firmware de atualização

Já temos nosso dispositivo rodando o NuttX, que também contém a aplicação do agente atualizador. Agora vamos compilar a nossa atualização.

Primeiro limpe o ambiente:

Para o nosso exemplo podemos pré-configurar uma aplicação mais simples, contendo apenas o shell e a aplicação de confirmação de imagem do MCUboot, já que faremos a atualização apenas uma vez:

Novamente vamos terminar de configurar no menu, algumas configurações serão as mesmas que as anteriores:

– Habilitar [Build Setup → Prompt for development and/or incomplete code/drivers].

– Alterar [System Type → Application Image Configuration → Application Image Format] para MCUboot-bootable format.

– Agora vamos alterar aquela configuração do slot em que será colocada a nova imagem [System Type → Application Image Configuration → Target slot for image flashing]:

– Habilitar o driver de SPI Flash [System Type → ESP32 Peripheral Selection]:

– Habilitar o comando de reset [Board Selection → Enable reset interfaces]:

– Habilitar a aplicação de confirmação de imagem do MCUboot [Application Configuration → Bootloader Utilities → MCUboot] e [Application Configuration → Bootloader Utilities → MCUboot → MCUboot slot confirm example]:

– Alterar a mensagem de inicialização do NuttX shell [Application Configuration → NSH Library → Message of the Day (MOTD)] para Welcome to NuttX from MCUboot, this is the UPDATED firmware!.

Observe que, como selecionamos a opção de que a imagem seria gravada no secondary slot, o sistema de build não adicionou a confirmação de imagem ao cabeçalho da imagem:

Execução da atualização OTA

Neste exemplo será necessário um servidor HTTP para disponibilizar nossa imagem de atualização. Abra outro terminal ou em background no mesmo diretório em que se encontra o binário da imagem:

Chegou a hora de executar nossa atualização. Abra novamente o monitoramento do dispositivo e o reinicie:

O próximo passo é conectar o dispositivo à sua rede Wi-Fi para que ele consiga buscar a atualização no servidor que está local em sua máquina:

Você pode testar a sua conexão através do ping:

Finalmente vamos utilizar o agente de atualização para fazer o download da nova imagem:

Note que após o download, o agente de atualização reiniciou o dispositivo para que o MCUboot faça a permuta entre a imagem nova, que está no slot secundário, e a imagem antiga que está no slot primário. Após a permuta, o bootloader iniciou a imagem atualizada e exibiu a mensagem colocada para indicar que a nova imagem está sendo executada como esperado.

Ainda falta um passo para completarmos a atualização, que é a confirmação desta imagem que foi atualizada. Caso essa confirmação não seja feita, ocorrerá um rollback no próximo boot, ou seja, ocorrerá uma permuta e a imagem antiga voltará ao slot primário. Caso queira (não é necessário, claro), você pode testar esse rollback reiniciando o dispositivo:

Caso tenha feito o rollback, repita os passos de conexão à rede Wi-Fi e download da imagem através do agente de atualização.

Para confirmar a imagem, vamos executar a aplicação de confirmação:

Pronto! Como a imagem foi confirmada, ela fica consolidada e não sofrerá rollback nos próximos boots.

Conclusão

O processo de atualização via permuta do MCUboot contribui na robustez dos projetos de firmwares, já que provê mecanismos de proteção ao longo de suas diversas etapas, como a verificação de corrupção dos dados da nova imagem, tolerância de falhas enquanto ocorre a permuta de imagens e rollback caso a imagem não se consolide.

Na perspectiva da camada de aplicação, há menor complexidade para a integração desse processo de atualização contendo todas as vantagens citadas. Sendo a imagem apenas responsável pelo recebimento (download) e correto posicionamento do novo firmware no Slot secundário. Também, caso desejável, logo após a permuta a imagem atualizada pode realizar seus próprios testes antes de se marcar como permanente – o rollback é realizado pelo próprio MCUboot no próximo boot caso haja algum problema.

Por outro lado, essa arquitetura demanda uma quantidade maior de memória e espaço em memória flash devido às áreas auxiliares da imagem como os trailers e a área de Scratch. Além disso, com o aumento de escritas na flash por causa da permuta, também acelera o desgaste da região dessa área.

Agora que passamos pelas etapas da atualização de firmware OTA e vimos algumas de suas vantagens e desvantagens, os próximos passos desta série sobre MCUboot + ESP32 serão relacionados à segurança: Secure boot, autenticação de imagem e criptografia de flash.

Referências

Outros artigos da série

<< Primeiros passos com ESP32 utilizando MCUboot como bootloader
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
0 Comentários
Inline Feedbacks
View all comments
Home » Software » Firmware update utilizando MCUboot no ESP32

EM DESTAQUE

WEBINARS

LEIA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste:


Seminário de
Sistemas Embarcados e IoT 2024
 
Data: 25/06 | Local: Hotel Holiday Inn Anhembi, São Paulo-SP
 
GARANTA SEU INGRESSO

 
close-link