Skip to content

OTAの活用(アーカイブ)

Hiroki Ishiguro edited this page Jun 16, 2020 · 1 revision

はじめに

  • 本稿ではAmazon FreeRTOSのOTA機能を活用するために必要な情報をまとめます。
  • 本稿は新ページに移行しました。
    • 以降本稿はアップデートされません。(2020/06/14更新停止)
  • 本稿はAmazon FreeRTOS V1.4.7向けに作られており、最新版とは異なる内容が含まれます。
  • 以降説明では「ですます調」でなくなります。

メモを書いている人

ブートローダの構築

ブートローダとは?

  • システム起動時に以下機能を提供するもの

    1. システムのファームウェアが破損していないかをチェックする機構
    2. システムのファームウェアが破損していた場合それを自動的に復旧する機構
    3. システムのファームウェアが正しい状態であることを確認し、選択的にシステムのファームウェアをロードし起動する機構
  • Amazon FreeRTOS Qualification Developer Guideにブートローダが備えるべき要件がまとめられている

ブートローダに求められる要件(Amazon FreeRTOS Qualification Developer Guideより)

  1. The bootloader shall be stored in non-volatile memory so it cannot be overwritten.
  2. The bootloader shall verify the cryptographic signature of the downloaded application image. Signature verification must be consistent with the OTA image signer. See Appendix I: OTA Updates for supported signatures.
  3. The bootloader shall not allow rolling back to a previously installed application image.
  4. The bootloader shall maintain at least one image that can be booted.
  5. If the MCU contains more than one image then the image that is executed shall be the latest (newest). The newest version can be determined based on implementation, for example a user defined sequence number, application version etc. As per other requirements, this can only be the case until a newer version has been verified and proven functional.
  6. If the MCU cannot verify any images then it shall place itself into a controlled benign state. In this state it prevents itself from being taken over by ensuring no actions are performed.
  7. These requirements shall not be breached even in the presence of an accidental or malicious write to any MCU memory location (key store, program memory, RAM, etc.)
  8. The bootloader shall support self-test of a new OTA image. If test execution fails, the bootloader shall roll back to the previous valid image. If test execution succeeds, the image shall be marked valid and the previous version erased.

要約

  1. ブートローダは不揮発性メモリに格納され、上書きできてはいけない
  2. ブートローダはダウンロードしたアプリケーションイメージに対して電子署名を用いて検証しなければならない。電子署名はOTA image signerと互換である必要がある。詳しくはAppendix I: OTA Updatesを参照。
  3. ブートローダは直前にインストールされていたアプリケーションにロールバックできてはいけない
  4. ブートローダは少なくとも1個のイメージでブートできるようシステムを維持できなければならない
  5. もしMCUが1個以上のイメージを持つ場合、起動できるイメージは最新のものでなければならない。バージョン選択は実装依存であり、それはたとえばユーザ定義のシーケンス番号であったりアプリバージョンであったりする。ただし、バージョン選択できるのは、最新のイメージが確定するまでの間である。
  6. もしMCUがイメージの検証に失敗する場合であっても正しく制御された"検証が失敗した"状態を維持できなければならない。この状態においては何ら有効な動作が行われない状態となり、そこから遷移できてしまってはいけない。
  7. これらの要件は事故や悪意のあるコードなどによる不正ROM書き換えによって妨げられてはならない。
  8. ブートローダは新しいOTAイメージに対しセルフテストを行えなければならない。このセルフテストが失敗するならば、ブートローダは直前の正常なイメージにロールバックできなければならない。もしセルフテストに成功するならば、ブートローダは直前の正常なイメージを削除し、新しいOTAイメージを正常なイメージと認識するようマークすることができる。

RX65Nでの実装方針(要件との照らし合わせ)

  1. ブートローダは不揮発性メモリに格納され、上書きできてはいけない
    • 不揮発性メモリに格納される:OK
    • 上書きできてはいけない:OK。
      • 0xFFEC0000-0xFFFFFFFF を Flash Access Window(FAW) でセルフプログラミング禁止にしておけば良い
      • さらに、FAW レジスタの書き換えを禁止する、FSPR (アクセスウィンドウプロテクトビット)をセットすれば buffer 以外が書き換え禁止になる。
      • この設定を行うと、そのチップはブランク状態に戻せなくなるので要注意
 +----------------------+----------------------+ 0xFFE00000+--------+---------------+
 |                      |  buffer              | <768KB>   |        | not protected |
 |  temporary area      +----------------------+ 0xFFEC0000| bank1  +---------------+
 |                      |  Bootloader(mirror)  | <256KB>   |        |               |
 +----------------------+----------------------+ 0xFFF00000+--------+               |
 |                      |  user application    | <768KB>   |        | protected     |
 |  execute area        +----------------------+ 0xFFFC0000| bank0  |               |
 |                      |  Bootloader          | <256KB>   |        |               |
 +----------------------+----------------------+ 0xFFFFFFFF+--------+ --------------+
  1. ブートローダはダウンロードしたアプリケーションイメージに対して電子署名を用いて検証しなければならない。電子署名はOTA image signerと互換である必要がある。詳しくはAppendix I: OTA Updatesを参照。
    • ブートローダはダウンロードしたアプリケーションイメージに対して電子署名を用いて検証しなければならない: OK。以下2ケースを想定。
      • case1: Amazon Web Services を使用する際はOTA image signer互換 (ECDSA + SHA256)
      • case2: Amazon Web Services を使用しない場合は独自形式 (SHA256)
        • ファームウェアの暗号化について追って実装する必要あり。
  2. ブートローダは直前にインストールされていたアプリケーションにロールバックできてはいけない
    • ブートローダは直前にインストールされていたアプリケーションにロールバックできてはいけない: OK
  3. ブートローダは少なくとも1個のイメージでブートできるようシステムを維持できなければならない
    • ブートローダは少なくとも1個のイメージでブートできるようシステムを維持できなければならない: OK
  4. もしMCUが1個以上のイメージを持つ場合、起動できるイメージは最新のものでなければならない。バージョン選択は実装依存であり、それはたとえばユーザ定義のシーケンス番号であったりアプリバージョンであったりする。ただし、バージョン選択できるのは、最新のイメージが確定するまでの間である。
    • もしMCUが1個以上のイメージを持つ場合、起動できるイメージは最新のものでなければならない: OK
    • バージョン選択は実装依存であり、それはたとえばユーザ定義のシーケンス番号であったりアプリバージョンであったりする。ただし、バージョン選択できるのは、最新のイメージが確定するまでの間である。: OK
      • 1個しかイメージが入らない。選択式になってないため、常に最新のものが起動される。将来ダウンロードデータフォーマットのSequence Numberを活用し、1個前のイメージのSequence Numberより大きなSequence Numberを持つイメージでないと、受け付けないように改良する見込み。このときSequence Numberはより強固に守るため、セキュリティIPと連動すると尚良い。現状はそこまで市場要求が高まってないと思われるため、フレームだけ用意して未実装とする。
  5. もしMCUがイメージの検証に失敗する場合、検証に成功するイメージを選択する状態に戻らなければならない。イメージの検証に失敗する状態が継続されてはならない。
    • もしMCUがイメージの検証に失敗する場合、検証に成功するイメージを選択する状態に戻らなければならない: OK
    • イメージの検証に失敗する状態が継続されてはならない: OK
  6. これらの要件は事故や悪意のあるコードなどによる不正ROM書き換えによって妨げられてはならない。
    • これらの要件は事故や悪意のあるコードなどによる不正ROM書き換えによって妨げられてはならない: OK
  7. ブートローダは新しいOTAイメージに対しセルフテストを行えなければならない。このセルフテストが失敗するならば、ブートローダは直前の正常なイメージにロールバックできなければならない。もしセルフテストに成功するならば、ブートローダは直前の正常なイメージを削除し、新しいOTAイメージを正常なイメージと認識するようマークすることができる。
    • ブートローダは新しいOTAイメージに対しセルフテストを行えなければならない: OK
    • このセルフテストが失敗するならば、ブートローダは直前の正常なイメージにロールバックできなければならない: OK
    • もしセルフテストに成功するならば、ブートローダは直前の正常なイメージを削除し、新しいOTAイメージを正常なイメージと認識するようマークすることができる: <<セルフリセットが2回必要なので敢えてのNG:今後Amazonと議論したい>>
    • セルフテストでOTA動作を確認しないと、ファームウェアの更新はできたがOTA機能が正しく動かない=以降アップデート不可、という状態を作り込んでしまう可能性がある。従って、ブートローダはTESTING状態を確認した後、いったんユーザアプリに制御を渡し、ユーザアプリ側のAmazon FreeRTOS OTAライブラリ内のOTA Taskによってセルフテストが実行され、そこでOKになったらようやく状態がVALIDになる恰好となる。
    • 通しの状態遷移は以下の通り <<Amazonの言う通り実装した場合(仮の実装の話)>>
      • VALID状態でOTA動作、新ファームウェアのライフサイクルはTESTING、この状態で <<セルフリセット=1回目>> しブートローダに制御を渡す
      • TESTING状態でファームウェア正当性確認を行い、問題なければTESTING状態のまま、ユーザアプリに制御を渡す
      • TESTING状態でユーザアプリはAmazon FreeRTOS OTAライブラリを起動するとOTAライブラリがセルフテストを行い成功すればTESTING2状態に変更し <<セルフリセット=2回目>> を行う
      • ブートローダはTESTING2状態でファームウェア正当性確認を行い、問題なければVALID状態に変更し、旧ファームウェアを削除し、ユーザアプリに制御を渡す(最初に戻る)
        • この動作は実現は可能と思われるが、システム上最適な動作かというとセルフリセットが2回も発生し疑問が残るため、以下<<Renesas実装(実際の実装の話)>>での実装とした
    • 通しの状態遷移は以下の通り <<Renesas実装(実際の実装の話)>>
      • VALID状態でOTA動作、新ファームウェアのライフサイクルはTESTING、この状態で <<セルフリセット=1回目>> しブートローダに制御を渡す
      • TESTING状態でファームウェア正当性確認を行い、問題なければVALIDに変更し、旧ファームウェアを削除し、ユーザアプリに制御を渡す
      • VALID状態でユーザアプリはAmazon FreeRTOS OTAライブラリを起動するとOTAライブラリがセルフテストを行い成功すればそのままシステム稼働する(然るべき手段でユーザがシステムリセットする。正しく電源OFFするとか)
<<ブートローダ/ファームウェアイメージが保有するファームウェアイメージの状態>>
#define LIFECYCLE_STATE_BLANK		(0xff)
#define LIFECYCLE_STATE_TESTING		(0xfe)
#define LIFECYCLE_STATE_INSTALLING	(0xfc) // 本フラグの説明は今後掲載予定。ブートローダとユーザアプリを合成したMOTファイルを一括ダウンロードしたときの初期状態。うまく整合すればLIFECYCLE_STATE_VALIDに遷移する
#define LIFECYCLE_STATE_VALID		(0xf8)
#define LIFECYCLE_STATE_INVALID		(0xf0)

RX65Nでの実装方針(前提条件おさらい)

フラッシュメモリの仕様おさらい

  • RX65N世代以降は、フラッシュメモリのコードフラッシュ領域はデュアルバンク機構を備えており、物理メモリ量2MB(max)を2分割できる
    • 以降の例では物理メモリ量は2MBを前提に説明する(実際はROM容量1.5MB版などもあるので自分が使用するマイコンのROM容量を正しく認識すること)
  • RX65Nではこのモードを「デュアルモード」と呼称している
  • 「デュアルモード」では、「バンクスワップ」と呼ばれる機能を使うことができる
  • 本稿では、以下のようにバンク面を定義する。bank0は実行面(execute area)、bank1はバッファ面(temporary area)である。
 +---------------------------------+ 0xFFE00000 +
 |                                 |            |
 |       temporary area            |            | bank1
 |                                 |            |
 +---------------------------------+ 0xFFF00000 +
 |                                 |            |
 |       execute area              |            | bank0
 |                                 |            |
 +---------------------------------+ 0xFFFFFFFF +
  • バンクスワップを実行すると(具体的にはフラッシュAPIのR_FLASH_Control()でバンクスワップコマンドを発行した後にリセット)、bank0にあるコードとbank1にあるコードがスワップ(入れ替わる)する。
  • これにより、execute areaでファームアップデート動作(インターネット経由でのイメージのダウンロードなど)を行い、temporary areaにイメージを書き込み、仕上がったらバンクスワップすることで、ファームウェアアップデート動作が実現できる
  • temporary areaへの新しいファームウェアイメージのダウンロード後にイメージの正当性検証を行い正しければソフトウェアリセットを実行、その後ブートローダが起動しブートローダがexecute areaにスワップされてきた新しいファームウェアイメージを検証し、正しければ起動する。(古いイメージがtemporary areaに残っているので削除する)

フラッシュメモリの仕様おさらい: 補足①

  • このスワップ動作がない場合は、bank0用のファームウェア、bank1用のファームウェアといった形でコンパイル時にどちらのバンク用のファームウェアなのかを識別して管理する必要があった
  • 常にexecute area面で実行することを制限にすることで、この管理が不要となる
  • デュアルバンク機構は、1チップでファームウェアアップデートを実現するための常套手段である
  • 1チップでファームアップデートを実現する場合、新しいイメージを格納しておくためのバッファ領域がチップ内で必要となり、多くの場合はこれまでに説明した通り、「物理メモリ容量の半分をバッファとして使用する」
    • RX65Nは最大2MBのROM容量があるが、ユーザが使用できる量は1MBであることに注意
    • ファームウェアアップデート機能をワンチップで実現する場合は、この点を最初に認識する必要がある
    • 外部シリアルフラッシュ・EEPROM等のストレージを配するための部品代に制約がないならばこの限りではない
      • むしろ、元から外部シリアルフラッシュ・EEPROMを持ったシステムのMCU部にファームウェアアップデート機能を追加するケースにおいては、RX65Nのようにデュアルバンク機構をもったMCUであったとしても、バッファ領域を外部シリアルフラッシュ・EEPROMとし、MCU内部フラッシュメモリを全面ユーザ領域とするのが健全であろう

フラッシュメモリの仕様おさらい: 補足②

  • 従来のフラッシュメモリ内蔵マイコンは、フラッシュメモリ書換時にはRAMにファームウェア書換動作を行うプログラムを配置し、RAMにプログラムカウンタを飛ばし、RAM上からフラッシュメモリ書換コマンドを実行しなければならなかった
  • このため、システム動作を維持したままフラッシュメモリを書き換えることは非常に難しかった
  • RX65Nのようにバンク構造を持つフラッシュメモリ内蔵マイコンでは、BGO(バックグラウンドオペレーション)機能により、この問題を回避できる製品が存在する
  • BGO機能を使うことで、例えばbank0にbank1に対するファームウェア書換動作を行うプログラムを配置し実行することが可能となる
  • このとき、割り込みベクタおよび割り込みベクタのジャンプ先にある割り込み処理関数もすべてbank0に配置しておけば、システム動作を維持したままフラッシュメモリを書き換えることが非常に容易となる

ブートローダとファームウェアアップデート機構

  • ファームウェアアップデート機構には以下2大処理が必要である
    1. ブートローダ機構(起動時のファームウェア正当性確認など)
    2. ファームウェアダウンロード&書換機構
  • ブートローダ動作は、ユーザアプリ起動前に行われる
  • ファームウェアダウンロード&書換動作は、ユーザアプリ起動中に行われる
  • ブートローダとユーザアプリはそれぞれ独立していなければならない(依存関係があってはならない)
  • ブートローダ用のプロジェクトと、ユーザアプリ用のプロジェクトを分割して作る必要がある
  • 依存関係は、ブートローダ動作完了時にユーザアプリにジャンプする命令とその引数であるユーザアプリのエントリポイント(疑似リセットベクタ)にのみ存在する
    • この依存関係も、絶対アドレス指定で固定とし、これ以外のプロジェクト間の依存関係は排除しておく
  • ここまではブートローダは「ブート時」の動作を規定する説明をしてきたが、もうひとつ、ブートローダは初期ファームウェアの「ロード時」の動作も担う

メモリマップ定義

  • ファームウェアアップデート機構を実現するためのRX65Nのメモリマップを以下のように定義する
  • contents は初期状態(ブランクチップ)ではblankとし、以降説明時に何かを書き込んだ場合、contents部分が新しいデータ名に置き換わる
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  contents            | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  contents            | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  contents            | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  contents            | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  • ブートローダ用の256KBはブート時に実行したい処理に依存するため、ユーザ依存である
  • 256KBは相当余裕のある数値であるが、ネットワーク経由の初期ファームロードを考える場合はAmazon FreeRTOSなどのネットワークスタックをブートローダに入れなければならずその場合は不足するかもしれない
  • 逆にネットワークロードが不要で、初期ファームウェアのロード時にUARTを使う場合は少ない容量(16KB等)で済む場合もある
  • 本稿ではネットワーク経由の初期ファームロードも想定に入れているため、その動作に十分な256KBとした
    • (実際は現状最も採用頻度の高いと思われるUARTによる初期ファームウェアのロードを実現しており、256KB中の32KB程度の容量しか使っていない)
  • この場合、ユーザアプリが使用できるROM容量は768KBとなる。Amazon FreeRTOSはこの768KB側に格納される
  • Bootloader(mirror)というのは、バンクスワップ後にbank0とbank1の内容が入れ替わったあとでも、まったく同じBootloaderが動作するようにするために必要な部分である
    • マイコンとしてのリセットベクタが0xFFFFFFFCであるため、バンクスワップ動作に備えてbank0とbank1の下位エリアには同じBootloaderを仕込んでおく必要がある
  • user application の先頭0x300バイトはBootloaderがuser applicationを検証するための署名データ等を入れる領域のため、user applicationの開始アドレスは0x300バイト後方にずらしてセクション設定を行う必要がある
  • ブートローダは本来immutable(不変)であるべきだが、ブートローダに不具合があり更新したいケースと相反する
    • この課題の暫定対策は以下のいずれかと考えられる
      • セキュリティ要件であるimmutable(不変)を諦めてブートローダを更新できる仕組みを入れる
      • 市場投入後に不具合が発生しない程度のシンプルなブートローダ機能に留める(ネットワークスタック等はブートローダに入れ込まない、等)
    • この課題の恒久対策は以下と考えられる
      • マイコン機能として以下をハードウェア実装する
        • ユーザ指定の特定領域の署名検証機能および署名値の更新機能
        • ユーザ指定の署名検証用公開鍵のマイコンへの登録(書込み)機能

ファームウェア書き込み順序

  1. ブランクチップを用意する
  2. BootloaderをROMライタで書き込む
  3. Bootloaderを実行し、Bootloader(mirror)をセルフプログラミングでコピー
  4. Bootloaderのロード機能を使用し、temporary areaにinitial firmwareを書き込みソフトウェアリセット
  5. Bootloaderがtemporary areaのinitial firmwareが正しいことを検証する
  6. ソフトウェアリセットを発行し、バンクスワップする
  7. bank0に再配置されたBootloader(mirror)がbank0に再配置されたtemporary areaにあるinitial firmwareが正しいことを検証する
  8. FAWによって、Bootloader(mirror), user application, Bootloaderにロックをかける。フラッシュAPIのR_FLASH_Control()でできる。このとき、FSPR "0" を書けばFAWが永久にロックされる。危険なのでユーザがソースコードの該当行を書き換えて使用することにしている。 FSPRの設定変更のためのコード:link
  • 具体的な変更方法
    • r_flash_type4.cの「faw.BIT.FSPR = 1;」を「faw.BIT.FSPR = 0;」にする
    • ブートローダにおいてBootloader(mirror)のコピーが終わったところで、フラッシュAPIのR_FLASH_Control()でFAWレジスタ設定を行う⇒この時点でロックがかかる
  • FAWの意味合い
    • FAW=Flash Access Windowの略。「アクセスできる窓」という意味であり、FAWの対象範囲「外」がロック対象となる。
    • つまり、FAWに設定すべきは、buffer領域である。
  • バンクスワップするとFAWの設定範囲もスワップされるのではないか?
    • されない。
    • 例えば下図において、FAWに0xFFE00000-0xFFEC0000を設定しバンクスワップしても、FAWは0xFFE00000-0xFFEC0000のまま。
  1. Bootloader(mirror)がinitial firmwareにジャンプする(initial firmwareが起動する)
  2. initial firmwareがtemporary areaにnext firmwareを書き込む
  3. initial firmwareがtemporary areaのnext firmwareが正しいことを検証する
  4. ソフトウェアリセットを発行し、バンクスワップする
  5. bank0に再配置されたBootloaderがbank0に再配置されたnext firmwareが正しいことを検証し、bank1に残っているinitial firmwareを消去する <ロールバック禁止はセキュリティ要件であるので、セキュリティを気にしない場合は古いファームウェアを残しておいてもよいが非推奨>
  6. Bootloaderが次期ファームウェアにジャンプする(next firmwareが起動する)
  7. 以下繰り返し

ファームウェア書き込み順序(図解)

  1. ブランクチップを用意する
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  blank               | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  blank               | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  blank               | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  blank               | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. BootloaderをROMライタで書き込む
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  blank               | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  blank               | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  blank               | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. Bootloaderを実行し、Bootloader(mirror)をセルフプログラミングでコピー
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  blank               | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  Bootloader(mirror)  | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  blank               | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. Bootloaderのロード機能を使用し、temporary areaにinitial firmwareを書き込みソフトウェアリセット
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  initial firmware    | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  Bootloader(mirror)  | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  blank               | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. Bootloaderがtemporary areaのinitial firmwareが正しいことを検証する
  2. ソフトウェアリセットを発行し、バンクスワップする
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  blank               | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank0
 |                      |  Bootloader(mirror)  |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  initial firmware    | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank1
 |                      |  Bootloader          |  Bootloader(mirror)  | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. Bootloader(mirror)がinitial firmwareを検証する
  2. FAWによって、Bootloader(mirror), user application, Bootloaderにロックをかける。フラッシュAPIのR_FLASH_Control()でできる。このとき、FSPR "0" を書けばFAWが永久にロックされる。危険なのでユーザがソースコードの該当行を書き換えて使用することにしている。 FSPRの設定変更のためのコード:link
  • 具体的な変更方法
    • r_flash_type4.cの「faw.BIT.FSPR = 1;」を「faw.BIT.FSPR = 0;」にする
    • ブートローダにおいてBootloader(mirror)のコピーが終わったところで、フラッシュAPIのR_FLASH_Control()でFAWレジスタ設定を行う⇒この時点でロックがかかる
  • FAWの意味合い
    • FAW=Flash Access Windowの略。「アクセスできる窓」という意味であり、FAWの対象範囲「外」がロック対象となる。
    • つまり、FAWに設定すべきは、buffer領域である。
  • バンクスワップするとFAWの設定範囲もスワップされるのではないか?
    • されない。
    • 例えば下図において、FAWに0xFFE00000-0xFFEC0000を設定しバンクスワップしても、FAWは0xFFE00000-0xFFEC0000のまま。
  1. Bootloader(mirror)がinitial firmwareにジャンプする(initial firmwareが起動する)
  2. initial firmwareがtemporary areaにnext firmwareを書き込む
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  next firmware       | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank0
 |                      |  Bootloader(mirror)  |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  initial firmware    | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank1
 |                      |  Bootloader          |  Bootloader(mirror)  | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. initial firmwareがtemporary areaのnext firmwareが正しいことを検証する
  2. ソフトウェアリセットを発行し、バンクスワップする
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  initial firmware    | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  Bootloader(mirror)  | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  next firmware       | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. Bootloaderがnext firmwareを検証し、temporary areaに残っているinitial firmwareを消去する <ロールバック禁止はセキュリティ要件であるので、セキュリティを気にしない場合は古いファームウェアを残しておいてもよいが非推奨>
 +----------------------+----------------------+----------------------+ 0xFFE00000-
 |                      |  buffer              |  blank               | <768KB>   |
 |  temporary area      +----------------------+----------------------+ 0xFFEC0000| bank1
 |                      |  Bootloader(mirror)  |  Bootloader(mirror)  | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFF00000-
 |                      |  user application    |  next firmware       | <768KB>   |
 |  execute area        +----------------------+----------------------+ 0xFFFC0000| bank0
 |                      |  Bootloader          |  Bootloader          | <256KB>   |
 +----------------------+----------------------+----------------------+ 0xFFFFFFFF-
  1. Bootloaderが次期ファームウェアにジャンプする(next firmwareが起動する)
  2. 以下繰り返し(9に戻る)

電源断対策

  • ブートローダの重要要件として、イメージの正当性検証がある
  • イメージが壊れたまま実行すると、壊れた命令をCPUが取り込み不正命令実行割り込みが起きてシステムが停止するためである
  • この対策として、システム起動時にイメージ全体の署名を検証(またはハッシュチェック)して、1ビットたりとも間違った値になっていないことを検証しなければならない
  • 署名検証やハッシュではなく、16bit のチェックサムでOKなのでは、という誤解があるが、たとえば隣り合う16ビットが入れ替わるような壊れ方をした場合、総和自体は変わらずチェックサムが合ってしまう問題がある
  • 従ってイメージの正当性検証には署名検証やハッシュを用いることが一般的である
    • 署名検証の場合は、限られた開発者(秘密鍵を持つ者)しか署名生成が出来ないメリットがある(一方で鍵のハンドリングを考える必要があるデメリットがある)
    • ハッシュの場合は、すべての開発者がハッシュを生成できるデメリットがある(一方で鍵のハンドリングを考える必要がないメリットがある)
      • と、一長一短なので、どちらも実現できるようにする
        • Amazon Web Servicesに繋ぐときは署名検証が推奨されているので署名検証方式とする
        • Amazon Web Servicesに繋がない場合かつ鍵のハンドリングを考えない場合は、ハッシュでもよい。
          • ブートローダ自体はハッシュでも正当性検証ができるように作っておく
          • ただしこれは公開鍵系暗号の概念を理解していない初心者向け、または公開鍵系暗号の概念を理解した上でセキュリティ実装にコストを掛けたくない上級者向けであり、基本的に非推奨

データフラッシュを用いたシステム上定数データのハンドリング

  • Amazon FreeRTOSはシステム動作中に必要になる鍵データや証明書データを不揮発性メモリに書き込むことをシステムに対し要求する
  • RXマイコンの実装ではこの要求がきたときはフラッシュAPIを使用してデータフラッシュにAmazon FreeRTOSが必要とするデータを書き込んでいる
  • このデータについても書き込み中に電源が落ちるなどのトラブル発生で壊れる可能性があるため、ハッシュ値を用いて正当性検証ができるようにしておく
  • このデータ自体は署名検証されたAmazon FreeRTOSが書き込むため、署名検証ではなくハッシュ値確認で問題ない

メモリマップ

                                                                             (section name)
+---------------------+---------------------------------------+ 0x00100000 + C_PKCS11_STORAGE
|                     | Amazon FreeRTOS PKCS const data       |   <8KB>    | 
|  const data of      +---------------------------------------+ 0x00102000 + C_PKCS11_STORAGE_MIRROR
|  user application   | Amazon FreeRTOS PKCS const data mirror|   <8KB>    | 
|                     +---------------------------------------+ 0x00104000 + 
|                     | free area for user application        |   <16KB>   | 
|---------------------+---------------------------------------+ 0x00108000 +
typedef struct _PKCS_CONTROL_BLOCK
{
    PKCS_STORAGE_CONTROL_BLOCK_SUB data;
    uint8_t hash_sha256[PKCS_SHA256_LENGTH];
} PKCS_CONTROL_BLOCK;

ダウンロードデータフォーマット

  • MOTファイルはデバイスに書き込む為の実データ以外のデータ(署名値など)を保持する機構がない
    • コメント的な機能があるようだが、規格で明確になってないので使わない
  • MOTファイル等のテキストデータの場合、バイナリと比べてデータ量が増える傾向にある
    • Amazon FreeRTOS OTAではアップデータをAWSに配してインターネット経由で量産済みのN台に配信する
    • 単純にテキストとバイナリではデータ量に2倍の重み差があるため、OTA実行時のパケット代も2倍かかることになる
    • 従って、OTAで転送するデータフォーマットはバイナリ一択である
  • ファームウェアアップデート時にファームウェアに対してSHAハッシュ値や署名値を持たせることは常套手段であるが組み込みシステム用のデータフォーマットに適切なものがないため、デファクトスタンダードが定まるか規格がなにか良いのが出てくるまで独自形式(.rsu(renesas secure update))を規定しそれを使用する
  • 以下のようなフォーマットとする。
----------------------------------------------------------------------------------------------------
output *.rsu
reference: https://docs.aws.amazon.com/ja_jp/freertos/latest/userguide/microchip-bootloader.html
----------------------------------------------------------------------------------------------------
offset              component           contents name               length(byte)    OTA Image(Signed area)
0x00000000          Header              Magic Code                  7
0x00000007                              Image Flags                 1
0x00000008          Signature           Firmware Verification Type  32
0x00000028                              Signature size              4
0x0000002c                              Signature                   256
0x0000012c          Option              Dataflash Flag              4
0x00000130                              Dataflash Start Address     4
0x00000134                              Dataflash End Address       4
0x00000138                              Image Size                  4
0x0000013c                              Resereved(0x00)             196
0x00000200          Descriptor          Sequence Number             4               ---
0x00000204                              Start Address               4                |
0x00000208                              End Address                 4                |
0x0000020c                              Execution Address           4                |
0x00000210                              Hardware ID                 4                |
0x00000214                              Resereved(0x00)             236              |
0x00000300          Application Binary                              N               --- <- provided as mot file
0x00000300 + N      Dataflash Binary                                M                   <- provided as mot file
----------------------------------------------------------------------------------------------------
Magic Code              : Renesas
Image Flags             : 0xff アプリケーションイメージは新しく、決して実行されません。
                         0xfe アプリケーションイメージにテスト実行のためのマークが付けられます。
                          0xfc アプリケーションイメージが有効とマークされ、コミットされます。
                          0xf8 アプリケーションイメージは無効とマークされています。
Firmware Verification Type
                        : ファームウェア検証方式を指定するための識別子です。
                          例: sig-sha256-ecdsa
Signature/MAC/Hash size : ファームウェア検証に用いる署名値やMAC値やハッシュ値などのデータサイズです。
Signature/MAC/Hash      : ファームウェア検証に用いる署名値やMAC値やハッシュ値です。
Dataflash Flag          : 【RX MCU特有】データフラッシュ用のデータが含まれるか否かを表すフラグです。
Dataflash Start Address : 【RX MCU特有】データフラッシュの開始アドレスです。
Dataflash End Address   : 【RX MCU特有】データフラッシュの終了アドレスです。
Image Size              : OTA Imageのバイトサイズです。
Sequence Number         : シーケンス番号は、新しい OTA イメージを構築する前に増加させる必要があります。
                         Renesas Secure Flash Programmerにてユーザが指定可能です。
                          ブートローダーは、この番号を使用してブートするイメージを決定します。
                          有効な値の範囲は 1~ 4294967295‬ です。 
Start Address           : デバイス上のOTA Imageの開始アドレスです。
                          Renesas Secure Flash Programmerが自動的に設定するため、ユーザ指定は不要です。
End Address             : イメージトレーラーを除く、デバイス上のOTA Imageの終了アドレスです。
                          Renesas Secure Flash Programmerが自動的に設定するため、ユーザ指定は不要です。
Hardware ID             : OTA Imageが正しいプラットフォーム用に構築されているかどうかを検証するために
                          ブートローダーによって使用される一意のハードウェア ID です。
                          例: 0x00000001    MCUROM_RX65N_2M_SB_64KB
  • MOT形式をRSU形式に変換するツールを作った
    • Visual Studio (C#) でデバッグ可能
    • 「MOTファイル変換ツール」と呼称
  • 課題
    • Image Size を Descriptor に入れて OTA Image(Signed area) に含めなければならない
      • 現状常にバンク全面分をROMデータ化しているが、バンク全面にコードが詰まっているケースは少なく、特にネットワーク経由でダウンロードデータを配信する場合は転送データ量を1バイトでも削減すべきであり、従って常にROMデータ長は可変であることを前提としなければならない。
      • 2020/02/21 時点ではGitHub上各種コードは修正完了していないが、Image SizeはHardware IDの次に移動するものとする(修正したら本課題の説明は削除)
    • 将来データ暗号化を考える場合、OTA Image(Signed area)のうち、Descriptor は非暗号領域としたほうがよい。
      • ∵Image Sizeは平文にしておかないと、何バイト暗号化されているか不明になるため

MOTファイル変換ツール使用方法

  1. exeファイル を実行する
    • 注意:exeファイル単体では完全動作しない。DLLが必要。実行する場合はエクスプローラでDebugフォルダまでいき、他のDLLファイルがexeファイルと同じフォルダにある状態で実行すること。
  2. "Initial Update"タブを押す (他の機能はTrusted Secure IPを使った高度なセキュアブート/アップデート機構を使いたい人向け。詳細はTrusted Secure IPドライバのマニュアル参照。Trusted Secure IPドライバはルネサス問い合わせで入手可能)
  3. Select MCU で "RX65N(ROM 2MB)/Secure Bootloader=256KB"を選ぶ
  4. Select Firmware Verification Type で 以下を選ぶ
    • "sig-sha256-ecdsa"
  5. Firmware Sequence Number で 1 を入力 (未実装。今後シーケンス番号が増えないとアップデートできない仕組みを増やす予定)
  6. Output Binary Formatのチェックを入れる:ユーザアプリケーション(署名付き)をRSUファイル(バイナリフォーマット)で出力する設定
  7. Private Key Path に OpenSSLで作成した署名生成用の楕円曲線暗号の秘密鍵ファイル(PEM形式)を指定する
  8. Boot Loader File Path にブートローダのMOTファイルを指定する
  9. File Path にユーザアプリケーションのMOTファイルを指定する
  10. Generateボタンを押して userprog.rsu を出力する
    • 参考: Output Binary Format のチェックを外すと、ブートローダとユーザアプリケーションを1枚のMOTファイルとして出力することが可能。量産工程ではこのほうが効率が良い。なぜならば1枚のMOTファイルをROMライタで書き込めばよいからである

OpenSSLでのECDSA+SHA256用の鍵ペア生成方法

  • <CA証明書の作成>
$ openssl ecparam -genkey -name secp256r1 -out ca.key
using curve name prime256v1 instead of secp256r1
$ openssl req -x509 -sha256 -new  -nodes -key ca.key -days 3650 -out ca.crt
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Kodaira
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Renesas Electronics
Organizational Unit Name (eg, section) []:Software Development Division
Common Name (e.g. server FQDN or YOUR name) []:Ishiguro
Email Address []:[email protected]
  • <楕円曲線暗号(パラメータはsecp256r1)の鍵ペアを生成>
$ openssl ecparam -genkey -name secp256r1 -out secp256r1.keypair
using curve name prime256v1 instead of secp256r1
  • <鍵ペアの証明書を作成>
$ openssl req -new -sha256 -key secp256r1.keypair > secp256r1.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Kodaira
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Renesas Electronics
Organizational Unit Name (eg, section) []:Software Development Division
Common Name (e.g. server FQDN or YOUR name) []:Ishiguro
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
  • <CA証明書を使用して鍵ペアの証明書を作成>
$ openssl x509 -req -sha256 -days 3650 -in secp256r1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out secp256r1.crt
Signature ok
subject=/C=JP/ST=Tokyo/L=Kodaira/O=Renesas Electronics/OU=Software Development Division/CN=Ishiguro/[email protected]
Getting CA Private Key
  • <楕円曲線暗号(パラメータはsecp256r1)の秘密鍵を抽出>
$ openssl ec -in secp256r1.keypair -outform PEM -out secp256r1.privatekey
read EC key
writing EC key
  • <楕円曲線暗号(パラメータはsecp256r1)の公開鍵を抽出>
$ openssl ec -in secp256r1.keypair -outform PEM -pubout -out secp256r1.publickey
read EC key
writing EC key

OpenSSLでのテスト用の署名生成/検証方法

  • <test.rsuに先にOpenSSLで作った秘密鍵で署名を付ける>
$ openssl dgst -sha256 -sign secp256r1.privatekey test.rsu > signature.dat
  • <OpenSSL作った公開鍵で検証>
$ openssl dgst -sha256 -verify secp256r1.publickey -signature signature.dat test.rsu
Verified OK

OTAジョブの作成

  • AWS上で以下参考にOTAに関するIAMロールや、OTAジョブ生成を行う
  • RX65Nマイコン固有の設定情報:
    • AWSサービス⇒IoT Core⇒管理⇒ジョブ⇒作成⇒OTA更新ジョブの作成⇒更新するデバイスの選択⇒作成済みの モノ を選択して次へ
    • 「新しいファームウェアイメージに署名します」を選択
    • 「コード署名プロファイル」を選択する
    • 「S3 のファームウェアイメージを選択またはアップロードします」を選択し、新しいuserprog.rsuを選択
    • 「デバイスのファームウェアイメージのパス名」に「aaa」等と入力(内容不問)
    • 「OTA 更新ジョブの IAM ロール」を選択⇒次へ
    • 「ID」に任意の文字列を入れる(内容不問)⇒作成

AWSでコード署名させる方法

  1. AWS IoT -> 管理 -> ジョブ -> 作成 -> Amazon FreeRTOS 無線通信経由 (OTA) の更新ジョブの作成 -> 更新するデバイスの選択 -> 新しいファームウェアイメージに署名します -> コード署名プロファイル
    • プロファイル名: なんでもOK
    • デバイスハードウェアプラットフォーム: Windows Simulator
    • コード署名証明書:
      • 証明書の選択: secp256r1.crt を指定
      • 証明書のプライベートキーを選択: secp256r1.key を指定
      • 証明書チェーンを選択 (オプション): ca.crt
    • デバイスのコード署名証明書のパス名: なんでもOK
  2. これでAWSにコード署名を実施させることができる。

実機動作確認方法

確実に動くビルド

動作確認済のボード

  • RX65N RSK (Ether)

ブートローダとアプリのOTAタイプのまとめ

  • Bootloader type: Initial firmware load from
  1. USB filesystem
  2. SCI-UART
  • Application OTA type: Firmware update data temporary buffer onto
  1. USB filesystem
  2. QSPI serial flash
  3. Internal Flash ROM (text data format) -> discarded
  4. Internal Flash ROM (binary data format) -> recommended

手順まとめ

  1. e2 studio でboot_loaderプロジェクトとuser_applicationプロジェクトを読み込みビルド
  2. user_applicationプロジェクトのaws_demo_runner.c を以下のように変更
  • 変更前: vStartMQTTEchoDemo()が有効になっている
/* Demo declarations. */
/* extern void vStartDeviceDefenderDemo( void ); */
/* extern void vStartGreenGrassDiscoveryTask( void ); */
extern void vStartMQTTEchoDemo( void );
/* extern void vStartOTAUpdateDemoTask( void );*/
:
:
void DEMO_RUNNER_RunDemos( void )
{
    /* vStartDeviceDefenderDemo(); */
    /* vStartGreenGrassDiscoveryTask(); */
     vStartMQTTEchoDemo();
    /*vStartOTAUpdateDemoTask();*/
  • 変更後: vStartOTAUpdateDemoTask()が有効になっている
/* Demo declarations. */
/* extern void vStartDeviceDefenderDemo( void ); */
/* extern void vStartGreenGrassDiscoveryTask( void ); */
/* extern void vStartMQTTEchoDemo( void ); */
extern void vStartOTAUpdateDemoTask( void );
:
:
void DEMO_RUNNER_RunDemos( void )
{
    /* vStartDeviceDefenderDemo(); */
    /* vStartGreenGrassDiscoveryTask(); */
    /* vStartMQTTEchoDemo(); */
    vStartOTAUpdateDemoTask();
  1. AWS関連のセットアップを以下参照して行う (aws_clientcredential.haws_clientcredential_keys.h に 各種パラメータをセットできればセットアップ完了)
  2. ファームウェア検証に使用する鍵をOpenSSLで作成する
  3. ファームウェア検証にECDSA+SHA256を使用するため、ブートローダに署名検証用の公開鍵=secp256r1.publickeyを仕込む
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWiAlaCQGEgIKoP+qk7Uqc/ME/hjw
amq1v/z/LWx15CKig59Pd3+ar2RFOlMMOhIfkYgS+Ha7tH+w0ggnKDrUug==
-----END PUBLIC KEY-----
  1. ファームウェア検証にECDSA+SHA256を使用するため、アプリケーションに署名検証用の公開鍵(証明書形式)=secp256r1.crtを仕込む
static const char signingcredentialSIGNING_CERTIFICATE_PEM[] =
"-----BEGIN CERTIFICATE-----\n"\
"MIICYDCCAgYCCQDqyS1m4rjviTAKBggqhkjOPQQDAjCBtzELMAkGA1UEBhMCSlAx\n"\
"DjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdLb2RhaXJhMRwwGgYDVQQKDBNSZW5l\n"\
"c2FzIEVsZWN0cm9uaWNzMSYwJAYDVQQLDB1Tb2Z0d2FyZSBEZXZlbG9wbWVudCBE\n"\
"aXZpc2lvbjERMA8GA1UEAwwISXNoaWd1cm8xLTArBgkqhkiG9w0BCQEWHmhpcm9r\n"\
"aS5pc2hpZ3Vyby5mdkByZW5lc2FzLmNvbTAeFw0xOTExMTYwMTI3NTBaFw0yOTEx\n"\
"MTMwMTI3NTBaMIG3MQswCQYDVQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNV\n"\
"BAcMB0tvZGFpcmExHDAaBgNVBAoME1JlbmVzYXMgRWxlY3Ryb25pY3MxJjAkBgNV\n"\
"BAsMHVNvZnR3YXJlIERldmVsb3BtZW50IERpdmlzaW9uMREwDwYDVQQDDAhJc2hp\n"\
"Z3VybzEtMCsGCSqGSIb3DQEJARYeaGlyb2tpLmlzaGlndXJvLmZ2QHJlbmVzYXMu\n"\
"Y29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWiAlaCQGEgIKoP+qk7Uqc/ME\n"\
"/hjwamq1v/z/LWx15CKig59Pd3+ar2RFOlMMOhIfkYgS+Ha7tH+w0ggnKDrUujAK\n"\
"BggqhkjOPQQDAgNIADBFAiArP+9pg0eWqaIkC77T8nDHs9r+18KKvntIDoo9FhKW\n"\
"gQIhAO75WVGyGt58QCGNx3wMcbaDgJ4Xpqj0SWTWdxdz0jh1\n"\
"-----END CERTIFICATE-----\n";
  1. user_applicationプロジェクトのリセットベクタ周りのセクション設定をデバッグ用からブートローダから起動する用に変更し、再ビルド
    • デバッグ用: 0xFFFFFF80=EXEPTVECT, 0xFFFFFFFC=RESETVECT
    • ブートローダから起動する用: 0xFFFBFF80=EXEPTVECT, 0xFFFBFFFC=RESETVECT
      • OTA用のプロジェクトは、この設定不要。「ブートローダから起動する用」に設定済み
      • OTA用のプロジェクトを詳細デバッグしたいときは「デバッグ用」の設定に変更することでデバッグ可能
  2. user_applicationのMOTファイル「aws_demos.mot」をMOTファイル変換ツールで変換する(userprog.rsuに変換される)
  3. RX65N RSKのG1CUSB端子とPCを繋ぎ、PCでCOMポートを開きターミナルソフト起動
    • ボーレート: 115200 bps
    • データ: 8bit
    • パリティ: none
    • ストップ: 1bit
    • フロー制御: none
    • 改行コード: CRLF
  4. ターミナルソフトは Tera Term 4.87で動作確認済み。(最新版だと57600bps以上の転送速度でのバイナリファイル転送がうまくいかない現象が有る)
  5. RX65N RSKにACアダプタで給電する
  6. e2 studio でboot_loaderプロジェクトをRX65Nにダウンロードする
  7. e2 studio でboot_loaderプロジェクトを実行する
  8. ターミナルソフトに以下のようなメッセージが出ることを確認
  9. LIFECYCLE_STATE_BLANK が LIFECYCLE_STATE_UNKNOWNになる場合は、デバッガでファームウェアをダウンロードするときの設定を見直すこと
    • e2 studioのデフォルトはコードフラッシュ上書き設定になっているため、何か書き込み済みのチップで実験するとLIFECYCLE_STATE_UNKNOWNになる。
    • e2 studioの場合、以下手順でチップ全消去してからダウンロード設定となる。(デフォルトだと単なる上書きなので注意)
      • 「プロジェクト・エクスプローラー」⇒「プロジェクト上で右クリック」⇒「デバッグ」⇒「デバッグの構成」⇒「Renesas GDB Hardware Debugging」にある「boot_loader HardwareDebug」⇒「Debugger」⇒「デバッグ・ツール設定」⇒「内部フラッシュメモリーの上書き」の右端のボタン⇒「すべて選択解除」(これで消去してから上書きになる)
-------------------------------------------------
RX65N secure boot program
-------------------------------------------------
Checking flash ROM status.
bank 0 status = 0xff [LIFECYCLE_STATE_BLANK]
bank 1 status = 0xff [LIFECYCLE_STATE_BLANK]
bank info = 1. (start bank = 0)
start installing user program.
erase bank1 secure boot mirror area...OK
copy secure boot (part1) from bank0 to bank1...OK
copy secure boot (part2) from bank0 to bank1...OK
========== install user program phase ==========
erase install area (data flash): OK
erase install area (code flash): OK
send "userprog.rsu" via UART.
  1. Tera Termのファイル⇒ファイルを送信で「ファイルを送信」ウィンドウが開く
  2. オプション「バイナリ」にチェックを入れて、userprog.rsuを指定し送信開始
  3. user_application (userprog.rsu) のインストールが始まる
  4. すべてのインストールが終わると再起動して、boot_loader経由でuser_applicationが起動してくる
  5. バージョンデータ値を増加させ(0.9.2 -> 0.9.3等)、再ビルド
  6. 再度MOTファイル変換ツールを使ってuserprog.rsu を生成
    • このとき、MOTファイル変換ツールのタブは"Initial Firm" ではなく、"Update Firm" を選択する
  7. OTAジョブが参照するS3のOTA対象フォルダにuserprog.rsuを格納
  8. boot_loader 経由でaws_demosを実行するとaws_demos 上のOTAエージェントがS3上のuserprog.rsuを検出し、RX65Nのファームウェアが書き変わり、自動的にリブートしてファームアップデートが完了。
  9. AWS画面上のOTAのジョブも「成功」表記に変わる

OTA性能イメージ

  • マイコンにBGO機能(BackGround Operation)があることを前提とする
  • BGO機能とは、フラッシュ書換中にフラッシュ上の命令コードをCPUがフェッチできる機能
  • これにより、フラッシュ書換完了を待つ間、AWSと通信し次の書換対象のデータ受信が可能となる。=フラッシュ書換処理と通信処理の重畳
  • AWSにアップデート用データ(1MB分)を配置し、RX65N内のフラッシュメモリ2MBの内、バンク1面分の1MBをインターネット経由で書き換えるケースで性能を考察する
    • Amazon FreeRTOS v1.4.7 の場合 (確認済み実績値)
      • 約20秒:(1MB分のOTA実行処理(約20秒) + インターネット通信時間) > 1MB分のフラッシュの書換時間 (typ で 約3秒)
    • Amazon FreeRTOS 201908.00 の場合 (実験中の設計目標値)
      • 約3秒:(1MB分のOTA実行処理(ほぼゼロ) + インターネット通信時間) < 1MB分のフラッシュの書換時間 (typ で 約3秒)
  • インターネット通信時間が曲者で、AWSとマイコン間のレイテンシと、マイコン側で持てるTCP受信ウィンドウ容量に大きく依存する
    • 十分にFreeRTOS+TCPの設定値がチューニングできていれば、RX65NでSSL通信はセキュリティIPで加速無しでも3Mbps出るので、1MBの転送にかかる時間は3秒以内に収まる
    • 以下にAWSとマイコン間のレイテンシと、マイコン側で持てるTCP受信ウィンドウ容量の組み合わせによるケーススタディを示す
      • AWSとマイコン間のレイテンシが悪い=200ms程度と仮定
        • TCPウィンドウウィングメカニズムを使わない場合、1パケット1500バイト程度に対しACKが戻ってきて送信完了と見做されるまでレイテンシ分(=200ms)の時間がかかる。つまり1秒間に1500バイト×5=7500バイト転送可能。1MBの転送に133秒かかる。
        • TCPウィンドウウィングメカニズムを使う場合、送信元(AWS)は送信先(マイコン)のTCP受信ウィンドウに空きが存在する限りACKを待たずに連続パケットを送信する。マイコン側でTCP受信ウィンドウを10個持つ場合(1500×10で15KBのRAMを割り当てる)、1パケット1500バイト程度×10個に対しACKが戻ってきて送信完了と見做されるまでレイテンシ分(=200ms)の時間がかかる。つまり1秒間に1500バイト×5×10=75000バイト転送可能。1MBの転送に13.3秒かかる。
      • AWSとマイコン間のレイテンシが良い=20ms程度と仮定
        • TCPウィンドウウィングメカニズムを使わない場合、1パケット1500バイト程度に対しACKが戻ってきて送信完了と見做されるまでレイテンシ分(=20ms)の時間がかかる。つまり1秒間に1500バイト×50=75000バイト転送可能。1MBの転送に13.3秒かかる。
          • 実際はこの限りではなく、多くのTCP/IP実装体は、「2個パケット受信を待ってからACKを返信する」という推奨ルールにより1個パケット受信したからといって即座にACKを返信するとは限らない。Windowsの場合1個だけパケットを受け取ったときは200msのタイムアウト時間を待ってACKを返信する。従って、TCP/IPの送信側は最低限2個パケットをACKを待たず送信できるよう、TCP送信ウィンドウは2個分の3000バイト用意しておくのがセオリーとなる。(FreeRTOS+TCPもデフォルト3000)
          • TCPウィンドウウィングメカニズムを使わない場合、上述のタイムアウト時間200msが1パケット送受信毎に発生する上、この200msという時間も実装体によってまちまちである。どの実装体も概ね200ms程度の時間を待つため、TCPウィンドウイングメカニズムを使わない場合は転送速度が著しく遅くなることを考慮に入れたい。
        • TCPウィンドウウィングメカニズムを使う場合、送信元(AWS)は送信先(マイコン)のTCP受信ウィンドウに空きが存在する限りACKを待たずに連続パケットを送信する。マイコン側でTCP受信ウィンドウを10個持つ場合(1500×10で15KBのRAMを割り当てる)、1パケット1500バイト程度×10個に対しACKが戻ってきて送信完了と見做されるまでレイテンシ分(=20ms)の時間かかる。つまり1秒間に1500バイト×50×10=750000バイト転送可能。1MBの転送に1.33秒かかる。
      • TCPウィンドウイングのON/OFFを決めるFreeRTOS+TCPの設定値

通信性能に関する考察

量産時のメモリ保護に対する考慮

AWS IoT Console ではできない OTA関連の AWS CLI の役に立つコマンド

  • コード署名プロファイルのリストを取得
$ aws signer list-signing-profiles
  • コード署名プロファイルを削除
$ aws signer cancel-signing-profile --profile-name <user_profile_name>

ブートローダの設計情報

  • ブートローダでは2種類のステータスにて処理を行っています。
    • フラッシュメモリ・ライフサイクルステータス
      • LIFECYCLE_STATE_BLANK:フラッシュメモリ・ブランク状態
      • LIFECYCLE_STATE_TESTING:フラッシュメモリ・テスト状態
      • LIFECYCLE_STATE_INSTALLING:フラッシュメモリ・インストール状態
      • LIFECYCLE_STATE_VALID:フラッシュメモリ有効状態
      • LIFECYCLE_STATE_INVALID:フラッシュメモリ無効状態
    • ブートローダ・ステータス
      • BOOT_LOADER_STATE_INITIALIZING:初期化中
      • BOOT_LOADER_STATE_BANK1_CHECK:バンク1の状態確認中
      • BOOT_LOADER_STATE_BANK1_UPDATE_LIFECYCLE_ERASE_WAIT:バンク1のライフサイクル領域の消去待ち
      • BOOT_LOADER_STATE_BANK1_UPDATE_LIFECYCLE_ERASE_COMPLETE:バンク1のライフサイクル領域の消去完了
      • BOOT_LOADER_STATE_BANK1_UPDATE_LIFECYCLE_WRITE_WAIT:バンク1のライフサイクル領域の書込み待ち
      • BOOT_LOADER_STATE_BANK1_UPDATE_LIFECYCLE_WRITE_COMPLETE:バンク1のライフサイクル領域の書込み完了
      • BOOT_LOADER_STATE_BANK0_CHECK:バンク0の状態確認中
      • BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_ERASE_WAIT:バンク0のセキュアブート領域の消去待ち
      • BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_ERASE_COMPLETE:バンク0のセキュアブート領域の消去完了
      • BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_WRITE_WAIT1:バンク0のセキュアブート領域の書込み待ち1
      • BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_WRITE_COMPLETE1:バンク0のセキュアブート領域の書込み完了1
      • BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_WRITE_WAIT2:バンク0のセキュアブート領域の書込み待ち2
      • BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_WRITE_COMPLETE2:バンク0のセキュアブート領域の書込み完了2
      • BOOT_LOADER_STATE_INSTALL_DATA_FLASH_ERASE_WAIT:データフラッシュ領域の消去待ち
      • BOOT_LOADER_STATE_INSTALL_DATA_FLASH_ERASE_COMPLETE:データフラッシュ領域の消去完了
      • BOOT_LOADER_STATE_BANK0_INSTALL_CODE_FLASH_ERASE_WAIT:バンク0のコードフラッシュ領域の消去待ち
      • BOOT_LOADER_STATE_BANK0_INSTALL_CODE_FLASH_ERASE_COMPLETE:バンク0のコードフラッシュ領域の消去完了
      • BOOT_LOADER_STATE_BANK0_INSTALL_CODE_FLASH_READ_WAIT:バンク0のコードフラッシュ領域の読出し待ち
      • BOOT_LOADER_STATE_BANK0_INSTALL_CODE_FLASH_READ_COMPLETE:バンク0のコードフラッシュ領域の読出し完了
      • BOOT_LOADER_STATE_BANK0_INSTALL_CODE_FLASH_WRITE_WAIT:バンク0のコードフラッシュ領域の書込み待ち
      • BOOT_LOADER_STATE_BANK0_INSTALL_CODE_FLASH_WRITE_COMPLETE:バンク0のコードフラッシュ領域の書込み完了
      • BOOT_LOADER_STATE_INSTALL_DATA_FLASH_READ_WAIT:データフラッシュ領域の読出し待ち
      • BOOT_LOADER_STATE_INSTALL_DATA_FLASH_READ_COMPLETE:データフラッシュ領域の読出し完了
      • BOOT_LOADER_STATE_INSTALL_DATA_FLASH_WRITE_WAIT:データフラッシュ領域の書込み待ち
      • BOOT_LOADER_STATE_INSTALL_DATA_FLASH_WRITE_COMPLETE:データフラッシュ領域の書込み完了
      • BOOT_LOADER_STATE_BANK0_UPDATE_CHECK:バンク0のアップデート状態確認中
      • BOOT_LOADER_STATE_BANK1_UPDATE_CODE_FLASH_ERASE_WAIT:バンク1のコードフラッシュ領域の消去待ち
      • BOOT_LOADER_STATE_BANK1_UPDATE_CODE_FLASH_ERASE_COMPLETE :バンク1のコードフラッシュ領域の消去完了
      • BOOT_LOADER_STATE_FINALIZE:完了
      • BOOT_LOADER_STATE_FATAL_ERROR:エラー状態
  • ブートローダの状態遷移図は次の通り。(状態遷移図の状態名は、上記の状態名を一部を省略したりWAITとCOMPLETEを1つにまとめた状態名になっています。例:BOOT_LOADER_STATE_BANK0_INSTALL_SECURE_BOOT_WRITE_WAIT2 → BANK0_INSTALL_SECURE_BOOT_WRITE_XXX2)

ホーム

  1. Home

開発環境

  1. 開発環境を揃える
  2. 開発環境を使う
  3. CS+を使う

チュートリアル

  1. デバイスをAWS IoTに登録する
  2. Amazon FreeRTOSをダウンロードする
  3. Amazon FreeRTOSを設定する
  4. Amazon FreeRTOSを実行し、RX65NをAWS IoTに接続する

AWSの各種サービスを使用する

  1. シャドウを使用しAWSからRX65Nを制御
  2. ElasticSearchを使用しRX65Nに接続されたセンサデータをAWSで可視化
  3. Lambdaを使用しAWS経由でRX65N間のM2M通信

Tracealyzerの活用

  1. Tracealyzerの活用

OTAの活用

  1. OTAの活用

Amazon FreeRTOSのシステムに関する考察

  1. ソフトウェアアーキテクチャ
  2. 機能ブロックとAPIプロトタイプ
  3. RXマイコンにおける実装(システムタイマとソフトウェア割り込み)
  4. スリープ機能
  5. タスク切り替えと割り込み発生時のレイテンシ
  6. ネットワークインタフェースとデバイスドライバの結合
  7. Amazon FreeRTOS Qualification Program
  8. Amazon FreeRTOS ROM/RAM容量考察
  9. Amazon FreeRTOS でFreeRTOS+TCPのみ使う方法
  10. シミュレータで動作させる
  11. 乱数生成

Amazon FreeRTOSの通信性能に関する考察

  1. TCP/IP層の通信性能評価
  2. RX65N内蔵セキュリティIPを活用したSSL/TLS層の通信性能評価
  3. Tracealyzerを用いた通信中のCPU負荷率評価

セキュリティに関する考察

  1. RX65N内蔵セキュリティIP Trusted Secure IP
  2. モノの証明書に紐づく秘密鍵等の重要データをTrusted Secure IPで秘匿する方法
  3. SSL/TLS通信のマスターシークレットをTrusted Secure IPで秘匿する方法
  4. セキュアブート/セキュアアップデートの実現方法
  5. NIST FIPS140-2 CMVPとTrusted Secure IP
  6. Trusted Secure IP と Arm TrustZone
  7. EEMBC SecureMark
  8. Trusted Secure IPの暗号処理性能評価

無線モジュールに関する考察

  1. ESP32

Amazon FreeRTOS 関連外部リンク集

  1. Amazon FreeRTOS
  2. Amazon FreeRTOS の使用開始
  3. Amazon FreeRTOS ドキュメント
    1. Amazon FreeRTOS ユーザーガイド
    2. Amazon FreeRTOS API リファレンス
    3. FreeRTOS カーネルリファレンスマニュアル
    4. FreeRTOS カーネル開発者ガイド
Clone this wiki locally