Armadilloフォーラム

ハードウェアWDTについて

inagaki

2024年7月24日 15時08分

お世話になります、稲垣と申します。

ハードウェアWDTについて教えて下さい。

ハードウェアWDTは「特にアプリ側で起動しなくても、Armadillo 起動直後から機能してカーネルが固まった際にハードウェアウォッチドッグタイマーリセットを発生させます。」などと記述されますが、現在私が動作確認しているアルマジロ(A4410-B00Z)ではハードウェアWDT機能が自動では動作していない様に思われます。

その事を営業技術部の尾藤様へ相談したところ
「ウォッチドッグタイマーは、Hermit-Atブートローダーによって有効化されます。」
と言う回答を頂きました。

そこで、以下のダウンロードページよりHermit-Atブートローダーのソースファイル(v3.11.0)をダウンロードしました。
【ダウンロードページ】
https://armadillo.atmark-techno.com/resources/software/armadillo-440/bo…

そして、以下の操作手順書の64ページにある「7.4. ブートローダーをビルドする」の手順に沿ってブートローダーを作成しました。
【操作手順書PDF】
https://armadillo.atmark-techno.com/files/downloads/armadillo-440/docum…

そして、作成したブートローダーを「hermit.exe」を使用してアルマジロへ書込み、再起動後にわざとフォーク爆弾コマンドを入力してシステム自体が動作しなくなるのを確認したのですが、数分待ってもハードウェアWDTでの再起動は起きませんでした。
【フォーク爆弾コマンド】
forkbomb(){ forkbomb|forkbomb & } ; forkbomb

もしかしたら、ハードウェアWDTが起動しないのは私が作成したカーネルが原因かと思い、以下のダウンロードページからカーネルのソースファイル(v3.14-at13)をダウンロードしました。
【ダウンロードページ】
https://armadillo.atmark-techno.com/resources/software/armadillo-440/li…

そして、同様に上記手順書の55ページにある「7.1. Linux カーネル/ユーザーランドをビルドする」の手順書通りにLinux カーネルを作成してアルマジロへ書き込みました。
しかし、同様にフォーク爆弾コマンドを入力してシステムは固まるが、ハードウェアWDTは何分待っても機能しないと思われます。

ハードウェアWDTをArmadillo 起動直後から機能させるには他に何か設定などが必要でしょうか?
また、ハードウェアWDTが機能する/確認する方法などあれば教えて下さい。

ちなみに、アルマジロの再起動後にコマンドで「echo "!" > /dev/watchdog0」を入力すると、ハードウェアWDTが起動したと思われ、約10秒後に再起動は起きます。(コマンドで1度書いただけなので、10秒以内に次にキックする人がいないので再起動したと思われます。)
その為、ハードウェアWDT自体は有効になっているが、それをキックする機能が正常に動作していないのかと推測されます。
(ハードウェアWDTをキックするのはブートローダー? それともLinux カーネル?)

お忙しいところ申し訳ありませんが、ご確認をお願いします。

コメント

溝渕です。

> ハードウェアWDTは「特にアプリ側で起動しなくても、Armadillo 起動直後から機能してカーネルが固まった際にハードウェアウォッチドッグタイマーリセットを発生させます。」などと記述されますが、

上記の通りで、カーネルが固まった(動作できなくなった)場合にハードウェアウォッチドッグタイマーリセットが発生します。アプリケーションが固まった等の理由ではリセットしない点に注意してください。

> また、ハードウェアWDTが機能する/確認する方法などあれば教えて下さい。

[armadillo]# echo 1 > /proc/sys/kernel/sysrq
[armadillo]# echo c > /proc/sysrq-trigger

のようにするとLinuxカーネルがクラッシュし、ハードウェアウォッチドッグタイマーリセットが発生すると思います。

溝渕様

お世話になります、稲垣です。

早速のご回答ありがとうございます。

> [armadillo]# echo 1 > /proc/sys/kernel/sysrq
> [armadillo]# echo c > /proc/sysrq-trigger
> のようにするとLinuxカーネルがクラッシュし、ハードウェアウォッチドッグタイマーリセットが発生すると思います。

ハードウェアWDTの動作確認方法を教えて頂き、ありがとうございます。
フォーク爆弾コマンドではカーネルはクラッシュはしなかったのですね。
申し訳ありませんでした。

ちなみに、私の動作確認しているアルマジロへログインして、「su」コマンドで「root」ユーザーへ変更します。
しかし、「/proc/sys/kernel」の配下に「sysrq」が無く、「/proc」の配下に「sysrq-trigger」もありません。

これらのファイルはカーネルを作成する時にどこかの設定を有効にすると作成されるファイルなのでしょうか?
それとも、通常から必ずあるファイルなのでしょうか?

本当に初心者の質問で申し訳ありません。
お手数をお掛けしますが、よろしくお願いします。

溝渕です。

> しかし、「/proc/sys/kernel」の配下に「sysrq」が無く、「/proc」の配下に「sysrq-trigger」もありません。
>
> これらのファイルはカーネルを作成する時にどこかの設定を有効にすると作成されるファイルなのでしょうか?
> それとも、通常から必ずあるファイルなのでしょうか?

設定が必要です。説明が不十分で申し訳ありません。

標準のLinuxカーネルイメージでは、該当機能が無効化されています。Linuxカーネルコンフィギュレーションで、以下のように設定を有効化し、

Kernel hacking --->
[*] Magic SysRq key

ビルドしたLinuxカーネルイメージで起動すると利用可能になります。

溝渕様

お世話になります、稲垣です。

早速のご回答、ありがとうございます。

> 標準のLinuxカーネルイメージでは、該当機能が無効化されています。Linuxカーネルコンフィギュレーションで、以下のように設定を有効化し、
>
> Kernel hacking --->
> [*] Magic SysRq key
>
> ビルドしたLinuxカーネルイメージで起動すると利用可能になります。

早速、上記設定を有効にしたLinuxカーネルを作成してアルマジロへ書き込んだところ、「/proc/sys/kernel」の配下に「sysrq」があり、「/proc」の配下に「sysrq-trigger」もある事が確認出来ました。
ありがとうございました。

ただし、教えて頂いた「echo 1 > /proc/sys/kernel/sysrq」「echo c > /proc/sysrq-trigger」を続けて入力したところシステムは停止したと思われますが、10秒待っても…3分待っても再起動は起きませんでした。(2回実施したが、2回とも3分以上待っても再起動はしない)

ちなみに、「halt」コマンドを入力すると約130秒ほどで再起動が起きました。(1回目:132秒後、2回目:133秒後)
こちらは以下のマニュアルの「9.3.16. ウォッチドッグタイマー」の注意書きにも記述されていますので正常動作だと思うのですが、何故か教えて頂いたコマンドでは3分待っても再起動が出来ませんでした。
【参考マニュアル】
https://manual.atmark-techno.com/armadillo-4x0/armadillo-400_series_sof…

やはり、まだ他にもカーネル作成時に何か設定などを有効にしないと、起動時に自動でハードウェアWDTは機能しないのでしょうか?
それとも、ブートローダーの作成時は特に自分で設定変更できる箇所が無かったが、ハードウェアWDTを起動させる場合にどこか設定変更が必要なのでしょうか?

ちなみに、私の「/proc/config.gz」の「Watchdog Device Drivers」の設定を確認しましたら以下の設定でした。
+++++++++++++++++++++++++++++++++
#
# Watchdog Device Drivers
#
CONFIG_SOFT_WATCHDOG=y
# CONFIG_GPIO_WATCHDOG is not set
# CONFIG_DW_WATCHDOG is not set
# CONFIG_MAX63XX_WATCHDOG is not set
CONFIG_IMX2_WDT=y
# CONFIG_MEN_A21_WDT is not set
+++++++++++++++++++++++++++++++++
(とりあえず、ハードウェアWDTは有効になっていると思われます。(ちなみに、ソフトウェアWDTは自作のアプリで使用予定です。))

他にも設定確認するファイルや箇所などがあれば教えて下さい。

色々とお手数をお掛けして申し訳ありませんが、よろしくお願いします。

溝渕です。

> ただし、教えて頂いた「echo 1 > /proc/sys/kernel/sysrq」「echo c > /proc/sysrq-trigger」を続けて入力したところシステムは停止したと思われますが、10秒待っても…3分待っても再起動は起きませんでした。(2回実施したが、2回とも3分以上待っても再起動はしない)

sysrqで停止させても、wdtをkickするtimerは停止しませんでした。確認不足ですみません。

> やはり、まだ他にもカーネル作成時に何か設定などを有効にしないと、起動時に自動でハードウェアWDTは機能しないのでしょうか?

「halt」コマンド実行時に再起動している時点でハードウェアWDTは機能しています。この再起動のリセット要因はWDTです。

--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -294,7 +294,7 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
                 * give max timeout before reboot will take place
                 */
                del_timer_sync(&wdev->timer);
-               imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+               imx2_wdt_set_timeout(wdog, 5);
                imx2_wdt_ping(wdog);
                dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
        }

上記のようにLinuxカーネルのソースコードを変更すると、

[armadillo ~]# halt
 :(snip)
Requesting system halt
imx2-wdt imx2-wdt.0: Device shutdown: Expect reboot!
reboot: System halted

"imx2-wdt imx2-wdt.0: Device shutdown: Expect reboot!"が出力された5秒後に再起動するようになると思います。

> それとも、ブートローダーの作成時は特に自分で設定変更できる箇所が無かったが、ハードウェアWDTを起動させる場合にどこか設定変更が必要なのでしょうか?

いえ。設定不要でWDTは有効になっています。

溝渕様

お世話になります、稲垣です。

早速のご回答、ありがとうございます。

> sysrqで停止させても、wdtをkickするtimerは停止しませんでした。確認不足ですみません。

了解しました。

>

> --- a/drivers/watchdog/imx2_wdt.c
> +++ b/drivers/watchdog/imx2_wdt.c
> @@ -294,7 +294,7 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
>                  * give max timeout before reboot will take place
>                  */
>                 del_timer_sync(&wdev->timer);
> -               imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
> +               imx2_wdt_set_timeout(wdog, 5);
>                 imx2_wdt_ping(wdog);
>                 dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
>         }
> 

>
> 上記のようにLinuxカーネルのソースコードを変更すると、
>
>

> [armadillo ~]# halt
>  :(snip)
> Requesting system halt
> imx2-wdt imx2-wdt.0: Device shutdown: Expect reboot!
> reboot: System halted
> 

>
> "imx2-wdt imx2-wdt.0: Device shutdown: Expect reboot!"が出力された5秒後に再起動するようになると思います。

了解しました。
早速上記変更を試してみたいと思います。

> いえ。設定不要でWDTは有効になっています。

こちらも了解しました。
「halt」コマンドが効いた時点でハードウェアWDTが有効だと思わるのですね。
もし、「halt」コマンド以外にハードウェアWDTを確認出来るコマンド/方法などがあれば教えて下さい。

まずは、上記「halt」コマンドのタイムアウト時間を変更して動作確認をしてみます。
少々お待ちください。

溝渕です。

> もし、「halt」コマンド以外にハードウェアWDTを確認出来るコマンド/方法などがあれば教えて下さい。

sysrqでWDTのkickが停止しないとなると、Linuxカーネルをカスタマイズするのが良いかと思います。

kickするのは以下の箇所なので、

drivers/watchdog/imx2_wdt.c
static int imx2_wdt_ping(struct watchdog_device *wdog)
{
	struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
	regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
	regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
	return 0;
}

ここを通らないようにするか、何かしらの割り込みハンドラの中で無限ループ(while(1);)する等すると、延々と再起動し続けるLinuxカーネルができると思います。

溝渕様

お世話になります、稲垣です。

早速のご回答、ありがとうございます。

教えて頂いた「imx2_wdt.c」を修正して、「halt」コマンドを入力後に早く再起動が起きる事を確認出来ました。
(タイムアウト時間を5秒に変更して約10秒後に再起動しました。)
ありがとうございました。

> sysrqでWDTのkickが停止しないとなると、Linuxカーネルをカスタマイズするのが良いかと思います。
>
> kickするのは以下の箇所なので、
>
>

> drivers/watchdog/imx2_wdt.c
> static int imx2_wdt_ping(struct watchdog_device *wdog)
> {
> 	struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
> 
> 	regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
> 	regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
> 	return 0;
> }
> 

>
> ここを通らないようにするか、何かしらの割り込みハンドラの中で無限ループ(while(1);)する等すると、延々と再起動し続けるLinuxカーネルができると思います。

また、確認方法のご提示、ありがとうございます。
とりあえず、「halt」コマンドでハードウェアWDT機能が入っている事が判れば、ひとまずハードウェアWDTの確認はここまでで大丈夫です。

そして、以下が現在の本来の問題なのですが…。

実は私の作成したシステムでソフトウェアWDTをメイン処理の無限ループ内で30秒間隔でキックする処理を行っています。(タイムアウト時間はデフォルトの60秒のまま)
そして、同じ無限ループ内でタグの読取り処理を行っているのですが、システムが数週間経つと読取り処理が止まっている問題現象が発生しました。

つまり、読取り処理が止まるのは何かの要因(障害)で処理が無限ループから抜けるか、処理が何かの要因で固まった可能性が考えられますが…、するとソフトウェアWDTをキックする処理も止まるので再起動が起こると思っていましたが、何時間/何日経っても再起動が起きなかったと思われます。(現在も詳細原因は不明です。)
そこで、その要因の一つとしてカーネル自体が固まっている可能性を考えました。

そこで、ソフトウェアWDTでの監視をハードウェアWDTへ変更してカーネルが固まっても再起動するかと思ったのですが、現時点でも「halt」コマンドで再起動する事からハードウェアWDT機能は既に有効で、もし現在もカーネルが固まったら自動的に再起動するかと思われます。
なので、カーネルが単に固まっていたとする可能性は低いかと思いました。

例えば、ハードウェアWDT機能は機能し続けるが、ソフトウェアWDTが機能しなくなる可能性が高い要因は何が考えられますでしょうか?
やはり、「echo 1 > /proc/sys/kernel/sysrq」「echo c > /proc/sysrq-trigger」でカーネルがクラッシュしても、ハードウェアWDTだけはが生き続けて再起動しなかった様な現象が発生した可能性でしょうか?

ちなみに、システムの電源を手動でOFF/ONすれば正常に立ち上がり、読取動作は開始します。(ただし、また数日/数週間したら止まってしまう現象を繰り返しています。)
お忙しいところ申し訳ありませんが、ご確認をお願いします。

溝渕です。

稲垣様が作成されたソフトウェアの実装を把握していないので推測になりますが、以下の確認は行った方が良いように思います。

- ソフトウェアWDTを正しく利用できていない
- ソフトウェアWDTをキックする処理が(意図せず)動き続けている

前者については、
https://armadillo.atmark-techno.com/blog/53/1319
や、稲垣様が作成されたソフトウェアで、ソフトウェアWDTをキックする処理を明示的に削除して再起動が発生するかを確認すると良いと思います。

後者については、稲垣様が作成されたソフトウェアで、ソフトウェアWDTをキックする箇所にデバッグコード(printf等のメッセージ出力)を追加することで確認できるかと思います。

溝渕様

お世話になります、稲垣です。

早速のご回答、ありがとうございます。

> - ソフトウェアWDTを正しく利用できていない
> - ソフトウェアWDTをキックする処理が(意図せず)動き続けている
>
> 前者については、
> https://armadillo.atmark-techno.com/blog/53/1319
> や、稲垣様が作成されたソフトウェアで、ソフトウェアWDTをキックする処理を明示的に削除して再起動が発生するかを確認すると良いと思います。
>
> 後者については、稲垣様が作成されたソフトウェアで、ソフトウェアWDTをキックする箇所にデバッグコード(printf等のメッセージ出力)を追加することで確認できるかと思います。

私のプログラムを記述せずに話を始めて申し訳ありません。
以下に私のシステムのメイン処理プログラム(抜粋)を記述します。

int main()
{
    int fd_wdt;
    char dev_wdt[]="/dev/watchdog1";   ←①
    uint64_t m_WatchDogTimer;
    :
    :
    fd_wdt = open(dev_wdt,O_WRONLY);        //wdt 60s  ←②
     m_WatchDogTimer = utl_GetCurrentCount();
    :
    :
    while(1) {
        :
        :
        /* ③ここでタグの読取り処理 */
        :
        :
         if (utl_GetElapsedMs(m_WatchDogTimer) >= 30000) {
            remtrace_printf("[WDT]WDT_START");       ←④ログ出力処理
            write(fd_wdt,"!",1);             ←⑤
            m_WatchDogTimer = utl_GetCurrentCount();
          }
    }
    :
    :
    close(fd_wdt);              ←⑥
    :
    :
}

現在はメイン処理の無限ループ前で「/dev/watchdog1」を「②open」して、無限ループ内で「⑤write」を行っています。
この「②open」処理は残して「⑤write」をコメントアウトでキック処理を行わない場合は、システム起動後の約60秒後に再起動します。
なので、ソフトウェアWDTは機能していると思われます。

また、「④ログ出力」処理にてソフトウェアWDTをキックする毎にログ出力を行っていますが、通常は約30秒毎にログ出力されますが、問題発生時にはログ出力が止まっています。
もちろん、ログ出力に問題があってログ出力は出来ないがソフトウェアWDTのキック処理は動作している可能性はあります。
ただし、その場合は「③タグの読取り処理」も動作し続けても良いように思っています。(この「③タグの読取り処理」が止まる事が問題です。)

もう一つ気になったのが無限ループから抜ける処理は無いが、何かの要因(障害など)で無限ループを抜けた場合に「⑥close」処理を行っていますが、この「⑥close」を実行してもソフトウェアWDTが停止されないかちょっと気になっています。

お忙しいところ申し訳ありませんが、ご確認をお願いします。

溝渕です。

> もう一つ気になったのが無限ループから抜ける処理は無いが、何かの要因(障害など)で無限ループを抜けた場合に「⑥close」処理を行っていますが、この「⑥close」を実行してもソフトウェアWDTが停止されないかちょっと気になっています。

ソースコードを確認したところ、closeしただけだと停止しなさそうです。その場合は、"watchdog did not stop!"とメッセージが出力されるようです。

drivers/watchdog/watchdog_dev.c:
static int watchdog_release(struct inode *inode, struct file *file)
{
 :(snip)
	/* If the watchdog was not stopped, send a keepalive ping */
	if (err < 0) {
		mutex_lock(&wdd->lock);
		if (!test_bit(WDOG_UNREGISTERED, &wdd->status))
			dev_crit(wdd->dev, "watchdog did not stop!\n");
		mutex_unlock(&wdd->lock);
		watchdog_ping(wdd);
	}

明示的に"V"を書き込んで停止させた後にcloseした場合は、上記メッセージは出力されないようです。

ソースコードを確認しただけなので、読み間違え等あるかもしれません。シンプルなプログラム(softdogを開始後、closeするだけ等)を作成して確認するのが確実かなと思います。

溝渕様

お世話になります、稲垣です。

早速のご回答、ありがとうございます。

> ソースコードを確認しただけなので、読み間違え等あるかもしれません。シンプルなプログラム(softdogを開始後、closeするだけ等)を作成して確認するのが確実かなと思います。

先ほどの私のプログラムで起動した120秒後に無限ループから抜ける処理を入れて、わざと「⑥close」処理を行う様なプログラムを作成してテストを行いました。

int main()
{
    int fd_wdt;
    char dev_wdt[]="/dev/watchdog1";
    uint64_t m_WatchDogTimer;
    uint64_t m_TestTimer;
    :
    :
    fd_wdt = open(dev_wdt,O_WRONLY);        //wdt 60s
     m_WatchDogTimer = utl_GetCurrentCount();
     m_TestTimer = utl_GetCurrentCount();
    :
    :
    while(1) {
        :
        :
        /* ここでタグの読取り処理 */
        :
        :
         if (utl_GetElapsedMs(m_WatchDogTimer) >= 30000) {
            remtrace_printf("[WDT]WDT_START");     ←ログ出力処理
            write(fd_wdt,"!",1);
            m_WatchDogTimer = utl_GetCurrentCount();
          }
          if (utl_GetElapsedMs(m_TestTimer) >= 120000) {
              break;         ←120秒後に無限ループを抜ける
          }
    }
    :
    :
    close(fd_wdt);
    :
    :
}

すると、起動後120秒までは読取動作など動いていますが、120秒後に無限ループを抜けて読取り処理が止まり「⑥close」処理を行いプログラムが終了し、その後60秒後に再起動が起こりました。

なので、溝渕様のご回答の通り「⑥close」処理を行ってもソフトウェアWDTでの再起動は止まらない事が確認出来ました。

また、元のプログラムへ戻してソフトウェアWDTを常に起動させた状態で、「echo 1 > /proc/sys/kernel/sysrq」「echo c > /proc/sysrq-trigger」コマンドを入力したところ、約60秒後に再起動が起きました。
なので、「echo 1 > /proc/sys/kernel/sysrq」「echo c > /proc/sysrq-trigger」コマンドでハードウェアWDTの再起動は起きないが、ソフトウェアWDT機能を有効にしていたら再起動は起きる様に感じました。

すると、現在は既に起動時にハードウェアWDTが機能しており、私のプログラムでソフトウェアWDTを機能していた場合には、カーネルがクラッシュしても固まってもどちらかのWDTが働いて再起動が起きそうな気がしてきました。

引き続き、私のプログラムでおかしな処理が無いか確認を行います。

もし、他にWDTで再起動しなそうな要因などがあれば教えて下さい。