/* StarForth — Steady-State Virtual Machine Runtime Copyright (c) 2023–2025 Robert A. James All rights reserved. Licensed under the StarForth License, Version 1.0 */ /** * repl.h - Emergency FORTH REPL for LithosAnanke kernel */ #ifndef STARKERNEL_REPL_H #define STARKERNEL_REPL_H #include "vm.h" #include "starkernel/homeblocks_sig.h" struct blkio_dev; #ifdef __cplusplus extern "C" { #endif /** * sk_repl - Run the emergency FORTH REPL on the serial console. * * Blocks until vm->halted is set (BYE word) or the VM encounters a halt. * Runs with interrupts enabled; the APIC heartbeat continues to fire. * * @param vm Mama VM instance (must be fully initialised) */ void sk_repl(VM *vm); /** * sk_repl_run - Bare REPL loop (no banner). * * Same as sk_repl but skips the version/welcome banner. Used by START * to enter a child VM's interpreter loop without reprinting the header. * * @param vm Fully initialised VM instance */ void sk_repl_run(VM *vm); /** * sk_repl_step - Execute one REPL turn on a VM and return. * * Prints the VM's prompt, reads one line, interprets it, prints ok/ERROR, * then returns. Used by the Compudynamics VM-STEP primitive so Hera can * give a single REPL quantum to a child VM without surrendering control * for the full sk_repl_run() loop. * * @param vm Fully initialised VM instance * @return 1 if the VM is still running, 0 if it halted during this turn */ int sk_repl_step(VM *vm); /** * sk_repl_set_active_vm - Redirect REPL input to a different VM (USE word). * * Pass NULL to restore default dispatch (Mama's VM). * The change takes effect on the next REPL iteration. * * @param vm Target VM, or NULL for default */ void sk_repl_set_active_vm(VM *vm); /** * sk_repl_get_active_vm - Return the current USE-redirected VM, or NULL. */ VM *sk_repl_get_active_vm(void); /** * sk_repl_get_homeblocks_dev / sk_repl_get_homeblocks_sig - The currently * attached home-blocks USB drive, or NULL if none is attached / the * attached drive didn't check out as HOMEBLOCKS_SIG_OK (FABRIC-2.md * §F.6/§F.9/§F.18). Both return NULL together; never one without the * other. */ struct blkio_dev *sk_repl_get_homeblocks_dev(void); const homeblocks_sig_t *sk_repl_get_homeblocks_sig(void); /** * sk_repl_get_attached_blk_dev - The currently attached USB block * device, regardless of home-blocks recognition (FABRIC-2.md * §F.8/§F.19) -- MINT's own target, since a blank/unminted drive never * sets sk_repl_get_homeblocks_dev() above. NULL if nothing is attached. */ struct blkio_dev *sk_repl_get_attached_blk_dev(void); /** * sk_console_getkey - Real body of the standard dictionary's KEY word * (called from shim.c's getchar()). Blocks until a key is available from * either input source (serial console or the PS2/virtio keyboard-event * bridge), servicing the heartbeat/idle loop while waiting so a KEY call * from inside any word never stalls the heartbeat. No echo -- that's the * caller's responsibility, same as any standard KEY. * * @param active_vm VM whose idle dispatch runs while waiting (see * sk_repl_idle()'s own doc comment on why this is a * parameter rather than read via sk_repl_get_active_vm()) * @return the key read, as an unsigned byte value */ int sk_console_getkey(VM *active_vm); /** * sk_console_key_available - Real body of the standard dictionary's * ?TERMINAL word (called from sf_terminal_ready()). Non-blocking peek: * returns 1 if a key is ready without consuming it (a following * sk_console_getkey() returns that exact key), 0 otherwise. */ int sk_console_key_available(void); /** * sk_console_readline - Real body of the standard dictionary's * QUERY/EXPECT words (called from shim.c's fgets()). Reads one line from * the console with echo and backspace support, servicing the heartbeat/ * idle loop while waiting -- the same line editor the REPL's own prompt * uses internally, so a mid-word EXPECT behaves identically to typing at * "ok>" itself. * * @param buf Destination buffer * @param size Buffer capacity, including the NUL terminator * @param active_vm VM whose idle dispatch runs while waiting * @param reanchor_prompt Nonzero to re-print the "ok> " prompt whenever * an idle bottom half (heartbeat, USB attach/detach) writes * to the console while this readline blocks at a bare, * untyped prompt -- keeps the top-level prompt as the last * thing shown once the chatter dies down. Callers whose * prompt line is their own (shim.c's fgets(), i.e. * QUERY/EXPECT/ACCEPT) pass 0 so "ok> " never gets stamped * onto their mid-word input context. * @return number of characters placed in buf, not counting the NUL */ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt); /** * sk_console_mark_login - Record that a real identity has logged in via an * attached thumbdrive, decided in conversation 2026-09-05: no console for * the running system unless a thumbdrive is present -- headless until the * first successful login, regardless of which path performs it (a regular * user's WIREBIND console-VM birth, capsule_wirebind.c, or Zuse's own * attach/genesis-mint, capsule_zuse_boot.c). Both call this on their own * success path; neither is treated as special here, per direct instruction * ("nothing special about zuse as a user except zuse has no ACLs") -- * this is one shared signal, not a Zuse-specific carve-out. Idempotent * (a second login, e.g. a second WIREBIND user later, is a harmless no-op). */ void sk_console_mark_login(void); /** * sk_console_login_occurred - Whether sk_console_mark_login() has ever * been called this boot. Read by sk_repl_headless_wait()'s own exit * condition; exposed publicly for anything else that needs to know * whether the console is unlocked yet. */ int sk_console_login_occurred(void); /** * sk_repl_headless_wait - Idle-service loop with no interactive surface * at all: no banner, no prompt, no console_getc()/readline. Runs * heartbeat_service() and the same SK_IDLE_BEAT_INTERVAL-gated * sk_repl_idle(mama) cadence sk_console_readline()'s own idle branch * uses -- so USB/WIREBIND/Zuse-attach detection, the heartbeat, and all * other idle-tick subsystems keep running -- until sk_console_login_ * occurred() becomes true, at which point it returns. Called from * kernel_main.c in place of an immediate sk_repl(mama) call when * EMERGENCY_CONSOLE_ENABLED is off (the new default, 2026-09-05): no * thumbdrive, no prompt, per direct instruction. When * EMERGENCY_CONSOLE_ENABLED is on (the debug/recovery escape hatch), * kernel_main.c skips this and calls sk_repl(mama) immediately instead, * exactly as before this change. * * @param mama Hera's own VM instance -- the idle-dispatch target, * same as every other sk_repl_idle() caller uses. */ void sk_repl_headless_wait(VM *mama); #ifdef __cplusplus } #endif #endif /* STARKERNEL_REPL_H */