feat(v4.0.0): the system boots from a nucleus and loads its capsules
One boot, v4/system/boot.c, for both products: it starts the nucleus image, finds each capsule in the baked capsule directory, recomputes its hash, checks its signature, gives its blocks to the node a line at a time, and prints PARITY:V4_NUCLEUS, PARITY:V4_CAPSULE and PARITY:OK before the prompt. A line the node does not accept ends the boot with the capsule, block and line named. docs/v4.0.0/NUCLEUS.md. - hosted Linux product for amd64, aarch64 and riscv64 (make -C v4 hosted); make -C v4 hosted-check boots all three and requires identical output - the kernel's v4 entry (STARFORTH_V4=1) calls the same boot - capsules/v4/forth79.4th, block 6000: no definitions yet - mkimage builds the nucleus only; no FORTH source is compiled at build time - capsule_blocks.c: the Block-header parse, free of any VM, for every loader Verified: make -C v4 test passes; hosted-check passes on the three ISAs with the same hashes; the kernel compiles with STARFORTH_V4=1 on the three. Not verified: no bare-metal boot of v4 has been run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
903321e548
commit
294e69463a
@@ -0,0 +1,50 @@
|
||||
/* boot.h -- how a StarForth v4 system comes up: the nucleus, then its
|
||||
* capsules, then the prompt. docs/v4.0.0/NUCLEUS.md.
|
||||
*
|
||||
* The hosted binary (tools/hosted.c) and the bare-metal kernel
|
||||
* (kernel/src/v4/sk_v4.c) both call v4_boot_run and differ only in where
|
||||
* the text goes. So the two start the same way and print the same lines:
|
||||
*
|
||||
* PARITY:V4_NUCLEUS words=N image_hash=0x...
|
||||
* PARITY:V4_CAPSULE name=... capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
* PARITY:OK
|
||||
* ok>
|
||||
*
|
||||
* or, if anything is wrong, what was wrong and then
|
||||
*
|
||||
* PARITY:FAIL
|
||||
* POST: FAILED
|
||||
*
|
||||
* A capsule is found by name in the directory tools/mkcapsule.c baked into
|
||||
* the binary, its hash is recomputed, its signature is checked -- one that
|
||||
* does not verify refuses the capsule, a missing one is only reported, as
|
||||
* for v3's capsules -- and its blocks are given to the node a line at a
|
||||
* time as if typed. The node must answer " ok" to every line; the first
|
||||
* line it does not accept ends the boot. What a line prints is shown.
|
||||
*
|
||||
* The dictionary hash is FNV-1a over the node's memory below HERE, a cell at
|
||||
* a time, low byte first, then LATEST. It does not depend on the machine:
|
||||
* every build of one commit, with one cell width, prints the same hashes.
|
||||
*/
|
||||
#ifndef V4_BOOT_H
|
||||
#define V4_BOOT_H
|
||||
|
||||
#include "v4/image.h"
|
||||
|
||||
typedef struct {
|
||||
v4_node *n;
|
||||
v4_exec_state *es;
|
||||
v4_heat *h;
|
||||
const v4_image *im; /* the nucleus */
|
||||
void (*out)(const char *text, unsigned len); /* the console */
|
||||
} v4_boot;
|
||||
|
||||
/* Start the node from the nucleus image, with `disk` as its block storage
|
||||
* (see v4_image_boot), and load the capsules. Returns 1 with the node
|
||||
* waiting at its prompt, the prompt printed; or 0, the failure printed. */
|
||||
int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks);
|
||||
|
||||
/* The dictionary hash of a node started from `im`. */
|
||||
uint64_t v4_boot_dict_hash(const v4_node *n, const v4_image *im);
|
||||
|
||||
#endif /* V4_BOOT_H */
|
||||
@@ -0,0 +1,71 @@
|
||||
/* image.h -- a capsule image: the host node's memory with the vocabulary in
|
||||
* it, and what a loader needs to know to start it.
|
||||
*
|
||||
* The compiler capsule is text (capsule/ *.v4) and FORTH source (capsule/
|
||||
* *.fth). tools/mkimage.c assembles the one and has a node compile the
|
||||
* other, on the build machine, and writes what the node's memory then holds
|
||||
* as a C file. A system that is to run the vocabulary -- the hosted binary,
|
||||
* the bare-metal kernel -- links that file and calls v4_image_boot: it needs
|
||||
* no assembler, no files and no C library.
|
||||
*
|
||||
* An image is for one cell width, one node size and one pair of stack sizes;
|
||||
* v4_image_boot refuses an image the engine was not built for.
|
||||
*/
|
||||
#ifndef V4_IMAGE_H
|
||||
#define V4_IMAGE_H
|
||||
|
||||
#include "v4/exec.h"
|
||||
|
||||
/* one word of memory that is not zero */
|
||||
typedef struct {
|
||||
v4_cell addr;
|
||||
v4_cell value;
|
||||
} v4_image_cell;
|
||||
|
||||
typedef struct {
|
||||
const v4_image_cell *cells; /* every non-zero word of memory, in address order */
|
||||
unsigned count;
|
||||
|
||||
/* what the image was built for */
|
||||
unsigned cell_bits, node_words, data_ring, ret_ring;
|
||||
|
||||
/* where to start, and where a fault goes */
|
||||
v4_cell entry; /* QUIT */
|
||||
v4_cell fault_table; /* (FAULTS) */
|
||||
|
||||
/* KEY's code: a node whose P is in key_start .. key_end - 1 with no
|
||||
* character pending is waiting for one */
|
||||
v4_cell key_start, key_end;
|
||||
|
||||
/* the memory-mapped registers (DECOMPOSITION.md section 7; D-4 leaves
|
||||
* the map to the loader, and this is the map the image was built with) */
|
||||
v4_cell console_tx, console_rx, console_status;
|
||||
v4_cell dstack_reg, rstack_reg;
|
||||
v4_cell node_error;
|
||||
v4_cell storage_reg;
|
||||
|
||||
/* the dictionary's two variables: DP holds HERE, a byte address, and
|
||||
* LATEST the newest word of FORTH. What lies below HERE, and LATEST,
|
||||
* is what the dictionary hash covers (v4/include/v4/boot.h). */
|
||||
v4_cell dp, latest;
|
||||
} v4_image;
|
||||
|
||||
/* The image built from v4/capsule (the generated file defines it). */
|
||||
extern const v4_image v4_capsule_image;
|
||||
|
||||
/* Reset `n`, load the image into it, attach its registers -- with `disk`,
|
||||
* `blocks` blocks of 1024 bytes, as its block storage, or none if `disk` is
|
||||
* 0 -- and leave it about to execute its first instruction. Returns 1, or 0
|
||||
* if the image is not for this build of the engine (nothing is then done).
|
||||
*
|
||||
* After it, the caller runs the node: v4_exec_step_word again and again,
|
||||
* taking what the node prints from n->console (and setting n->console_len
|
||||
* back to 0) and giving it what is typed with v4_node_console_feed. */
|
||||
int v4_image_boot(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
|
||||
unsigned char *disk, unsigned blocks);
|
||||
|
||||
/* 1 if the node is waiting for a character: it is inside KEY and none is
|
||||
* pending. */
|
||||
int v4_image_waiting(const v4_node *n, const v4_image *im);
|
||||
|
||||
#endif /* V4_IMAGE_H */
|
||||
Reference in New Issue
Block a user