# 通知設計書 47-CPU温度閾値超過通知

## 概要

本ドキュメントは、FreeBSD カーネルの coretemp ドライバが、Intel CPU のオンダイ温度センサーがクリティカル温度閾値を超過した際に発行する devctl 通知「coretemp / Thermal / {temperature}」の設計を記述する。

### 本通知の処理概要

Intel CPU のデジタル温度センサー（DTS）が Thermal Critical Status（TCC アクティベーション温度への到達）を検知した際に、現在の温度情報とともに devctl 通知を発行する。これにより、システムの過熱をユーザーランドで検知し、緊急シャットダウンなどの保護アクションを実行できる。

**業務上の目的・背景**：CPU の過熱はハードウェアの恒久的な損傷やデータ損失につながるリスクがある。この通知により、devd(8) 経由でCPU温度のクリティカル状態を即座に検知し、自動シャットダウン、冷却ファンの強制回転、管理者へのアラート通知などの保護措置を実行できる。サーバー運用やデータセンターにおけるハードウェア保護の重要な機構である。

**通知の送信タイミング**：sysctl 経由で coretemp の温度値が読み取られた際に、MSR_THERM_STATUS の Thermal Critical Status ビットが設定されていた場合に送信される。すなわち、温度の読み取り操作がトリガーとなる。

**通知の受信者**：devd(8) デーモンを経由して、システム管理ツール（shutdown コマンドの自動呼び出し等）や監視システムが受信する。

**通知内容の概要**：クリティカル温度到達時の温度値（TZ_ZEROC 基準、0.1 K 単位）と通知コード（0xcc）が含まれる。

**期待されるアクション**：受信者はシステムのシャットダウンを強く推奨される。devd.conf で自動シャットダウンをトリガーすることが典型的な使用方法。

## 通知種別

devctl カーネル通知（devd(8) 経由のシステムイベント通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（カーネル内 devctl_notify） |
| 優先度 | 最高（クリティカル温度） |
| リトライ | 無 |

### 送信先決定ロジック

devctl_notify() によりカーネルの devctl キューに投入される。

## 通知テンプレート

### devctl 通知フォーマット

| 項目 | 内容 |
|-----|------|
| system | coretemp |
| subsystem | Thermal |
| type | 温度値（0.1 K 単位の整数文字列） |
| data | notify=0xcc |

### 本文テンプレート

```
!system=coretemp subsystem=Thermal type=3731
notify=0xcc
```

注：type=3731 は 100.0C を表す（(100 - delta) * 10 + 2731）

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type（温度値） | 現在のCPU温度（0.1 K 単位） | (sc->sc_tjmax - tmp) * 10 + TZ_ZEROC | Yes |
| notify | 通知コード | 固定値 "0xcc" | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| sysctl 読み取り | coretemp_get_val_sysctl 実行 | THERM_STATUS_LOG かつ THERM_CRITICAL_STATUS ビット設定 | CPU クリティカル温度到達 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| THERM_CRITICAL_STATUS ビット未設定 | クリティカル温度に達していない場合（通常の温度ログのみ） |
| MSR 読み取りが無効 | 温度値の有効ビット（THERM_STATUS_VALID_MASK）が 0 の場合は温度値は -1 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[sysctl 温度値読み取り] --> B[coretemp_get_val_sysctl 実行]
    B --> C[MSR_THERM_STATUS 読み取り]
    C --> D{THERM_STATUS_LOG ビット設定?}
    D -->|No| E[通常の温度返却]
    D -->|Yes| F[MSR クリア、throttle_log = 1]
    F --> G{THERM_CRITICAL_STATUS ビット設定?}
    G -->|No| H[温度値返却（通知なし）]
    G -->|Yes| I[温度値計算]
    I --> J[device_printf でクリティカル警告出力]
    J --> K[snprintf で温度文字列構築]
    K --> L[devctl_notify coretemp/Thermal/temp 発行]
    L --> M[温度値返却]
    E --> N[終了]
    H --> N
    M --> N
```

## データベース参照・更新仕様

### 参照テーブル一覧

| 構造体フィールド | 用途 | 備考 |
|-----------|------|------|
| sc->sc_tjmax | TCC アクティベーション温度 | CPU モデルにより 85-110C |
| MSR_THERM_STATUS | CPU 温度 MSR | ハードウェアレジスタ |

### 更新テーブル一覧

| 構造体フィールド | 操作 | 概要 |
|-----------|------|------|
| sc->sc_throttle_log | UPDATE (= 1) | スロットルログフラグの設定 |
| MSR_THERM_STATUS | クリア | 温度ログビットのクリア |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 温度値無効 | THERM_STATUS_VALID_MASK が 0 | val = -1 を返却 |
| MSR 読み取り失敗 | CPU がサポートしていない場合 | rdmsr_safe でエラーハンドリング（attach 時） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 明示的な制限なし（sysctl 読み取り頻度に依存） |
| 1日あたり上限 | 明示的な制限なし |

### 配信時間帯

制限なし

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

- 通知には CPU 温度値のみが含まれ、機密情報は含まれない
- /dev/devctl の読み取りには root 権限が必要
- クリティカル温度通知は安全性に直結するため、確実な受信と対応が求められる

## 備考

- TZ_ZEROC = 2731（絶対零度からのオフセット、0.1 K 単位で 0C = 2731）
- notify=0xcc は温度クリティカル通知を示す固定値
- sc_tjmax は CPU モデルにより異なる（Core 2: 85-105C、Atom: 90-100C、その他: MSR から取得、デフォルト 100C）
- 温度読み取りは sysctl dev.cpu.N.temperature からトリガーされるため、ポーリング間隔は監視ツールの設定に依存する

---

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

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

### 推奨読解順序

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

coretemp ドライバの softc 構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | coretemp.c | `sys/dev/coretemp/coretemp.c` | struct coretemp_softc（行64-68）。sc_dev, sc_tjmax, sc_throttle_log |

**読解のコツ**: sc_tjmax は CPU の最大接合部温度であり、DTS の温度読み取り値はこの値からの差分（delta）として報告される。実温度 = sc_tjmax - delta。

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

温度読み取りと通知発行の流れを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | coretemp.c | `sys/dev/coretemp/coretemp.c` | coretemp_get_val_sysctl()（行342-408）が sysctl ハンドラ |

**主要処理フロー**:
1. **行353**: coretemp_get_thermal_msr() で MSR_THERM_STATUS を読み取り
2. **行357-378**: 有効ビットチェックと温度値の計算
3. **行380-382**: THERM_STATUS_LOG ビット検出 → MSR クリア、throttle_log 設定
4. **行395-396**: THERM_CRITICAL_STATUS 検出 → 温度値計算
5. **行399-400**: device_printf でクリティカル警告メッセージ
6. **行401-403**: snprintf で温度文字列構築、devctl_notify() 発行

#### Step 3: Tjmax の設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | coretemp.c | `sys/dev/coretemp/coretemp.c` | coretemp_attach()（行153-302）でCPUモデル別に sc_tjmax を設定 |

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

```
sysctl dev.cpu.N.temperature          [ユーザーランドからの読み取り]
    |
    +-- coretemp_get_val_sysctl()      [行342: sysctl ハンドラ]
            |
            +-- coretemp_get_thermal_msr()  [行326: MSR 読み取り]
            +-- coretemp_clear_thermal_msr() [行336: MSR クリア]
            +-- devctl_notify()             [行402: クリティカル温度通知]
```

### データフロー図

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

sysctl 読み取り --------> MSR_THERM_STATUS 読み取り --> 温度値返却
                              |
THERM_CRITICAL_STATUS --> 温度計算                    --> devctl キュー
sc_tjmax                  (tjmax - delta) * 10 + 2731      |
                          devctl_notify()               devd(8) 受信
                                                       --> shutdown 実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| coretemp.c | `sys/dev/coretemp/coretemp.c` | ソース | Intel CPU 温度センサードライバ。通知発行元 |
| specialreg.h | `sys/amd64/include/specialreg.h` | ヘッダー | MSR_THERM_STATUS 等の MSR 定義 |
| subr_bus.c | `sys/kern/subr_bus.c` | ソース | devctl_notify() 実装 |
