G.2 (v2.0.0): unified rng_get_bytes() entropy entry point; virtio-rng sole backend
The QEMU-verifiable slice of the real-hardware RNG driver (per FABRIC-3.md §G.2). New include/starkernel/rng.h + src/starkernel/rng/rng.c provide the single entropy entry point: rng_init() probes the backend set (v2.0.0: virtio-rng only) and, on no backend, prints a loud boot-time warning while rng_get_bytes() returns RNG_ERR_NO_BACKEND - never silently degrading to a deterministic seed. The backend-selection switch in rng.c is the exact seam v2.5.0's per-arch drivers (amd64 RDRAND, riscv64 Zkr, aarch64 peripheral) plug into without touching the call path. Consumers route through the unified layer instead of virtio-rng directly: capsule_mint.c (identity seed + drive_uuid) and kernel_main.c phase 8 (rng_init()). virtio_rng.c stays as the sole backend. Built clean on amd64/aarch64/riscv64. QEMU amd64 boot: POST 1012/0/0 + ok>, "rng: backend = virtio-rng" + "entropy: ready", Zuse identity confirmed from thumbdrive - mint/cert behavior unchanged. FABRIC-3.md §G.2 v2.0.0 slice marked BUILT+VERIFIED.
This commit is contained in:
+13
@@ -3362,6 +3362,19 @@ redesign of the call path.
|
|||||||
loudly (boot-time message, safe fallback to this-boot-only cert) if no backend is present,
|
loudly (boot-time message, safe fallback to this-boot-only cert) if no backend is present,
|
||||||
and the pre-existing Zuse mint/cert behavior is unchanged on all three arches. The
|
and the pre-existing Zuse mint/cert behavior is unchanged on all three arches. The
|
||||||
per-arch backends themselves are parked, explicitly, for v2.5.0.
|
per-arch backends themselves are parked, explicitly, for v2.5.0.
|
||||||
|
- **v2.0.0 slice — BUILT and VERIFIED 2026-08-29.** `include/starkernel/rng.h` +
|
||||||
|
`src/starkernel/rng/rng.c` provide the single `rng_get_bytes()` entry point; `rng_init()`
|
||||||
|
probes the backend set (v2.0.0: virtio-rng only) and, on no backend, prints a loud
|
||||||
|
boot-time warning and `rng_get_bytes()` returns `RNG_ERR_NO_BACKEND` — it never silently
|
||||||
|
degrades to a deterministic seed. The backend-selection switch in `rng.c` is the exact seam
|
||||||
|
the v2.5.0 real per-arch drivers (amd64 RDRAND, riscv64 Zkr, aarch64 peripheral RNG) plug
|
||||||
|
into without touching the call path. Kernel consumers no longer touch `virtio_rng_*`
|
||||||
|
directly: `capsule_mint.c` (identity seed + `drive_uuid`) and `kernel_main.c` phase 8
|
||||||
|
(`rng_init()`) route through the unified layer; `virtio_rng.c` stays as the sole backend.
|
||||||
|
Built clean on all three arches (`make -f Makefile.starkernel ARCH={amd64,aarch64,riscv64}`).
|
||||||
|
QEMU amd64 boot: POST `1012/0/0` + `ok>`, `rng: backend = virtio-rng` + `entropy: ready`
|
||||||
|
printed by the unified layer, and Zuse attach/identity confirmed from the thumbdrive —
|
||||||
|
Zuse mint/cert behavior unchanged.
|
||||||
- **Exit criterion (v2.5.0 completion, for reference):** on each real board `rng_get_bytes()`
|
- **Exit criterion (v2.5.0 completion, for reference):** on each real board `rng_get_bytes()`
|
||||||
returns genuinely non-deterministic bytes (two boots differ) and the Zuse mint path seeded
|
returns genuinely non-deterministic bytes (two boots differ) and the Zuse mint path seeded
|
||||||
from it produces a valid distinct cert per boot when bleached.
|
from it produces a valid distinct cert per boot when bleached.
|
||||||
|
|||||||
@@ -431,6 +431,7 @@ LOADER_SRCS_BASE := \
|
|||||||
$(wildcard $(KERNEL_SRC)/capsule/*.c) \
|
$(wildcard $(KERNEL_SRC)/capsule/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/pci/*.c) \
|
$(wildcard $(KERNEL_SRC)/pci/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
|
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
|
||||||
|
$(wildcard $(KERNEL_SRC)/rng/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/usb/*.c) \
|
$(wildcard $(KERNEL_SRC)/usb/*.c) \
|
||||||
$(KERNEL_SRC)/repl.c \
|
$(KERNEL_SRC)/repl.c \
|
||||||
$(KERNEL_SRC)/doe_log.c \
|
$(KERNEL_SRC)/doe_log.c \
|
||||||
@@ -483,6 +484,7 @@ KERNEL_SRCS_BASE := \
|
|||||||
$(wildcard $(KERNEL_SRC)/capsule/*.c) \
|
$(wildcard $(KERNEL_SRC)/capsule/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/pci/*.c) \
|
$(wildcard $(KERNEL_SRC)/pci/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
|
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
|
||||||
|
$(wildcard $(KERNEL_SRC)/rng/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/usb/*.c) \
|
$(wildcard $(KERNEL_SRC)/usb/*.c) \
|
||||||
$(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.c) \
|
$(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.c) \
|
||||||
$(KERNEL_SRC)/repl.c \
|
$(KERNEL_SRC)/repl.c \
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-08-29T13:48:09Z -->
|
<!-- Generated by mkcapsule --manifest 2026-08-29T13:51:54Z -->
|
||||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* rng.h — Unified entropy entry point for StarKernel
|
||||||
|
*
|
||||||
|
* The single place any kernel consumer (keygen, identity mint, drive_uuid,
|
||||||
|
* certificate serials, ...) asks for entropy. All entropy flows through
|
||||||
|
* rng_get_bytes() and never touches a backend directly.
|
||||||
|
*
|
||||||
|
* The set of active backends is determined at rng_init() time by probing,
|
||||||
|
* in order, until one (or more) come up:
|
||||||
|
* - v2.0.0 (QEMU): virtio-rng is the sole backend — there is no virtio-rng
|
||||||
|
* on real hardware, but QEMU exposes it uniformly on all three arches
|
||||||
|
* (amd64/aarch64/riscv64), and the paravirtualized device sidesteps the
|
||||||
|
* per-ISA gap where no single CPU RNG covers all three models (amd64 has
|
||||||
|
* RDRAND, riscv64 has Zkr, but QEMU's aarch64 CPU models expose neither —
|
||||||
|
* see virtio_rng.h / vm_uuid.h for the identical finding).
|
||||||
|
* - v2.5.0 (real hardware): real per-arch backends are inserted here without
|
||||||
|
* touching the call path — amd64 RDRAND, riscv64 Zkr (RNDR), aarch64
|
||||||
|
* peripheral RNG — each handled by a case in rng_init() and rng_get_bytes()
|
||||||
|
* (grid §G.4). On QEMU all three arches stay on virtio-rng; nothing changes.
|
||||||
|
*
|
||||||
|
* Probe-and-refuse-loudly contract (§G.2): if no backend comes up at
|
||||||
|
* rng_init(), the kernel prints a loud boot-time message. A later
|
||||||
|
* rng_get_bytes() call with no backend returns -1 (RNG_ERR_NO_BACKEND) rather
|
||||||
|
* than ever silently degrading to a deterministic throwaway — the exact failure
|
||||||
|
* Phases A/G call out as unacceptable. Callers (e.g. capsule_mint_identity)
|
||||||
|
* must surface that refusal as an explicit no-entropy error, never proceed with
|
||||||
|
* a deterministic seed.
|
||||||
|
*
|
||||||
|
* Important ordering: rng_init() must run before any rng_get_bytes()/mint call
|
||||||
|
* (it already does in kernel_main phase 8, ahead of Zuse boot attach, which is
|
||||||
|
* the only mint path in v2.0.0). rng_get_bytes() with rng_init() never
|
||||||
|
* successful returns RNG_ERR_NO_BACKEND, never blocks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STARKERNEL_RNG_H
|
||||||
|
#define STARKERNEL_RNG_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Return codes (negative = failure). */
|
||||||
|
#define RNG_ERR_NO_BACKEND (-1) /* rng_init() found no working entropy source */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rng_init — probe and bring up the entropy backends. Returns 0 if at least
|
||||||
|
* one backend is active (rng_get_bytes() will succeed), nonzero otherwise.
|
||||||
|
* Prints a loud boot-time message when no backend comes up. Call once, early.
|
||||||
|
*/
|
||||||
|
int rng_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rng_ready — 1 if at least one backend is active, 0 otherwise.
|
||||||
|
*/
|
||||||
|
int rng_ready(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rng_get_bytes — fill buf with n bytes of real entropy, blocking until all
|
||||||
|
* n bytes are obtained.
|
||||||
|
*
|
||||||
|
* Returns 0 on success (buf fully filled).
|
||||||
|
* Returns RNG_ERR_NO_BACKEND (-1) if no backend is active.
|
||||||
|
*/
|
||||||
|
int rng_get_bytes(uint8_t *buf, size_t n);
|
||||||
|
|
||||||
|
#endif /* STARKERNEL_RNG_H */
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
#include "starkernel/user_identity_seed.h"
|
#include "starkernel/user_identity_seed.h"
|
||||||
#include "starkernel/x509_ed25519.h"
|
#include "starkernel/x509_ed25519.h"
|
||||||
#include "starkernel/ed25519.h"
|
#include "starkernel/ed25519.h"
|
||||||
#include "starkernel/virtio_rng.h"
|
#include "starkernel/rng.h"
|
||||||
#include "block_subsystem.h" /* compute_crc64() */
|
#include "block_subsystem.h" /* compute_crc64() */
|
||||||
#include "blkio.h"
|
#include "blkio.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -101,11 +101,11 @@ MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
|||||||
/* issuer_vm==NULL is genesis mode (§F.21) -- no existing Zuse to
|
/* issuer_vm==NULL is genesis mode (§F.21) -- no existing Zuse to
|
||||||
* require a cert from. */
|
* require a cert from. */
|
||||||
if (issuer_vm && !issuer_vm->zuse_cert_installed) return MINT_ERR_NO_ZUSE_CERT;
|
if (issuer_vm && !issuer_vm->zuse_cert_installed) return MINT_ERR_NO_ZUSE_CERT;
|
||||||
if (!virtio_rng_ready()) return MINT_ERR_NO_ENTROPY;
|
if (!rng_ready()) return MINT_ERR_NO_ENTROPY;
|
||||||
|
|
||||||
/* Fresh identity keypair. */
|
/* Fresh identity keypair. */
|
||||||
uint8_t seed[32], pubkey[32];
|
uint8_t seed[32], pubkey[32];
|
||||||
if (virtio_rng_get_bytes(seed, sizeof(seed)) != 0) return MINT_ERR_NO_ENTROPY;
|
if (rng_get_bytes(seed, sizeof(seed)) != 0) return MINT_ERR_NO_ENTROPY;
|
||||||
ed25519_keygen(seed, pubkey);
|
ed25519_keygen(seed, pubkey);
|
||||||
if (out_pubkey) memcpy(out_pubkey, pubkey, 32);
|
if (out_pubkey) memcpy(out_pubkey, pubkey, 32);
|
||||||
if (out_seed) memcpy(out_seed, seed, 32);
|
if (out_seed) memcpy(out_seed, seed, 32);
|
||||||
@@ -114,7 +114,7 @@ MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
|||||||
* the identity seed (§F.8 decision 3: "which physical drive," not
|
* the identity seed (§F.8 decision 3: "which physical drive," not
|
||||||
* "whose identity"). */
|
* "whose identity"). */
|
||||||
uint8_t drive_uuid[16];
|
uint8_t drive_uuid[16];
|
||||||
if (virtio_rng_get_bytes(drive_uuid, sizeof(drive_uuid)) != 0)
|
if (rng_get_bytes(drive_uuid, sizeof(drive_uuid)) != 0)
|
||||||
return MINT_ERR_NO_ENTROPY;
|
return MINT_ERR_NO_ENTROPY;
|
||||||
|
|
||||||
uint32_t cert_devblock = 0;
|
uint32_t cert_devblock = 0;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ EFI_RUNTIME_SERVICES *g_sk_runtime_services = NULL;
|
|||||||
#include "starkernel/repl.h"
|
#include "starkernel/repl.h"
|
||||||
#include "starkernel/pci.h"
|
#include "starkernel/pci.h"
|
||||||
#include "starkernel/virtio_blk.h"
|
#include "starkernel/virtio_blk.h"
|
||||||
#include "starkernel/virtio_rng.h"
|
#include "starkernel/rng.h"
|
||||||
#include "starkernel/virtio_input.h"
|
#include "starkernel/virtio_input.h"
|
||||||
#include "starkernel/xhci_driver.h"
|
#include "starkernel/xhci_driver.h"
|
||||||
#include "block_subsystem.h"
|
#include "block_subsystem.h"
|
||||||
@@ -590,20 +590,20 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phase 8: virtio-rng entropy source. Real per-arch RNG doesn't cover
|
/* Phase 8: entropy. Real per-arch RNG doesn't cover all three
|
||||||
* all three architectures (amd64 RDRAND, riscv64 Zkr, but aarch64 has
|
* architectures (amd64 RDRAND, riscv64 Zkr, but aarch64 has neither in
|
||||||
* neither in QEMU's CPU models -- see vm_uuid.h's identical finding),
|
* QEMU's CPU models -- see vm_uuid.h's identical finding), so signing/
|
||||||
* so signing/keygen entropy comes from this paravirtualized device
|
* keygen entropy comes from the unified rng_get_bytes() layer, whose
|
||||||
* instead. Unconditional call site, same graceful-noop precedent as
|
* v2.0.0 backend is the paravirtualized virtio-rng device. Unconditional
|
||||||
* virtio_blk_find_artemis() above -- boot proceeds either way, the
|
* call site, same graceful-noop precedent as virtio_blk_find_artemis()
|
||||||
* device is only required once something actually calls
|
* above -- boot proceeds either way, the device is only required once
|
||||||
* virtio_rng_get_bytes(). */
|
* something actually calls rng_get_bytes(). */
|
||||||
{
|
{
|
||||||
int rrc = virtio_rng_init();
|
int rrc = rng_init();
|
||||||
if (rrc == 0) {
|
if (rrc == 0) {
|
||||||
console_println("virtio-rng: ready");
|
console_println("entropy: ready");
|
||||||
} else {
|
} else {
|
||||||
console_println("virtio-rng: not available (continuing without)");
|
console_println("entropy: not available (continuing without)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
StarKernel — Unified entropy layer (rng_get_bytes)
|
||||||
|
|
||||||
|
Single entropy entry point for the kernel; see include/starkernel/rng.h for
|
||||||
|
the contract and the probe-and-refuse-loudly discipline this implements.
|
||||||
|
|
||||||
|
v2.0.0: virtio-rng is the sole active backend (QEMU-only, uniform across all
|
||||||
|
three arches). The backend-selection switch in rng_get_bytes() is the exact
|
||||||
|
seam where the v2.5.0 real per-arch drivers (amd64 RDRAND, riscv64 Zkr,
|
||||||
|
aarch64 peripheral RNG) plug in without touching the call path.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STARKERNEL__
|
||||||
|
#error "rng.c is kernel-only"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "starkernel/rng.h"
|
||||||
|
#include "starkernel/virtio_rng.h"
|
||||||
|
#include "starkernel/console.h"
|
||||||
|
|
||||||
|
/* Number of entropy backends known to this build. Each maps to one case in
|
||||||
|
* rng_init() and rng_get_bytes(). v2.0.0 has exactly one: virtio-rng. */
|
||||||
|
enum {
|
||||||
|
RNG_BACKEND_NONE = 0,
|
||||||
|
RNG_BACKEND_VIRTIO, /* virtio-rng (QEMU, all three arches) */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int g_rng_backend = RNG_BACKEND_NONE;
|
||||||
|
|
||||||
|
int rng_init(void) {
|
||||||
|
/* Probe backends in priority order; first success wins. virtio-rng is
|
||||||
|
* the sole backend at v2.0.0; v2.5.0 adds real per-arch drivers here. */
|
||||||
|
if (virtio_rng_init() == 0) {
|
||||||
|
g_rng_backend = RNG_BACKEND_VIRTIO;
|
||||||
|
console_println("rng: backend = virtio-rng");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Refuse loudly: never fall through to a deterministic seed. */
|
||||||
|
g_rng_backend = RNG_BACKEND_NONE;
|
||||||
|
console_println(
|
||||||
|
"rng: WARNING — no entropy backend available; rng_get_bytes() "
|
||||||
|
"will refuse (no deterministic seed fallback)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rng_ready(void) {
|
||||||
|
return g_rng_backend != RNG_BACKEND_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rng_get_bytes(uint8_t *buf, size_t n) {
|
||||||
|
switch (g_rng_backend) {
|
||||||
|
case RNG_BACKEND_VIRTIO:
|
||||||
|
return virtio_rng_get_bytes(buf, n);
|
||||||
|
default:
|
||||||
|
/* v2.5.0 real per-arch cases land here. No backend: refuse loudly,
|
||||||
|
* never return a deterministic throwaway. */
|
||||||
|
return RNG_ERR_NO_BACKEND;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user