Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O CFU (Component Firmware Update) é um protocolo e um processo para enviar novas imagens de firmware a serem instaladas no dispositivo de destino.
Observação
A CFU está disponível no Windows 10, versão 2004 (Atualização do Windows 10 de maio de 2020) e versões posteriores.
Os envios de CFU para o firmware residente são pares de arquivos: um arquivo é a parte de oferta, e o outro arquivo é a parte de conteúdo. Cada envio de CFU (cada oferta e par de conteúdo) deve ser criado off-line antes de ser enviado para o firmware que implementa o processo de CFU.
No código-fonte firmware de exemplo no repositório CFU no GitHub, o código comum independente de implementação geral para 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
- As partes da oferta e do conteúdo
Partes da oferta e do conteúdo
A oferta e o conteúdo compõem um par de arquivos no esquema CFU.
A parte da oferta é simplesmente um arquivo 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 de CFU fornecido usa arquivos SREC para conteúdo de firmware.
A oferta é uma sequência de 16 bytes. Essa estrutura de oferta é colocada no arquivo 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 arquivo 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 a 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 ao 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 registro de oferta
A ID do produto. Um valor de ID de produto exclusivo para essa imagem de CFU pode ser aplicado a esse campo.
UINT16 productID;
O marco importante do firmware que o conteúdo da oferta representa. Os marcos de desenvolvimento podem ser versões diferentes da construção de hardware (HW), por exemplo, construção EV1, construção EV2 e assim por diante. A definição de marco e a atribuição de valor são deixadas para o desenvolvedor.
UINT8 milestone : 3;
Se o firmware for destinado a um banco específico, o campo de 2 bits oferecerá suporte a quatro bancos. O uso de um registro bancário é incluído no formato da oferta porque há instâncias em que os dispositivos de destino usam regiões de firmware bancárias.
Se esse for o caso, e a oferta se destinava a atualizar um banco em uso, o firmware que implementa o CFU no alvo pode rejeitar a oferta. Caso contrário, o firmware no alvo que implementa CFU pode tomar outras medidas como necessário.
Se o banco de imagens de firmware NÃO estiver no design do firmware do usuário final, será razoável ignorar esse campo (definido como quaisquer valores convenientes, mas o valor no campo de banco é opcional e depende da maneira como o firmware de destino implementa a CFU).
UINT8 bank : 2;
A versão de protocolo do protocolo CFU usada está em 4 bits.
UINT8 protocolRevision : 4;
A máscara de bits correspondente a todo o hardware único em que esta imagem de firmware pode operar. Por exemplo, a oferta pode significar que pode ser executada na versão X de HW, mas não na versão Y de HW. 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 está fazendo a oferta. Isso se destina a diferenciar os drivers e as ferramentas que podem estar tentando atualizar o mesmo firmware em execução. Por exemplo, um driver de atualização de CFU pode receber o token 0xA e uma ferramenta de atualização de desenvolvimento pode ser atribuída ao token 0xB. Agora, o firmware em execução pode optar seletivamente por aceitar ou ignorar comandos com base em qual processo está tentando atualizá-lo.
UINT8 token;
O componente do dispositivo responsável por aplicar a atualização de firmware.
UINT8 componentId;
sinais de interpretação de oferta: 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 ignorância de versão.
UINT8 forceIgnoreVersion: 1;
Forçar a redefinição imediata é sinalizado com um bit. Se esse bit for ativado, o software host espera que o firmware in situ faça com que o dispositivo execute uma reinicialização. As ações da reinicialização são específicas da plataforma. O firmware do dispositivo pode optar por executar uma ação que troque os bancos de memória para tornar o firmware recém-atualizado o firmware ativo in situ. Ou não. Fica a critério da implementação do firmware. A expectativa geralmente é que, se a redefinição imediata for forçada, o dispositivo fará o necessário para que o firmware atualize o novo banco de memória e o torne o firmware ativo em execução no dispositivo de destino.
UINT8 forceImmediateReset : 1;
Caso a parte de conteúdo da oferta e do par de conteúdo envolva várias partes do conteúdo.
UINT8 segmentNumber;
Processando ofertas
A API ProcessCFWUOffer aceita dois argumentos:
void ProcessCFWUOffer(FWUPDATE_OFFER_COMMAND* pCommand,
FWUPDATE_OFFER_RESPONSE* pResponse)
Nesse caso de uso, suponha que o software do usuário envie bytes de dados para o firmware em execução e, em seguida, 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 é o dado usado pelo firmware em execução para processar a oferta.
Durante o processamento da oferta, o firmware em execução notifica o remetente preenchendo campos na estrutura FWUPDATE_OFFER_RESPONSE.
Interpretando a oferta
O firmware em execução deve acompanhar seu estado no processo de atualização de firmware contínua (CFU). Pode estar pronto/aguardando para aceitar uma oferta, no meio de uma transação CFU ou aguardando para alternar entre bancos de firmware ativo/inativo.
Se o firmware em execução estiver no meio de uma transação CFU, não aceite/processe essa oferta e notifique o host adequadamente.
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 está sendo solicitada. No código de exemplo CFU, um comando de oferta especial é usado pelo host para recuperar o status do mecanismo CFU, verificando se o software em execução é capaz e está pronto para aceitar Ofertas de 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, uma verificação será feita se houver uma troca de banco pendente. A troca de banco refere-se ao firmware que persiste a informação sobre se ainda está ou não no processo de alternar do aplicativo ativo em execução para a imagem recém-baixada.
A alternância bancária é uma tarefa específica de implementação para o firmware embarcado, e sua execução depende de como e onde é realizada. O protocolo cfu e o processo permitem que as informações sejam trocadas entre o aplicativo de usuário remoto que conduz a CFU e o firmware in situ que está 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;
}
Por fim, 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 nenhuma troca de banco pendente, então podemos processar essa oferta.
O processamento de uma oferta envolve, mas não se limita às quatro etapas descritas abaixo:
Etapa 1 – Verificar banco
Verifique o banco de dados do aplicativo em execução em relação ao banco de dados na oferta. Eles são iguais ou diferentes?
Se forem iguais, rejeite a oferta (não queremos substituir a imagem ativa/em execução).
Caso contrário, prossiga.
Etapa 2 – Verificar hwVariantMask
O firmware em execução verifica a hwVariantMask oferta em relação ao HW em que está em execução. Isso permite que o firmware embutido rejeite uma oferta se a oferta for inválida para o alvo. (por exemplo, se o firmware em execução estiver em um build HW antigo e o novo firmware oferecido for destinado a uma compilação HW mais recente, o firmware em execução deverá rejeitar essa oferta)
Se for inválido, rejeite a oferta.
Caso contrário, continue.
Etapa 3 – Verificar a versão do firmware
Verifique se a versão do conteúdo de firmware oferecido tem uma versão mais antiga ou mais recente do que o firmware do aplicativo atual.
Cabe à implementação feita pelos usuários decidir como verificar qual firmware é mais recente do que outro e se o campo 'forceIgnoreVersion' na oferta pode ser utilizado. O desenvolvimento de firmware típico permitiria que o campo 'forceIgnoreVersion' fosse usado durante o desenvolvimento do produto e em versões de depuração do firmware, mas não permitido (não permitindo que firmware mais antigo seja atualizado sobre o novo firmware) no firmware de produto/lançamento.
Se essa verificação falhar, rejeite a oferta.
Caso contrário, siga.
Etapa 4 – Aceitar oferta
A oferta é boa. Aceite a oferta com uma resposta personalizada para a maneira como as mensagens e o status são retornados pelo firmware para o aplicativo de usuário remoto. A chamada "resposta" é um dado (uma estrutura de dados empacotada, conforme mostrado nos arquivos de cabeçalho de demonstração) e esses dados são gravados no aplicativo do usuário pelos meios apropriados para o dispositivo.
Processar o conteúdo
O processamento do conteúdo geralmente é um processo de várias etapas. As várias etapas referem-se à capacidade do firmware de aceitar a imagem de 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 inserido, portanto, é realista esperar que a implementação do protocolo CFU e o processo aceitem conteúdo em partes pequenas.
Essa discussão usa a suposição ao descrever o processo do conteúdo da CFU.
O computador de estado do processamento de conteúdo envolve três estados.
O estado do processamento do primeiro bloco.
O estado do processamento do último bloco.
O estado do processamento de qualquer bloco entre o primeiro e o último.
A estrutura do comando de conteúdo
Assim como a oferta, o conteúdo tem uma estrutura com campos que são usados pelos algoritmos de 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 da 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 conteúdo "bloco" é o primeiro, o último ou outro.UINT8 lengthMarca o comprimento dopDatacampo. No código de demonstração para CFU, o limite do 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á sendo enviado para conteúdo.UINT32 addressO deslocamento de endereço do bloco. Na demonstração da CFU desta versão, a implementação predefini informações sobre o endereço físico de cada região do aplicativo. Por exemplo, uma implementação de firmware de dois bancos pode fazer com que o App1 comece no endereço0x9000e o App2 comece no endereço0xA0000. Portanto, dependendo de como a imagem de firmware foi preparada (S-Records), o endereço no SREC pode ser o endereço físico ou um deslocamento. De qualquer forma, é necessário haver uma compreensão compartilhada entre a preparação do conteúdo e as rotinas específicas para a implementação do processamento do conteúdo da CFU, a fim de determinar o verdadeiro endereço físico onde gravar o bloco na memória. Cabe ao desenvolvedor de firmware adotar as práticas recomendadas e verificar se há intervalos de endereços válidos para cada blog de conteúdo. Por exemplo, o código CFU demonstra uma verificação feita se talvez o App1 (destinado a0x9000) tenha endereços que se sobrepõem ao App2 e assim por diante.UINT8 pData[MAX_UINT8]- Esses são os bytes brutos do bloco de imagem de firmware. O cuidado é tomado no aplicativo do usuário para colocar apenaslengthbytes no fluxo de bytes completo do bloco de conteúdo.
Não há campos de bits usados na estrutura de conteúdo, conforme demonstra a 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 em memória não volátil. É claro que o conteúdo "bloco" contém informações sobre onde na memória o bloco deve ser gravado, quantos dados gravar e outros campos.
Cada dispositivo de destino componentID é diferente e há vários métodos para manter os dados na memória. Por exemplo, um componentId pode exigir 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 destino para o qual foi projetado.
Qualquer outro bloco, exceto primeiro ou ú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 observar que, a qualquer momento em que o sistema falhe em capturar e persistir o bloco na memória, é responsabilidade do firmware in situ responder com um código de falha.
O último bloco
O último bloco só apresentará um desafio se o firmware in situ precisar realizar 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 de 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. Cabe 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 de CRC leva tempo. Ao contrário do fluxo normal da execução da CFU para a apresentação de ofertas e o envio de blocos. O último envio de bloco, se incluir uma verificação de CRC, terá algum atraso devido ao fato de a verificação de CRC possivelmente examinar uma grande região de memória. Dependendo do dispositivo de destino e de outros fatores, isso pode não ser uma preocupação.
Importante
A verificação CRC da imagem de entrada é opcional e pode ser desativada. No entanto, as melhores práticas devem ser implementadas para, pelo menos, adotar essa verificação. É altamente recomendável que, neste momento, no processo de CFU, outras ações sejam executadas para garantir a integridade da imagem baixada. Algumas dessas ações podem incluir verificar uma parte "assinada" da imagem e/ou verificar cadeias de certificados de confiança ou outras abordagens de prática recomendada para garantir uma imagem de firmware segura. Elas são deixadas para o desenvolvedor de firmware.
Realizar limpeza após o último bloco
Agora que o último bloco foi gravado e a verificação de CRC está concluída, o firmware poderá responder com uma falha se alguma parte da validação falhar.
Caso contrário, a expectativa é que o processo de CFU no firmware responda com um status de sucesso.
Reinicialização forçada verificada
O sinalizador de redefinição forçada na oferta é usado para determinar se o MCU do destino 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 de variáveis persistentes para indicar em qual imagem de firmware inicializar na redefinição é incumbida ao desenvolvedor de firmware.