A block is a kernel request, as ENGINE.md 3.3 has it: the node puts the
block's number and the address of 256 cells on its stack and writes the
request to port 0, and the kernel leaves the status there. The requests
are -1, read, and -2, write, the same for every node. v4/system/blocks.c
serves them from the kernel's block subsystem, which is v3's. The four
storage registers are gone from the engine.
The device that spoke block messages (4a505a15) is withdrawn with its
test and its message types: Captain Bob ruled on 2026-10-07 that it, a
node's own drive, and nodes with no storage had left the OS as designed
(docs/v4.0.0/MESH.md 8.5).
Hera no longer sends POST to the nodes she births: POST is the kernel's,
once. Every node has its kernel on port 0; it serves a node's blocks and,
for Hera alone, her requests for nodes and capsules.
Bare metal: the node boots and is POSTed against POST's own block RAM,
and the kernel's chain -- fast RAM, the ramdrive, the virtio disk -- is
set up after POST and before the prompt, as on the v3 path. The disk is
read and not written: nothing in v4 yet gives the owner's word that it
may be formatted. A hosted program has the chain's fast RAM, as hosted
v3 has with no disk. Error 17 is Storage refused.
make -C v4 test and sanitize pass at both widths; hosted-check passes on
three ISAs; amd64, aarch64 and riscv64 boot, POST 538 of 538, with the
typed session: logs/20261007-081603, -081839, -082226. The hashes are
the same on all six.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
3.0 KiB
C
86 lines
3.0 KiB
C
/* hosted.c -- StarForth v4 as a Linux program: the nucleus image on the
|
|
* golden model, its capsules loaded as the system comes up (v4/include/v4/
|
|
* boot.h, the same boot the bare-metal kernel runs), the console on stdin
|
|
* and stdout.
|
|
*
|
|
* It runs until its input ends. Blocks are kept in memory and are gone
|
|
* when it stops.
|
|
*/
|
|
#include "v4/boot.h"
|
|
#include "block_subsystem.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
static v4_node n;
|
|
static v4_exec_state es;
|
|
static v4_heat h;
|
|
|
|
/* STORAGE. The node asks its kernel for its blocks (v4/blocks.h), and the
|
|
* kernel's block subsystem has them (docs/v4.0.0/MESH.md section 8). A
|
|
* Linux program is given what hosted v3 has when it is started with no
|
|
* disk: the chain's fast RAM, blocks 1 to 2047, which is gone when the
|
|
* program ends. */
|
|
static unsigned char block_ram[(size_t)BLK_RAM_BLOCKS * BLK_FORTH_SIZE];
|
|
extern void sf_time_init(void);
|
|
|
|
static void console_out(const char *text, unsigned len)
|
|
{
|
|
(void)fwrite(text, 1, len, stdout);
|
|
}
|
|
|
|
/* a character for a line that reads the keyboard */
|
|
static int console_key(void)
|
|
{
|
|
int c;
|
|
fflush(stdout);
|
|
c = getchar();
|
|
return c == EOF ? V4_BOOT_KEY_END : c;
|
|
}
|
|
|
|
/* THE KERNEL'S WORDS, for a node that is a Linux program: the words that
|
|
* are C in hosted v3 because only the host can do them. */
|
|
static const char *const kernel_words[] = { "BYE" };
|
|
static int leaving;
|
|
|
|
static void serve(v4_node *node, unsigned request)
|
|
{
|
|
(void)node;
|
|
if (request == 1) { /* BYE ( -- ): as hosted v3, say so and leave */
|
|
fputs("Goodbye!\n", stdout);
|
|
leaving = 1;
|
|
}
|
|
}
|
|
|
|
/* The prompt is the host's, as it is the kernel's REPL's for a v3 VM: read a
|
|
* line, hand it to the node, say how it ended. */
|
|
int main(void)
|
|
{
|
|
static char line[1026];
|
|
v4_boot boot;
|
|
|
|
boot.n = &n; boot.es = &es; boot.h = &h; boot.im = &v4_capsule_image;
|
|
boot.out = console_out; boot.key = console_key;
|
|
boot.words = kernel_words; boot.word_count = sizeof kernel_words / sizeof kernel_words[0]; boot.serve = serve;
|
|
sf_time_init();
|
|
if (blk_subsys_init(block_ram, sizeof block_ram) != BLK_OK) { fputs("V4: no block storage\n", stderr); return 1; }
|
|
if (!v4_boot_run(&boot)) { fflush(stdout); return 1; }
|
|
|
|
for (;;) {
|
|
size_t len;
|
|
int how;
|
|
|
|
fputs("ok> ", stdout);
|
|
fflush(stdout);
|
|
if (!fgets(line, sizeof line, stdin)) { putchar('\n'); return 0; }
|
|
len = strlen(line);
|
|
if (len && line[len - 1] == '\n') len--;
|
|
how = v4_boot_line(&boot, line, (unsigned)len);
|
|
if (how == V4_TEXT_COMPLETED) fputs(" ok\n", stdout);
|
|
if (leaving) { fflush(stdout); return 0; }
|
|
else if (how == V4_TEXT_ERROR) fputs(" ERROR\n", stdout);
|
|
else if (how == V4_BOOT_LINE_TOO_LONG) fputs("Line too long\n ERROR\n", stdout);
|
|
else if (how == V4_BOOT_LINE_NO_INPUT) { putchar('\n'); return 0; }
|
|
else if (how == V4_BOOT_LINE_STOPPED) { fflush(stdout); fprintf(stderr, "starforth4: the node stopped on a fault\n"); return 1; }
|
|
}
|
|
}
|