fwup
は Unix設定ライブラリ(libconfuse)を使っています.
したがって その設定は 他のプログラムに似ているところがあります.
設定ファイルはファームウェアアーカイブを作るために使われます.
作成中, fwup
は, 処理した設定ファイルを アーカイブに埋め込みます.
埋め込まれる設定ファイルは, コメントを削除し, 変数が解決されたあと, 有用なメタデータを追加されたものになります.
設定ファイルはスコープブロックに属し, オプションは key = value
構文を使ってセットされます.
加えて, 設定ファイルは include("filename")
を呼び出すことで他のファイルや分割された設定を取り込みます.
ビルドシステムや他のスクリプトへの統合のため, fwup
は設定ファイル内の変数置換を実施します.
環境変数は, ファームウェア更新ファイルを作成する間, ホスト上で解決されることに留意ください.
生成されたファームウェアファイルは含みません.
環境変数は以下のように参照されます:
key = ${ANY_ENVIRONMENT_VARIABLE}
:-
シンボルを使うことで, 環境変数のデフォルト値を提供することができます:
key = ${ANY_ENVIRONMENT_VARIABLE:-adefault}
設定ファイルの中で, ファイルをまたいで使われる定数を定義するのに便利です.
定数は, 環境変数とおなじように参照されます.
以下が例です:
define(MY_CONSTANT, 5)
デフォルトでは, 同じ定数の定義の繰り返しは, 定数値を変更しません.
いいかえると, 最初の宣言が勝ちます.
最初の定義は, 同じ名前の環境変数から取得できることに注意しましょう.
これによりビルドスクリプト内の定数を上書きすることができます.
場合によっては, 環境変数または以前の define
の呼び出しによって上書きされることのない定数には, 最後の定義が勝つことが望ましいです.
この動作には, define!
を使用します:
define!(MY_CONSTANT, "Can't override this")
単純マッチ計算も, define-eval()
と define-eval!()
とを使って反映することができます.
たとえば:
define-eval(AN_OFFSET, "${PREVIOUS_OFFSET} + ${PREVIOUS_COUNT}")
これらの2つの関数は リリース 0.10.0 から追加されましたが,
これらはファームウェア作成時に評価されます.
.fw ファイルは, fwup
の旧バージョンにあわせて 作られます.
最後に, file-resource
は リソースのサイズを定義した, FWUP_SIZE_<resource_name>
と名付けられた変数を定義します.
file-resource zImage {
host-path = "output/images/zImage"
}
execute("echo zImage size is ${FWUP_SIZE_zImage} bytes")
グローバルスコープでは, 以下のオプションがあります:
Key |
Description |
require-fwup-version |
この更新を適用するために 要求する fwupの最低バージョン |
meta-product |
プロダクト名 |
meta-description |
プロダクトあるいはファームウェア更新の概要 |
meta-version |
ファームウェアバージョン |
meta-author |
更新のうしろにいる作者あるいは会社 |
meta-platform |
この更新が走るプラットフォーム (rpi,bbbなど) |
meta-architecture |
プラットフォームアーキテクチャ(armなど) |
meta-vcs-identifier |
このイメージを再現するのに使うバージョン管理ID |
meta-misc |
その他の追加データ. 書式と内容はユーザ次第. |
meta-creation-date |
更新が作られたときのタイムスタンプ(ZIPメタデータからもたらされる). 再現するためには, SOURCE_DATE_EPOCH 環境変数をセットしてください. |
meta-fwup-version |
更新を作るために使われる fwupのバージョン(廃止予定. 1.2.0以降で追加されなくなっている) |
meta-uuid |
このファームウェアを再現するためのUUID. UUIDは, .fwファイルが(自動生成)作られたあとに, デジタル署名された場合でも, かわりません. |
上記オプションの設定のあと, ほかのオプションのために, スコープを作ることが必要です.
現在存在するスコープは:
Scope |
Description |
file-resource |
アーカイブに含まれなければならないファイルへの参照を定義 |
mbr |
宛先のMBR(master boot record)を定義 |
gpt |
宛先の GPTパーティションを定義 |
task |
ファームウェア更新タスクの定義(コマンドラインから -t を使って参照される) |
file-resource
は, アーカイブ中に含まれるべき ホスト上のファイルを与えます.
各々の file-resource
は, 更新設定ファイルの他の部分から参照できるように,
ユニークな名前を与える必要があります.
fwup
は, アーカイブ内のファイルの長さと BLAKE2b-256ハッシュ値とを 自動的に記録します.
これらのフィールドは 進捗を計算することと, アーカイブコンテンツの検証のために, 内部的に使われます.
標準的な file-resource
セクションは 次のようになります:
file-resource zImage {
host-path = "output/images/zImage"
}
リソースは通常, ファームウェアアーカイブの data
ディレクトリ内に保存されます.
これは多くのユーザに透過です.
他のソフトウェアと使うために, .fw
ファイルを作る必要があるなら,
他の場所にファイルを埋め込むのが使いやすいことがあります.
これは絶対パスリソースを与えることで実現できます:
file-resource "/my_custom_metadata" {
host-path = "path/to/my_custom_metadata_file"
}
ときおり, `file-resourceP から複数のファイルを互いに結合する必要があります.
raw_write
を複数回呼び出して使うことで, これを実現できますが,
事前にファイルオフセットがわからない時や, オフセットが ブロック境界に該当しない場合には機能しません.
ほかの選択肢は, 前のステップでファイルを結合することです.
もし不便であれば, fwup
は, セミコロンで分割された host-path
で 複数のパスを与えることを許容します.
それらのファイルは, 記述順に結合されます.
file-resource kernel_and_rootfs {
# Concatenate uImage and the rootfs. OpenWRT mtd splitter will
# separate them back out at runtime.
host-path = "output/images/uImage;output/images/rootfs.squashfs"
}
アーカイブを作るとき, fwup
は単純なエラーを捕まえるため, ファイルリソースの検証チェックを行うことができます.
このチェックは, ファイルリソースが宛先に入らないくらい大きすぎたり,
ビルドの中断によって末尾が欠けたりする共通的なエラーを捕まえます.
これらのチェックは, 更新を適用するときに適用されないことに注意してください.
なぜならば, 実際の長さ(とハッシュ)はアーカイブメタデータ内に記録されており,
検証に使われるからです.
以下のチェックがサポートされています:
Check |
Description |
assert-size-lte |
ファイルサイズが与えられたもの以下の場合, エラーを報告します. |
assert-size-gte |
ファイルサイズが与えられたもの以上の場合, エラーを報告します. |
サイズは 512バイトブロック単位で与えます(fwup
の他のものと同様に):
file-resource rootfs.img {
host-path = "output/images/rootfs.squashfs"
assert-size-lte = ${ROOTFS_A_PART_COUNT}
}
ときおり, fwup
設定ファイル内で短いファイルを作成することは,
ファイルを参照することよりも有用です.
file-resource
内の contents
キーを使うことで達成できます.
変数置換は, fwup
設定ファイルの他の文字列と同様に, contents
文字列でも行われます.
file-resource short-file.txt {
contents = "You're looking at a short\n\
file creating by fwup.\n\
When it was made, FOO was ${FOO}.\n"
}
mbr
セクションは, 宛先メディアの Master Boot Recordのコンテンツを指定します.
このセクションは, メディア上に存在するファイルシステムを見つけるために,
Linuxとブートローダによって読まれるパーティションテーブルを含みます.
fdisk
のようなツールと比べて, fwup
はとても単純なパーティション設定のみをサポートします.
fdisk
のようなツールは,設定ファイルのブロックオフセットやパーティションサイズを検出するのに使えます.
オフセットとサイズは 512 byteブロックで与えられます.
潜在的な mbr定義は以下のとおりです:
mbr mbr-a {
bootstrap-code-host-path = "path/to/bootstrap-data" # should be 440 bytes
signature = 0x01020304
partition 0 {
block-offset = ${BOOT_PART_OFFSET}
block-count = ${BOOT_PART_COUNT}
type = 0x1 # FAT12
boot = true
}
partition 1 {
block-offset = ${ROOTFS_A_PART_OFFSET}
block-count = ${ROOTFS_A_PART_COUNT}
type = 0x83 # Linux
}
partition 2 {
block-offset = ${ROOTFS_B_PART_OFFSET}
block-count = ${ROOTFS_B_PART_COUNT}
type = 0x83 # Linux
}
partition 3 {
block-offset = ${APP_PART_OFFSET}
block-count = ${APP_PART_COUNT}
type = 0x83 # Linux
}
}
Intel Edisonや似たようなプラットフォームを使っている場合,
fwup
は MBR内の OSIPヘッダの生成をサポートします.
このヘッダは, ブートローダ(たとえば U-Boot)をメモリ上の何処にロードすべきかという情報を提供します.
OSIPとイメージレコード(OSII)オプション名は, 長さ, チェックサム,
イメージ数のフィールドは自動的に計算されることを除いて, ヘッダフィールドに直接マップされます.
以下は全てのオプションを示した例です:
mbr mbr-a {
include-osip = true
osip-major = 1
osip-minor = 0
osip-num-pointers = 1
osii 0 {
os-major = 0
os-minor = 0
start-block-offset = ${UBOOT_OFFSET}
ddr-load-address = 0x01100000
entry-point = 0x01101000
image-size-blocks = 0x0000c000
attribute = 0x0f
}
partition 0 {
block-offset = ${ROOTFS_A_PART_OFFSET}
block-count = ${ROOTFS_A_PART_COUNT}
type = 0x83 # Linux
}
}
まれに, ストレージの残りを最終パーティションで埋めることは有用です.
ターゲットのストレージサイズが判らない場合に必要で,
可能であれば, コレをできるだけ使う必要があります.
expand
オプションはfwup
が block-count
を可能な限り大きくなるように伸ばすことを要求します.
expand
を使うとき, block-count
は, 今は最小のパーティションサイズです.
唯一最後のパーティションが拡張可能です.
例を挙げます:
mbr mbr-a {
partition 0 {
block-offset = ${BOOT_PART_OFFSET}
block-count = ${BOOT_PART_COUNT}
type = 0x1 # FAT12
boot = true
}
partition 1 {
block-offset = ${ROOTFS_A_PART_OFFSET}
block-count = ${ROOTFS_A_PART_COUNT}
type = 0x83 # Linux
}
partition 2 {
block-offset = ${ROOTFS_B_PART_OFFSET}
block-count = ${ROOTFS_B_PART_COUNT}
type = 0x83 # Linux
}
partition 3 {
block-offset = ${APP_PART_OFFSET}
block-count = ${APP_PART_COUNT}
type = 0x83 # Linux
expand = true
}
}
gpt
の節では, GUIDパーティションテーブル
の内容を指定します.
gpt my-gpt {
# UUID for the entire disk
guid = b443fbeb-2c93-481b-88b3-0ecb0aeba911
partition 0 {
block-offset = ${EFI_PART_OFFSET}
block-count = ${EFI_PART_COUNT}
type = c12a7328-f81f-11d2-ba4b-00a0c93ec93b # EFI type UUID
guid = 5278721d-0089-4768-85df-b8f1b97e6684 # ID for partition 0 (create with uuidgen)
name = "efi-part.vfat"
}
partition 1 {
block-offset = ${ROOTFS_PART_OFFSET}
block-count = ${ROOTFS_PART_COUNT}
type = 44479540-f297-41b2-9af7-d131d5f0458a # Rootfs type UUID
guid = fcc205c8-2f1c-4dcd-bef4-7b209aa15cca # Another uuidgen'd UUID
name = "rootfs.ext2"
}
}
fwup
によって, 保護されたMBR と、プライマリ・バックアップGPTテーブルを書かせるために, gpt_write
を呼びます.
U-Bootブートローダを使っているシステムのために,
U-Boot環境ブロックを修正するためのサポートが含まれます.
このアドバンテージを得るためには, トップレベルに 環境ブロックをどうするかを記述する
uboot-environment
セクションを宣言する必要があります.
uboot-environment my_uboot_env {
block-offset = 2048
block-count = 16
}
U-boot変数の取得・設定については, taskセクション中の機能を参照ください.
注意: 現時点では, U-Boot環境をサポートする実装は私が使う分だけです.
特に, 冗長な環境, ビッグエンディアンターゲット, raw NANDパーティションへの書き込みをサポートしていません.
あなたがこれらを使う場合, これらをサポートするために貢献することを検討してください.
fwup
の U-Bootサポートが, あなたのニーズにあわなければ,
mkenvimage
ユーティリディを使って環境イメージを作ることが可能です.
そして, 正しい場所へ raw_write
を使って書き込めます.
これはおそらく, たくさんの変数をセットするときは, より適切な手段です.
task
セクションは, ファームウェア更新タスクを指定します.
これらのセクションは, 更新が適用される状態と更新を適用するステップを記述するため, ファームウェア更新の主要な部分です.
各 task
せく処んは, ユニークな名前を持つ必要があります.
しかし, タスクを探すときには, ファームウェア更新ツールが前方照合を行うだけです.
これはあなたに,ターゲットハードウェアの状態に基づいて評価できる複数のタスクを定義させてくれます.
最初に照合されたタスクが適用されます.
これは, ターゲット上の現在のファームウェアバージョンやターゲットアーキテクチャなどに基づいて 更新手順が異なる場合にとても使いやすいです.
以下の表に, サポートされる制約を列挙します:
Constraint |
Min fwup version |
Description |
require-fat-file-exists(block_offset, filename) |
0.7.0 |
指定されたFATfsにあるファイルを要求する |
require-fat-file-match(block_offset, filename, pattern) |
0.14.0 |
ファイル名の一致と, パターンがファイル内のバイト数と一致することを要求する |
require-partition-offset(partition, block_offset) |
0.7.0 |
パーティションのブロックオフセットが 指定された値であることを要求する. |
require-path-on-device(path, device) |
0.13.0 |
指定されたパス(たとえば"/")が指定されたパーティションデバイス(たとえば"/dev/mmcblk0p1)にあることを要求する. |
require-path-at-offset(path, offset) |
0.19.0 |
指定されたパス(たとえば "/")が, 指定されたブロックオフセット(たとえば1024)にあることを要求する. require-path-on-device と組み合わせます. |
require-uboot-variable(my_uboot_env, varname, value) |
0.10.0 |
U-Boot環境で, 変数が指定された値に設定されていることを要求する. |
task
セクションがイベントハンドラのリストであることを思い出してください.
イベントハンドラはスコープとして編成されます.
イベントハンドラは, イベントが発生したときに, ファームウェアのアプリケーションが更新する間, 一致します.
イベントは初期化, 完了, エラー, アーカイブからのファイル展開を含みます.
アーカイブはストリーミングマナーで処理されるので, イベントの順序はファイルがアーカイブに追加された順序に基づいて, 決定的です.
あるイベントが 他のイベントの前に発生することが重要である場合は,
file-resource
セクションが, 望みの順序で 指定されていることを確認してください.
Event |
Description |
on-init |
タスクが適用されたときに, 送られる最初のイベント |
on-finish |
イベント処理中にエラーが検出されなかったと仮定した最後のイベント |
on-error |
エラーが生じた場合に送られる.したがって, 中間ファイルは削除可能です. |
on-resource <resource name> |
イベント発生のように送られる.現状, これは アーカイブから処理された file-resources を送るようになっています. |
イベントスコープには, アクションのリストが含まれています.
アクションは, ファイルシステムをフォーマットしたり, ファイルをファイルシステムにコピーしたり, 宛先のナマの場所に書き込むことができます.
Action |
Min fwup version |
Description |
error(message) |
0.12.0 |
エラーとして ファームウェア更新を直ちに失敗します. |
execute(command) |
0.16.0 |
ホスト上でコマンドを実行します. --unsafe フラグを要求します. |
fat_mkfs(block_offset, block_count) |
0.1.0 |
指定されたブロックオフセットとカウントに, FATfsを作ります. |
fat_write(block_offset, filename) |
0.1.0 |
指定されたブロックオフセットに, リソースをFATfsに書き込みます. |
|
|
|
fat_attrib(block_offset, filename, attrib) |
0.1.0 |
ファイル属性を変更します. 属性は "RHS"のような文字列です(R:読み込み専用, H:隠し属性, S:システム). |
fat_mv(block_offset, oldname, newname) |
0.1.0 |
FATfs上の指定されたファイルの名前を変更します. |
fat_mv!(block_offset, oldname, newname) |
0.14.0 |
すでに新しい名前があったとしても, 指定されたファイルの名前を変更します. |
fat_rm(block_offset, filename) |
0.1.0 |
指定されたファイルを削除します. |
fat_mkdir(block_offset, filename) |
0.2.0 |
FATfs上にディレクトリを作ります. ディレクトリがすでに存在していた場合でも成功します. |
fat_setlabel(block_offset, label) |
0.2.0 |
FATfs上にボリュームラベルをセットします. |
fat_touch(block_offset, filename) |
0.7.0 |
ファイルが存在していなければ, 空のファイルを作ります.(Linuxのようにタイムスタンプ更新しません) |
gpt_write(gpt) |
1.4.0 |
指定されたGPTをターゲットに書き込みます. |
info(message) |
0.13.0 |
情報メッセージを表示します. |
mbr_write(mbr) |
0.1.0 |
指定された mbrをターゲットに書き込みます. |
path_write(destination_path) |
0.16.0 |
リソースをホスト上のパスへ書き込みます. --unsafe フラグを要求します. |
pipe_write(command) |
0.16.0 |
ホスト上で, リソースをパイプでコマンドへ渡します. --unsafe フラグを要求します. |
raw_memset(block_offset, block_count, value) |
0.10.0 |
指定されたブロックへ, 指定されたバイトの値を繰り返し書き込みます. |
raw_write(block_offset, options) |
0.1.0 |
リソースを指定されたブロックオフセットへ書き込みます. オプションは cipher と secret を含みます. |
trim(block_offset, count) |
0.15.0 |
以前に範囲に書き込まれたデータを破棄します. "--enable-trim" が fwupに渡されると, TRIM要求がデバイスに発行されます. |
uboot_recover(my_uboot_env) |
0.15.0 |
U-Boot環境(変数領域)が壊れている場合, 最初期化します. 壊れていない場合は なにもしません. |
uboot_clearenv(my_uboot_env) |
0.10.0 |
U-Boot環境のクリーン, 変数を開放します. |
uboot_setenv(my_uboot_env, name, value) |
0.10.0 |
指定されたU-Boot変数をセットします. |
uboot_unsetenv(my_uboot_env, name) |
0.10.0 |
指定されたU-Boot変数を案セットします. |
スパースファイルは, ファイルシステム上のメタデータ中のみで表現されるギャップを持ったファイルです.
すべてのファイルシステムでサポートされていませんが, 一般的に Linuxは良いサポートをしています.
スパースファイルを作るのは簡単です.
ファイル末尾の位置から後方へシークして, なにかデータを書くのです.
ギャップは, ファイルシステムのメタデータ中で, 穴が空いたたように"保存"されます.
データは, ホールから読み出したゼロになります.
データとホールは, 厳密にファイルシステム上のブロック境界上で開始・終了します.
したがって, 小さなギャップは, ホールに保存されるのではなく, ゼロで埋められます.
Why is this important? If you're using fwup
to write a large EXT2 partition,
you'll find that it contains many gaps. It would be better to just write the
EXT2 data and metadata without filling in all of the unused space. Sparse file
support in fwup
lets you do that. Since EXT2 filesystems legitimately contain
long runs of zeros that must be written to Flash, fwup
queries the filesystem
containing the EXT2 data to find the gaps. Other tools like dd(1)
only look
for runs of zeros so their sparse file support cannot be used to emulate this.
You may see warnings about copying sparse files to Flash and it has to do with
tools not writing long runs of zeros. The consequence of fwup
querying the
filesystem for holes is that this feature only works when firmware update
archives are created on operating systems and filesystems that support it. Of
course, firmware updates can be applied on systems without support for querying
holes in files. Those systems also benefit from not having to write as much to
Flash devices. If you instead apply a firmware update to a normal file, though,
the OS will likely fill in the gaps with zeros and thus offer no improvement.
There is one VERY important caveat with the sparse file handling: Some zeros in
files are important and some are not. If runs in zeros in a file are important
and they are written to a file as a "hole", fwup
will not write them back.
This is catastrophic if the zeros represent things like free blocks on a
filesystem. Luckily, the file system formatting utilities write the important
zeros to the disk and the OS does not scan bytes to see which ones are runs on
zeros and automatically create holes. Programs like dd(1)
can do this, though,
so it is crucial that you do not run files through dd
to make then sparser
before passing them to fwup
.
To turn this feature off, set skip-holes
on the resource to false
:
file-resource rootfs.img {
host-path = "output/images/rootfs.img"
skip-holes = false
}
raw_write
機能は, Linuxの dm-crypt
カーネルドライバと適合するディスク暗号化のサポートに制約があります.
これは安静時に読み出されれない方法で, ファイルシステムのデータを書き込むことを可能とします.
fwup
は暗号鍵の処理に対応しておらず, 不適切な処理は暗号化の利点を簡単に損なう可能性があります.
.fw
アーカイブは暗号化されません. このメカニズムは アーカイブの秘密は他の意味で保護されます.
もちろん, アーカイブ内のデータを暗号化しておくことも可能です.
しかし, デバイス固有の秘密鍵を持つことはできません.
- 最も単純は
dm-crypt
暗号は, 現状サポートされます("aes-cbc-plain").
これは知られた定義です.
fwup
のApacheライセンスのもとに, 組み込むことができる他のモードへのプルリクエストは歓迎します.
インターネット上には, 暗号化ファイルシステムを作り, dm-crypt
を用いてファイルシステムをマウントするためのいくつかのチュートリアルがあります.
fwup
はもっと単純です.
書き込むためのバイト数のブロックを取得し, 暗号化し, 宛先に書き込みます.
たとえば, ディスクに暗号化して書き込みたい, SquashFSでフォーマットされたファイルシステムがある場合, 以下の断片があるでしょう:
on-resource fs.squashfs {
raw_write(${PARTITION_START}, "cipher=aes-cbc-plain", "secret=\${SECRET_KEY}")
}
上記の例では, SECRET_KEY
は, ファームウェア更新時にデバイス上で環境変数からくることが期待されます.
もちろん, テストするために設定ファイル中にハードコードした暗号鍵を使うこともできます.
鍵は 16進数文字列にエンコードされています.
さて, デバイス上では, SquashFSパーティションをマウントしますが, dm-crypt
を使います.
手順は以下のようになるでしょう:
losetup /dev/loop0 /dev/mmcblk0p2
cryptsetup open --type=plain --cipher=aes-cbc-plain --key-file=key.txt /dev/loop0 my-filesystem
mount /dev/mapper/my-filesystem /mnt
上記の引数の多くをシステムに適したものに置き換える必要があるでしょう.
It's possible for the system time to be saved in various places when using
fwup
. This means that an archive with the same contents, but built at
different times results in .fw
files with different bytes. See
reproducible-builds.org for a discussion on
this topic.
fwup
obeys the
SOURCE_DATE_EPOCH
environment variable and will force all timestamps to the value of that
variable when needed. Set $SOURCE_DATE_EPOCH
to the number of seconds since
midnight Jan 1, 1970 (run date +%s
) to use this feature.
A better way of comparing .fw
archives, though, is to use the firmware UUID.
The firmware UUID is computed from the contents of the archive rather than the
bit-for-bit representation of the .fw
file, itself. The firmware UUID is
unaffected by timestamps (with or without SOURCE_DATE_EPOCH
) or other things
like compression algorithm improvements. This is not to say that
SOURCE_DATE_EPOCH
is not important, but that the UUID is an additional tool
for ensuring that firmware updates are reproducible.
The scenario is that you need to store some metadata or some other information
that is useful to another program. For example, you'd like to include some
documentation or other notes inside the firmware update archive that the
destination device can pull out and present on a UI. To do this, just add
file-resource
blocks for each file. These blocks don't need to be referenced
by an on-resource
block.
gitを使っている場合, fwup
を以下のように起動することができます:
GITDESCRIBE=`git describe` fwup -c -f myupdate.conf -o out.fw
そして, myupdate.conf
に以下の行を追加してください.
meta-version = "${GITDESCRIBE}"
ターゲットデバイス上で, -m
オプションを使うことでバージョンを確認することができます.
以下に例示します:
$ fwup -m -i out.fw
meta-product = "Awesome product"
meta-description = "A description"
meta-version = "v0.0.1"
meta-author = "Me"
meta-platform = "bbb"
meta-architecture = "arm"
meta-uuid="07a34e75-b7ea-5ed8-b5d9-80c10daf4939"
よろしい. FAQではないけれども, 何らかの理由でこれはクールだと思える人が要るでしょう.
わたしの働いている多くのシステムは, sshでネットワークに接続しています.
時々, 私は以下のように更新しています:
$ cat mysoftware.fw | ssh root@192.168.1.20 \
'fwup -a -U -d /dev/mmcblk2 -t upgrade && reboot'
fwup
を介して, パイプでソフトウェア更新する機能は便利です.
これは, 何らかの理由で, デバイス上に更新データを保持するのに十分な容量が無いような状況からも, わたしを抜け出させてくれました.
一度に複数の署名鍵を持つ必要があるようないくつかのユースケースは存在します.
たとえば, インフラストラクチャですべてのファームウェアの更新が署名されるように強制できますが, QAビルドの公式の安全なパスを全員に強制することはできません.
現状, 各ファームウェアファイルは, 1つの署名しかできません.
しかし, 検証(デバイス)は, 複数の公開鍵を指定(-pオプションをくりかえす)することができます.
鍵毎に fwup
を呼び出すことができますが, fwupを介してストリーム更新をサポートし,
検証を実行するため, そして, このクリティカルなコードパスを単純にするためにも,
複数の鍵を指定することを推奨します.
私は, (eMMCやSDカードとは対象的に)ラップトップ上の一般ファイルに更新を適用して, バイナリエディタで検証しています.
- コンテンツを検査するため, .fw ファイルを展開する. それは一般のZIPファイルで,
meta.conf
ファイルが変数展開後に見える, あなたの設定が剥ぎ取らたものです.
- printfスタイルデバッグを行う為に
error()
関数を追加する.
- 動作するイメージを見つけ, 一部のセクションの更新をスキップします.
たとえば, 一部のプロセッサはMBRの内容に非常にこだわりがあり,
パーティションの制約に取り組む前に他のすべてを機能させるのが簡単です.
There are a few options. Most people can specify root=/dev/mmcblk0p1
or
root=/dev/sda1
or something similar on the kernel commandline and everything
will work out fine. On systems with multiple drives and an unpredictable boot
order, you can specify root=PARTUUID=01234567-01
where the -01
part
corresponds to the 1-based partition index and 01234567
is any signature. In
your fwup.conf
file's MBR block, specify signature = 0x01234567
. A third
option is to use an initramfs and not worry about any of this.
In general, fwup
writes to Flash memory in large blocks so that the update
can occur quickly. Obviously, reducing the amount that needs to get written
always helps. Beyond that, most optimizations are platform dependent. Linux
caches writes so aggressively that writes to Flash memory are nearly as fast as
possible. OSX, on the other hand, does very little caching, so doing things
like only working with one FAT filesystem at a time can help. In this case,
fwup
only caches writes to one FAT filesystem at a time, so mixing them will
flush caches. OSX is also slow to unmount disks, so keep in mind that
performance can only be so fast on some systems.
特別なeMMCブートパーティションは, メインパーティションと同じ方法で更新可能です.
製品の .fwファイルを作るとき, 2つのターゲットを作ります.
メインeMMCを更新するcomplete
ターゲット と mmcblock0boot0
を更新する bootloader
ターゲットです.
製品スクリプトは, fwup
を二度実行します.
最初は complete
ターゲット, そして再び bootloader
ターゲットです.
/dev/mmcblock0boot0
デバイスは カーネルによって読み込み専用に強制されます.
これをアンロックするには, 以下を実行します:
echo 0 > /sys/block/mmcblk0boot0/force_ro
fwupはいくつかの方法をサポートします:
meta-version
にバージョンを格納しています. これはエンドユーザにとって, 使いやすい方法です.
meta-vcs-identifier
に git
ハッシュ値を格納します. これは開発者向けです.
meta-uuid
にある( ${FWUP_META_UUID}
) fwup
の計算した UUIDを使う.
もちろん, fwup `v1.2.1' から 3つ目の方法は常に存在します.
この背景にあるのは, インストールされたファームウェアが目的のファームウェアと一致するかどうかを明確に知るためです.
UUIDは計算されるので, fwupの前のバージョンで生成された .fw
ファイルは UUIDを持ちます.
最初の2つのオプションは, fwup.conf
ファイルへ追加されるべきバージョンを要求します.
通常, 環境変数を使って追加されるので, バージョン番号はハードコードされません.
Use jq
!
$ fwup -m -i $FW_FILE | jq -n -R 'reduce inputs as $i ({}; . + ($i | (match("([^=]*)=\"(.*)\"") | .captures | {(.[0].string) : .[1].string})))'
{
"meta-product": "My Awesome Product",
"meta-version": "0.1.0",
"meta-author": "All of us",
"meta-platform": "imx6",
"meta-architecture": "arm",
"meta-creation-date": "2018-11-07T14:46:38Z",
"meta-uuid": "7add3c6d-230c-5bf1-77ec-5f785e91be40"
}
"raw" NANDフラッシュは, UBIのようなウェアレベリングレイヤを要求します.
UBI toolchainと
fwupとを統合する方法は, UBI Example fwup.conf を参照ください.
以前は eff-double-you-up
と発音していましたが, 同僚や他の人は .fw
ファイルを参照するときに "fwup"(一音節)や "fwup-dates" と呼び始めました.
いまは一音節を使っています.
これにより"a"ではなく"an"が使われているドキュメントで問題がおきました.
気軽にプルリクを送ってください.