次の方法で共有


コンポーネント ファームウェア更新プログラム (CFU) ファームウェア実装ガイド

コンポーネント ファームウェア更新 (CFU) は、ターゲット デバイスにインストールする新しいファームウェア イメージを送信するためのプロトコルとプロセスです。

Note

CFU は、Windows 10 バージョン 2004 (Windows 10 May 2020 Update) 以降で使用できます。

常駐ファームウェアへの CFU 送信はファイル ペアであり、1 つのファイルはオファー部分、もう 1 つのファイルはコンテンツ 部分です。 各 CFU 申請 (各オファーとコンテンツ ペア) は、CFU プロセスを実装するファームウェアに送信される前に、オフラインで作成する必要があります。

GitHub の CFU リポジトリのサンプル ファームウェア ソース コードでは、CFU の一般的な実装に依存しない共通コードが ComponentFwUpdate.c に含まれています。 他のすべてのファイルは、開発者固有の実装に対して更新または変更できるヘルパー ファイルです。

内容

オファーとコンテンツ パーツ

オファーとコンテンツは、CFU スキーマ内のファイルのペアを構成します。

オファー パーツは、次に示すFWUPDATE_OFFER_COMMAND構造にマップされる 16 バイトの長いファイルです。

コンテンツ部分は、更新される実際のファームウェアは、エンドユーザー開発者によって指示された形式である。 提供される CFU サンプル コードでは、ファームウェアコンテンツに SREC ファイルを使用します。

オファーは 16 バイト シーケンスです。 このオファー構造は、オファー ファイルに格納されます。 オファーには特定の意味のビット フィールドが含まれているため、基本的にはテキストではなくバイナリ データです。

ファイルで表されるオファーは、次の 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;

低アドレスから高アドレスまで、オファーの最初のバイトはセグメント番号です。

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

高いアドレスから低いアドレスへ:

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

オファーの登録の詳細

製品 ID。 この CFU イメージの一意の製品 ID 値をこのフィールドに適用できます。

UINT16 productID;  

オファーのコンテンツが表すファームウェアのマイルストーン。 マイルストーンには、EV1 ビルド、EV2 ビルドなど、HW ビルドのさまざまなバージョンがあります。 マイルストーンの定義と値の割り当ては開発者に任されます。

UINT8 milestone : 3;

ファームウェアが特定のバンクを対象としている場合、2 ビット フィールドは 4 つのバンクをサポートします。 ターゲット デバイスがバンクファームウェアリージョンを使用するインスタンスがあるため、銀行レジスタの使用はオファーの形式に含まれます。

その場合、オファーが使用中の銀行を更新することを意図していた場合、ターゲットに CFU を実装するファームウェアはオファーを拒否できます。 それ以外の場合、CFU を実装するターゲット上のファームウェアは、保証どおりに他のアクションを実行できます。

ファームウェア イメージのバンク処理がエンド ユーザー ファームウェアの設計にない場合は、このフィールドを無視するのが妥当です (便利な値に設定しますが、バンク フィールドの値は省略可能であり、オン ターゲット ファームウェアが CFU を実装する方法によって異なります)。

UINT8 bank : 2;

使用される CFU プロトコルのプロトコル バージョンは 4 ビットです。

UINT8 protocolRevision : 4;

このファームウェア イメージが操作できるすべての一意の HW に対応するビットマスク。 たとえば、オファーは HW の verX で実行できるが、HW の verY では実行できない可能性があることを示している可能性があります。 ビット定義と値の割り当ては開発者に任されます。

UINT32 hwVariantMask;

提供されているファームウェアのバージョン。

UINT32 version;

オファーを作成するユーザー固有のソフトウェアを識別するバイト トークン。 これは、同じ実行中のファームウェアを更新しようとしている可能性があるドライバーとツールを区別するためのものです。 たとえば、CFU 更新プログラム ドライバーにはトークン 0xAが割り当てられ、開発アップデーター ツールが0xB割り当てられる場合があります。 これで、実行中のファームウェアは、更新しようとしているプロセスに基づいて、コマンドを受け入れるか無視するかを選択できるようになりました。

UINT8 token;

ファームウェア更新プログラムを適用するデバイス内のコンポーネント。

UINT8 componentId;

オファー解釈フラグ: in situ ファームウェアでバージョンの不一致 (新しいバージョンよりも古いバージョン) を無視する場合は、ビットを強制的に [バージョンの無視] に設定します。

UINT8 forceIgnoreVersion: 1;

即時リセットの強制は、1 ビットでアサートされます。 そのビットがアサートされた場合、ホスト ソフトウェアは in situ ファームウェアによってデバイスがリセットを実行することを期待します。 リセットのアクションはプラットフォーム固有です。 デバイスのファームウェアは、新しく更新されたファームウェアをアクティブな現場ファームウェアにするためにバンクをスワップするアクションを実行することを選択できます。 または次の値ではない. ファームウェアの実装に任されています。 通常、強制即時リセットがアサートされた場合、新しいバンクが更新されてターゲット デバイスで実行されているアクティブなファームウェアになるようにファームウェアを作成するために必要な操作がデバイスで実行されることが期待されます。

UINT8 forceImmediateReset : 1;

オファーとコンテンツのペアのコンテンツ部分がコンテンツの複数の部分を含む場合。

UINT8 segmentNumber;

オファーの処理

ProcessCFWUOffer API は、次の 2 つの引数を受け入れます。

void ProcessCFWUOffer(FWUPDATE_OFFER_COMMAND* pCommand,
                     FWUPDATE_OFFER_RESPONSE* pResponse)

このユース ケースでは、ユーザー ソフトウェアが実行中のファームウェアにデータ バイトを送信し、最初のメッセージがオファー メッセージであるとします。

オファー メッセージは、上で説明した 16 バイトのメッセージ (FWUPDATE_OFFER_COMMAND構造体) です。

そのオファー メッセージは、実行中のファームウェアがオファーを処理するために使用するデータです。

オファーの処理中に、実行中のファームウェアは FWUPDATE_OFFER_RESPONSE 構造体のフィールドに値を設定することによって送信者に通知します。

オファーの解釈

実行中のファームウェアは、CFU プロセスでその状態を追跡する必要があります。 オファーの受け入れ、CFU トランザクションの途中、またはアクティブ/非アクティブファームウェア間のバンクのスワップを待機している可能性があります。

実行中のファームウェアが CFU トランザクションの途中にある場合は、このオファーを受け入れる/処理せず、それに応じてホストに通知してください。

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

オファーのコンポーネント ID フィールドは、実行中のファームウェアから特別なアクションが要求されたことを実行中のファームウェアに通知するために使用できます。 CFU コード例では、ホストによって特別オファー コマンドが使用され、CFU エンジンの状態 (実行中のソフトウェアが 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;
       }
   }

最後に、銀行スワップが保留中の場合、チェックが作成されます。 銀行スワップとは、実行中のアクティブなアプリケーションから新しくダウンロードしたイメージに切り替える処理中かどうかに関する情報を保持するファームウェアを指します。

銀行の切り替えを実行する方法と場所は、埋め込みファームウェアの実装固有のタスクです。 CFU プロトコルとプロセスを使用すると、CFU を実行しているリモート ユーザー アプリケーションと実行中の in situ ファームウェアの間で情報を交換できます。

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

最後に、実行中のファームウェアの状態がビジーでなく、componentId が特別なコマンドではなく、保留中の銀行スワップがない場合は、このオファーを処理できます。

オファーの処理には、次の 4 つの手順が含まれますが、これに限定されません。

手順 1 - 銀行を確認する

実行中のアプリケーションの銀行をオファー内の銀行に確認します。 それらは同じですか、それとも異なりますか?

同じ場合は、オファーを拒否します (実行中またはアクティブなイメージは上書きしません)。

それ以外の場合は続行します。

手順 2 - hwVariantMask を確認する

実行中のファームウェアは、オファー内の hwVariantMask を、それが実行されている HWと照合してチェックします。 これにより、埋め込みファームウェアは、ターゲットに対してオファーが無効な場合にオファーを拒否できます。 (たとえば、実行中のファームウェアが古い HW ビルド上にあり、新しく提供されるファームウェアが新しい HW ビルド用である場合、実行中のファームウェアはこのオファーを拒否する必要があります)

無効な場合は、オファーを拒否します。

それ以外の場合は続行します。

手順 3 - ファームウェアのバージョンを確認する

提供されているファームウェア コンテンツのバージョンに、現在のアプリケーション ファームウェアより古いバージョンまたは新しいバージョンがあるかどうかを確認します。

どのファームウェアが別のファームウェアよりも大きいかをチェックする方法と、オファーの 'forceIgnoreVersion' フィールドの使用を許可するかどうかは、ユーザーの実装に任されます。 一般的なファームウェア開発では、'forceIgnoreVersion' フィールドを製品の開発中およびデバッグ バージョンのファームウェアで使用できますが、製品/リリース ファームウェアでは許可されません (古いファームウェアを新しいファームウェア上で更新することはできません)。

このチェック失敗した場合は、オファーを拒否します。

それ以外の場合は続行します。

手順 4 - オファーを受け入れる

オファーは良いです。 メッセージと状態がファームウェアによってリモート ユーザー アプリケーションに返される方法に合わせて調整された応答でオファーを受け入れます。 いわゆる "応答" はデータ (デモンストレーション ヘッダー ファイルに示すようにパックされたデータ構造) であり、このデータはデバイスの適切な手段によってユーザー アプリケーションに書き出されます。

コンテンツを処理する

通常、コンテンツの処理は複数ステップのプロセスです。 複数の手順は、データの "ブロック" とも呼ばれる部分でファームウェア イメージを受け入れるファームウェアの機能を指します。 埋め込みファームウェアにイメージ全体を一度に送信できるわけではありません。そのため、CFU プロトコルとプロセスの実装が小さな部分でコンテンツを受け入れることを期待するのが現実的です。

この説明では、CFU コンテンツのプロセスを記述するときに想定を使用します。

コンテンツ処理のステート マシンには、3 つの状態が含まれます。

  1. 最初のブロックを処理する状態。

  2. 最後のブロックを処理している状態。

  3. 最初と最後の間の任意のブロックを処理する状態。

コンテンツコマンドの構造

オファーと同様に、コンテンツには、デモンストレーションで CFU アルゴリズムによって使用されるフィールドを含む構造があります。

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

コンテンツ コマンドの構造は、オファーの構造よりも簡単です。 コンテンツは、メモリに書き込まれるバイトシーケンスとして定義されます。 コンテンツのプリアンブルは、この構造体のフィールドです。

  1. UINT8 flags コンテンツ "ブロック" が最初、最後、またはその他であるかどうかを示します。

  2. フィールドUINT8 length の長さをマします pData 。 CFU のデモ コードでは、サイズの pData 制限は 255 バイトです。 その他の実装では、"ブロック" の最大サイズが異なる場合があります。

  3. UINT16 sequenceNumber ブロックが送信されているインデックス カウンターをコンテンツとしてマークします。

  4. UINT32 address ブロックのアドレス オフセット。 このリリースの CFU のデモでは、実装には、各アプリ リージョンの物理アドレスに関する定義済みの情報があります。 たとえば、2 バンクのファームウェア実装では、App1 がアドレス 0x9000 で始まり、App2 がアドレス 0xA0000で始まる場合があります。 そのため、ファームウェア イメージの準備方法 (S レコード) によっては、SREC 内のアドレスが物理アドレスまたはオフセットのいずれかになります。 いずれの場合も、コンテンツの準備と CFU コンテンツ処理の実装固有のルーチンの間で、ブロックをメモリに書き込む場所の実際の物理アドレスを決定する際に、共通の理解が必要です。 ベスト プラクティスを採用し、各コンテンツ ブログの有効なアドレス範囲に対してチェックを行うには、ファームウェア開発者に任されています。 たとえば、CFU コードは、おそらく App1 ( 0x9000を意味する) に App2 と重複するアドレスがあるかどうかのチェックを示しています。

  5. UINT8 pData[MAX_UINT8] - ファームウェア イメージ ブロックの生バイトです。 ユーザー アプリケーションでは、コンテンツ ブロックの完全なバイト ストリームに length バイトのみを入れるように注意してください。

提供されたコードの CFU デモに従って、コンテンツ構造で使用されるビット フィールドはありません。

最初のブロック

最初のブロックは、ファームウェアの内容のダウンロードを開始します。 実行中のファームウェアは、ブロックを不揮発性メモリに書き込もうとします。 もちろん、コンテンツ "ブロック" には、メモリ内のブロックを書き込む場所、書き込むデータの量、およびその他のフィールドに関する情報が含まれています。

各 componentID ターゲット デバイスは異なり、データをメモリに保持する方法は複数あります。 たとえば、ある componentId が内部フラッシュへの書き込みを必要とする場合、別の componentId が外部 SPI フラッシュに書き込む場合や、別の IC の I2C プロトコルを使用してそのイメージを更新する場合があります。 このドキュメントに含まれるデモでは ICompFwUpdateBspWrite と呼ばれる関数の使用法を強調しています。各固有のファームウェアは、設計対象のターゲットの基礎となる不揮発性メモリ I/O 関数を認識して実装する必要があります。

最初または最後を除く他のブロック

新しいブロックを受け入れるプロセスは、ユーザー アプリケーションが別のブロックを配信するときに続行されます。また、ブロックの書き込み先のアドレス、含まれるバイト数、およびその他のフィールドのメタデータがメッセージに含まれます。

in situ ファームウェアでは、これは最初のブロック シナリオと同じように扱われます。

ただし、システムがブロックをキャプチャしてメモリに保持できない場合はいつでも、エラー コードで応答するのは in situ ファームウェアにかかっていることを確認する必要があります。

最後のブロック

最後のブロックは、in situ ファームウェアがメモリに書き込まれたイメージを検証するためにタスクを実行する必要がある場合にのみ、チャレンジを提示します。

最初に、最後のブロックがメモリに書き込まれます。

次に、少なくとも、メモリに既に書き込まれているデータ (最初から最後のブロック) と最後のブロックの CRC フィールドとの間に CRC チェックを作成する必要があります。 ダウンロードしたイメージの CRC を取得する方法を知るために、各実装ファームウェアに任されます。

CRC チェックの実行には時間がかかることに注意してください。 オファーとブロックの送信に対する CFU の実行の通常のフローとは異なります。 最後のブロック送信には、CRC チェックが含まれている場合、CRC チェックがメモリの大きな領域を調べている可能性があるという事実に対して、一定の遅延が発生します。 ターゲット デバイスやその他の要因によっては、これは問題にならない可能性があります。

重要

受信イメージの CRC チェックは省略可能であり、コメント アウトできます。ただし、少なくともこのチェックを採用するには、ベスト プラクティスを実施する必要があります。 CFU プロセスのこの時点で、ダウンロードしたイメージの整合性を確保するために他のアクションを実行することを強くお勧めします。 これらのアクションの一部には、イメージの "署名済み" 部分の検証や、信頼の証明書チェーンのチェック、またはセキュリティで保護されたファームウェア イメージを確保するためのその他のベスト プラクティスアプローチが含まれます。 これらはファームウェア開発者に任されています。

最後のブロックの後にクリーンアップする

最後のブロックが書き込まれ、CRC チェックが完了したら、検証の一部が失敗した場合にファームウェアがエラーで応答する可能性があります。

それ以外の場合は、ファームウェア内の CFU プロセスが正常な状態で応答することが期待されます。

強制リセットチェック

オファーの強制リセット フラグは、ターゲットの MCU がリセット (ユーザー定義のリセット) を受けるかどうかを判断するために使用されます。

通常、リセットが強制されると、MCU がリセットを実行して、アプリ バンクが切り替わります。 リセット時に起動するファームウェア イメージを示す永続的変数の更新は、ファームウェア開発者に任されます。