Repository navigation
kernel: the SG2002 TRNG as a hw_random driver, loaded on demand - #375
Conversation
The true random number generator of the security subsystem (TRM 22.2) gets a driver of our own, cv181x_trng: it registers 128-bit outputs of the core's DRBG with the hw_random core as /dev/hwrng, seeds it from the noise source when it becomes the current source and again after every 1024 outputs, and zeroizes it on unload. Like the other accelerator drivers it is built and installed but blacklisted, so udev does not load it at boot; modprobe cv181x_trng loads it. The block sits behind the efuse clock gates (clk_efuse, clk_apb_efuse), which Linux turns off as unused: with them off, a register read hangs the bus and the board restarts through the watchdog. U-Boot leaves every gate on; comparing its clk_en words with Linux's and enabling only the two efuse gates made the block answer. The device-tree node names both clocks, and the driver enables them before it touches a register. The registers are the Synopsys NIST TRNG core's (COREKIT_REL 0x200a), which the TRM documents only in part. A second GEN_NOISE or a RENEW_STATE on an instantiated generator raises its illegal-sequence alarm, after which the core ignores every command, and ZEROIZE with that alarm pending hung the bus. Each seed therefore clears ALARMS and ISTAT, zeroizes (command 0xf, ISTAT bit 0) and instantiates from fresh noise; every command checks ALARMS. On the stand, Linux 7.3: 1 MiB in 3.6 s across 64 seeds, output that does not compress, three unloads and loads in a row, and the efuse clocks on only while the module is loaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Build outputsCompared with the build of main at 9c1b999. 32 changed, 1 added, 0 removed of 561 outputs.
|
dormancygrace
left a comment
There was a problem hiding this comment.
Code review found one API correctness issue: the read callback ignores the nonblocking request and enters sleepable hardware polling. Fix and regression coverage are being prepared. The original firmware build passed. The Go job failed in TestAutostartPreservesNamesAndSeparateLogs (empty log immediately after the wrapper published exited); this code is unchanged by this PR and its wrapper publishes status before the pipe reader finishes writing the log. Checking that separately from the TRNG change.
| if (ret) | ||
| break; | ||
| } | ||
| ret = trng_command(trng, CMD_GEN_RANDOM, ISTAT_DONE); |
There was a problem hiding this comment.
[P2] Honor wait=false before issuing sleepable commands. hw_random passes false for an O_NONBLOCK read, but this path calls readl_poll_timeout (and may first run three seed commands), each with a 100 ms timeout. Thus a nonblocking consumer can sleep repeatedly and receive ETIMEDOUT instead of promptly observing no available data. Since this implementation has no asynchronous output queue, a minimal fix is to return 0 before touching hardware when !wait; hw_random will return EAGAIN if its own buffer is empty, while normal blocking reads and the entropy feeder retain the tested sequence. Add execution coverage for seeded, unseeded and reseed-due states. Confirmed with the actual callback compiled against an MMIO model; the nonblocking assertion fails on this head.
There was a problem hiding this comment.
Fixed in 264dbd7. wait=false returns 0 before MMIO or polling, so hw_random uses any existing buffered bytes or returns EAGAIN. Blocking reads and the entropy feeder keep the original hardware command sequence. tests/test-trng.py executes the actual driver code with injected MMIO failures, covers all three nonblocking states plus alarms/timeouts/recovery/reseeding/partial reads/cleanup, and is wired into CI. The nonblocking test demonstrably fails on the original commit. Documentation now states the behavior explicitly.
dormancygrace
left a comment
There was a problem hiding this comment.
Final review of 264dbd7: the nonblocking-read issue is fixed; no remaining blocking findings.
Reviewed the MMIO command sequence, alarm clearing before zeroization, timeout/error propagation, output withholding after alarms, periodic reseeding, devres teardown ordering (hwrng unregister before clocks are disabled), DT clock references, build installation and autoload blacklist. The hardware command sequence for blocking reads is unchanged by the review fix.
Validation: tests/test-trng.py executes the production command/read functions with a fault-injecting MMIO model. Covers seeded/unseeded/reseed-due nonblocking calls without hardware access, seed order, periodic reseeding, alarm and timeout recovery, partial output on later errors, failed initialization and cleanup. Negative control fails on the original implementation. Also passed platform-build, package-versions, platform-config, startup-aes-policy and git diff --check. Existing autostart test passed 30 local repetitions.
CI for this final head: Init scripts and tooling (including the new test), Go server, Web UI, RustDesk, C/C++ analysis, Python analysis and Actions analysis passed. The earlier Go failure did not recur. Full firmware build/hash, pion-ice and Go analysis are still running; not waiting for the full run under the existing instruction. CodeQL aggregate currently reports neutral/missing configurations, so this is not a claim that every CI check is green. Original-head full firmware build passed.
No new device testing or deployment in this review. The author's PCIe tests remain the hardware evidence; MMIO tests do not establish entropy quality or other-board behavior. Module remains explicitly loaded only. Ready to merge.
What
The SG2002's true random number generator (TRM 22.2) gets a driver of our own,
cv181x_trng, which registers it with the kernel's hw_random core as/dev/hwrng.nanokvm-accelerators.conf, so udev does not load it at boot.modprobe cv181x_trngloads it./dev/hwrng.quality, so while it is loaded the hw_random core credits it fully and feeds the kernel's entropy pool from it./sys/class/misc/hw_random/rng_qualitylowers that.Changes:
platform/modules/cv181x-trng: the driver, built inplatform/build.sh.firmware/boards/sg2002-nanokvm-common.dtsi: noderng@2070000with the two clocks.docs/ACCELERATORS.md.No kernel patch, no config change (
CONFIG_HW_RANDOM=yalready), no kernel release bump. The DTB and the kmod package change content.The clock
clk_efuse,clk_apb_efuse), which Linux turns off as unused at boot.clk_en_0..4words (all0xffffffff) with Linux's and enabling only those two gates made the block answer.The core
The register layout and
COREKIT_REL(0x1c) = 0x200a indicate the Synopsys NIST TRNG core. This identification is inferred from the hardware; no vendor document says so. The TRM documents only part of the core and omits the following, all found on the stand:ALARMS(0x18) is a register the TRM does not list.ZEROIZEis command 0xf and completes in ISTAT bit 0.GEN_NOISE, or aRENEW_STATE, on an instantiated generator raises the illegal-command-sequence alarm (ALARMSbit 4). After that the core ignores every command.ZEROIZEwith that alarm still pending hung the bus.The driver's sequences:
ZEROIZE,GEN_NOISEandCREATE_STATE.ZEROIZE.-EIOon an alarm. The next read then seeds again.Tested on the stand (NanoKVM PCIe, Linux 7.3)
The stand restarted twice through the watchdog during development: once on a register read with the clocks gated, and once on
ZEROIZEwith an alarm pending. The driver cannot do either, and the doc warns againstdevmemon the block.Not covered
EAGAIN. Fresh output requires a blocking read. Regression tests exercise the actual driver code with mocked MMIO, including reseeding, alarms, timeouts, partial reads and cleanup (added in review).🤖 Generated with Claude Code