# 帳票設計書 36-efitable

## 概要

本ドキュメントは、FreeBSDのefitableコマンドが生成するEFIテーブル情報レポートの設計を記述する。efitableはUEFI（Unified Extensible Firmware Interface）のシステムテーブル情報を読み取り、構造化された形式でレポートするCLIユーティリティである。

### 本帳票の処理概要

efitableコマンドは、/dev/efiデバイスを通じてカーネルのEFIインターフェースにアクセスし、EFIIOC_GET_TABLE ioctlを使用して指定されたEFIテーブルのデータを取得する。取得したデータをテーブルタイプに応じたパーサーで解析し、libxo(3)を使用してテキスト/JSON/XML形式で出力する。

**業務上の目的・背景**：UEFIファームウェアの設定情報やリソースステータスを確認することは、ファームウェア更新管理やセキュアブート設定の検証、メモリマッピングの確認などシステム管理に重要である。

**帳票の利用シーン**：ファームウェア更新（ESRT）の確認、UEFIプロパティテーブルの確認、メモリ属性テーブルの確認、セキュアブート関連の設定検証に利用される。

**主要な出力内容**：
1. ESRT（EFI System Resource Table）：ファームウェアリソース数、バージョン、各エントリーの詳細
2. Properties Table：バージョン、長さ、メモリ保護属性
3. Memory Attributes Table：バージョン、記述子サイズ、エントリー数、各メモリ記述子の詳細

**帳票の出力タイミング**：ユーザーがefitableコマンドを実行した際に即時出力される。

**帳票の利用者**：ファームウェアエンジニア、システム管理者

## 帳票種別

詳細情報レポート / 一覧表

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | CLIターミナル | N/A | `efitable [-g guid | -t name] [--libxo]` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト / JSON / XML（libxo経由） |
| 用紙サイズ | N/A（ターミナル出力） |
| 向き | N/A |
| ファイル名 | N/A（標準出力） |
| 出力方法 | 標準出力（stdout）via libxo |
| 文字コード | ASCII |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

テーブルタイプに応じて異なるレイアウトで出力される。

#### ESRT形式
```
┌──────────────────────────────────────────┐
│  FwResourceCount: N                       │
│  FwResourceCountMax: N                    │
│  FwResourceVersion: N                     │
│                                           │
│  Entries:                                 │
│    FwClass: UUID-STRING                   │
│    FwType: N                              │
│    FwVersion: N                           │
│    LowestSupportedFwVersion: N            │
│    CapsuleFlags: 0xXXXX                   │
│    LastAttemptVersion: N                   │
│    LastAttemptStatus: N                    │
│  ...                                      │
└──────────────────────────────────────────┘
```

#### Properties形式
```
┌──────────────────────────────────────────┐
│  Version: 0xXXXX                          │
│  Length: N                                │
│  MemoryProtectionAttribute: 0xXXXX        │
└──────────────────────────────────────────┘
```

#### Memory形式
```
┌──────────────────────────────────────────┐
│  Version: 0xXXXX                          │
│  Length: N                                │
│  Entries: N                               │
│  ID: 0xXX                                │
│  Attributes: 0xXX                         │
│  Type: 0xXX                              │
│  Pages: 0xXX                              │
│  Phyaddr: 0xXXXX                          │
│  Virtaddr: 0xXXXX                         │
│  ...                                      │
└──────────────────────────────────────────┘
```

### ヘッダー部

該当なし（テーブル種別ごとにサマリーフィールドが先頭に出力される）

### 明細部

#### ESRT テーブル（efi_table_print_esrt関数 行171-224）

**サマリー部**

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | fw_resource_count | ファームウェアリソース数 | esrt->fw_resource_count | "%u" |
| 2 | fw_resource_count_max | 最大リソース数 | esrt->fw_resource_count_max | "%u" |
| 3 | fw_resource_version | リソーステーブルバージョン | esrt->fw_resource_version | "%u" |

**エントリー部（fw_resource_count回繰り返し）**

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | fw_class | ファームウェアクラスGUID | entries_v1[i].fw_class | UUID文字列 |
| 2 | fw_type | ファームウェアタイプ | entries_v1[i].fw_type | "%u" |
| 3 | fw_version | ファームウェアバージョン | entries_v1[i].fw_version | "%u" |
| 4 | lowest_supported_fw_version | 最低サポートバージョン | entries_v1[i].lowest_supported_fw_version | "%u" |
| 5 | capsule_flags | カプセルフラグ | entries_v1[i].capsule_flags | "%#x" |
| 6 | last_attempt_version | 最終試行バージョン | entries_v1[i].last_attempt_version | "%u" |
| 7 | last_attempt_status | 最終試行ステータス | entries_v1[i].last_attempt_status | "%u" |

#### Properties テーブル（efi_table_print_prop関数 行226-243）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | version | テーブルバージョン | prop->version | "%#x" |
| 2 | length | テーブル長 | prop->length | "%u" |
| 3 | memory_protection_attribute | メモリ保護属性 | prop->memory_protection_attribute | "%#lx" |

#### Memory Attributes テーブル（efi_table_print_memory関数 行245-288）

**サマリー部**

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | version | テーブルバージョン | attr->version | "%#x" |
| 2 | length | 記述子サイズ | attr->descriptor_size | "%u" |
| 3 | entries | エントリー数 | attr->num_ents | "%u" |

**記述子部（num_ents回繰り返し）**

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | id | 記述子ID | ループインデックス | "%#x" |
| 2 | attributes | 属性 | desc->attrs | "%#x" |
| 3 | type | メモリタイプ | desc->type | "%#x" |
| 4 | pages | ページ数 | desc->pages | "%#x" |
| 5 | phyaddr | 物理アドレス | desc->phy_addr | "%#p" |
| 6 | virtaddr | 仮想アドレス | desc->virt_addr | "%#p" |

### フッター部

該当なし

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| -t name | テーブル名指定（esrt/prop/memory） | -tまたは-gが必須 |
| -g uuid / -u uuid | GUID指定 | -tまたは-gが必須 |

### ソート順

テーブル内のエントリー順（変更不可）

### 改ページ条件

改ページなし

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| /dev/efi | EFIテーブルデータ取得 | ioctl(EFIIOC_GET_TABLE) |

### テーブル別参照項目詳細

#### efi_get_table_ioc

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| uuid | テーブルGUID | ioctl引数 | EFI_TABLE_ESRT/EFI_PROPERTIES_TABLE/EFI_MEMORY_ATTRIBUTES_TABLE |
| buf | テーブルデータ | EFIIOC_GET_TABLE | 2回呼び出し（1回目でサイズ取得、2回目でデータ取得） |
| table_len | テーブル長 | 1回目のioctl | malloc用サイズ |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| GUIDテーブルマッチ | memcmp(&uuid, &efi_table_ops[n].guid, sizeof(uuid)) | N/A | -gオプション時 |
| テーブル名マッチ | strcmp(table_name, efi_table_ops[n].name) | N/A | -tオプション時 |
| メモリ記述子ポインタ進行 | (char *)desc + attr->descriptor_size | N/A | 行278-279 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コマンド実行] --> B[xo_parse_args]
    B --> C[getopt_longによるオプション解析]
    C --> D{-t or -g?}
    D -->|-t| E[テーブル名でefi_table_ops検索]
    D -->|-g/-u| F[uuid_from_stringでUUIDパース]
    F --> G[UUIDでefi_table_ops検索]
    E --> H[/dev/efi オープン]
    G --> H
    H --> I[EFIIOC_GET_TABLE 1回目: table_len取得]
    I --> J[malloc(table_len)]
    J --> K[EFIIOC_GET_TABLE 2回目: データ取得]
    K --> L{テーブルタイプ}
    L -->|esrt| M[efi_table_print_esrt]
    L -->|prop| N[efi_table_print_prop]
    L -->|memory| O[efi_table_print_memory]
    M --> P[xo_finish]
    N --> P
    O --> P
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| テーブル未指定 | -tも-gも指定なし | "table is not set" | -tまたは-gオプション指定 |
| 非対応テーブル | 未知のテーブル名/GUID | "unsupported efi table" / "unsupported table" | 対応テーブル名確認 |
| 不正UUID | UUID文字列のパース失敗 | "invalid UUID" | UUID形式確認 |
| デバイスオープン失敗 | /dev/efiが開けない | xo_err: "/dev/efi" | 権限/モジュール確認 |
| ioctl失敗 | テーブル取得失敗 | "EFIIOC_GET_TABLE" | EFI機能の有効化確認 |
| UUID変換失敗 | ESRT出力時のUUID変換失敗 | "uuid_to_string error" | - |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数件〜数十件のEFIテーブルエントリー |
| 目標出力時間 | ミリ秒単位 |
| 同時出力数上限 | 制限なし |

## セキュリティ考慮事項

- /dev/efiへのアクセスにはO_RDWRフラグが必要であり、root権限が通常必要
- EFIテーブル情報にはファームウェアバージョンやメモリマッピングなどのシステム構成情報が含まれる

## 備考

- 対応テーブルは3種類: esrt（EFI_TABLE_ESRT）、prop（EFI_PROPERTIES_TABLE）、memory（EFI_MEMORY_ATTRIBUTES_TABLE）
- libxo(3)によるJSON/XML出力対応（--libxoオプション）
- efi_table_ops配列は関数ポインタによるテーブルドリブン設計（行50-63）
- Memory Attributesテーブルの記述子サイズはsizeof(efi_memory_descriptor)と異なる場合がある（行266-270コメント）

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | efitable.c | `usr.sbin/efitable/efitable.c` | 行50-63: efi_table_ops配列（テーブル名/パーサー/GUID対応表） |
| 1-2 | efitable.c | `usr.sbin/efitable/efitable.c` | 行42-43: TABLE_MAX_LEN, EFITABLE_XO_VERSION定数 |

**読解のコツ**: efi_table_opsは関数ポインタテーブル。名前/GUID→パーサー関数のディスパッチに使用される。

#### Step 2: エントリーポイント（main）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | efitable.c | `usr.sbin/efitable/efitable.c` | 行65-169: main関数 |

**主要処理フロー**:
1. **行87-143**: getopt_longによるオプション解析（-g/-u: UUID指定、-t: テーブル名指定）
2. **行151-153**: /dev/efiオープン（O_RDWR）
3. **行155-163**: 2段階ioctl（サイズ取得→データ取得）
4. **行165**: テーブルタイプ別パーサー呼び出し

#### Step 3: 各テーブル出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | efitable.c | `usr.sbin/efitable/efitable.c` | 行171-224: efi_table_print_esrt（ESRT出力） |
| 3-2 | efitable.c | `usr.sbin/efitable/efitable.c` | 行226-243: efi_table_print_prop（Properties出力） |
| 3-3 | efitable.c | `usr.sbin/efitable/efitable.c` | 行245-288: efi_table_print_memory（Memory Attributes出力） |

### プログラム呼び出し階層図

```
main() [efitable.c:65]
    |
    +-- xo_parse_args() [libxo]
    +-- getopt_long() [オプション解析]
    |       +-- uuid_from_string() [-g/-uオプション時]
    |
    +-- open("/dev/efi", O_RDWR)
    +-- ioctl(EFIIOC_GET_TABLE) x2 [サイズ取得→データ取得]
    |
    +-- efi_table_ops[efi_idx].parse() [テーブル別パーサー]
            |
            +-- efi_table_print_esrt() [efitable.c:171]
            |       +-- uuid_to_string() [GUID文字列化]
            |       +-- xo_emit() [libxo出力]
            |
            +-- efi_table_print_prop() [efitable.c:226]
            |       +-- xo_emit() [libxo出力]
            |
            +-- efi_table_print_memory() [efitable.c:245]
                    +-- xo_emit() [libxo出力]
```

### データフロー図

```
[入力]                        [処理]                      [出力]

コマンドライン引数 ──────> テーブル名/GUID解析         ──> efi_idx
                               |                            |
/dev/efi ────────────> EFIIOC_GET_TABLE ioctl          ──> raw table data
                               |                            |
raw table data ──────> テーブル別パーサー               ──> xo_emit()
                               |                            |
                         +-- uuid_to_string() [ESRT]    ──> 標準出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| efitable.c | `usr.sbin/efitable/efitable.c` | ソース | メインプログラム（全機能を単一ファイルに実装） |
| Makefile | `usr.sbin/efitable/Makefile` | 設定 | ビルド設定 |
| efi.h | `sys/sys/efi.h` | ヘッダ | EFIテーブル構造体定義（efi_esrt_table, efi_prop_table等） |
| efiio.h | `sys/sys/efiio.h` | ヘッダ | EFI ioctl定義（EFIIOC_GET_TABLE） |
| uuid.h | `/usr/include/uuid.h` | ヘッダ | UUID操作関数 |
