feat(v4): no identity drive, headless; Zuse's drive, a console
The identity gate on the v4 boot (plan 2026-10-26-engine-step4-identity-gate,
task G2; ENGINE.md 2, ruled 2026-10-20). As v3, by the kernel with no v3 VM:
after POST and the block chain, Zuse's public key from the genesis marker,
every xHCI controller brought up, the heartbeat started; then headless until
her drive is attached and checked (capsule_zuse_boot_check, G1). A drive that
arrives is given to the block subsystem by the kernel (Artemis is the
kernel's); her session is kept in the kernel for Hera, never in a node's
memory. The prompt is v3's, [zuse@Hera] ok>; pulling her drive ends the
session and the system goes headless; putting it back brings the prompt.
A blank pair stays headless: genesis writes Artemis's disk, Phase 5 (D2).
kernel/Makefile: ARTDISK and ZUSEDISK default to the minted pair,
disk/zuse-scratch/ (D4); .claude/CLAUDE.md's acceptance says so.
Fixed with it, at Captain Bob's word:
- kernel/Makefile: the ROM-and-map rule is a grouped target (&:). As two
targets of one plain rule its recipe ran twice at once under -j and the
copies met ("cp: cannot create regular file ... File exists"): 3 of 20
parallel builds failed, now 0 of 20.
- The v4 boot drops the logger to --log-level after POST, as v3 does
(sk_log_level_after_post, shared by both paths); INFO lines after POST,
3 before, 0 now.
Accepted: three clean qemu boots as built to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f on all three (unchanged), 0 INFO after POST;
the hot-plug session (attach, line, detach, headless, re-attach) on amd64,
aarch64 and riscv64; headless with no drive; make -C v4 test test-32
sanitize hosted-check EXIT 0; make -C v4 test-32 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
75785fb025
commit
8d9c91b2bc
+7
-1
@@ -341,9 +341,15 @@ audit artifacts — they are committed to the repo. Do not delete them. There is
|
||||
timestamped convention (self-documented via its own README); not a contradiction, just a
|
||||
second, less-structured log location.
|
||||
|
||||
**The disks (Captain Bob, 2026-10-26, the identity gate):** with no identity thumbdrive the system
|
||||
is headless -- no prompt -- so every boot needs Zuse. `kernel/Makefile`'s `ARTDISK` and `ZUSEDISK`
|
||||
default to the minted Zuse pair, `disk/zuse-scratch/artemis.img` and `zuse-thumb-ident.img` (a
|
||||
pair: her genesis marker is on that Artemis disk; `disk/README.md`). Put both back as committed
|
||||
(`git checkout -- disk/zuse-scratch`) before each architecture. The prompt is `[zuse@Hera] ok> `.
|
||||
|
||||
Do not claim a change is accepted until all three architectures have booted, and their logs are
|
||||
present in `logs/`:
|
||||
- **as built (v4)** to `ok> `, with `PARITY:V4_POST tests=538 pass=538 fail=0` (the count
|
||||
- **as built (v4)** to `[zuse@Hera] ok> `, with `PARITY:V4_POST tests=538 pass=538 fail=0` (the count
|
||||
grows with v4's POST) and `POST: PASSED`, and `PARITY:V4_SYSTEM ... dict_hash=` equal across
|
||||
the three;
|
||||
- **the 32-bit build** (Captain Bob, 2026-10-14: "the 32 bit build needs to go into the
|
||||
|
||||
+16
-7
@@ -121,7 +121,12 @@ DOE_RUNS_DIR := experiments/bare_metal/runs
|
||||
DOE_LATEST_DIR := experiments/bare_metal/latest
|
||||
|
||||
CAPSULES_DIR ?= capsules
|
||||
ARTDISK ?= disk/artemis.img
|
||||
# ARTDISK and ZUSEDISK default to the minted Zuse pair (disk/zuse-scratch/,
|
||||
# disk/README.md; Captain Bob, 2026-10-26, the identity gate's D4): with no
|
||||
# identity drive the system is headless, so a boot with the blank
|
||||
# disk/artemis.img and thumbdrives/zuse-thumb-ident.img never reaches a
|
||||
# prompt. The two are a pair: Zuse's genesis marker is on that Artemis disk.
|
||||
ARTDISK ?= disk/zuse-scratch/artemis.img
|
||||
# XHCI_PORTS -- real top-level port count the qemu-xhci controller exposes on the
|
||||
# xhci0.0 bus (p2 == p3 == this value; these are the SAME physical dual-role ports
|
||||
# counted from the USB2 and USB3 register sets respectively, NOT additive to p2+p3 --
|
||||
@@ -157,7 +162,7 @@ XHCI_ARGS_SLOT4 := $(if $(strip $(XHCI_QEMU_ARGS)),$(XHCI_QEMU_ARGS),$(XHCI_D
|
||||
# xhci_poll_events() alone is purely hotplug-event-driven and would never
|
||||
# see a device present before controller reset. Override to "" (empty) to
|
||||
# boot without Zuse attached, e.g. `make -f kernel/Makefile qemu ZUSEDISK=`.
|
||||
ZUSEDISK ?= disk/thumbdrives/zuse-thumb-ident.img
|
||||
ZUSEDISK ?= disk/zuse-scratch/zuse-thumb-ident.img
|
||||
# Precomputed (not inlined as $(if ...,...)) because the drive/device specs
|
||||
# below are comma-heavy and GNU make's $(if) function splits its own
|
||||
# arguments on every top-level comma -- inlining it silently truncated the
|
||||
@@ -640,8 +645,8 @@ V4_ENGINE_SRCS := $(addprefix v4/src/,node.c exec.c stack.c iword.c heat.c guard
|
||||
V4_ROM_C := $(BUILD_DIR)/v4_rom_64.c
|
||||
V4_MAP_C := $(BUILD_DIR)/v4_map_64.c
|
||||
|
||||
LOADER_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c
|
||||
KERNEL_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c
|
||||
LOADER_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c $(KERNEL_SRC)/v4/sk_v4_identity.c
|
||||
KERNEL_EXTRA_SRCS += $(KERNEL_SRC)/v4/sk_v4.c $(KERNEL_SRC)/v4/sk_v4_identity.c
|
||||
# v4/system/boot.c is the boot the hosted v4 system runs too: the ROM
|
||||
# assembles the system, then the capsules from this kernel's own capsule
|
||||
# directory, then the prompt.
|
||||
@@ -789,10 +794,14 @@ endif
|
||||
|
||||
# StarForth v4: the ROM and the map, built on this machine by v4's Makefile,
|
||||
# and the engine, compiled like any other kernel source.
|
||||
# One recipe makes both (a grouped target, GNU make 4.3+): as two targets of
|
||||
# one plain rule it ran once for each, at the same time under -j, and the
|
||||
# two copies met ("cp: cannot create regular file ... File exists", fixed
|
||||
# 2026-10-26).
|
||||
ifeq ($(STARFORTH_V4),1)
|
||||
$(V4_ROM_C) $(V4_MAP_C): FORCE
|
||||
@mkdir -p $(dir $@)
|
||||
@echo " V4ROM capsules/v4/rom -> $@"
|
||||
$(V4_ROM_C) $(V4_MAP_C) &: FORCE
|
||||
@mkdir -p $(dir $(V4_ROM_C))
|
||||
@echo " V4ROM capsules/v4/rom -> $(V4_ROM_C) $(V4_MAP_C)"
|
||||
@$(MAKE) --no-print-directory -C v4 CC=cc $(CURDIR)/v4/build/rom-64.c $(CURDIR)/v4/build/v4_map_64.c
|
||||
@cmp -s v4/build/rom-64.c $(V4_ROM_C) || cp v4/build/rom-64.c $(V4_ROM_C)
|
||||
@cmp -s v4/build/v4_map_64.c $(V4_MAP_C) || cp v4/build/v4_map_64.c $(V4_MAP_C)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* sk_v4_identity.h -- the identity gate for the v4 boot: no identity drive,
|
||||
* headless; Zuse's minted thumbdrive, a console.
|
||||
* docs/v4.0.0/plans/2026-10-26-engine-step4-identity-gate.md.
|
||||
*
|
||||
* Built only with STARFORTH_V4=1 (Kconfig.kernel).
|
||||
*/
|
||||
#ifndef STARKERNEL_V4_SK_V4_IDENTITY_H
|
||||
#define STARKERNEL_V4_SK_V4_IDENTITY_H
|
||||
|
||||
/* After POST and the block chain: Zuse's public key from the genesis marker,
|
||||
* every xHCI controller brought up, and the heartbeat started, as the v3
|
||||
* path does before its headless wait. */
|
||||
void sk_v4_identity_boot(void);
|
||||
|
||||
/* 1 while Zuse's session holds: her drive is attached and checked. */
|
||||
int sk_v4_identity_present(void);
|
||||
|
||||
/* Service the heartbeat and, once a second, the USB drives that have arrived
|
||||
* or left (v3's idle beat, its USB part). Called while waiting for a key
|
||||
* with nothing typed. */
|
||||
void sk_v4_identity_beat(void);
|
||||
|
||||
/* Headless: no prompt, no input, until Zuse's session begins (v3's
|
||||
* sk_repl_headless_wait()). */
|
||||
void sk_v4_identity_wait(void);
|
||||
|
||||
#endif /* STARKERNEL_V4_SK_V4_IDENTITY_H */
|
||||
+22
-11
@@ -464,6 +464,23 @@ void kernel_main(BootInfo *boot_info) {
|
||||
kernel_main_deep(boot_info);
|
||||
}
|
||||
|
||||
#ifdef STARFORTH_ENABLE_VM
|
||||
/* The logger after POST: whatever --log-level asked for (default: LOG_WARN).
|
||||
* Both systems' boots call it once POST is done. */
|
||||
static void sk_log_level_after_post(const BootInfo *boot_info)
|
||||
{
|
||||
LogLevel repl_level;
|
||||
switch (boot_info->args.log_level) {
|
||||
case KARGS_LOG_DEBUG: repl_level = LOG_DEBUG; break;
|
||||
case KARGS_LOG_INFO: repl_level = LOG_INFO; break;
|
||||
case KARGS_LOG_ERROR: repl_level = LOG_ERROR; break;
|
||||
case KARGS_LOG_WARN:
|
||||
default: repl_level = LOG_WARN; break;
|
||||
}
|
||||
log_set_level(repl_level);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STARFORTH_V4
|
||||
/* THE BLOCK CHAIN, for the v4 node. It asks this kernel for its blocks
|
||||
* (v4/include/v4/blocks.h, docs/v4.0.0/MESH.md 8.3). The chain is set up
|
||||
@@ -483,6 +500,10 @@ static void sk_v4_block_chain(void)
|
||||
static blkio_dev_t artemis_dev;
|
||||
size_t i;
|
||||
|
||||
/* POST is done: the logger drops to --log-level, as on the v3 path
|
||||
* (fixed 2026-10-26: the v4 boot left it where POST had it, and
|
||||
* INFO lines showed after POST that v3 does not show) */
|
||||
sk_log_level_after_post(sk_v4_boot_info);
|
||||
if (!blk_ram || !krd) {
|
||||
console_println("StarForth v4: no memory for the block chain");
|
||||
for (;;) { }
|
||||
@@ -659,17 +680,7 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* LOG_WARN) so the per-word "ECW: w=... func=... 'NAME'" trace from
|
||||
* vm_core.c doesn't flood every REPL command. --log-level=info/debug
|
||||
* re-enables it if you actually want to watch word dispatch. */
|
||||
{
|
||||
LogLevel repl_level;
|
||||
switch (boot_info->args.log_level) {
|
||||
case KARGS_LOG_DEBUG: repl_level = LOG_DEBUG; break;
|
||||
case KARGS_LOG_INFO: repl_level = LOG_INFO; break;
|
||||
case KARGS_LOG_ERROR: repl_level = LOG_ERROR; break;
|
||||
case KARGS_LOG_WARN:
|
||||
default: repl_level = LOG_WARN; break;
|
||||
}
|
||||
log_set_level(repl_level);
|
||||
}
|
||||
sk_log_level_after_post(boot_info);
|
||||
|
||||
/* Wire parity log so PARITY:MAMA_INIT/BIRTH/RUN/KILL reach serial */
|
||||
capsule_parity_set_output(NULL, console_puts);
|
||||
|
||||
+37
-12
@@ -10,7 +10,10 @@
|
||||
* - what the node prints goes to the kernel's console;
|
||||
* - the prompt, and the line: it is read and edited here and handed to the
|
||||
* node whole (docs/v4.0.0/ENGINE.md 3.1), and how it ended is said here;
|
||||
* - blocks are kept in memory, and are gone at power-off.
|
||||
* - blocks are kept in memory, and are gone at power-off;
|
||||
* - the identity gate: with no identity drive the system is headless,
|
||||
* and a console exists only while Zuse's drive is attached and checked
|
||||
* (sk_v4_identity.c; ENGINE.md 2, ruled 2026-10-20).
|
||||
*
|
||||
* This is the lone node, started before the kernel's fleet and beside it.
|
||||
* It goes when the node is brought up in the VM's place (ENGINE.md step 4).
|
||||
@@ -18,13 +21,19 @@
|
||||
* Nothing of the v3 VM is started. docs/v4.0.0/DECOMPOSITION.md.
|
||||
*/
|
||||
#include "starkernel/v4/sk_v4.h"
|
||||
#include "starkernel/v4/sk_v4_identity.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/arch.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "v4/boot.h"
|
||||
#include "block_subsystem.h"
|
||||
|
||||
#define SK_V4_LINE 255u /* what the line editor here takes */
|
||||
|
||||
/* v3's prompt (repl.c's SK_PROMPT_TEXT): "ok> " in bright cyan, after the
|
||||
* console's own "[zuse@Hera] " line prefix. */
|
||||
#define SK_V4_PROMPT "\x1b[38;2;85;255;255mok> \x1b[39m"
|
||||
|
||||
static v4_node sk_v4_node;
|
||||
static v4_exec_state sk_v4_es;
|
||||
static v4_heat sk_v4_heat;
|
||||
@@ -67,17 +76,28 @@ static void sk_v4_serve(v4_node *node, unsigned request)
|
||||
}
|
||||
|
||||
/* Read a line from the keyboard: characters are echoed, backspace rubs one
|
||||
* out, Enter ends it. Returns its length. */
|
||||
static unsigned sk_v4_readline(void)
|
||||
* out, Enter ends it. Returns its length; or -1 when, with nothing typed,
|
||||
* Zuse's session has ended (her drive was pulled): the caller goes headless.
|
||||
* While nothing is typed the idle beat runs, as v3's sk_console_readline(). */
|
||||
static int sk_v4_readline(void)
|
||||
{
|
||||
unsigned len = 0;
|
||||
int len = 0;
|
||||
for (;;) {
|
||||
int c = console_getc();
|
||||
if (c < 0) continue;
|
||||
if (c < 0) {
|
||||
if (len == 0) {
|
||||
sk_v4_identity_beat();
|
||||
if (!sk_v4_identity_present()) return -1;
|
||||
} else {
|
||||
heartbeat_service();
|
||||
}
|
||||
arch_relax();
|
||||
continue;
|
||||
}
|
||||
if (c == '\r' || c == '\n') { console_putc('\n'); return len; }
|
||||
if (c == 8 || c == 127) {
|
||||
if (len > 0) { len--; console_putc(8); console_putc(' '); console_putc(8); }
|
||||
} else if (c >= 32 && c < 127 && len < SK_V4_LINE) {
|
||||
} else if (c >= 32 && c < 127 && len < (int)SK_V4_LINE) {
|
||||
sk_v4_text[len++] = (char)c;
|
||||
console_putc((char)c);
|
||||
}
|
||||
@@ -107,24 +127,29 @@ void sk_v4_run(void (*chain)(void))
|
||||
for (;;) { }
|
||||
}
|
||||
}
|
||||
sk_v4_identity_boot();
|
||||
|
||||
/* The prompt is the host's: read a line, hand it to the node, say how it
|
||||
* ended. */
|
||||
for (;;) {
|
||||
unsigned len;
|
||||
int len;
|
||||
int how;
|
||||
|
||||
console_puts("ok> ");
|
||||
/* no identity, no console: headless until Zuse's drive is checked */
|
||||
if (!sk_v4_identity_present()) sk_v4_identity_wait();
|
||||
console_puts(SK_V4_PROMPT);
|
||||
len = sk_v4_readline();
|
||||
how = v4_boot_line(&boot, sk_v4_text, len);
|
||||
if (len < 0) continue;
|
||||
how = v4_boot_line(&boot, sk_v4_text, (unsigned)len);
|
||||
/* The line is waiting for an answer no one here can send. The next
|
||||
* line typed breaks the wait: the line that was waiting ends in an
|
||||
* error, and then the line just typed is done (v4/boot.h). */
|
||||
while (how == V4_BOOT_LINE_WAITING) {
|
||||
len = sk_v4_readline();
|
||||
how = v4_boot_line(&boot, sk_v4_text, len);
|
||||
if (how == V4_TEXT_ERROR) console_puts(" ERROR\nok> ");
|
||||
else if (how == V4_TEXT_COMPLETED) console_puts(" ok\nok> ");
|
||||
if (len < 0) { sk_v4_identity_wait(); continue; }
|
||||
how = v4_boot_line(&boot, sk_v4_text, (unsigned)len);
|
||||
if (how == V4_TEXT_ERROR) console_puts(" ERROR\n" SK_V4_PROMPT);
|
||||
else if (how == V4_TEXT_COMPLETED) console_puts(" ok\n" SK_V4_PROMPT);
|
||||
else break;
|
||||
how = v4_boot_line(&boot, 0, 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/* sk_v4_identity.c -- the identity gate for the v4 boot: no identity drive,
|
||||
* headless; Zuse's minted thumbdrive, a console.
|
||||
* docs/v4.0.0/plans/2026-10-26-engine-step4-identity-gate.md, ENGINE.md 2.
|
||||
*
|
||||
* As v3 (kernel_main.c, repl.c's sk_repl_headless_wait()/sk_repl_idle(),
|
||||
* capsule_zuse_boot.c), done by the kernel with no v3 VM behind it: Artemis
|
||||
* and Hera are the kernel's (ENGINE.md 2, Q1), so a drive that arrives is
|
||||
* given to the block subsystem here, and Zuse's session is kept here, for
|
||||
* the first node, Hera. The check that the drive is hers is v3's own
|
||||
* (capsule_zuse_boot_check()).
|
||||
*
|
||||
* Not here (the plan's "not in this gate"): WIREBIND identities, EJECT,
|
||||
* ACL-ZUSE-BOOT, and genesis -- which writes Artemis's disk, and the v4 boot
|
||||
* does not write it yet (Phase 5).
|
||||
*/
|
||||
#include "starkernel/v4/sk_v4_identity.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/arch.h"
|
||||
#include "starkernel/apic.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "starkernel/xhci_driver.h"
|
||||
#include "starkernel/blkio_usb.h"
|
||||
#include "starkernel/homeblocks_sig.h"
|
||||
#include "starkernel/capsule_zuse_boot.h"
|
||||
#ifdef ARCH_AMD64
|
||||
#include "starkernel/ioapic.h"
|
||||
#include "starkernel/i8042.h"
|
||||
#endif
|
||||
#include "block_subsystem.h"
|
||||
#include <string.h>
|
||||
|
||||
#define SK_V4_IDLE_BEAT 100u /* ticks between idle beats, v3's SK_IDLE_BEAT_INTERVAL (1 s at 100 Hz) */
|
||||
|
||||
/* ZUSE'S STATE, for Hera. The cert is installed once and never replaced
|
||||
* (v3's vm_zuse_cert_install(), one-way); the session ends when her drive
|
||||
* leaves and begins again when it comes back. */
|
||||
static int g_zuse_session;
|
||||
static int g_zuse_cert_installed;
|
||||
static uint8_t g_zuse_seed[32], g_zuse_pubkey[32];
|
||||
static uint8_t g_zuse_root_pubkey[32];
|
||||
static int g_zuse_root_known;
|
||||
static struct blkio_dev *g_zuse_dev;
|
||||
|
||||
/* A blkio_dev per slot, per xHCI controller, as repl.c's g_usb_ctrl. */
|
||||
static struct {
|
||||
blkio_dev_t *slots;
|
||||
uint32_t count;
|
||||
} g_usb[XHCI_MAX_CONTROLLERS];
|
||||
|
||||
static uint64_t g_last_beat;
|
||||
static int g_said_no_genesis;
|
||||
|
||||
static const char *sk_v4_user_prefix(void)
|
||||
{
|
||||
return g_zuse_session ? "zuse" : (const char *)0;
|
||||
}
|
||||
|
||||
int sk_v4_identity_present(void)
|
||||
{
|
||||
return g_zuse_session;
|
||||
}
|
||||
|
||||
void sk_v4_identity_boot(void)
|
||||
{
|
||||
unsigned xi;
|
||||
static xhci_dev_t xhci_devs[XHCI_MAX_CONTROLLERS];
|
||||
|
||||
/* Zuse's public key, from the genesis marker on Artemis's disk */
|
||||
g_zuse_root_known = capsule_zuse_boot_root_pubkey(g_zuse_root_pubkey) == 0;
|
||||
|
||||
/* every xHCI controller, as kernel_main.c's v3 path: a drive already in
|
||||
* a port is found by the bring-up's own port scan */
|
||||
for (xi = 0; xi < XHCI_MAX_CONTROLLERS; xi++) {
|
||||
int rc = xhci_find_and_map(&xhci_devs[xi], xi);
|
||||
if (rc == 1) break;
|
||||
if (rc == 0) (void)xhci_bringup(&xhci_devs[xi]);
|
||||
}
|
||||
|
||||
/* the heartbeat, as kernel_main.c's v3 path starts it */
|
||||
console_println("Starting heartbeat...");
|
||||
apic_timer_start();
|
||||
#ifdef ARCH_AMD64
|
||||
i8042_drain_stale();
|
||||
ioapic_unmask_legacy_irq(1);
|
||||
console_println("I/O APIC: keyboard IRQ1 unmasked");
|
||||
#endif
|
||||
arch_enable_interrupts();
|
||||
console_println("Heartbeat running.");
|
||||
g_last_beat = heartbeat_ticks();
|
||||
}
|
||||
|
||||
/* A drive that has arrived: given to the block subsystem (Artemis's, the
|
||||
* kernel's), then, if it is Zuse's, her session begins. */
|
||||
static int sk_v4_drive_arrived(blkio_dev_t *dev)
|
||||
{
|
||||
homeblocks_sig_t sig;
|
||||
homeblocks_sig_result_t sig_rc = homeblocks_sig_check(dev, HOMEBLOCKS_SIG_START_FBLOCK, &sig);
|
||||
uint8_t seed[32], pubkey[32];
|
||||
zuse_drive_t which;
|
||||
|
||||
if (blk_subsys_attach_device(dev) != BLK_OK) {
|
||||
console_println("xhci: USB MSC block-subsystem attach failed");
|
||||
return 0;
|
||||
}
|
||||
if (g_zuse_session) return 1;
|
||||
|
||||
which = capsule_zuse_boot_check(dev, sig_rc, &sig, seed, pubkey);
|
||||
if (which == ZUSE_DRIVE_GENESIS) {
|
||||
if (!g_said_no_genesis) {
|
||||
console_println("Zuse: no genesis on this disk -- the system stays headless");
|
||||
g_said_no_genesis = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (which != ZUSE_DRIVE_HERS) return 1;
|
||||
|
||||
console_set_vm_name("Hera");
|
||||
console_set_user_prefix_provider(sk_v4_user_prefix);
|
||||
console_println("Zuse: identity confirmed from attached thumbdrive");
|
||||
if (!g_zuse_cert_installed) {
|
||||
memcpy(g_zuse_seed, seed, 32);
|
||||
memcpy(g_zuse_pubkey, pubkey, 32);
|
||||
g_zuse_cert_installed = 1;
|
||||
}
|
||||
memcpy(g_zuse_root_pubkey, pubkey, 32); /* as v3's install_and_activate() */
|
||||
g_zuse_root_known = 1;
|
||||
g_zuse_dev = dev;
|
||||
g_zuse_session = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sk_v4_drive_left(blkio_dev_t *dev)
|
||||
{
|
||||
blk_subsys_detach_device(dev);
|
||||
if (dev != g_zuse_dev) return;
|
||||
g_zuse_session = 0;
|
||||
g_zuse_dev = (struct blkio_dev *)0;
|
||||
console_println("Zuse: session ended -- reattach to re-authenticate");
|
||||
}
|
||||
|
||||
/* One idle beat: the xHCI event ring, then every drive that has arrived or
|
||||
* left since the last (repl.c's sk_repl_idle(), its USB part). */
|
||||
static void sk_v4_idle(void)
|
||||
{
|
||||
uint32_t xc, slot;
|
||||
|
||||
console_ensure_line_start();
|
||||
{
|
||||
uint64_t tx_before = console_tx_count();
|
||||
xhci_poll_events();
|
||||
for (xc = 0; xc < xhci_dev_count() && xc < XHCI_MAX_CONTROLLERS; xc++) {
|
||||
xhci_dev_t *xdev = xhci_dev_at(xc);
|
||||
if (!xdev) continue;
|
||||
if (!g_usb[xc].slots || g_usb[xc].count < xdev->max_slots + 1) {
|
||||
size_t bytes = (size_t)(xdev->max_slots + 1) * sizeof(blkio_dev_t);
|
||||
blkio_dev_t *fresh = (blkio_dev_t *)kmalloc_aligned(bytes, 64);
|
||||
if (!fresh) continue;
|
||||
memset(fresh, 0, bytes);
|
||||
g_usb[xc].slots = fresh;
|
||||
g_usb[xc].count = xdev->max_slots + 1;
|
||||
}
|
||||
for (slot = 1; slot <= xdev->max_slots; slot++) {
|
||||
xhci_msc_slot_t *ms = xhci_msc_slot_for(xdev, slot);
|
||||
if (!ms || !ms->bot_msc_attach_pending) continue;
|
||||
ms->bot_msc_attach_pending = 0;
|
||||
if (blkio_usb_open_msc(&g_usb[xc].slots[slot], xdev, slot) == 0 &&
|
||||
sk_v4_drive_arrived(&g_usb[xc].slots[slot]))
|
||||
ms->bot_msc_attached = 1;
|
||||
}
|
||||
for (slot = 1; slot <= xdev->max_slots; slot++) {
|
||||
xhci_msc_slot_t *ms = xhci_msc_slot_for(xdev, slot);
|
||||
if (!ms || !ms->bot_msc_detach_pending) continue;
|
||||
ms->bot_msc_detach_pending = 0;
|
||||
sk_v4_drive_left(&g_usb[xc].slots[slot]);
|
||||
}
|
||||
}
|
||||
if (console_tx_count() == tx_before) console_cancel_deferred_line_start();
|
||||
}
|
||||
}
|
||||
|
||||
void sk_v4_identity_beat(void)
|
||||
{
|
||||
uint64_t now;
|
||||
|
||||
heartbeat_service();
|
||||
now = heartbeat_ticks();
|
||||
if (now - g_last_beat >= SK_V4_IDLE_BEAT) {
|
||||
g_last_beat = now;
|
||||
sk_v4_idle();
|
||||
}
|
||||
}
|
||||
|
||||
void sk_v4_identity_wait(void)
|
||||
{
|
||||
while (!g_zuse_session) {
|
||||
sk_v4_identity_beat();
|
||||
arch_relax();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user