lib: sbi: Apply budget restriction when polling Zkr CSR state transition

Zkr architecture doesn't define a time limit on state transitions
which results in hanging on unresponsive or event-driven platforms.
To prevent this, we need to limit polling iterations and fall back
in case the budget is over, and stack guard keeps its initial value.
The budget is configurable with CONFIG_ZKR_POLL_BUDGET, defaulting
to 1000 iterations. Successful reads do not consume a try.

Signed-off-by: Evgeny Voevodin <evvoevod@tenstorrent.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20260519225014.244672-1-evvoevod@tenstorrent.com
Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
Evgeny Voevodin
2026-05-19 22:50:14 +00:00
committed by Anup Patel
parent ecc92e87a9
commit b508e6e25e
2 changed files with 24 additions and 3 deletions
+12
View File
@@ -6,6 +6,18 @@ config CONSOLE_EARLY_BUFFER_SIZE
int "Early console buffer size (bytes)"
default 256
config ZKR_POLL_BUDGET
int "Zkr seed polling budget (iterations)"
default 1000
help
Maximum number of iterations to poll CSR_SEED when initializing
the stack guard variable. The Zkr specification doesn't define
a time limit on transitioning to ES16 between polls, which
makes it impossible to tell whether entropy is being
accumulated slowly or the entropy source is not functioning.
This also limits the wait time on systems with an event-driven
entropy source. A successful read doesn't consume a try.
config SBI_ECALL_TIME
bool "Timer extension"
default y
+12 -3
View File
@@ -280,20 +280,29 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
if (sbi_hart_has_extension(scratch, SBI_HART_EXT_ZKR)) {
unsigned long guard_val = 0;
int chunks = sizeof(unsigned long) / sizeof(uint16_t);
bool res = true;
#ifndef CONFIG_ZKR_POLL_BUDGET
#define CONFIG_ZKR_POLL_BUDGET 1000
#endif
unsigned int tries = CONFIG_ZKR_POLL_BUDGET;
bool res = false;
while (chunks) {
while (chunks && tries) {
unsigned long seed = csr_swap(CSR_SEED, 0);
unsigned long opst = seed & SEED_OPTS_MASK;
res = false;
if (opst == SEED_OPTS_DEAD) {
res = false;
break;
}
if (opst == SEED_OPTS_ES16) {
guard_val = (guard_val << 16) | (seed & SEED_ENTROPY_MASK);
chunks--;
res = true;
/* Successful read doesn't consume a try */
tries++;
}
tries--;
continue;
}
if (res)