fix(v4.0.0): a node blocked at a port with no one on it is given an error, not left there
A node writing to a node that was stuck, and was then killed, stayed blocked for ever: killing a stuck node could cost its neighbours. And on the hosted and bare-metal products a write to an empty port, 5 7 PORT!, ended the program with "the node stopped". Now a node that can take an error, blocked writing to or reading from one port that nothing is wired to -- nothing ever was, or what was there has been killed or the wire cut -- has error 18, No one on that port, raised on it and goes on. A bare node waits as on the fabric; so does a node whose neighbour is asleep, and one reading "any port". test_host_unit.c: Hera kills node 14 while node 12 is blocked writing to it. It failed first: 12 stayed blocked. test_fabric.c: a bare node still waits. hosted-check types 5 7 PORT! and goes on; it failed first too. make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and riscv64 boot, POST 538 of 538, dict_hash 0x5f0a949a6fc8ef2b on all six: logs/20261007-121743, -122008, -122337. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
18adf59091
commit
bc6deab3f5
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-10-07T15:31:38Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-10-07T16:22:56Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
@@ -116,6 +116,29 @@ word address `base`:
|
||||
That is how an F18 node runs code from a port, and it is what makes
|
||||
ruling 8 need no code in a newborn node.
|
||||
- A port with nothing on the other end blocks for ever, as on the fabric.
|
||||
**Fixed 2026-10-07 ("Fix the error. no bad code is ever released"):**
|
||||
that holds for a bare node. A node that can take an error is not left
|
||||
there. When it is blocked writing to one port, or reading from one, that
|
||||
nothing is wired to — because nothing ever was, or because what was
|
||||
there has been killed or the wire cut — error 18, "No one on that
|
||||
port", is raised on it: what it was doing ends with the message and it
|
||||
goes on (`v4/src/node.c`, `v4_node_port_gone`; `v4/src/fabric.c`,
|
||||
`v4_fabric_gone_error`; the lone node, `v4/system/boot.c`). A node whose
|
||||
neighbour is asleep waits, and so does one reading "any port".
|
||||
What it mended: a node writing to a node that was stuck, and was then
|
||||
killed, stayed blocked for ever, so that killing a stuck node could cost
|
||||
its neighbours (found while step 7 was being designed); and on the two
|
||||
products a write to an empty port, `5 7 PORT!`, ended the program.
|
||||
`v4/tests/test_host_unit.c`: Hera kills node 14 while node 12 is blocked
|
||||
writing to it; 12's line ends "No one on that port", every other node
|
||||
answers, and a later send to 14 is that error at once.
|
||||
`v4/tests/test_fabric.c`: a bare node still waits. `hosted-check` and the
|
||||
three boots type `5 7 PORT!` and go on: `logs/20261007-121743` (amd64),
|
||||
`-122008` (aarch64), `-122337` (riscv64); POST 538 of 538,
|
||||
`dict_hash=0x5f0a949a6fc8ef2b` on all six.
|
||||
**Not mended, and reported:** a node that waits at "any port" for an
|
||||
answer that never comes (`AWAIT`, on a node that never answers) waits
|
||||
for ever, and on the lone node that ends the line as "stopped".
|
||||
|
||||
### 4.2 A node at reset
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;042;160t[2J[001;001H[2J[001;001H[8;056;240t[2J[001;001HBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
|
||||
BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
RAW SERIAL UP
|
||||
[CKPT 002] Serial (COM1) initialized
|
||||
Monolithic build - kernel linked directly
|
||||
Collecting boot information...
|
||||
CmdLine: parsed OK
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
GOP: linear framebuffer found
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
EBS...
|
||||
EBS OK
|
||||
Calling kernel_main (monolithic)...
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0
|
||||
Architecture: amd64
|
||||
Build: Oct 7 2026 12:17:15
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 131
|
||||
Total memory: 1023 MB
|
||||
Usable memory: 966 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 248744
|
||||
Free pages : 247221
|
||||
Used pages : 1523
|
||||
Total MB : 971
|
||||
Free MB : 965
|
||||
Used MB : 5
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
APIC: IA32_APIC_BASE MSR=0x00000000fee00900
|
||||
APIC: stale-ISR drain: 0 EOI(s) issued
|
||||
APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear)
|
||||
APIC: init done
|
||||
|
||||
I/O APIC: init...
|
||||
I/O APIC: base=0xfec00000, gsi_base=0, overrides=5
|
||||
override: source=00 gsi=2 flags=0x0000
|
||||
override: source=05 gsi=5 flags=0x000d
|
||||
override: source=09 gsi=9 flags=0x000d
|
||||
override: source=0a gsi=10 flags=0x000d
|
||||
override: source=0b gsi=11 flags=0x000d
|
||||
i8042: keyboard ACKed enable-scanning
|
||||
i8042: IRQ1 enabled in controller config byte
|
||||
I/O APIC: keyboard IRQ1 routed (masked)
|
||||
|
||||
Timer: init...
|
||||
Timer: init start
|
||||
Timer: PM_TMR_BLK discovered from FADT at port 1544
|
||||
Timer: VM mode detected (hypervisor present).
|
||||
Timer: HPET calibration disabled (VM-exit MMIO would poison timing).
|
||||
Timer: WARNING: invariant TSC not present under hypervisor.
|
||||
Timer: continuing in RELATIVE mode (no determinism guarantees).
|
||||
Timer: RDTSCP not present; using RDTSC (less serialized).
|
||||
Timer: CPUID frequency unavailable; trying PM Timer...
|
||||
Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2091392980 Hz
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 536870872
|
||||
Free bytes: 536870872
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 24641536
|
||||
Heap end addr: 561512448
|
||||
|
||||
Heartbeat: init...
|
||||
APIC Timer: calibrating...
|
||||
APIC Timer: apic_hz=1007112438, tick_hz=100, initial_count=10071124
|
||||
APIC Timer: configured (masked, ready to start)
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
V4: capsule v4:nucleus-64.f18 signature: missing (unsigned)
|
||||
PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0xbb8f7aba92a2f5dc capsule_hash=0xbb8f7aba92a2f5dc words=308
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x145ecc5563d10b54
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=314 dict_hash=0x5f0a949a6fc8ef2b
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks)
|
||||
PCI: init...
|
||||
PCI: ECAM mapped (amd64)
|
||||
virtio-blk: found device
|
||||
Artemis: virtio-blk attached
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 80440941] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b
|
||||
ok> : SQ DUP * ;
|
||||
ok
|
||||
ok> 7 SQ . 3 4 U* . .
|
||||
49 0 12 ok
|
||||
ok> T{
|
||||
UNKNOWN WORD: 'T{'
|
||||
ERROR
|
||||
ok> RS1
|
||||
UNKNOWN WORD: 'RS1'
|
||||
ERROR
|
||||
ok> COLD
|
||||
FORTH-79 Cold Start
|
||||
System initialized.
|
||||
ok
|
||||
ok> 3 4 U* . .
|
||||
0 12 ok
|
||||
ok> FORGET U*
|
||||
Protected word
|
||||
ERROR
|
||||
ok> 9 KERNEL-WORD ASK9 ASK9
|
||||
Argument out of range
|
||||
ERROR
|
||||
ok> 1 BLOCK C@ . 2047 BLOCK C@ .
|
||||
0 0 ok
|
||||
ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ .
|
||||
65 ok
|
||||
ok> 3072 BLOCK C@ .
|
||||
0 ok
|
||||
ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS
|
||||
Storage refused
|
||||
ERROR
|
||||
ok> 9999999 BLOCK
|
||||
Block out of range
|
||||
ERROR
|
||||
ok> 5 7 PORT!
|
||||
No one on that port
|
||||
ERROR
|
||||
ok> 1 2 + .
|
||||
3 ok
|
||||
ok> HERE .
|
||||
8300 ok
|
||||
ok> BYE
|
||||
BYE: cold restart
|
||||
@@ -0,0 +1,133 @@
|
||||
UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026)
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;031;100t[2J[001;001HBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found
|
||||
BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found
|
||||
BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
|
||||
BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
Collecting boot information...
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0
|
||||
Architecture: aarch64
|
||||
Build: Oct 7 2026 12:19:41
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 108
|
||||
Total memory: 4093 MB
|
||||
Usable memory: 4054 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 1039358
|
||||
Free pages : 1037947
|
||||
Used pages : 1411
|
||||
Total MB : 4059
|
||||
Free MB : 4054
|
||||
Used MB : 5
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
AArch64: running at EL1
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
PSCI: no DTB -- using HVC (QEMU virt-machine default)
|
||||
GICv2: no DTB GIC node -- using QEMU virt-machine defaults
|
||||
GICv2: distributor+CPU interface enabled, PPI 30
|
||||
APIC: init done
|
||||
|
||||
Timer: init...
|
||||
Timer: AArch64 generic timer initialised.
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 2147483608
|
||||
Free bytes: 2147483608
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 1207959552
|
||||
Heap end addr: 3355443200
|
||||
|
||||
Heartbeat: init...
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
V4: capsule v4:nucleus-64.f18 signature: missing (unsigned)
|
||||
PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0xbb8f7aba92a2f5dc capsule_hash=0xbb8f7aba92a2f5dc words=308
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x145ecc5563d10b54
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=314 dict_hash=0x5f0a949a6fc8ef2b
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks)
|
||||
PCI: init...
|
||||
virtio-blk: found device
|
||||
Artemis: virtio-blk attached
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 1354093] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b
|
||||
ok> : SQ DUP * ;
|
||||
ok
|
||||
ok> 7 SQ . 3 4 U* . .
|
||||
49 0 12 ok
|
||||
ok> T{
|
||||
UNKNOWN WORD: 'T{'
|
||||
ERROR
|
||||
ok> RS1
|
||||
UNKNOWN WORD: 'RS1'
|
||||
ERROR
|
||||
ok> COLD
|
||||
FORTH-79 Cold Start
|
||||
System initialized.
|
||||
ok
|
||||
ok> 3 4 U* . .
|
||||
0 12 ok
|
||||
ok> FORGET U*
|
||||
Protected word
|
||||
ERROR
|
||||
ok> 9 KERNEL-WORD ASK9 ASK9
|
||||
Argument out of range
|
||||
ERROR
|
||||
ok> 1 BLOCK C@ . 2047 BLOCK C@ .
|
||||
0 0 ok
|
||||
ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ .
|
||||
65 ok
|
||||
ok> 3072 BLOCK C@ .
|
||||
0 ok
|
||||
ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS
|
||||
Storage refused
|
||||
ERROR
|
||||
ok> 9999999 BLOCK
|
||||
Block out of range
|
||||
ERROR
|
||||
ok> 5 7 PORT!
|
||||
No one on that port
|
||||
ERROR
|
||||
ok> 1 2 + .
|
||||
3 ok
|
||||
ok> HERE .
|
||||
8300 ok
|
||||
ok> BYE
|
||||
BYE: cold restart
|
||||
@@ -0,0 +1,203 @@
|
||||
|
||||
OpenSBI v1.8
|
||||
____ _____ ____ _____
|
||||
/ __ \ / ____| _ \_ _|
|
||||
| | | |_ __ ___ _ __ | (___ | |_) || |
|
||||
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
|
||||
| |__| | |_) | __/ | | |____) | |_) || |_
|
||||
\____/| .__/ \___|_| |_|_____/|____/_____|
|
||||
| |
|
||||
|_|
|
||||
|
||||
Platform Name : riscv-virtio,qemu
|
||||
Platform Features : medeleg
|
||||
Platform HART Count : 1
|
||||
Platform HART Protection : pmp
|
||||
Platform IPI Device : aclint-mswi
|
||||
Platform Timer Device : aclint-mtimer @ 10000000Hz
|
||||
Platform Console Device : uart8250
|
||||
Platform HSM Device : ---
|
||||
Platform PMU Device : ---
|
||||
Platform Reboot Device : syscon-reboot
|
||||
Platform Shutdown Device : syscon-poweroff
|
||||
Platform Suspend Device : ---
|
||||
Platform CPPC Device : ---
|
||||
Firmware Base : 0x80000000
|
||||
Firmware Size : 321 KB
|
||||
Firmware RW Offset : 0x40000
|
||||
Firmware RW Size : 65 KB
|
||||
Firmware Heap Offset : 0x47000
|
||||
Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free)
|
||||
Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free)
|
||||
Runtime SBI Version : 3.0
|
||||
Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr
|
||||
Experimental SBI Extensions : none
|
||||
|
||||
Domain0 Name : root
|
||||
Domain0 Boot HART : 0
|
||||
Domain0 HARTs : 0*
|
||||
Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: ()
|
||||
Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: ()
|
||||
Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
|
||||
Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
|
||||
Domain0 Next Address : 0x0000000020000000
|
||||
Domain0 Next Arg1 : 0x00000000bfe00000
|
||||
Domain0 Next Mode : S-mode
|
||||
Domain0 SysReset : yes
|
||||
Domain0 SysSuspend : yes
|
||||
|
||||
Boot HART ID : 0
|
||||
Boot HART Domain : root
|
||||
Boot HART Priv Version : v1.12
|
||||
Boot HART Base ISA : rv64imafdch
|
||||
Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu
|
||||
Boot HART PMP Count : 16
|
||||
Boot HART PMP Granularity : 2 bits
|
||||
Boot HART PMP Address Bits : 54
|
||||
Boot HART MHPM Info : 16 (0x0007fff8)
|
||||
Boot HART Debug Triggers : 2 triggers
|
||||
Boot HART MIDELEG : 0x0000000000001666
|
||||
Boot HART MEDELEG : 0x0000000000f4b509
|
||||
[2J[004D[=3h[2J[009D[2J[004D[8;031;100t[2J[016DRISC-V EDK2 firmware version 2025.11-3ubuntu7.3
|
||||
Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850
|
||||
BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr
|
||||
om PciRoot(0x0)/Pci(0x1,0x0): Not Found
|
||||
[2J[001;001H[=3h[2J[009DStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
Monolithic build - kernel linked directly
|
||||
Collecting boot information...
|
||||
CmdLine: parsed OK
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
GOP: linear framebuffer found
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
Calling kernel_main (monolithic)...
|
||||
riscv64 item 4.3.5a: satp state at kernel entry (before switch)
|
||||
satp.MODE = 0x000000000000000a
|
||||
satp.PPN = 0x00000000000bf868
|
||||
__kernel_start = 0x00000000bdca29f8
|
||||
riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0
|
||||
Architecture: riscv64
|
||||
Build: Oct 7 2026 12:22:56
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 100
|
||||
Total memory: 1020 MB
|
||||
Usable memory: 975 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 250273
|
||||
Free pages : 249621
|
||||
Used pages : 652
|
||||
Total MB : 977
|
||||
Free MB : 975
|
||||
Used MB : 2
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000)
|
||||
PLIC: init (S-mode context 1, threshold=0)
|
||||
APIC: init done
|
||||
|
||||
Timer: init...
|
||||
Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree)
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 536870872
|
||||
Free bytes: 536870872
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 2214588416
|
||||
Heap end addr: 2751459328
|
||||
|
||||
Heartbeat: init...
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
V4: capsule v4:nucleus-64.f18 signature: missing (unsigned)
|
||||
PARITY:V4_NUCLEUS name=v4:nucleus-64.f18 capsule_id=0xbb8f7aba92a2f5dc capsule_hash=0xbb8f7aba92a2f5dc words=308
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x145ecc5563d10b54
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=314 dict_hash=0x5f0a949a6fc8ef2b
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 0] blk: raw device LBN 2048..3071 (1024 blocks)
|
||||
PCI: init...
|
||||
virtio-blk: found device
|
||||
Artemis: virtio-blk attached
|
||||
[32m[HADES][INFO ] [0m[KRELTSC: 37118739] blk: disk 'StarForth Volume' v2 LBN 3072..789009 (785938 user b
|
||||
ok> : SQ DUP * ;
|
||||
ok
|
||||
ok> 7 SQ . 3 4 U* . .
|
||||
49 0 12 ok
|
||||
ok> T{
|
||||
UNKNOWN WORD: 'T{'
|
||||
ERROR
|
||||
ok> RS1
|
||||
UNKNOWN WORD: 'RS1'
|
||||
ERROR
|
||||
ok> COLD
|
||||
FORTH-79 Cold Start
|
||||
System initialized.
|
||||
ok
|
||||
ok> 3 4 U* . .
|
||||
0 12 ok
|
||||
ok> FORGET U*
|
||||
Protected word
|
||||
ERROR
|
||||
ok> 9 KERNEL-WORD ASK9 ASK9
|
||||
Argument out of range
|
||||
ERROR
|
||||
ok> 1 BLOCK C@ . 2047 BLOCK C@ .
|
||||
0 0 ok
|
||||
ok> 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ .
|
||||
65 ok
|
||||
ok> 3072 BLOCK C@ .
|
||||
0 ok
|
||||
ok> 3072 BLOCK DROP UPDATE SAVE-BUFFERS
|
||||
Storage refused
|
||||
ERROR
|
||||
ok> 9999999 BLOCK
|
||||
Block out of range
|
||||
ERROR
|
||||
ok> 5 7 PORT!
|
||||
No one on that port
|
||||
ERROR
|
||||
ok> 1 2 + .
|
||||
3 ok
|
||||
ok> HERE .
|
||||
8300 ok
|
||||
ok> BYE
|
||||
BYE: cold restart
|
||||
@@ -198,6 +198,8 @@ hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt) $(BINDIR)/star
|
||||
@printf 'RS1\nT{\nWORDS\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/after-post-amd64.txt
|
||||
@grep -q "^ok> UNKNOWN WORD: 'RS1'$$" $(BINDIR)/after-post-amd64.txt || { echo "hosted-check: a word a POST case defined is still there"; exit 1; }
|
||||
@grep -q "^ok> UNKNOWN WORD: 'T{'$$" $(BINDIR)/after-post-amd64.txt || { echo "hosted-check: POST's harness is on the node"; exit 1; }
|
||||
@printf '5 7 PORT!\n1 2 + .\n' | $(BINDIR)/starforth4-amd64 > $(BINDIR)/noone-amd64.txt 2>&1; true
|
||||
@grep -q '^ok> No one on that port$$' $(BINDIR)/noone-amd64.txt && grep -q '^ok> 3 ok$$' $(BINDIR)/noone-amd64.txt || { echo "hosted-check: a write to a port with no one on it was not an error the node came back from"; cat $(BINDIR)/noone-amd64.txt | tail -4; exit 1; }
|
||||
@$(BINDIR)/starforth4-postfail < /dev/null > $(BINDIR)/postfail.txt; test $$? -ne 0 || { echo "hosted-check: a boot with a failing case did not fail"; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.wrong out<5 5 $$' $(BINDIR)/postfail.txt || { echo "hosted-check: the failing case was not named"; cat $(BINDIR)/postfail.txt; exit 1; }
|
||||
@grep -q '^POST FAIL: fail.many out<QQQQ' $(BINDIR)/postfail.txt || { echo "hosted-check: the case that prints too much was not named"; exit 1; }
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
\ 11 Division by zero (Q./) 12 Argument out of range
|
||||
\ 13 Block out of range 14 No block is being loaded
|
||||
\ 15 Deferred word not set 16 Not a word
|
||||
\ 17 Storage refused
|
||||
\ 17 Storage refused 18 No one on that port
|
||||
\ -1 the word has printed its own message
|
||||
|
||||
macro SWAP over push push drop pop pop endmacro
|
||||
|
||||
+2
-1
@@ -284,7 +284,7 @@ header ABORT
|
||||
POS: -1 + if M1 -1 + if M2 -1 + if M3 -1 + if M4
|
||||
-1 + if M5 -1 + if M6 -1 + if M7 -1 + if M8 -1 + if M9
|
||||
-1 + if M10 -1 + if M11 -1 + if M12 -1 + if M13 -1 + if M14
|
||||
-1 + if M15 -1 + if M16 -1 + if M17
|
||||
-1 + if M15 -1 + if M16 -1 + if M17 -1 + if M18
|
||||
drop 2 jump (DONE)
|
||||
M1: drop $6167654E (EMIT4) $65766974 (EMIT4) $756F6320 (EMIT4) $746E (EMIT4) CR 2 jump (DONE)
|
||||
M2: drop $20746F4E (EMIT4) $756E2061 (EMIT4) $7265626D (EMIT4) CR 2 jump (DONE)
|
||||
@@ -303,6 +303,7 @@ header ABORT
|
||||
M15: drop $65666544 (EMIT4) $64657272 (EMIT4) $726F7720 (EMIT4) $6F6E2064 (EMIT4) $65732074 (EMIT4) $74 (EMIT4) CR 2 jump (DONE)
|
||||
M16: drop $20746F4E (EMIT4) $6F772061 (EMIT4) $6472 (EMIT4) CR 2 jump (DONE)
|
||||
M17: drop $726F7453 (EMIT4) $20656761 (EMIT4) $75666572 (EMIT4) $646573 (EMIT4) CR 2 jump (DONE)
|
||||
M18: drop $6F206F4E (EMIT4) $6F20656E (EMIT4) $6874206E (EMIT4) $70207461 (EMIT4) $74726F (EMIT4) CR 2 jump (DONE)
|
||||
|
||||
\ The table the loader gives the node: six words, one for each kind of
|
||||
\ fault in the node's order, each a jump. A jump fills its word, so they
|
||||
|
||||
@@ -54,11 +54,23 @@ typedef struct {
|
||||
typedef struct {
|
||||
v4_place *place;
|
||||
unsigned capacity;
|
||||
v4_cell gone_error; /* see v4_fabric_gone_error; 0: none */
|
||||
} v4_fabric;
|
||||
|
||||
/* An empty fabric with room for `capacity` nodes, in `places`. */
|
||||
void v4_fabric_init(v4_fabric *f, v4_place *places, unsigned capacity);
|
||||
|
||||
/* A PORT WITH NOTHING ON IT. On the fabric a node that writes to such a
|
||||
* port, or reads from it, waits for ever (docs/v4.0.0/MESH.md 4.1). That
|
||||
* is so here for a bare node. But a node that can take an error is not
|
||||
* left there: when it is blocked writing to, or reading from, one port that
|
||||
* nothing is wired to -- because nothing ever was, or because what was
|
||||
* there has been removed or the wire cut -- the error `code` is raised on
|
||||
* it and it goes on (node.h, v4_node_port_gone). A node whose neighbour is
|
||||
* asleep waits, and so does one reading "any port". With `code` 0, which
|
||||
* is how a fabric begins, nothing is raised. */
|
||||
void v4_fabric_gone_error(v4_fabric *f, v4_cell code);
|
||||
|
||||
/* More room: `places`, of `capacity` no less than before, takes over; every
|
||||
* node keeps its number and its wiring. */
|
||||
void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity);
|
||||
|
||||
@@ -60,6 +60,11 @@ typedef struct {
|
||||
v4_cell block_window;
|
||||
} v4_image;
|
||||
|
||||
/* The nucleus's error for a node blocked at a port with no one on it
|
||||
* (v4/capsule/core.v4's list; node.h, v4_node_port_gone): "No one on that
|
||||
* port". */
|
||||
#define V4_ERROR_NO_ONE 18
|
||||
|
||||
/* The description of the nucleus built from v4/capsule (the generated file
|
||||
* defines it). */
|
||||
extern const v4_image v4_capsule_image;
|
||||
|
||||
@@ -214,6 +214,16 @@ void v4_node_port_attach(v4_node *n, v4_cell base);
|
||||
/* The neighbour has taken what the node wrote. */
|
||||
void v4_node_port_served(v4_node *n);
|
||||
|
||||
/* THERE IS NO ONE ON THE PORT the node is blocked at -- writing to it, or
|
||||
* reading from that one port -- and there will not be. A node that can
|
||||
* take an error (it has an error register and a fault table: node.h,
|
||||
* v4_node_error_attach, v4_node_fault_attach) is let go and the error
|
||||
* `code` is raised on it, as if it had stored the code to its error
|
||||
* register: what it was doing ends there. Returns 1. A node that cannot
|
||||
* stays blocked, as on the fabric, and 0 is returned; so is 0 for a node
|
||||
* that is not blocked at a port, or is reading "any port". */
|
||||
int v4_node_port_gone(v4_node *n, v4_cell code);
|
||||
|
||||
/* The neighbour on `port` writes `value`: the node, blocked reading that
|
||||
* port or "any", is unblocked and will fetch it. */
|
||||
void v4_node_port_give(v4_node *n, unsigned port, v4_cell value);
|
||||
|
||||
@@ -17,9 +17,15 @@ void v4_fabric_init(v4_fabric *f, v4_place *places, unsigned capacity)
|
||||
unsigned i;
|
||||
f->place = places;
|
||||
f->capacity = capacity;
|
||||
f->gone_error = 0;
|
||||
for (i = 0; i < capacity; i++) clear_place(&places[i]);
|
||||
}
|
||||
|
||||
void v4_fabric_gone_error(v4_fabric *f, v4_cell code)
|
||||
{
|
||||
f->gone_error = code;
|
||||
}
|
||||
|
||||
void v4_fabric_grow(v4_fabric *f, v4_place *places, unsigned capacity)
|
||||
{
|
||||
unsigned i;
|
||||
@@ -196,5 +202,16 @@ unsigned v4_fabric_step(v4_fabric *f)
|
||||
for (i = 0; i < f->capacity; i++)
|
||||
if (awake(f, i) && f->place[i].node->n.reading && !f->place[i].node->n.given) done += hand_over_read(f, i);
|
||||
|
||||
/* a node blocked at one port that nothing is wired to */
|
||||
if (f->gone_error != 0)
|
||||
for (i = 0; i < f->capacity; i++) {
|
||||
v4_node *n;
|
||||
if (!awake(f, i)) continue;
|
||||
n = &f->place[i].node->n;
|
||||
if ((n->asking && f->place[i].wire[n->ask_port].kind == V4_WIRE_NONE)
|
||||
|| (n->reading && !n->given && n->read_port != V4_PORT_ANY && f->place[i].wire[n->read_port].kind == V4_WIRE_NONE))
|
||||
done += (unsigned)v4_node_port_gone(n, f->gone_error);
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
@@ -222,3 +222,13 @@ void v4_node_port_served(v4_node *n)
|
||||
{
|
||||
n->asking = 0;
|
||||
}
|
||||
|
||||
int v4_node_port_gone(v4_node *n, v4_cell code)
|
||||
{
|
||||
if (code == 0 || n->error_reg < 0 || n->fault_vector < 0 || n->stopped) return 0;
|
||||
if (n->asking) n->asking = 0;
|
||||
else if (n->reading && !n->given && n->read_port != V4_PORT_ANY) n->reading = 0;
|
||||
else return 0;
|
||||
v4_node_store(n, n->error_reg, code); /* raises it: P is the node's handler now */
|
||||
return 1;
|
||||
}
|
||||
|
||||
+5
-1
@@ -139,13 +139,17 @@ static int run_line(const v4_boot *b, const char *text, unsigned len, char *keep
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (n->asking) return V4_BOOT_LINE_STOPPED; /* a port with nothing on it */
|
||||
if (n->asking) { /* a port with no one on it: an error on the node */
|
||||
if (!v4_node_port_gone(n, V4_ERROR_NO_ONE)) return V4_BOOT_LINE_STOPPED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n->reading && !n->given) {
|
||||
if (sent < out.count && (n->read_port == CONSOLE_PORT || n->read_port == V4_PORT_ANY)) {
|
||||
v4_node_port_give(n, CONSOLE_PORT, out.word[sent++]); /* a word of the message to the node */
|
||||
continue;
|
||||
}
|
||||
if (n->read_port != CONSOLE_PORT && n->read_port != KERNEL_PORT && v4_node_port_gone(n, V4_ERROR_NO_ONE)) continue; /* reading one port, with no one on it */
|
||||
return V4_BOOT_LINE_STOPPED; /* waiting for what will not come */
|
||||
}
|
||||
if (v4_image_waiting(n, b->im)) { /* the text is reading the keyboard */
|
||||
|
||||
@@ -273,6 +273,14 @@ int main(void)
|
||||
CHECK(ND(c)->n.mem[OUT] == 2, "who gets its next: %ld", (long)ND(c)->n.mem[OUT]);
|
||||
CHECK(ND(a)->n.asking && ND(a)->n.request == 3, "and the writer waits with its third");
|
||||
CHECK(v4_fabric_unwire(&f, a, 0) && settle(100) == 0 && ND(a)->n.asking, "with the wire cut it goes on waiting");
|
||||
v4_fabric_gone_error(&f, 18);
|
||||
CHECK(settle(100) == 0 && ND(a)->n.asking && ND(a)->n.faults == 0, "and still does when the fabric has an error for it: a bare node cannot take one");
|
||||
v4_node_error_attach(&ND(a)->n, OUT + 20);
|
||||
v4_node_fault_attach(&ND(a)->n, 900);
|
||||
CHECK(v4_fabric_step(&f) == 1 && !ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 18
|
||||
&& ND(a)->n.p == 900 + (v4_cell)V4_FAULT_RAISED && ND(a)->n.mem[OUT + 20] == 18,
|
||||
"a node that can take an error is let go, and the error is raised on it: its P is its handler");
|
||||
CHECK(!v4_node_port_gone(&ND(c)->n, 18), "a node that is not blocked at a port is not touched");
|
||||
|
||||
/* ---- asleep, awake, and removed, while looping; and a node born while others run ---- */
|
||||
v4_fabric_init(&f, places, 4);
|
||||
|
||||
@@ -380,6 +380,7 @@ int main(void)
|
||||
|
||||
/* ---- Hera is born empty, and takes in the nucleus ---- */
|
||||
v4_fabric_init(&f, places, PLACES);
|
||||
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
|
||||
place = host_born(0);
|
||||
CHECK(place == 0, "a node is born");
|
||||
hera_place = (unsigned)place;
|
||||
@@ -498,6 +499,22 @@ int main(void)
|
||||
CHECK(strcmp(tell(10, "(LOST) @ ."), "0 ") == 0 && strcmp(tell(12, "(LOST) @ ."), "0 ") == 0, "and no message was let go");
|
||||
CHECK(waiting(10) && waiting(11) && waiting(12) && waiting(13) && waiting(14), "all five are waiting at their ports again");
|
||||
|
||||
/* ---- a node is killed while its neighbour is writing to it ---- */
|
||||
step_limit = 3000000ul;
|
||||
CHECK(strcmp(tell(14, ": SPIN BEGIN 0 UNTIL ; SPIN"), "(still running)") == 0, "node 14 is stuck in a loop that never ends");
|
||||
CHECK(strcmp(tell(12, ": TO14 S\" 65 EMIT\" 14 SEND ; TO14"), "(still running)") == 0 && node_numbered(12)->asking,
|
||||
"node 12, beside it, sends it text: 14 never reads, and 12 is blocked writing to it");
|
||||
{
|
||||
unsigned born = born_count;
|
||||
const char *r = tell(10, "(P4) @ NODE-KILL 65 EMIT");
|
||||
CHECK(strstr(printed, "A") != NULL && node_numbered(14) == NULL && born_count == born, "Hera kills node 14: \"%s\"", r);
|
||||
}
|
||||
CHECK(!node_numbered(12)->asking && !node_numbered(12)->stopped && waiting(12), "node 12 is no longer blocked: it is waiting at its ports");
|
||||
CHECK(strstr(printed, "No one on that port") != NULL, "what it was doing ended in an error, which said so: \"%s\"", printed);
|
||||
step_limit = 30000000ul;
|
||||
CHECK(strcmp(tell(12, "12 100 * ."), "1200 ") == 0 && strcmp(tell(13, "13 100 * ."), "1300 ") == 0 && strcmp(tell(10, "1 2 + ."), "3 ") == 0, "and everything else keeps running: \"%s\"", printed);
|
||||
CHECK(strstr(tell(12, ": AGAIN14 S\" 65 EMIT\" 14 SEND ; AGAIN14"), "No one on that port") != NULL && waiting(12), "a later write to where node 14 was is an error at once, not a wait: \"%s\"", printed);
|
||||
|
||||
printf(" %d checks, %d failures\n", checks, failures);
|
||||
return failures != 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user