mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 16:51:12 -07:00
image.health: the watchdog's proof is WDOG1's own WCR, not the sysfs state
The sysfs state of watchdog0 says whether a process holds the device, and none does: the kernel's core feeds the boot-armed hardware. The check reads WCR through /dev/mem (WDE set, a 60 s period) and expects the state to read inactive. Bench: PASS on image 20260903003213 with WCR 0x771f. The BRINGUP facts bullet says the same.
This commit is contained in:
+6
-2
@@ -1264,8 +1264,12 @@ is committed.
|
|||||||
115200, the strings present in the fielded binary); the same adapter on the
|
115200, the strings present in the fielded binary); the same adapter on the
|
||||||
SoC console pins shows U-Boot at every normal boot and a console in the
|
SoC console pins shows U-Boot at every normal boot and a console in the
|
||||||
recovery image after a button-hold recovery from power-off. An oddity of
|
recovery image after a button-hold recovery from power-off. An oddity of
|
||||||
the watchdog reboot, recorded, not an open item. The kernel config now
|
the watchdog reboot, recorded, not an open item. The kernel config carries
|
||||||
carries CONFIG_WATCHDOG_SYSFS so the state is readable without /dev/mem.
|
CONFIG_WATCHDOG_SYSFS (identity, timeout, bootstatus). The sysfs `state`
|
||||||
|
reads `inactive`: it says whether a process holds the device, which none
|
||||||
|
does, the kernel's core feeds the hardware. The proof that WDOG1 is armed
|
||||||
|
is its own WCR (WDE set, a 60 s period), which `image.health` reads through
|
||||||
|
/dev/mem.
|
||||||
## Next work
|
## Next work
|
||||||
|
|
||||||
Open items only. Anything closed is in `CAMPAIGN-LOG.md`. Open items (bugs,
|
Open items only. Anything closed is in `CAMPAIGN-LOG.md`. Open items (bugs,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
"""image.* - the post-flash health of the running image (always-required)."""
|
"""image.* - the post-flash health of the running image (always-required)."""
|
||||||
import glob
|
import glob
|
||||||
import gzip
|
import gzip
|
||||||
|
import mmap
|
||||||
import os
|
import os
|
||||||
|
import struct
|
||||||
import re
|
import re
|
||||||
import stat
|
import stat
|
||||||
|
|
||||||
@@ -9,6 +11,23 @@ from ..catalog import test
|
|||||||
from .. import hw
|
from .. import hw
|
||||||
|
|
||||||
|
|
||||||
|
WDOG1_BASE = 0x020BC000 # i.MX6 WDOG1; WCR is the 16-bit word at offset 0
|
||||||
|
|
||||||
|
|
||||||
|
def _wdog1_wcr():
|
||||||
|
"""WDOG1's control register, read through /dev/mem (MMIO stays readable
|
||||||
|
under STRICT_DEVMEM), or None."""
|
||||||
|
try:
|
||||||
|
with open("/dev/mem", "r+b") as f:
|
||||||
|
m = mmap.mmap(f.fileno(), 4096, offset=WDOG1_BASE)
|
||||||
|
try:
|
||||||
|
return struct.unpack_from("<H", m, 0)[0]
|
||||||
|
finally:
|
||||||
|
m.close()
|
||||||
|
except (OSError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _read(path, default=None):
|
def _read(path, default=None):
|
||||||
try:
|
try:
|
||||||
with open(path, "r", encoding="utf-8", errors="replace") as f:
|
with open(path, "r", encoding="utf-8", errors="replace") as f:
|
||||||
@@ -107,17 +126,28 @@ def image_health(ctx):
|
|||||||
ev[opt] = val
|
ev[opt] = val
|
||||||
ctx.log("%s=%s", opt, val)
|
ctx.log("%s=%s", opt, val)
|
||||||
ctx.check(val in want, "%s=%s, expected one of %s", opt, val, want)
|
ctx.check(val in want, "%s=%s, expected one of %s", opt, val, want)
|
||||||
# The boot-armed hardware watchdog, as the kernel's core sees it: U-Boot
|
# The boot-armed hardware watchdog: U-Boot arms WDOG1 at 60 s and the
|
||||||
# arms WDOG1 at 60 s and the core keeps it fed (no userspace opens it).
|
# kernel's core keeps it fed (no userspace opens it, so the sysfs state
|
||||||
# The sysfs view needs CONFIG_WATCHDOG_SYSFS; bootstatus carries the
|
# reads "inactive": that attribute says whether a process holds the
|
||||||
# last reset's cause (32 = the watchdog's timeout).
|
# device, not whether the hardware runs). The hardware's own word is
|
||||||
|
# WCR: WDE set, and WT giving the period. The sysfs view needs
|
||||||
|
# CONFIG_WATCHDOG_SYSFS; bootstatus carries the last reset's cause (32 =
|
||||||
|
# the watchdog's timeout).
|
||||||
wd = {k: (_read("/sys/class/watchdog/watchdog0/" + k) or "").strip()
|
wd = {k: (_read("/sys/class/watchdog/watchdog0/" + k) or "").strip()
|
||||||
for k in ("identity", "state", "timeout", "bootstatus")}
|
for k in ("identity", "state", "timeout", "bootstatus")}
|
||||||
|
wcr = _wdog1_wcr()
|
||||||
|
wd["wcr"] = ("%#06x" % wcr) if wcr is not None else None
|
||||||
|
wd["wde"] = bool(wcr & 0x4) if wcr is not None else None
|
||||||
|
wd["period_s"] = ((wcr >> 8) + 1) / 2.0 if wcr is not None else None
|
||||||
ev["watchdog"] = wd
|
ev["watchdog"] = wd
|
||||||
ctx.log("watchdog0: %s", wd)
|
ctx.log("watchdog0: %s", wd)
|
||||||
ctx.check(wd["state"] == "active", "watchdog0 is %r, expected active (armed by the bootloader, "
|
ctx.check(wd["identity"], "watchdog0 has no sysfs view (CONFIG_WATCHDOG_SYSFS)")
|
||||||
"fed by the kernel core)", wd["state"] or None)
|
|
||||||
ctx.check(wd["timeout"] == "60", "watchdog0 timeout %r, expected 60 s", wd["timeout"] or None)
|
ctx.check(wd["timeout"] == "60", "watchdog0 timeout %r, expected 60 s", wd["timeout"] or None)
|
||||||
|
ctx.check(wcr is not None, "WDOG1 WCR unreadable through /dev/mem")
|
||||||
|
ctx.check(wd["wde"], "WDOG1 is not enabled (WCR %s): nothing resets a hung kernel", wd["wcr"])
|
||||||
|
ctx.check(wd["period_s"] == 60.0, "WDOG1 period %s s (WCR %s), expected 60", wd["period_s"], wd["wcr"])
|
||||||
|
ctx.check(wd["state"] == "inactive", "watchdog0 is %r: a process holds the device, which the image "
|
||||||
|
"does not do", wd["state"] or None)
|
||||||
rel = _read("/proc/sys/kernel/osrelease", "").strip()
|
rel = _read("/proc/sys/kernel/osrelease", "").strip()
|
||||||
ev["kernel_release"] = rel
|
ev["kernel_release"] = rel
|
||||||
mods = manifest.platform.get("kernel_modules") or []
|
mods = manifest.platform.get("kernel_modules") or []
|
||||||
|
|||||||
Reference in New Issue
Block a user