feat(kernel): Hera in the kernel's fabric and registry; centre.4th and hera.4th on her
#189, ENGINE step 4 Phase 1, Task 5a. Captain Bob, 2026-11-13: "Full births now"; "Hera as now, in a fabric". - sk_v4.c: the kernel's fabric (v4/fabric.h), Hera's node at its one place, entered in its registry (v4/manage.h) as node 10. The registry's answers are real: a birth is "no room" -- the fabric has one place until 5b; CAPSULE-OPEN/-LINE read the kernel's capsule directory, checked as the boot checks (no capsule of F18 code is there until 5b); a born node's parity line. She is not told her number: the boot's console addresses node 0 (told 10, the boot stopped after POST -- kept, labelled, logs/20261113-132712). - boot.h/boot.c: v4_boot's `request` hook (the registry's requests) and `capsules` (the kernel's own, loaded before the seal, so POST runs on them). hosted.c sets neither: the hosted product's boot is as it was. - kernel/Makefile: manage.c in the kernel's v4 engine. - qemu_session.py: a v4 acceptance boot asks NODE-ME . and wants 0. - v4-dictionary.tsv: the 55 words of centre.4th and hera.4th, written from their source and manage.h; mkdictionary.py loads the kernel's capsules into the hosted system before WORDS, so the live list is the kernel's -- 375 words. - .claude/memory/rules.md, rule 6: every boot command under timeout 570. Seen to fail first (logs/20261113-132410): NODE-ME was an unknown word. After: amd64 NODE-ME . gives 0 ok; POST 539/539; word_count 375. v4 suite: test, test-32 99 programs 0 failures; v4-checks 79 under the sanitizers 0 failures, the hosted builds alike. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
@@ -13,6 +13,10 @@
|
||||
before acting.** (Bob, 2026-11-12: "you are supposed to stop and ask when something comes up ... What
|
||||
if I had missed that message?") I installed qemu-user unasked when hosted-check could not find
|
||||
qemu-aarch64, and only said so afterwards, in a summary. Telling him after is not asking him first.
|
||||
6. **Every foreground boot command is wrapped in `timeout 570`.** A boot that hangs past the tool's
|
||||
10-minute limit is moved to the background by the tool -- an acceptance run in the background,
|
||||
against rule 1. It happened 2026-11-13 (a v4 boot that stopped after POST); QEMU was stopped at
|
||||
once with SIGTERM. `timeout` ends it in the foreground instead.
|
||||
|
||||
Source of authority: `.claude/CLAUDE.md` (wins), then the FABRIC record (`docs/fabric/`, FABRIC-3 living),
|
||||
then `docs/v4.0.0/`, `docs/reference/ROADMAP.md`, `boards/BRINGUP.md`. Code wins over all documents.
|
||||
|
||||
@@ -321,3 +321,58 @@ XOR ( x1 x2 -- x3 ) Bitwise exclusive or.
|
||||
[LITERAL] ( x -- ) Another name for LITERAL, as v3 has it.
|
||||
\ ( -- ) \ text: a comment to the end of the line; immediate.
|
||||
] ( -- ) Start compiling what follows.
|
||||
(FAIL) ( -- ) A birth went wrong: print "BIRTH: node n did not do as it was told" and raise an error (centre.4th).
|
||||
(JOIN) ( -- ) Join two outer nodes of a unit: port 3 of X to port 4 of Y, each told the other is there (centre.4th).
|
||||
(KID#) ( -- addr ) Variable: the number of the node being born (centre.4th).
|
||||
(KID) ( -- addr ) Variable: the place of the node being born (centre.4th).
|
||||
(KIDC) ( -- addr ) Variable: the newborn node's own port that leads back to its parent (centre.4th).
|
||||
(KIDP) ( -- addr ) Variable: this node's port that leads to the node being born (centre.4th).
|
||||
(LINES) ( baddr u -- ) Send the newborn node the named capsule of FORTH blocks, a line at a time, each to be completed (centre.4th).
|
||||
(N) ( k -- number ) The number of the unit's k-th outer node: the unit's number plus k (centre.4th).
|
||||
(NO-NODE) ( n -- ) Drop n, print "no such node" and raise an error (hera.4th).
|
||||
(NUCLEUS) ( -- ) Send the newborn node the system, the capsule of F18 code, cell by cell to its port (centre.4th).
|
||||
(P1) ( -- addr ) Variable: the place of a unit's first outer node (centre.4th).
|
||||
(P2) ( -- addr ) Variable: the place of a unit's second outer node (centre.4th).
|
||||
(P3) ( -- addr ) Variable: the place of a unit's third outer node (centre.4th).
|
||||
(P4) ( -- addr ) Variable: the place of a unit's fourth outer node (centre.4th).
|
||||
(PERS#) ( -- addr ) Variable: the length of the newborn node's personality capsule's name; 0: none (centre.4th).
|
||||
(PERS) ( -- addr ) Variable: the byte address of the newborn node's personality capsule's name (centre.4th).
|
||||
(SAY) ( them port me -- ) Tell node me that the port, by its number, leads to node them, and that node them is its neighbour there (centre.4th).
|
||||
(T#) ( -- addr ) Variable: how many characters of text for another node have been built in PAD (centre.4th).
|
||||
(T) ( -- baddr u ) The text built in PAD for another node (centre.4th).
|
||||
(T0) ( -- ) Begin building text for another node in PAD: empty (centre.4th).
|
||||
(TC) ( c -- ) Add a character to the text being built in PAD (centre.4th).
|
||||
(TELL) ( baddr u -- ) Send the newborn node the text to interpret, wait for how it ended, and fail the birth if it did not complete (centre.4th).
|
||||
(THERE?) ( n -- n flag ) True if node n is live and is not Hera herself (hera.4th).
|
||||
(TN) ( n -- ) Add a number and a space to the text being built in PAD (centre.4th).
|
||||
(TOLD) ( how -- ) Fail the birth unless how is 1: the text completed (centre.4th).
|
||||
(TS) ( baddr u -- ) Add a string to the text being built in PAD (centre.4th).
|
||||
(U) ( -- addr ) Variable: the number of the unit being born; its outer nodes are this plus 1 to 4 (centre.4th).
|
||||
(WHO) ( -- ) Tell the newborn node its number, where its printing goes, its default route and who is at its port back (centre.4th).
|
||||
(X) ( place number -- ) Set X, the first of the two outer nodes (JOIN) joins (centre.4th).
|
||||
(XN) ( -- addr ) Variable: X's number (centre.4th).
|
||||
(XP) ( -- addr ) Variable: X's place (centre.4th).
|
||||
(Y) ( place number -- ) Set Y, the second of the two outer nodes (JOIN) joins (centre.4th).
|
||||
(YN) ( -- addr ) Variable: Y's number (centre.4th).
|
||||
(YP) ( -- addr ) Variable: Y's place (centre.4th).
|
||||
BIRTH ( number port childport -- place ) A node is born, numbered number, its port childport joined to this node's port: given the system and FORTH-79; its place.
|
||||
BIRTH-AS ( number port childport baddr u -- place ) BIRTH, and given the capsule named by the string as its personality when u is not 0.
|
||||
CAPSULE-CELL ( -- w flag ) The next cell of the capsule of F18 code this node has open, and true; 0 0 at its end. A kernel request.
|
||||
CAPSULE-LINE ( baddr -- u | -1 ) The next line of the capsule of FORTH blocks this node has open, copied to baddr: its length, or -1 at its end. A kernel request.
|
||||
CAPSULE-OPEN ( baddr u -- flag ) Find the named capsule, check its hash and signature, and open it to be read from its start by this node. A kernel request.
|
||||
CENTRE ( n -- ) Hera only: a second centre, node n, from its port 6 to Hera's port 6, given centre.4th; it births its own unit, n+1 to n+4.
|
||||
KILL ( n -- ) Hera only: node n is removed, whatever it was doing; every node is told it is gone, and Hera forgets the way to it.
|
||||
NODE-BORN ( number -- place | -1 ) A node is born, empty, and entered in the registry with this node as its parent: its place, or -1 if there is no room. A kernel request.
|
||||
NODE-CHILD ( number i -- child | 0 ) The number of node number's i-th live child, or 0. A kernel request.
|
||||
NODE-KILL ( number -- ) Hera only: remove the node; its children become hers. A kernel request; KILL is the word to use.
|
||||
NODE-ME ( -- place ) This node's place: where it is in the kernel's fabric. A kernel request.
|
||||
NODE-PARITY ( place number -- ) Record the parity of a node this one birthed, under the number it was born as. A kernel request.
|
||||
NODE-PLACE ( number -- place | -1 ) The node's place in the kernel's fabric, or -1: not live. A kernel request.
|
||||
NODE-SLEEP ( number -- ) Hera only: put the node to sleep. A kernel request; PAUSE is the word to use.
|
||||
NODE-UNWIRE ( a pa -- ) Cut the wire on port pa of node a, this node or one it birthed. A kernel request.
|
||||
NODE-WAKE ( number -- ) Hera only: wake the node. A kernel request; RESUME is the word to use.
|
||||
NODE-WIRE ( a pa b pb -- flag ) Join port pa of node a to port pb of node b, each this node or one it birthed: true if done. A kernel request.
|
||||
PAUSE ( n -- ) Hera only: put node n to sleep; it executes nothing until RESUME.
|
||||
RESUME ( n -- ) Hera only: wake node n.
|
||||
UNIT ( n -- ) Birth a unit: four outer nodes, n+1 to n+4, on ports 2 to 5 of this one, joined in a square.
|
||||
UNIT-KILL ( n -- ) Hera only: remove node n's children, one by one, then n.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 10 and column 3.
|
@@ -139,10 +139,17 @@ own sources.
|
||||
|
||||
Each its own increment, each test first, each a boot:
|
||||
|
||||
- [ ] **5a. A fabric in the kernel, Hera in it.** `v4/src/fabric.c` and `manage.c` into the kernel
|
||||
build; Hera, node 10, at a place of a kernel fabric, entered in the registry; the prompt's lines go
|
||||
to her through it. `centre.4th` and `hera.4th` loaded on her: `NODE-ME` answers her place (word
|
||||
count and `dict_hash` change).
|
||||
- [x] **5a. A fabric in the kernel, Hera in it.** Ruled 2026-11-13 (Captain Bob): **"Hera as now, in
|
||||
a fabric"** -- she boots by `v4_boot_run` as before (the hosted product's parity kept), and her node
|
||||
is place 0 of the kernel's fabric (`sk_v4.c`), entered in the registry as node 10; her registry
|
||||
requests go to `v4_manage_serve` through `v4_boot`'s new `request` hook, and `centre.4th` and
|
||||
`hera.4th` are loaded on her through its new `capsules` list -- before the seal, so POST runs on
|
||||
them. The fabric has one place: `NODE-BORN` is answered "no room" until 5b. `CAPSULE-OPEN/-LINE`
|
||||
read the kernel's capsule directory, checked as the boot checks; no capsule of F18 code is there
|
||||
until 5b. She is not told her number ((ME) stays 0): the boot's console addresses node 0. Word
|
||||
count 375 (55 from the two capsules), each in the dictionary; `mkdictionary.py` loads the kernel's
|
||||
capsules into the hosted system before `WORDS`, so the live list is the kernel's.
|
||||
Seen to fail first: the acceptance check `NODE-ME .` gave UNKNOWN WORD; then `0 ok`.
|
||||
- [ ] **5b. Births.** `NODE-BORN`: room for a node from the kernel's heap, a place in the fabric, a
|
||||
Stadium quota granted from Hera's under the new node's key (`stadium_node_key(number)`), its
|
||||
opcode patrons; `NODE-KILL` gives the room and the quota back. The capsule words
|
||||
|
||||
+1
-1
@@ -727,7 +727,7 @@ V4_DEFS := -DSTARFORTH_V4=1 -DSK_V4_DEFAULT=$(V4_DEFAULT) -Iv4/include \
|
||||
KERNEL_CFLAGS += $(V4_DEFS)
|
||||
LOADER_CFLAGS += $(V4_DEFS)
|
||||
|
||||
V4_ENGINE_SRCS := $(addprefix v4/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c message.c wire.c)
|
||||
V4_ENGINE_SRCS := $(addprefix v4/src/,node.c exec.c stack.c iword.c heat.c guard.c image.c fabric.c capsule.c message.c wire.c manage.c)
|
||||
V4_ROM_C := $(BUILD_DIR)/v4_rom_64.c
|
||||
V4_MAP_C := $(BUILD_DIR)/v4_map_64.c
|
||||
|
||||
|
||||
+142
-5
@@ -32,7 +32,13 @@
|
||||
#include "starkernel/arch.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "v4/boot.h"
|
||||
#include "v4/fabric.h"
|
||||
#include "v4/manage.h"
|
||||
#include "block_subsystem.h"
|
||||
#include "starkernel/capsule.h"
|
||||
#include "starkernel/capsule_generated.h"
|
||||
#include "starkernel/capsule_sig.h"
|
||||
#include "starkernel/capsule_blocks.h"
|
||||
#ifdef STARFORTH_ENABLE_VM
|
||||
#include "starkernel/vm/stadium.h"
|
||||
#include "starkernel/vm/stadium_ops.h"
|
||||
@@ -44,10 +50,119 @@
|
||||
* 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;
|
||||
static v4_image sk_v4_image;
|
||||
/* THE KERNEL'S FABRIC (#189, ENGINE step 4 Phase 1, Task 5a; Captain Bob, 2026-11-13: "Hera as now,
|
||||
* in a fabric"). Hera -- node 10, the one the kernel brings up -- is booted as before (v4_boot_run)
|
||||
* and is the node at place 0 of the kernel's fabric, entered in its registry (v4/manage.h,
|
||||
* MESH.md 9a): her registry requests (centre.4th, hera.4th) are served by v4_manage_serve. The
|
||||
* fabric has her one place: a birth is refused, "no room" (-1), until the fabric has room for more
|
||||
* (Task 5b). */
|
||||
#define SK_V4_PLACES 1u
|
||||
static v4_fabric_node sk_v4_hera; /* her node, its exec state and its heat */
|
||||
static v4_place sk_v4_places[SK_V4_PLACES];
|
||||
static v4_fabric sk_v4_fabric;
|
||||
static v4_manage sk_v4_manage;
|
||||
static v4_manage_entry sk_v4_registry[SK_V4_PLACES];
|
||||
static unsigned sk_v4_hera_place;
|
||||
static v4_image sk_v4_image;
|
||||
#define sk_v4_heat (sk_v4_hera.h)
|
||||
|
||||
/* What each place has open of a capsule (CAPSULE-OPEN, -LINE): a FORTH capsule's payload, read a
|
||||
* block line at a time, as the boot reads one (v4/system/boot.c, load_capsule). */
|
||||
typedef struct { const uint8_t *p, *end; int in_block; } sk_v4_reader;
|
||||
static sk_v4_reader sk_v4_reads[SK_V4_PLACES];
|
||||
|
||||
static int sk_v4_born(void *self)
|
||||
{
|
||||
(void)self;
|
||||
return -1; /* the fabric has no room beyond Hera's place (Task 5b gives it room) */
|
||||
}
|
||||
static void sk_v4_gone(void *self, unsigned place, v4_fabric_node *was)
|
||||
{
|
||||
(void)self; (void)was;
|
||||
if (place < SK_V4_PLACES) sk_v4_reads[place].p = sk_v4_reads[place].end = 0;
|
||||
}
|
||||
/* The capsule `name`: found in the kernel's directory, its content and signature checked as the
|
||||
* boot checks them (a signature that does not verify refuses it), and opened for `asker`. Only a
|
||||
* capsule of FORTH blocks can be opened: there is none of F18 code in the directory to read a cell
|
||||
* at a time until Task 5b puts the nucleus there. */
|
||||
static int sk_v4_open(void *self, unsigned asker, const char *name, unsigned len)
|
||||
{
|
||||
const CapsuleDirHeader *dir = capsule_get_directory();
|
||||
const CapsuleDesc *descs = capsule_get_descriptors();
|
||||
const CapsuleNameEntry *names = capsule_get_names();
|
||||
const uint8_t *arena = capsule_get_arena();
|
||||
const CapsuleDesc *cap;
|
||||
const uint8_t *payload;
|
||||
char cname[V4_MANAGE_LINE + 1u];
|
||||
unsigned i;
|
||||
|
||||
(void)self;
|
||||
if (asker >= SK_V4_PLACES || len == 0 || len > V4_MANAGE_LINE) return 0;
|
||||
for (i = 0; i < len; i++) cname[i] = name[i];
|
||||
cname[len] = 0;
|
||||
if (len < 4 || cname[len - 4] != '.' || cname[len - 3] != '4' || cname[len - 2] != 't' || cname[len - 1] != 'h') return 0;
|
||||
cap = capsule_find_by_name(dir, descs, names, cname);
|
||||
if (!cap || capsule_validate(cap, arena, dir->arena_size, 1) != CAPSULE_VALID) return 0;
|
||||
if (capsule_verify_signature(descs, names, capsule_get_signatures(), arena, dir->desc_count, (int)(cap - descs))
|
||||
== CAPSULE_SIG_INVALID) return 0;
|
||||
payload = capsule_get_payload(cap, arena);
|
||||
if (!payload) return 0;
|
||||
sk_v4_reads[asker].p = payload;
|
||||
sk_v4_reads[asker].end = payload + cap->length;
|
||||
sk_v4_reads[asker].in_block = 0;
|
||||
return 1;
|
||||
}
|
||||
static int sk_v4_cell(void *self, unsigned asker, v4_cell *w)
|
||||
{
|
||||
(void)self; (void)asker; (void)w;
|
||||
return 0; /* no capsule of F18 code is open: none can be (sk_v4_open) */
|
||||
}
|
||||
/* The next line of the open capsule that is part of a block, at most V4_MANAGE_LINE characters:
|
||||
* its length, or -1 at its end (or a line too long, which no capsule mkcapsule passes has). */
|
||||
static int sk_v4_line(void *self, unsigned asker, char *text)
|
||||
{
|
||||
sk_v4_reader *r;
|
||||
(void)self;
|
||||
if (asker >= SK_V4_PLACES) return -1;
|
||||
r = &sk_v4_reads[asker];
|
||||
while (r->p && r->p < r->end) {
|
||||
const uint8_t *after, *nl;
|
||||
uint32_t num;
|
||||
unsigned len, i;
|
||||
if (capsule_block_header(r->p, r->end, &num, &after)) { r->in_block = 1; r->p = after; continue; }
|
||||
for (nl = r->p; nl < r->end && *nl != '\n'; nl++) { }
|
||||
len = (unsigned)(nl - r->p);
|
||||
if (len && r->p[len - 1] == '\r') len--;
|
||||
if (r->in_block && len > V4_MANAGE_LINE) { r->p = r->end; return -1; }
|
||||
if (r->in_block) for (i = 0; i < len; i++) text[i] = (char)r->p[i];
|
||||
r->p = nl < r->end ? nl + 1 : r->end;
|
||||
if (r->in_block) return (int)len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* A node the asker birthed has booted: its parity line, as the boot prints a capsule's. */
|
||||
static void sk_v4_parity(void *self, unsigned place, v4_cell number, const v4_node *n)
|
||||
{
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
uint64_t h = v4_image_dict_hash(n, &sk_v4_image);
|
||||
char line[64];
|
||||
unsigned at = 0, k;
|
||||
const char *s;
|
||||
(void)self; (void)place;
|
||||
for (s = "PARITY:V4_BIRTH node="; *s; s++) line[at++] = *s;
|
||||
{ char d[20]; unsigned nd = 0; v4_ucell v = (v4_ucell)number; do { d[nd++] = (char)('0' + v % 10u); v /= 10u; } while (v && nd < 20);
|
||||
while (nd) line[at++] = d[--nd]; }
|
||||
for (s = " dict_hash=0x"; *s; s++) line[at++] = *s;
|
||||
for (k = 16; k-- > 0; ) line[at++] = hex[(h >> (4 * k)) & 0xFu];
|
||||
line[at] = 0;
|
||||
console_println(line);
|
||||
}
|
||||
static int sk_v4_request(void *self, v4_node *n, v4_cell request)
|
||||
{
|
||||
(void)self; (void)n;
|
||||
return v4_manage_serve(&sk_v4_manage, sk_v4_hera_place, request);
|
||||
}
|
||||
static const char *const sk_v4_capsules[] = { "v4:centre.4th", "v4:hera.4th" };
|
||||
|
||||
static char sk_v4_text[SK_V4_LINE + 1u];
|
||||
|
||||
@@ -170,7 +285,25 @@ void sk_v4_boot(void (*chain)(void), const BootDisk *boot_disk)
|
||||
{
|
||||
console_println("StarForth v4: one host node, the F18-derived engine");
|
||||
sk_v4_image = v4_map_image;
|
||||
boot.n = &sk_v4_node; boot.es = &sk_v4_es; boot.h = &sk_v4_heat; boot.im = &sk_v4_image;
|
||||
/* the kernel's fabric, Hera at its one place, entered in its registry as node 10 (#189) */
|
||||
v4_fabric_init(&sk_v4_fabric, sk_v4_places, SK_V4_PLACES);
|
||||
v4_fabric_gone_error(&sk_v4_fabric, V4_ERROR_NO_ONE);
|
||||
{
|
||||
int place = v4_fabric_add(&sk_v4_fabric, &sk_v4_hera, sk_v4_image.port);
|
||||
if (place < 0) { console_println("StarForth v4: no place for Hera in the fabric"); sk_v4_stop(); }
|
||||
sk_v4_hera_place = (unsigned)place;
|
||||
}
|
||||
sk_v4_manage.f = &sk_v4_fabric; sk_v4_manage.reg = sk_v4_registry; sk_v4_manage.reg_cap = SK_V4_PLACES;
|
||||
sk_v4_manage.hera = sk_v4_hera_place;
|
||||
sk_v4_manage.born = sk_v4_born; sk_v4_manage.gone = sk_v4_gone; sk_v4_manage.open = sk_v4_open;
|
||||
sk_v4_manage.cell = sk_v4_cell; sk_v4_manage.line = sk_v4_line; sk_v4_manage.parity = sk_v4_parity;
|
||||
sk_v4_manage.self = 0;
|
||||
if (!v4_manage_enter(&sk_v4_manage, (v4_cell)SK_V4_HERA_NODE, sk_v4_hera_place, 0)) {
|
||||
console_println("StarForth v4: Hera not entered in the registry"); sk_v4_stop();
|
||||
}
|
||||
boot.n = &sk_v4_hera.n; boot.es = &sk_v4_hera.es; boot.h = &sk_v4_hera.h; boot.im = &sk_v4_image;
|
||||
boot.request = sk_v4_request; boot.request_self = 0;
|
||||
boot.capsules = sk_v4_capsules; boot.capsule_count = sizeof sk_v4_capsules / sizeof sk_v4_capsules[0];
|
||||
boot.out = sk_v4_out; boot.key = sk_v4_key;
|
||||
boot.words = sk_v4_words; boot.word_count = sizeof sk_v4_words / sizeof sk_v4_words[0]; boot.serve = sk_v4_serve;
|
||||
blk_subsys_init(sk_v4_post_blk_ram, sizeof(sk_v4_post_blk_ram));
|
||||
@@ -178,6 +311,10 @@ void sk_v4_boot(void (*chain)(void), const BootDisk *boot_disk)
|
||||
console_println("StarForth v4: not started");
|
||||
sk_v4_stop(); /* #177: halts, not a 100% spin */
|
||||
}
|
||||
/* She is not told her number ((ME) stays 0): the boot's console addresses its lines to node 0,
|
||||
* and a node takes a message as its own only when its first word is its number (quit.f18). The
|
||||
* registry knows her as 10; NODE-ME answers her place. (Told 10, she let the console's next line
|
||||
* go -- the boot stopped at "did not let go of POST's blocks", 2026-11-13.) */
|
||||
if (chain) {
|
||||
/* the blocks are other blocks now: what the node has in its two
|
||||
* buffers is POST's, and is let go */
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# #189 Phase 1 Task 5a: the registry check (qemu_session.py registry()) before Hera is in the kernel's fabric: NODE-ME is an unknown word.
|
||||
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
LOG: logs/20261113-132410/amd64/qemu-amd64-20261113-132410.log
|
||||
PASS: POST: PASSED
|
||||
PASS: Boot disk: not a StarshipOS stick (an ISO or ESP boot)
|
||||
PASS: Zuse: genesis minted onto attached thumbdrive (a fresh data stick)
|
||||
PASS: the Stadium: its cells allocated
|
||||
PASS: the Stadium: conservation CONSERVED
|
||||
PASS: the heartbeat: ticking
|
||||
PASS: [zuse@Hera] ok>
|
||||
PASS: 7 ok, and a prompt
|
||||
FAIL: NODE-ME: Hera is at place 0 of the kernel's fabric
|
||||
--- serial log, the log's last 40 lines (logs/20261113-132410/amd64/qemu-amd64-20261113-132410.log):
|
||||
142 | PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||
143 | V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||
144 | PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||
145 | V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||
146 | PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||
147 | PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59537530
|
||||
148 | V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
149 | PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x7d5965f7983485b9
|
||||
150 | PARITY:V4_POST tests=539 pass=539 fail=0
|
||||
151 | PARITY:V4_SYSTEM word_count=320 dict_hash=0x47570d4ced6ce255
|
||||
152 | PARITY:OK
|
||||
153 | POST: PASSED
|
||||
154 | PCI: init...
|
||||
155 | PCI: ECAM mapped (amd64)
|
||||
156 | virtio-rng: no device on PCI bus 0
|
||||
157 | rng: backend = rdrand
|
||||
158 | entropy: ready
|
||||
159 | virtio-input: no device on PCI bus 0
|
||||
160 | Starting heartbeat...
|
||||
161 | APIC Timer: started (LVT=0x00020020 ICR=10052969)
|
||||
162 |
|
||||
163 | I/O APIC: keyboard IRQ1 unmasked
|
||||
164 | Heartbeat running.
|
||||
165 | Stadium opcodes: 30 resident, hottest opcode 8
|
||||
166 | Stadium words: promotions=0 evictions=0
|
||||
167 | Stadium conservation: resident_sum=43673 reservoir=21863 sum=65536 (Q48_ONE=65536)
|
||||
168 | Stadium conservation: CONSERVED
|
||||
169 | Stadium quota grant self-test: OK
|
||||
170 | Hera reservoir=21863
|
||||
171 | test-vm reservoir=65536
|
||||
172 | Heartbeat: 4 ticks, trust=0x00010000, variance=0x00000000
|
||||
173 | blkio_usb: MSC device ready
|
||||
174 | Artemis: the stick's partition attached
|
||||
175 | \x1b[38;2;255;165;0m[Hera]\x1b[39m Zuse: genesis minted onto attached thumbdrive
|
||||
176 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m \x1b[38;2;85;255;255mok> \x1b[39m3 4 + .
|
||||
177 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m 7 ok
|
||||
178 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m \x1b[38;2;85;255;255mok> \x1b[39mNODE-ME .
|
||||
179 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m UNKNOWN WORD: 'NODE-ME'
|
||||
180 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m ERROR
|
||||
181 | \x1b[38;2;255;165;0m[zuse@Hera]\x1b[39m \x1b[38;2;85;255;255mok> \x1b[39m
|
||||
---
|
||||
RESULT: FAIL
|
||||
@@ -0,0 +1,5 @@
|
||||
# Stopped, not a result: #189 Task 5a's first boot, with Hera told '10 (ME) !' after the boot.
|
||||
# The boot passed POST, then stopped at 'StarForth v4: the node did not let go of POST's blocks':
|
||||
# the console addresses node 0, and told she was 10 she let its next line go. The boot outlasted
|
||||
# the tool's 10 minutes and was moved to the background; QEMU was stopped with SIGTERM at once.
|
||||
# The (ME) line was taken out; every boot command is now under 'timeout 570' (memory rule 6).
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
# #189 Phase 1 Task 5a
|
||||
../../20261113-132410/amd64: the registry check before -- NODE-ME is an unknown word.
|
||||
../amd64: the amd64 boot after -- NODE-ME . gives 0 ok; POST 539/539; word_count 375.
|
||||
test-test32.log: make -C v4 test test-32: 99 programs, 3724180 checks, 0 failures.
|
||||
../../20261113-135049/v4-checks: scripts/nightly.sh v4-checks: 79 programs under the sanitizers, 0 failures; the hosted builds alike.
|
||||
Binary file not shown.
Binary file not shown.
@@ -487,6 +487,16 @@ def physics():
|
||||
check("the heartbeat: ticking", wait_for(r"Heartbeat: [1-9]\d* ticks", 120))
|
||||
|
||||
|
||||
def registry():
|
||||
"""Hera in the kernel's fabric and registry (#189, Phase 1 Task 5a): NODE-ME, made by centre.4th,
|
||||
is answered by the kernel with her place, 0 -- as the host mesh answers it (test_host_unit.c)."""
|
||||
n = count(PROMPT)
|
||||
type_line("NODE-ME .")
|
||||
check("NODE-ME: Hera is at place 0 of the kernel's fabric",
|
||||
wait_for(PROMPT, 60, n) and re.search(r"(?:^|[^0-9])0\s+ok", text()[-200:]) is not None
|
||||
and "UNKNOWN WORD" not in text()[-200:])
|
||||
|
||||
|
||||
check("POST: PASSED", wait_for(r"POST: PASSED", 900))
|
||||
m = a.mode
|
||||
|
||||
@@ -503,6 +513,7 @@ elif m == "zuse":
|
||||
n = count(PROMPT)
|
||||
type_line("3 4 + .")
|
||||
check("7 ok, and a prompt", wait_for(PROMPT, 60, n) and re.search(r"7\s+ok", text()) is not None)
|
||||
registry()
|
||||
|
||||
elif m in ("stick_boot", "two_sticks"):
|
||||
def disks():
|
||||
@@ -575,6 +586,7 @@ elif m in ("genesis", "stick_genesis"):
|
||||
n = count(PROMPT)
|
||||
type_line("3 4 + .")
|
||||
check("7 ok", wait_for(PROMPT, 60, n) and re.search(r"7\s+ok", text()[-400:]) is not None)
|
||||
registry()
|
||||
check("no fault", count(r"EXCEPTION|PANIC|panic") == 0)
|
||||
if m == "genesis":
|
||||
shutdown()
|
||||
|
||||
@@ -62,6 +62,22 @@ typedef struct {
|
||||
unsigned word_count;
|
||||
void (*serve)(v4_node *n, unsigned request);
|
||||
|
||||
/* THE KERNEL'S REGISTRY (MESH.md 9a; #189, ENGINE step 4 Phase 1). A
|
||||
* request that is not a block's and not one of the kernel's words goes
|
||||
* to `request`, if there is one: it returns 1 when it served the request
|
||||
* -- or refused it, raising error 12 on the node itself (v4/manage.h) --
|
||||
* and 0 when it is not one of its; then the request is error 12, as
|
||||
* before. 0: none (the hosted product). */
|
||||
int (*request)(void *self, v4_node *n, v4_cell request);
|
||||
void *request_self;
|
||||
|
||||
/* The kernel's own capsules, by name, loaded after the boot's
|
||||
* (forth79.4th) and before the system is sealed, so POST runs on them
|
||||
* and COLD comes back to them: on bare metal, centre.4th and hera.4th
|
||||
* (#189). 0 of them: the hosted product. */
|
||||
const char *const *capsules;
|
||||
unsigned capsule_count;
|
||||
|
||||
} v4_boot;
|
||||
|
||||
/* What `key` returns when it has no character. */
|
||||
|
||||
@@ -268,6 +268,8 @@ static int run_line(const v4_boot *b, const char *text, unsigned len, char *keep
|
||||
} else if (b->serve && n->request >= 1 && n->request <= (v4_cell)b->word_count) {
|
||||
b->serve(n, (unsigned)n->request);
|
||||
v4_node_port_served(n);
|
||||
} else if (b->request && b->request(b->request_self, n, n->request)) {
|
||||
v4_node_port_served(n); /* the registry's, served or refused (#189) */
|
||||
} else {
|
||||
/* a request no one serves is an error, as any other (D-18):
|
||||
* 12, Argument out of range */
|
||||
@@ -596,6 +598,8 @@ int v4_boot_run(const v4_boot *b)
|
||||
|
||||
for (i = 0; i < sizeof boot_capsules / sizeof boot_capsules[0]; i++)
|
||||
if (!load_capsule(b, boot_capsules[i])) { say(b, "PARITY:FAIL\nPOST: FAILED\n"); return 0; }
|
||||
for (i = 0; i < b->capsule_count; i++) /* the kernel's own (#189) */
|
||||
if (!load_capsule(b, b->capsules[i])) { say(b, "PARITY:FAIL\nPOST: FAILED\n"); return 0; }
|
||||
/* The kernel's words and the capsules are the system: COLD comes back
|
||||
* to here, and FORGET will not go below it. */
|
||||
v4_image_seal(b->n, b->im);
|
||||
|
||||
@@ -84,6 +84,8 @@ int main(void)
|
||||
boot.n = &n; boot.es = &es; boot.h = &h; boot.im = &im;
|
||||
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;
|
||||
boot.request = 0; boot.request_self = 0; /* no registry, and no capsules of its own: the hosted product */
|
||||
boot.capsules = 0; boot.capsule_count = 0;
|
||||
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; }
|
||||
|
||||
+22
-14
@@ -14,8 +14,8 @@ with its stack notation, a description, and where it is defined.
|
||||
v4/tools/mkdictionary.py md TSV OUT.md the dictionary as Markdown, alphabetical, for the book
|
||||
|
||||
The live word list is the system's own: the hosted v4 (`make -C v4 hosted`) booted and asked
|
||||
`WORDS`, plus the kernel's words of the lone node (`sk_v4_words[]` in kernel/src/v4/sk_v4.c) --
|
||||
the words a booted StarshipOS has. The table (docs/reference/v4-dictionary.tsv) holds the stack
|
||||
`WORDS` with the kernel's own capsules loaded (`sk_v4_capsules[]`), plus the kernel's words
|
||||
(`sk_v4_words[]`), both in kernel/src/v4/sk_v4.c -- the words a booted StarshipOS has. The table (docs/reference/v4-dictionary.tsv) holds the stack
|
||||
notation and the description, which only a person can write; the names are never typed by hand.
|
||||
"""
|
||||
import os, re, subprocess, sys
|
||||
@@ -29,22 +29,30 @@ SOURCES = ([os.path.join("capsules/v4/sys", f) for f in sorted(os.listdir(os.pat
|
||||
KERNEL_WORDS_SRC = "kernel/src/v4/sk_v4.c"
|
||||
|
||||
|
||||
def kernel_capsules():
|
||||
"""The kernel's own capsules (sk_v4_capsules[] in kernel/src/v4/sk_v4.c), as files of capsules/v4."""
|
||||
src = open(os.path.join(ROOT, KERNEL_WORDS_SRC)).read()
|
||||
m = re.search(r"sk_v4_capsules\[\]\s*=\s*\{([^}]*)\}", src)
|
||||
return [os.path.join("capsules/v4", n.split(":", 1)[1]) for n in re.findall(r'"([^"]+)"', m.group(1) if m else "")]
|
||||
|
||||
|
||||
def live_words():
|
||||
"""The hosted system's WORDS, then the kernel's own words not among them."""
|
||||
"""The hosted system's WORDS, with the kernel's own capsules loaded first, as the kernel loads
|
||||
them (#189: centre.4th, hera.4th); then the kernel's own words not among them."""
|
||||
if not os.path.exists(HOSTED):
|
||||
sys.exit(f"mkdictionary: {HOSTED} is missing: make -C v4 hosted")
|
||||
out = subprocess.run([HOSTED], input="WORDS\n", capture_output=True, text=True, timeout=120).stdout
|
||||
lines = out.split("\n")
|
||||
try:
|
||||
start = next(k for k, l in enumerate(lines) if l.startswith("ok> ") and l[4:].strip())
|
||||
except StopIteration:
|
||||
feed = []
|
||||
for path in kernel_capsules():
|
||||
for l in open(os.path.join(ROOT, path)):
|
||||
if not re.match(r"^Block \d+\s*$", l):
|
||||
feed.append(l.rstrip("\n"))
|
||||
feed.append('." [[WORDS]]" CR WORDS')
|
||||
out = subprocess.run([HOSTED], input="\n".join(feed) + "\n", capture_output=True, text=True, timeout=120).stdout
|
||||
if "ERROR" in out.split("[[WORDS]]")[0]:
|
||||
sys.exit("mkdictionary: a kernel capsule did not load in the hosted system")
|
||||
if "[[WORDS]]" not in out:
|
||||
sys.exit("mkdictionary: the hosted system printed no WORDS")
|
||||
got = []
|
||||
for l in lines[start:]:
|
||||
if l.startswith("ok> ") and got:
|
||||
break
|
||||
got.append(l[4:] if l.startswith("ok> ") else l)
|
||||
text = " ".join(got)
|
||||
text = out.split("[[WORDS]]", 1)[1].replace("ok>", " ")
|
||||
if " ok" in text:
|
||||
text = text[:text.rfind(" ok")]
|
||||
words = text.split()
|
||||
|
||||
Reference in New Issue
Block a user