Bug-fix sweep: repl reentrancy, virtio/blocksys bounds, identity CRCs, LOG_LINE_MAX

Code review fixes, all compile clean (hosted gcc + aarch64/riscv64 kernel flags):

- repl.c (H1): reentrancy guards on the MSG-TICK idle pump. sk_repl_idle()
  now defers when Hera is mid-interpret (g_mama_interpreting) or when its
  own vm_interpret is on the stack (g_idle_pump_active), so a blocking
  KEY/EXPECT/QUERY inside a dispatched line can no longer re-enter the
  interpreter and clobber the in-flight input buffer.
- virtio_rng.c: clamp device-returned used_len to VRNG_BUF_SIZE before the
  caller's data_buf copy, closing a device-controlled OOB read.
- block_subsystem.c: first-write path now keys off created_time==0 instead
  of dead magic==0 so fresh blocks get a real created_time stamp; first_free/
  last_allocated fixed to absolute Forth LBNs (set in blk_compute_fresh_geometry
  from slot->start_lbn, no longer the wrong physical-BAM-index values from
  compute_totals_from_B); physical-bounds guard on blk_meta_zone_read/write
  prevents unsigned underflow on a corrupt fence >= device size.
- capsule_zuse_boot.c / capsule_wirebind.c: identity seed validated magic ->
  version -> CRC-64 (compute_crc64 over offsetof(crc)) before trusting it,
  so a corrupt/format-mismatched record is refused, never loaded.
- log.h / starkernel/log.h: unused LOG_LINE_MAX 256 renamed LOG_MSG_LINE_MAX
  to lift the include-order collision with vm.h's LOG_LINE_MAX 64; stale
  include-order comments dropped (kernel_main.c, shim.c, capsule_birth.c).
- FABRIC-3.md: three stale-doc carry-forward items closed [x] with cbe7b49
  notes.

Real KEY/?TERMINAL/QUERY/EXPECT bodies (console WIP):
- repl.h/repl.c: sk_console_getkey()/sk_console_key_available()/
  sk_console_readline() public bodies; non-destructive peek buffers the
  found byte so a following KEY returns it.
- shim.c: getchar()/fgetc()/fgets()/sf_terminal_ready() routed through the
  real console paths instead of stubs; sf_terminal_ready() in platform_io.h
  with sf_terminal_ready() implemented for the hosted build (linux/io.c,
  POSIX select on fd 0) wired into Makefile.
- io_words.c: ?TERMINAL now returns actual terminal-readiness, not constant 0.

Artifacts: minted disk/artemis.img + rebuilt lfs kernel; BLOCK_MAP.md,
doe csv + qemu log regenerated.
This commit is contained in:
Robert Allan James
2026-08-28 23:28:10 -04:00
parent a54e84b2d6
commit 5689c397fc
21 changed files with 9742 additions and 48 deletions
+48 -6
View File
@@ -58,10 +58,17 @@
#endif
#include "platform_time.h"
#include "platform_lock.h"
/* No LOG_LINE_MAX include-order constraint anymore: vm.h's own
* LOG_LINE_MAX (persistent block-log line size, 64) and log.h's in-memory
* message line length (renamed LOG_MSG_LINE_MAX, 256) no longer share a
* name, so include order is irrelevant here. */
#include "starkernel/repl.h"
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h"
#include "log.h"
#include "vm_host.h"
#include "console.h"
#include "kmalloc.h"
#include "platform_io.h"
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
@@ -1126,12 +1133,39 @@ void rewind(FILE *stream) { (void)stream; }
int fscanf(FILE *stream, const char *fmt, ...) { (void)stream; (void)fmt; return -1; }
/** @brief Kernel @c sscanf(): always returns -1 — not implemented in shim. */
int sscanf(const char *str, const char *fmt, ...) { (void)str; (void)fmt; return -1; }
/** @brief Kernel @c fgets(): always returns @c NULL — no filesystem in kernel. */
char *fgets(char *s, int size, FILE *stream) { (void)s; (void)size; (void)stream; return NULL; }
/* fgets()/getchar()'s real target: whichever VM the console is currently
* addressing (Tripod's USE redirect), or Mama when nothing is redirected --
* the same fallback sk_repl_run()/sk_repl_step() themselves use, since
* neither fgets() nor getchar() has a VM* of its own to work with (unlike
* a FORTH primitive, which always does). */
static VM *shim_console_vm(void) {
VM *active = sk_repl_get_active_vm();
return active ? active : (VM *)sk_get_mama_vm();
}
/** @brief Kernel @c fgets(): real body -- QUERY/EXPECT's underlying line
* read, routed through sk_console_readline() (the same echo/backspace
* line editor the REPL's own prompt uses). @p stream is ignored: the
* kernel has exactly one input source, the attached console, regardless
* of which stdio handle a caller passes. Returns NULL only if @p s is
* NULL or @p size is non-positive, matching glibc's own fgets() contract;
* an empty line (bare Enter) still returns @p s with @p s[0] == '\0',
* same as glibc. */
char *fgets(char *s, int size, FILE *stream) {
(void)stream;
if (!s || size <= 0) return NULL;
sk_console_readline(s, size, shim_console_vm());
return s;
}
/** @brief Kernel @c fputc(): ignores stream; emits @p c to kernel console. */
int fputc(int c, FILE *stream) { (void)stream; console_putc((char)c); return c; }
/** @brief Kernel @c fgetc(): always returns -1 (EOF) — no filesystem in kernel. */
int fgetc(FILE *stream) { (void)stream; return -1; }
/** @brief Kernel @c fgetc(): real body -- same one input source as
* @c getchar(), @p stream ignored (see @c fgets() above). Forward-declared
* here since @c getchar() itself isn't defined until further down this
* file and shim.c has no shared stdio.h to declare it earlier (its own
* @c FILE typedef, above, would collide with freestanding/stdio.h's). */
int getchar(void);
int fgetc(FILE *stream) { (void)stream; return getchar(); }
/**
* @brief Kernel @c __isoc99_sscanf() stub (ISO C99 internal sscanf symbol).
@@ -1207,14 +1241,22 @@ const unsigned short ** __ctype_b_loc(void) {
return &p;
}
/** @brief Kernel @c getchar(): always returns -1 (EOF) — no stdin in kernel. */
int getchar(void) { return -1; }
/** @brief Kernel @c getchar(): real body -- KEY's underlying single-key
* read, routed through sk_console_getkey() (blocks with heartbeat/idle
* servicing, no echo). See fgets()'s own doc comment on shim_console_vm(). */
int getchar(void) { return sk_console_getkey(shim_console_vm()); }
/** @brief Kernel @c getc(): ignores stream, same as @c getchar(). GCC's -O2
* folds @c getchar() call sites into @c getc(stdin) (FABRIC.md item 4.5d) --
* this symbol was never needed at -O0 because that fold pass is inactive
* there. */
int getc(FILE *stream) { (void)stream; return getchar(); }
/** @brief Kernel @c sf_terminal_ready(): real body of the standard
* dictionary's ?TERMINAL word (platform_io.h) -- non-blocking peek via
* sk_console_key_available(), which buffers any found byte so a
* following KEY/getchar() still returns it. */
int sf_terminal_ready(void) { return sk_console_key_available(); }
/* -----------------------------------------------------------------------------
* Misc platform stubs
* ---------------------------------------------------------------------------*/