Delen via


Firmware-implementatiehandleiding voor CFU-firmware-update van componenten

Component Firmware Update (CFU) is een protocol en een proces voor het indienen van nieuwe firmware-installatiekopieën die op het doelapparaat moeten worden geïnstalleerd.

Opmerking

CFU is beschikbaar in Windows 10, versie 2004 (Windows 10 mei 2020 Update) en latere versies.

CFU-inzendingen naar de residente firmware zijn bestandsparen, één bestand is het deel van de aanbieding, het andere bestand is het inhoudsonderdeel. Elke CFU-inzending (elk aanbod en inhoudspaar) moet off-line worden gemaakt voordat de inzending wordt verzonden naar de firmware waarmee het CFU-proces wordt geïmplementeerd.

In de broncode van de voorbeeldfirmware in de CFU-opslagplaats op GitHub is de algemeen implementatie-agnostische gemeenschappelijke code voor CFU opgenomen in ComponentFwUpdate.c. Alle andere bestanden zijn helperbestanden die kunnen worden bijgewerkt of gewijzigd in de unieke implementatie van de ontwikkelaar.

Inhoud

De aanbieding en inhoudsonderdelen

Het aanbod en de inhoud vormen een tweepel van bestanden in het CFU-schema.

Het aanbiedingsonderdeel is gewoon een bestand van 16 bytes lang dat overeenkomt met de FWUPDATE_OFFER_COMMAND-structuur die hieronder wordt beschreven.

Het inhoudsonderdeel, de werkelijke firmware die moet worden bijgewerkt, heeft de indeling die wordt bepaald door de ontwikkelaar van de eindgebruiker. De opgegeven CFU-voorbeeldcode maakt gebruik van SREC-bestanden voor firmware-inhoud.

Het aanbod is een reeks van 16 bytes. Deze aanbiedingsstructuur wordt in het aanbiedingsbestand geplaatst. Het zijn in wezen binaire gegevens, geen tekst, omdat de aanbieding bitvelden van specifieke betekenis bevat.

Het aanbod dat in het bestand wordt weergegeven, komt overeen met deze C-structuur.

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;

Van laag adres naar hoog adres is de eerste byte van het aanbod een segmentnummer.

  <------- 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  |
+================================-=============================================+

Van hoog adres tot laag adres:

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
---------------------------------------------------------

Details van aanbiedingsregister

De Product-ID. Een unieke product-id-waarde voor deze CFU-afbeelding kan worden toegepast op dit veld.

UINT16 productID;  

De mijlpaal van de firmware die de inhoud van de aanbieding vertegenwoordigt. Mijlpalen kunnen verschillende versies van de HW-build zijn, bijvoorbeeld EV1-build, EV2-build, enzovoort. Mijlpaaldefinitie en waardetoewijzing worden overgelaten aan de ontwikkelaar.

UINT8 milestone : 3;

Als de firmware is bedoeld voor een specifieke bank, ondersteunt het 2-bits veld vier banken. Het gebruik van een bankregister is opgenomen in de indeling van het voorstel, omdat er gevallen zijn waar de doelapparaten gepartitioneerde firmware regio's gebruiken.

Als dat het geval was en de aanbieding bedoeld was om een bank in gebruik bij te werken, kan de firmware die CFU op het doel implementeert, de aanbieding afwijzen. Anders kan de firmware op het doelsysteem dat CFU implementeert andere acties ondernemen indien gerechtvaardigd.

Als het opslaan van firmware-installatiekopieën NIET is opgenomen in het ontwerp van de eindgebruikersfirmware, is het redelijk om dit veld te negeren (stel in op willekeurige waarden die handig zijn, maar de waarde in het veld voor opslag is optioneel en afhankelijk van de manier waarop de doelfirmware CFU implementeert).

UINT8 bank : 2;

De protocolversie van het gebruikte CFU-protocol is in 4 bits.

UINT8 protocolRevision : 4;

De bitmask die overeenkomt met alle unieke hardware waarop deze firmware-afbeeldingen kunnen functioneren. De aanbieding kan bijvoorbeeld betekenen dat deze kan worden uitgevoerd op verX van HW, maar niet op verY van HW. Bit-definitie en waardetoewijzing worden overgelaten aan de ontwikkelaar.

UINT32 hwVariantMask;

De versie van de firmware die wordt aangeboden.

UINT32 version;

Een bytetoken om de gebruikerspecifieke software te identificeren die de aanbieding aanbiedt. Dit is bedoeld om onderscheid te maken tussen stuurprogramma's en hulpprogramma's die mogelijk beide proberen dezelfde actieve firmware bij te werken. Aan een CFU-update-stuurprogramma kan bijvoorbeeld het token 0xA worden toegewezen, en een hulpprogramma voor het updaten van ontwikkeling kan het token 0xB toegewezen krijgen. Nu kan de actieve firmware selectief opdrachten accepteren of negeren op basis van welk proces het probeert bij te werken.

UINT8 token;

Het onderdeel op het apparaat om de firmware-update toe te passen.

UINT8 componentId;

bieden interpretatievlaggen: Als we willen dat de in-situ firmware versieverschillen negeert (ouder boven op nieuwer), stelt u de bitwaarde in om Ignore Version af te dwingen.

UINT8 forceIgnoreVersion: 1;

Het afdwingen van onmiddellijk opnieuw instellen wordt met één bit ingesteld. Als dat bit wordt ingesteld, verwacht de hostsoftware dat de in situ-firmware het apparaat een reset laat uitvoeren. De acties van het opnieuw instellen zijn platformspecifiek. De firmware van het apparaat kan ervoor kiezen om actie te ondernemen die de geheugenbanken verwisselt om de nieuw bijgewerkte firmware als de actieve in situ-firmware te maken. Of niet. Het wordt overgelaten aan de implementatie van de firmware. De verwachting is meestal dat als het forceren van een onmiddellijke herstart wordt gebruikt, het apparaat alles doet wat nodig is, zodat de nieuwe bank wordt bijgewerkt en de actieve firmware wordt die draait op het doelapparaat.

UINT8 forceImmediateReset : 1;

In het geval dat het inhoudsgedeelte van het aanbiedings- en inhoudspaar meerdere delen van inhoud omvat.

UINT8 segmentNumber;

Verwerkingsaanbiedingen

De ProcessCFWUOffer-API accepteert twee argumenten:

void ProcessCFWUOffer(FWUPDATE_OFFER_COMMAND* pCommand,
                     FWUPDATE_OFFER_RESPONSE* pResponse)

In dit gebruiksscenario wordt ervan uitgegaan dat de gebruikerssoftware gegevensbytes naar de actieve firmware verzendt en vervolgens het eerste bericht het aanbiedingsbericht is.

Het aanbiedingsbericht is een bericht van 16 bytes dat hierboven wordt beschreven (de FWUPDATE_OFFER_COMMAND structuur).

Dat aanbiedingsbericht is de gegevens die door de actieve firmware worden gebruikt om de aanbieding te verwerken.

Tijdens de afhandeling van de aanbieding meldt de lopende firmware de afzender door velden in de structuur in te FWUPDATE_OFFER_RESPONSE vullen.

De aanbieding interpreteren

De actieve firmware moet de status bijhouden in het CFU-proces. Het kan gereed zijn/erop wachten om een aanbod te accepteren, tijdens een CFU-transactie bezig zijn, of wachten op het overschakelen van banken tussen actieve/inactieve firmware.

Als de actieve firmware zich midden in een CFU-transactie bevindt, accepteert/verwerkt u deze aanbieding niet en informeert u de host dienovereenkomstig.

   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;
   }

Het component-ID-veld van de aanbieding kan worden gebruikt om de actieve firmware te signaleren dat een speciale actie door de lopende firmware wordt aangevraagd. In de voorbeeld-CFU-code wordt een opdracht voor speciale aanbiedingen door de host gebruikt om de status van de CFU-engine op te halen: of de actieve software geschikt is en gereed is om CFU-aanbiedingen te accepteren.

   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;
       }
   }

Ten slotte wordt er een controle uitgevoerd als er een bankwisseling in behandeling is. De bankswap verwijst naar de firmware die de informatie vasthoudt of het systeem nog steeds bezig is met het overstappen van de actieve toepassing naar het zojuist gedownloade image.

Hoe en waar bankwisselingen worden uitgevoerd, is een implementatiespecifieke taak voor de ingesloten firmware. Met het CFU-protocol en -proces kan informatie worden uitgewisseld tussen de externe gebruikerstoepassing die de CFU uitvoert en de in situ-firmware die wordt uitgevoerd.

   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;
   }

Als de status van de actieve firmware niet bezet is en de componentId geen speciale opdracht is en er geen bankwisseling in behandeling is, kunnen we deze aanbieding verwerken.

Het verwerken van een aanbieding omvat, maar is niet beperkt tot, de vier stappen die hieronder worden beschreven:

Stap 1: Bank controleren

Vergelijk de bank van de actieve applicatie met de bank in de aanbieding. Zijn ze hetzelfde of anders?

Als dit hetzelfde is, wijs de aanbieding af (we willen de draaiende/actieve installatiekopieën niet overschrijven).

Ga verder.

Stap 2: hwVariantMask controleren

De actieve firmware controleert de hwVariantMask aanbieding op de HW waarop deze wordt uitgevoerd. Hierdoor kan de ingesloten firmware een aanbieding weigeren als de aanbieding ongeldig is voor het doel. (bijvoorbeeld als de actieve firmware zich op een oude HW-build bevindt en de nieuwe aangeboden firmware is bedoeld voor een nieuwere HW-build - dan moet de actieve firmware deze aanbieding afwijzen)

Als deze ongeldig is, wijst u de aanbieding af.

Ga verder.

Stap 3: firmwareversie controleren

Controleer of de versie van de aangeboden firmware-inhoud een oudere of nieuwere versie heeft dan de huidige toepassingsfirmware.

Het wordt overgelaten aan de gebruikersimplementatie om te bepalen hoe gecontroleerd wordt welke firmware nieuwer is dan een andere en of het veld 'forceIgnoreVersion' in het aanbod moet worden gebruikt. Typische firmwareontwikkeling maakt het mogelijk dat het veld 'forceIgnoreVersion' wordt gebruikt tijdens de productontwikkeling en in foutopsporingsversies van de firmware, maar het mag niet worden toegepast (waardoor oudere firmware niet bovenop nieuwe firmware kan worden bijgewerkt) in product- of releasefirmware.

Als deze controle is mislukt, negeert u de aanbieding.

Ga verder.

Stap 4: Aanbieding accepteren

Het aanbod is goed. Accepteer de aanbieding met een antwoord dat is afgestemd op de manier waarop berichten en status worden geretourneerd door de firmware naar de externe gebruikerstoepassing. Het zogenaamde 'antwoord' is gegevens (een verpakte gegevensstructuur zoals weergegeven in de demonstratieheaderbestanden) en deze gegevens worden op de juiste manier voor het apparaat naar de gebruikerstoepassing geschreven.

De inhoud verwerken

De verwerking van de inhoud is meestal een proces met meerdere stappen. De meerdere stappen verwijzen naar de mogelijkheid van de firmware om de firmware-installatiekopieën in delen te accepteren, ook wel 'blokken' van gegevens genoemd. Het is niet altijd haalbaar om de hele afbeelding tegelijk naar de ingesloten firmware te verzenden, dus het is realistisch om de implementatie van het CFU-protocol en het proces te verwachten om inhoud in kleine stukken te accepteren.

Deze discussie maakt gebruik van de aanname bij het beschrijven van het proces van de CFU-inhoud.

De statusmachine van de inhoudsverwerking omvat drie statussen.

  1. De status van de verwerking van het eerste blok.

  2. De status van de verwerking van het laatste blok.

  3. De status van het verwerken van geheel willekeurige blokken tussen de eerste en laatste.

De structuur van de inhoudsopdracht

Net als de aanbieding heeft de inhoud een structuur met velden die worden gebruikt door de CFU-algoritmen in de demonstratie.

typedef struct
{
   UINT8 flags;
   UINT8 length;
   UINT16 sequenceNumber;
   UINT32 address;
   UINT8 pData[MAX_UINT8];
} FWUPDATE_CONTENT_COMMAND;

De structuur van de inhoudsopdracht is eenvoudiger dan de aanbiedingsstructuur. De inhoud wordt gedefinieerd als een reeks bytes die in het geheugen moeten worden geschreven. De inleiding van de inhoud bestaat uit de velden van deze structuur.

  1. UINT8 flags Geeft aan of het inhoudsblok als eerste, laatste of anders is.

  2. UINT8 length Hiermee wordt de lengte van het pData veld gemarkeerd. In de demonstratiecode voor CFU is de limiet voor de grootte van de pData code 255 bytes. Andere implementaties kunnen de maximale grootte van het blok variëren.

  3. UINT16 sequenceNumber Hiermee wordt de index van het blok opgegeven dat als inhoud wordt ingediend.

  4. UINT32 address De adressoffset van het blok. In de demonstratie van CFU van deze release heeft de implementatie vooraf gedefinieerde informatie over het fysieke adres van elke app-regio. Een implementatie van twee bankfirmware kan bijvoorbeeld app1 laten beginnen op adres 0x9000 en App2 beginnen op adres 0xA0000. Afhankelijk van hoe de firmware-installatiekopieën zijn voorbereid (S-Records), kan het adres in de SREC dus het fysieke adres of een offset zijn. In elk geval moet er een gedeeld begrip zijn tussen de voorbereiding van de inhoud en de implementatiespecifieke routines van de CFU-inhoudsverwerking om het werkelijke fysieke adres te bepalen van waar het blok in het geheugen moet worden geschreven. Het wordt aan de firmwareontwikkelaar overgelaten om best practices te gebruiken en controleert op geldige adresbereiken voor elke inhoudsblog. De CFU-code demonstreert bijvoorbeeld een controle of app1 (bedoeld voor 0x9000) adressen bevat die overlappen met App2, enzovoort.

  5. UINT8 pData[MAX_UINT8] - Dit zijn de ruwe bytes van het firmware image blok. Zorg wordt ervoor gedragen dat binnen de gebruikerstoepassing length bytes alleen worden opgenomen in de volledige bytestroom van het inhoudsblok.

Er zijn geen bitvelden die in de inhoudsstructuur worden gebruikt volgens de CFU-demonstratie van de opgegeven code.

Het eerste blok

Het eerste blok start het downloaden van de firmware-inhoud. De firmware die wordt uitgevoerd, probeert het blok naar niet-vluchtig geheugen te schrijven. Natuurlijk bevat het inhoudsblok informatie over waar in het geheugen het blok moet worden geschreven, hoeveel gegevens er moeten worden geschreven en andere velden.

Elk componentID-doelapparaat is verschillend en er zijn meerdere methoden om de gegevens in het geheugen te behouden. Eén componentId kan bijvoorbeeld schrijven naar interne flash vereisen, een andere componentId kan schrijven naar een externe SPI-flash of een andere kan gebruikmaken van het I2C-protocol van een andere IC om de afbeelding bij te werken. In de demonstratie die bij dit document is inbegrepen, wordt het gebruik van een functie getoond die elke unieke firmware moet implementeren, met kennis van de onderliggende niet-vluchtige geheugen I/O-functies van het doel waarvoor het is ontworpen.

Elk ander blok, behalve eerste of laatste

Het proces van het accepteren van nieuwe blokken wordt voortgezet wanneer de gebruikerstoepassing een ander blok levert, opnieuw met metagegevens in het bericht voor het adres waar het blok moet worden geschreven, hoeveel bytes er zijn en andere velden.

De in situ-firmware zou dit net als een eerste blokscenario behandelen.

Er moet echter worden opgemerkt dat als het systeem er op enig moment niet in slaagt het blok vast te leggen en op te slaan in het geheugen, dan is het aan de in situ-firmware om te reageren met een foutcode.

Het laatste blok

Het laatste blok vormt alleen een uitdaging als de in situ-firmware taken moet uitvoeren om het beeldbestand te valideren dat zojuist naar het geheugen is geschreven.

Ten eerste wordt het laatste blok naar het geheugen geschreven.

Vervolgens moet er ten minste een CRC-controle worden uitgevoerd tussen de gegevens die al naar het geheugen zijn geschreven (van de eerste tot laatste blokken) vergeleken met het CRC-veld in het laatste blok. Het is aan elke implementatiefirmware overgelaten om te weten hoe u de CRC voor de gedownloade installatiekopieën kunt verkrijgen.

Houd er rekening mee dat de uitvoering van de CRC-controle wel tijd in beslag neemt. In tegenstelling tot de normale stroom van de uitvoering van de CFU voor het indienen van aanbiedingen en blokkeren. De laatste blokverzending, als deze een CRC-controle bevat, heeft een bepaalde vertraging, alleen voor het feit dat de CRC-controle mogelijk een grote hoeveelheid geheugen onderzoekt. Afhankelijk van het doelapparaat en andere factoren is dit mogelijk geen probleem.

Belangrijk

De CRC-controle van de binnenkomende afbeelding is optioneel en kan worden uitgeschakeld. Er moeten echter best practices worden ingevoerd om deze controle ten minste aan te nemen. Het wordt sterk aanbevolen dat op dit punt in het CFU-proces andere acties worden ondernomen om de integriteit van de gedownloade afbeelding te waarborgen. Sommige van deze acties kunnen bestaan uit het verifiëren van een 'ondertekend' gedeelte van de installatiekopieën en/of het controleren van certificaatketens van vertrouwen of andere best practice-benaderingen om een veilige firmware-installatiekopieën te garanderen. Deze worden overgelaten aan de firmwareontwikkelaar.

Opschonen na laatste blok

Nu het laatste blok is geschreven en de CRC-controle is voltooid, kan de firmware reageren met een fout als een deel van de validatie is mislukt.

Anders is de verwachting dat het CFU-proces in de firmware reageert met een geslaagde status.

Geforceerd opnieuw instellen ingeschakeld

De vlag voor geforceerde reset in de aanbieding wordt gebruikt om te bepalen of de MCU van het doel opnieuw moet worden ingesteld (door de gebruiker gedefinieerde reset).

Wanneer een reset wordt afgedwongen, is het de bedoeling om de MCU te laten resetten, zodat de App-bank kan overschakelen. Het bijwerken van permanente variabelen om aan te geven in welke firmware-installatiekopie moet worden opgestart bij het opnieuw instellen, wordt aan de firmwareontwikkelaar overgelaten.