Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
A Atualização de Firmware de Componente (CFU) é um protocolo e um processo para enviar novas imagens de firmware a serem instaladas no dispositivo de destino.
Observação
CFU está disponível no Windows 10, versão 2004 (Windows 10 May 2020 Update) e versões posteriores.
Os envios CFU para o firmware residente são pares de ficheiros, sendo um ficheiro a parte da oferta e o outro ficheiro a parte do conteúdo. Cada submissão de CFU (cada oferta e par de conteúdo) deve ser criada offline antes de ser transmitida para o firmware que implementa o processo de CFU.
No código-fonte de exemplo de Firmware no repositório CFU no GitHub, o código comum, agnóstico em termos de implementação geral para o CFU, está contido em ComponentFwUpdate.c. Todos os outros arquivos são arquivos auxiliares que podem ser atualizados ou modificados para a implementação exclusiva do desenvolvedor.
Conteúdos
- A oferta e as partes de conteúdo
A oferta e as partes de conteúdo
A oferta e o conteúdo compõem um par de ficheiros no esquema CFU.
A parte da oferta é simplesmente um ficheiro de 16 bytes de comprimento que mapeia para a estrutura FWUPDATE_OFFER_COMMAND descrita abaixo.
A parte de conteúdo, o firmware real a ser atualizado está no formato ditado pelo desenvolvedor do usuário final. O código de exemplo CFU fornecido usa arquivos SREC para conteúdo de firmware.
A oferta é uma sequência de 16 bytes. Esta estrutura de oferta é colocada no ficheiro de oferta. São essencialmente dados binários, não texto, porque a oferta contém campos de bits de significado específico.
A oferta que está representada no ficheiro corresponde a esta estrutura C:
typedef struct
{
struct
{
UINT8 segmentNumber;
UINT8 reserved0 : 6;
UINT8 forceImmediateReset : 1;
UINT8 forceIgnoreVersion : 1;
UINT8 componentId;
UINT8 token;
} componentInfo;
UINT32 version;
UINT32 hwVariantMask;
struct
{
UINT8 protocolRevision : 4;
UINT8 bank : 2;
UINT8 reserved0 : 2;
UINT8 milestone : 3;
UINT8 reserved1 : 5;
UINT16 productId;
} productInfo;
} FWUPDATE_OFFER_COMMAND;
De endereço baixo para endereço alto, o primeiro byte da oferta é um número de segmento.
<------- 4 bytes -----------> <-- 8 bytes --> <-------- 4 bytes --------->
+================================-=============================================+
| 15:0 7:3 2:0 7:6 5:4 3:0 31:0 31:0 7:0 7:0 7:7 6:6 5:0 7:0 |
| PI | R1 | MS | R0 | BK | PR | VM | VN | TK | CI | FV | FR | R0 | SN |
+================================-=============================================+
Do endereço alto para o endereço baixo:
Byte(s) Value
---------------------------------------------------------
15:14 | (PI) Product ID is 2 bytes
13 | (R1) Reserved1 5-bit register
| (MS) Milestone 3-bit register
12 | (R2) Reserved2 2-bit register
| (BK) Bank 2-bit register
| (PR) Protocol Revision 2-bit register
11:8 | (VM) Hardware Variant Mask 32-bit register
7:4 | (VN) Version 32-bit register
3 | (TK) Token 8-bit register
2 | (CI) Component ID 8-bit register
1 | (FV) Force Ignore Version 1-bit register
| (FR) Force Immediate Reset 1-bit register
| (R0) Reserved0 6-bit register
0 | (SN) Segment Number 8-bit register
---------------------------------------------------------
Detalhes do registo de ofertas
O ID do produto. Um valor de ID de produto único para a imagem CFU pode ser aplicado a este campo.
UINT16 productID;
A etapa do firmware que o conteúdo da oferta representa. As etapas podem ser diferentes versões da compilação de hardware, por exemplo, versão EV1, versão EV2, e assim por diante. A definição do marco e a atribuição de valor são deixadas para o desenvolvedor.
UINT8 milestone : 3;
Se o firmware se destina a um banco específico - o campo de 2 bits suporta quatro bancos. O uso de um registo de banco está incluído no formato da oferta porque há casos em que os dispositivos de destino usam regiões de firmware em banco.
Se fosse esse o caso, e a oferta se destinasse a atualizar um banco em uso, o firmware que implementa CFU no alvo pode rejeitar a oferta. Caso contrário, o firmware no alvo que implementa CFU pode tomar outras ações conforme necessário.
Se o banco de imagens de firmware NÃO estiver no design do firmware do usuário final, então é razoável ignorar este campo (definido para quaisquer valores que sejam convenientes, mas o valor no campo banco é opcional e depende da maneira como o firmware no destino implementa CFU).
UINT8 bank : 2;
A versão do protocolo CFU utilizada é em 4 bits.
UINT8 protocolRevision : 4;
A máscara de bits correspondente a todo o hardware distinto em que esta imagem de firmware pode operar. Por exemplo, a oferta pode significar que pode ser executada na versão X do hardware, mas não na versão Y do hardware. A definição de bits e a atribuição de valor são deixadas para o desenvolvedor.
UINT32 hwVariantMask;
A versão do firmware que está sendo oferecida.
UINT32 version;
Um token de byte para identificar o software específico do usuário que faz a oferta. Isso se destina a diferenciar entre drivers e ferramentas que podem estar tentando atualizar o mesmo firmware em execução. Por exemplo, um driver de atualização CFU pode ser atribuído ao token 0xA e uma ferramenta de atualização de desenvolvimento ao token 0xB. Agora, o firmware em execução pode escolher seletivamente aceitar ou ignorar comandos com base no processo que está tentando atualizá-lo.
UINT8 token;
O componente no dispositivo destinado a aplicar a atualização de firmware.
UINT8 componentId;
oferecer indicadores de interpretação: Se quisermos que o firmware in situ ignore a incompatibilidade de versão (mais antiga sobre a mais recente), defina o bit para forçar a ignorar a versão.
UINT8 forceIgnoreVersion: 1;
Forçar a redefinição imediata é definido com um bit. Se esse bit for definido, o software do host espera que o firmware in situ faça com que o dispositivo execute uma reinicialização. As ações da redefinição são específicas da plataforma. O firmware do dispositivo pode optar por tomar medidas que substituam as partições de memória para tornar o firmware recém-atualizado o firmware ativo in situ. Ou não. Resta a implementação do firmware. A expectativa geralmente é que, se a reinicialização imediata for forçada, o dispositivo fará o necessário para que o firmware atualize a nova versão do banco de firmware, tornando-se o firmware ativo em execução no dispositivo alvo.
UINT8 forceImmediateReset : 1;
No caso de a parte de conteúdo da oferta e do par de conteúdos envolver várias componentes de conteúdo.
UINT8 segmentNumber;
Processamento de ofertas
A API ProcessCFWUOffer aceita dois argumentos:
void ProcessCFWUOffer(FWUPDATE_OFFER_COMMAND* pCommand,
FWUPDATE_OFFER_RESPONSE* pResponse)
Neste caso de uso, suponha que o software do usuário envia bytes de dados para o firmware em execução, então a primeira mensagem é a mensagem de oferta.
A mensagem de oferta é uma mensagem de 16 bytes descrita acima (a estrutura FWUPDATE_OFFER_COMMAND).
Essa mensagem de oferta é os dados usados pelo firmware em execução para processar a oferta.
Durante o processamento da oferta, o firmware que está a funcionar notifica o remetente preenchendo os campos na estrutura FWUPDATE_OFFER_RESPONSE.
Interpretação da oferta
O firmware em execução deve manter o controle de seu estado no processo CFU. Pode estar pronto/à espera de aceitar uma oferta, no meio de uma transação CFU, ou à espera de trocar bancos entre firmware ativo/inativo.
Se o firmware em execução estiver no meio de uma transação CFU, não aceite/processe esta proposta e notifique o sistema anfitrião de forma adequada.
if (s_currentOffer.updateInProgress)
{
memset(pResponse, 0, sizeof (FWUPDATE_OFFER_RESPONSE));
pResponse->status = FIRMWARE_UPDATE_OFFER_BUSY;
pResponse->rejectReasonCode = FIRMWARE_UPDATE_OFFER_BUSY;
pResponse->token = token;
return;
}
O campo ID do componente da oferta pode ser usado para sinalizar ao firmware em execução que uma ação especial é solicitada do firmware em execução. No exemplo de código CFU, um comando de oferta especial é usado pelo host para recuperar o status do mecanismo CFU - se o software em execução é capaz e pronto para aceitar ofertas CFU.
else if (componentId == CFU_SPECIAL_OFFER_CMD)
{
FWUPDATE_SPECIAL_OFFER_COMMAND* pSpecialCommand =
(FWUPDATE_SPECIAL_OFFER_COMMAND*)pCommand;
if (pSpecialCommand->componentInfo.commandCode == CFU_SPECIAL_OFFER_GET_STATUS)
{
memset(pResponse, 0, sizeof (FWUPDATE_OFFER_RESPONSE));
pResponse->status = FIRMWARE_UPDATE_OFFER_COMMAND_READY;
pResponse->token = token;
return;
}
}
Por fim, é feita uma verificação se houver um swap bancário pendente. A troca de banco refere-se ao firmware que persiste na informação sobre se ainda está ou não no processo de mudança da aplicação ativa em execução para a imagem recém-transferida.
Como e onde a mudança de banco é realizada é uma tarefa específica de implementação para o firmware incorporado. O protocolo e o processo CFU permitem a troca de informações entre a aplicação de utilizador remoto que conduz a CFU e o firmware in situ em execução.
else if (s_bankSwapPending)
{
memset(pResponse, 0, sizeof (FWUPDATE_OFFER_RESPONSE));
pResponse->status = FIRMWARE_UPDATE_OFFER_REJECT;
pResponse->rejectReasonCode = FIRMWARE_UPDATE_OFFER_SWAP_PENDING;
pResponse->token = token;
return;
}
Finalmente, se o estado do firmware em execução não estiver ocupado, e o componentId não for um comando especial e não houver troca bancária pendente - ENTÃO podemos processar esta oferta.
O processamento de uma oferta envolve, mas não está limitado a, as quatro etapas descritas abaixo:
Passo 1 - Verificar banco
Verifique o banco de dados da aplicação em execução em relação ao banco na oferta. São iguais ou diferentes?
Se for igual, então rejeite a proposta (não queremos substituir a imagem que está em execução/ativa).
Caso contrário, continue.
Passo 2 - Verifique hwVariantMask
O firmware em execução verifica o hwVariantMask na oferta em relação ao HW em que está sendo executado. Isso permite que o firmware incorporado rejeite uma oferta se a oferta for inválida para o alvo. (por exemplo, se o firmware em execução estiver numa compilação HW antiga e o novo firmware oferecido se destinar a uma compilação HW mais recente - então o firmware em execução deve rejeitar esta oferta)
Se for inválido, rejeite a oferta.
Caso contrário, continue.
Passo 3 - Verifique a versão do firmware
Verifique se a versão do conteúdo do firmware oferecido tem uma versão mais antiga ou mais recente do que o firmware do aplicativo atual.
Cabe à implementação dos usuários decidir como verificar qual firmware é maior do que outro e se permitir que o campo 'forceIgnoreVersion' na oferta seja usado. O desenvolvimento típico de firmware permitiria que o campo 'forceIgnoreVersion' fosse usado durante o desenvolvimento do produto e em versões de depuração do firmware, mas seria desativado (evitando que o firmware mais antigo fosse atualizado sobre o novo firmware) na versão final do firmware do produto/lançamento.
Se esta verificação falhar, rejeite a oferta.
Caso contrário, continue.
Passo 4 - Aceitar oferta
A oferta é boa. Aceite a oferta com uma resposta adaptada à forma como as mensagens e o estado são devolvidos pelo firmware à aplicação de utilizador remoto. A denominada "resposta" são dados (uma estrutura de dados compactada, tal como ilustrado nos ficheiros de cabeçalho de demonstração) e esses dados são gravados na aplicação do utilizador pelos meios apropriados para o dispositivo.
Processar o conteúdo
O processamento do conteúdo é geralmente um processo de várias etapas. Os vários passos referem-se à capacidade do firmware de aceitar a imagem do firmware em partes, também conhecidas como "blocos" de dados. Nem sempre é viável enviar a imagem inteira de uma só vez para o firmware incorporado, por isso é realista esperar que a implementação do protocolo CFU e o processo aceitem conteúdo em pequenos pedaços.
Esta discussão parte do pressuposto na descrição do processo do conteúdo de CFU.
A máquina de estado do processamento de conteúdo envolve três estados.
O estado de processamento do primeiro bloco.
O estado de processamento do último bloco.
O estado de processamento de qualquer bloco entre o primeiro e o último.
A estrutura do comando de conteúdo
Tal como a oferta, o conteúdo tem uma estrutura com campos que são utilizados pelos algoritmos CFU na demonstração.
typedef struct
{
UINT8 flags;
UINT8 length;
UINT16 sequenceNumber;
UINT32 address;
UINT8 pData[MAX_UINT8];
} FWUPDATE_CONTENT_COMMAND;
A estrutura do comando de conteúdo é mais simples do que a estrutura de oferta. O conteúdo é definido como uma sequência de bytes a serem gravados na memória. O preâmbulo do conteúdo são os campos desta estrutura:
UINT8 flagsIndica se o "bloco" de conteúdo é o primeiro, o último ou um outro qualquer.UINT8 lengthMarca o comprimento dopDatacampo. No código de demonstração para CFU, o limite no tamanho dopDataé de 255 bytes. Outras implementações podem variar o tamanho máximo do "bloco".UINT16 sequenceNumberMarca o contador de índice do bloco que está a ser submetido como conteúdo.UINT32 addressO deslocamento de endereço do bloco. Na demonstração do CFU desta versão, a implementação tem informações predefinidas sobre o endereço físico de cada região do aplicativo. Por exemplo, uma implementação de firmware de dois bancos pode ter App1 começar no endereço0x9000e App2 começar no endereço0xA0000. Assim, dependendo de como a imagem do firmware foi preparada (S-Records), o endereço no SREC pode corresponder ao endereço físico ou representar um deslocamento. Em qualquer caso, precisa haver um entendimento compartilhado entre a preparação do conteúdo e as rotinas específicas de implementação do processamento de conteúdo CFU para determinar o verdadeiro endereço físico de onde escrever o bloco na memória. Cabe ao desenvolvedor de firmware adotar as melhores práticas e verificar intervalos de endereços válidos para cada blog de conteúdo. Por exemplo, o código CFU demonstra uma verificação para ver se o App1 (destinado a0x9000) possui endereços que se sobrepõem ao App2, e assim por diante.UINT8 pData[MAX_UINT8]- Estes são os bytes brutos do bloco de imagem do firmware. No aplicativo do usuário, é tomado cuidado para colocar apenaslengthbytes no fluxo completo de bytes do bloco de conteúdo.
Não são utilizados campos de bits na estrutura de conteúdo, conforme a demonstração CFU no código fornecido.
O primeiro bloco
O primeiro bloco inicia o download do conteúdo do firmware. O firmware em execução tenta gravar o bloco na memória não volátil. É claro que o "bloco" de conteúdo contém informações sobre onde na memória o bloco deve ser escrito, quantos dados escrever e outros campos.
Cada dispositivo de destino componentID é diferente e há vários métodos para persistir os dados na memória. Por exemplo, um componentId pode exigir a gravação em flash interno, outro componentId pode gravar em um flash SPI externo ou outro pode utilizar o protocolo I2C de outro IC para atualizar sua imagem. A demonstração incluída neste documento destaca o uso de uma função chamada ICompFwUpdateBspWrite que cada firmware exclusivo deve implementar com conhecimento das funções de E/S de memória não voláteis subjacentes do alvo para o qual foi projetado.
Qualquer outro bloco, exceto o primeiro ou o último
O processo de aceitação de novos blocos continua quando o usuário-aplicativo entrega outro bloco, novamente com metadados na mensagem para o endereço de onde o bloco deve ser gravado, quantos bytes estão contidos e outros campos.
O firmware in situ trataria isso como um cenário de primeiro bloco.
No entanto, deve-se notar que, a qualquer momento, o sistema não consegue capturar e persistir o bloco na memória, cabe ao firmware in situ responder com um código de falha.
O último bloco
O último bloco apresenta um desafio apenas se o firmware in situ precisar fazer tarefas para validar a imagem que acabou de ser gravada na memória.
Primeiro, o último bloco é gravado na memória.
Em seguida, no mínimo, uma verificação CRC deve ser feita entre os dados já gravados na memória (do primeiro ao último bloco) em comparação com o campo CRC no último bloco. Resta a cada firmware de implementação saber como adquirir o CRC para a imagem baixada.
Tenha em mente que a execução da verificação CRC leva tempo. Ao contrário do fluxo normal de execução do CFU para oferta e submissão de blocos. A submissão do último bloco, se incluir uma verificação CRC, terá um certo atraso devido ao facto de que a verificação CRC está potencialmente a examinar uma grande região de memória. Dependendo do dispositivo alvo e de outros fatores, isso pode não ser uma preocupação.
Importante
A verificação CRC da imagem recebida é opcional e pode ser comentada. No entanto, devem ser postas em prática as melhores práticas para, pelo menos, adotar esta verificação. Recomenda-se vivamente que, nesta fase do processo de CFU, sejam realizadas outras ações para garantir a integridade da imagem descarregada. Algumas dessas ações podem incluir verificar uma parte "assinada" da imagem e/ou verificar cadeias de confiança de certificados ou outras abordagens de práticas recomendadas para garantir uma imagem de firmware segura. Estes são deixados para o desenvolvedor do firmware.
Limpeza após o último bloco
Agora que o último bloco foi gravado e a verificação CRC foi concluída, o firmware pode indicar uma falha caso alguma parte da validação falhe.
Caso contrário, a expectativa é que o processo CFU no firmware responda com um status bem-sucedido.
Reinicialização forçada verificada
O sinalizador de redefinição forçada na oferta é usado para determinar se o MCU do dispositivo-alvo deve passar por uma redefinição (redefinição definida pelo usuário).
Normalmente, quando uma redefinição é forçada, a intenção é fazer com que o MCU faça uma redefinição para fazer com que o banco de aplicativos mude. A atualização das variáveis persistentes para indicar em qual imagem de firmware inicializar durante a reinicialização é responsabilidade do desenvolvedor do firmware.