Tock Binary Format

Tockプロセスバイナリは、TBF (Tock Binary Format) でなければなりません。TBFは、プロセスに 関するメタデータをエンコードするヘッダ部分と直接実行されるバイナリブロブ、オプションのパディングから なります。

Tock App Binary:

Start of app -> +-------------------+
                | TBF Header        |
                +-------------------+
                | Compiled app      |
                | binary            |
                |                   |
                |                   |
                +-------------------+
                | Optional padding  |
                +-------------------+

ヘッダは、アプリの重要な側面を理解するためカーネル(および tockloaderなどのツール)により解釈されます。 特に、カーネルは、アプリを初めて実行する際に実行を開始すべきエントリーポイントがアプリケーションバイナリの どこにあるのかを知る必要があります。

ヘッダの後は、アプリが望むバイナリデータを自由に含めることができ、そのフォーマットは完全にアプリ次第です。 たとえば、再配置のためのすべてのサポートはアプリ自体によって処理されなければなりません。

最後に、アプリバイナリは特定の長さにパディングすることができます。これは、長さと始点が2の累乗でなければ ならないというMPUの制限のために必要です。

アプリの連結リスト

Tockのアプリは、フラッシュ内で実質的な連結リスト構造を作成します。つまり、次のアプリの開始点は、前の アプリの終了時点のすぐ後にあります。したがって、カーネルが次のアプリの開始を見つけることができるように、 TBFヘッダはアプリの長さを指定しなければなりません。

アプリ間にギャップがある場合は、連結リスト構造をそのまま維持するために「空のアプリ」を挿入することができます。

また、機能的には、Tockアプリはサイズの長いものから短いものへとソートされます。これは、MPUのアライメントに 関する規則に一致します。

空のTockアプリ

「アプリ」はコードを含む必要はありません。アプリは無効であるとマーク付けられ、実質的にはアプリ間の パディングとして機能します。

TBFヘッダー

TBFヘッダのフィールドは以下の通りである。ヘッダのすべてのフィールドはリトルエンディアンです。


#![allow(unused)]
fn main() {
struct TbfHeader {
    version: u16,            // Version of the Tock Binary Formatのバージョン(現在は2)
    header_size: u16,        // TBFヘッダの総バイト数
    total_size: u32,         // プログラムイメージのヘッダを含むバイトサイズ
    flags: u32,              // このアプリケーションに関連するさまざまなフラグ
    checksum: u32,           // 既存のオプションの構造体を含むヘッダの全4バイトワードのXOR

    // オプションの構造体。すべてのオプション構造は4バイト境界から開始する。
    main: Option<TbfHeaderMain>,
    pic_options: Option<TbfHeaderPicOption1Fields>,
    name: Option<TbfHeaderPackageName>,
    flash_regions: Option<TbfHeaderWriteableFlashRegions>,
}

// オプションのヘッダ構造体用の識別子。
enum TbfHeaderTypes {
    TbfHeaderMain = 1,
    TbfHeaderWriteableFlashRegions = 2,
    TbfHeaderPackageName = 3,
    TbfHeaderPicOption1 = 4,
    TbfHeaderFixedAddresses = 5,
}

// 各構造体を識別する型-長さ-値ヘッダ。
struct TbfHeaderTlv {
    tipe: TbfHeaderTypes,    // どの構造体に従うかを示す16ビットの識別子。
                             // 16ビット識別子の最上位ビットがセットされた場合は、
                             // ツリー外(プライベート)のTLVエントリを示す。
    length: u16,             // 続く構造体のバイト数
}

// すべてのアプリに必要な主な設定。これが存在しない場合、「アプリ」はパディングとみなされ、
// 空の連結リスト要素をアプリのフラッシュスペースに挿入するために使用されます。
struct TbfHeaderMain {
    base: TbfHeaderTlv,
    init_fn_offset: u32,     // アプリケーションを開始するためにコールする関数
    protected_size: u32,     // アプリケーションが書き込みできないバイト数
    minimum_ram_size: u32,   // アプリケーションが必要とするRAMの量
}

// アプリのパッケージ名(オプション)
struct TbfHeaderPackageName {
    base: TbfHeaderTlv,
    package_name: [u8],      // アプリケーション名のUTF-8文字列
}

// アプリのフラッシュ空間内の定義されたフラッシュ領域
struct TbfHeaderWriteableFlashRegion {
    writeable_flash_region_offset: u32,
    writeable_flash_region_size: u32,
}

//アプリが書き込みを意図している1以上の特に識別されたフラッシュ領域
struct TbfHeaderWriteableFlashRegions {
    base: TbfHeaderTlv,
    writeable_flash_regions: [TbfHeaderWriteableFlashRegion],
}

// RAMの処理およびフラッshの処理に必要な固定の必要なアドレス
struct TbfHeaderV2FixedAddresses {
    start_process_ram: u32,
    start_process_flash: u32,
}
}

すべてのヘッダは4バイトの倍数であり、すべてのTLV構造体は4バイトの倍数でなければならないので、 TBFヘッダ全体は常に4バイトの倍数になります。

TBFヘッダのベース

TBFヘッダは、ベースヘッダとそれに続く型-長さ-値がエンコードされた要素シーケンスを含む。ベースヘッダと TLV要素のすべてのフィールドはリトルエンディアンである。ベースヘッダは16バイトで、5つのフィールドを持つ。

0             2             4             6             8
+-------------+-------------+---------------------------+
| Version     | Header Size | Total Size                |
+-------------+-------------+---------------------------+
| Flags                     | Checksum                  |
+---------------------------+---------------------------+
  • Version TBFヘッダバージョンを示す16ビットの符号なし整数。常に2

  • Header Size TBFヘッダ全体(ベースヘッダとすべてのTLV要素を含む)の長さをバイト単位で示す 16ビットの符号なし整数。

  • Total Size TBF全体(ヘッダを含む)のサイズをバイト単位で示す32ビットの符号なし整数。

  • Flags プロセスの属性を指定する。

       3                   2                   1                   0
     1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | Reserved                                                  |S|E|
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    
    • Bit 0 はプロセスが有効であるか否かを示す。1はプロセスが有効であることを示す。 有効でないプロセスは起動時に実行されない。
    • Bit 1 はプロセスがスティッキーであるか否かを示す。1はプロセスがスティッキーであることをindicates the process is 示す。スティッキープロセスは削除時に追加の確認が行われる。たとえば、tockloaderでは 削除するのに--forceフラグの指定が必要になる。これは常に利用可能であるべきプロセスとして 実行するサービスに有用である。
    • Bits 2-31 はリザーブで0をセットする必要がある。
  • Checksum は、チェックサムフィールドを含むワードを除いたヘッダーの各4倍とワードをXORした結果で ある。

TLV要素

ヘッダの後には直接、TLV要素のシーケンスが続きます。TLV要素は4バイトにアラインされます。TLV要素のサイズが 4バイトアラインでない場合は、最大3バイトのパディングが行われます。各要素は、16ビットの型と16 ビットの長さで 始まり、要素データが続きます。

0             2             4
+-------------+-------------+-----...---+
| Type        | Length      | Data      |
+-------------+-------------+-----...---+
  • Type 要素の型を示す16ビットの符号なし整数。
  • Length データフィードの長さをバイト単位で示す16ビットの符号なし整数。
  • Data 要素固有のデータ。dataフィールドの形式はtypeにより決定される。

TLVの型

TBFは任意の要素型を含むことができます。Tockプロジェクトで定義された要素と外部で定義された要素の間で 型IDが衝突しないように、ID空間は2つのセグメントに分割されています。Tockプロジェクトで定義された型IDは 最上位ビット(ビット15)がアンセットされ、外部で定義された型IDは最上位ビットがセットされている必要が あります。

1 Main

Main要素は3つの32ビットフィールを持ちます。

0             2             4             6             8
+-------------+-------------+---------------------------+
| Type (1)    | Length (12) | init_offset               |
+-------------+-------------+---------------------------+
| protected_size            | min_ram_size              |
+---------------------------+---------------------------+
  • init_offset 最初の実行命令(通常は_startシンボル)を含むバイナリペイロード(すなわち、 実際のアプリケーションバイナリ)の開始点からのバイト単位のオフセット値。
  • protected_size プロセスが書き込めないようにするヘッダ後のバイト単位のフラッシュの量。
  • minimum_ram_size プロセスが必要とするバイト単位のメモリの最小量。

Main TLVヘッダが存在しない場合、これらの値はすべてのデフォルト値の0となる。

2 Writeable flash regions(書き込み可能なフラッシュ領域)

Writeable flash regionsは、フラッシュ内のプロセスが変更を行うバイナリの領域を示します。

0             2             4             6             8
+-------------+-------------+---------------------------+
| Type (2)    | Length (8)  | offset                    |
+-------------+-------------+-------------+-------------+
| size                      |
+---------------------------+
  • offset 書き込み可能領域のバイナリ開始時点からのオフセット値。
  • size 書き込み可能領域のサイズ。

3 Package Name(パッケージ名)

Package nameは、バイナリのユニークな名前を指定します。唯一のフィールドはUTF−8エンコーディングの パッケージ名です。

0             2             4
+-------------+-------------+----------...-+
| Type (3)    |   Length    | package_name |
+-------------+-------------+----------...-+
  • package_nameはUTF−8エンコーディングのパッケージ名です。

5 Fixed Addresses(固定アドレス)

Fixed Addressesは、プロセスがフラッシュやRAMに必要な特定のアドレスを指定することを可能にします。 Tockは位置非依存のアプリをサポートしますが、すべてのアプリが位置非依存であるわけではありません。 これにより、カーネル(および他のツール)は、位置非依存でないバイナリを誤った場所にロードすることを 避けることができます。

0             2             4             6             8
+-------------+-------------+---------------------------+
| Type (5)    | Length (8)  | ram_address               |
+-------------+-------------+-------------+-------------+
| flash_address             |
+---------------------------+
  • ram_address プロセスのメモリアドレスがスタートすべきメモリ内のアドレス。固定アドレスが 不要な場合、0xFFFFFFFFを設定するべきです。
  • flash_address プロセスバイナリ(ヘッダではない)が位置すべきフラッシュ内のアドレス。 フラッシュ用にリンカに提供された値と一致する。固定アドレスが不要な場合、0xFFFFFFFFを 設定するべきです。

コード

プロセスのコード自体には特定のフォーマットはありません。それはフラッシュに存在しますが、特定のアドレスが プラットフォームによって決定されています。バイナリ内のコードは、位置非依存のコードを使用するなど、 どのようなアドレスでも正常に実行できなければなりません。