B4: the disk remembers whether the last start arrived

The loader marks the superblock before it hands over and the system clears
the mark when it reaches its prompt, so a system that crashes on the way
there leaves it set. The loader finding it still set next time is how a
machine that will not start says so to the only thing in a position to do
anything about it. Without that, pointing boot.cfg at something that dies
before the shell is a machine that can never be told anything again - the
shell is the only way to change the file, and the file is what stops the
shell from starting.

Three states rather than two, and the third is the one worth having:

  0 settled    the last start arrived; use the configuration
  1 trying     handed over, and nothing came back to say it got there
  2 fell back  a try failed and the fallback was used, until settled

With only 0 and 1 the machine alternates for ever: fall back, reach a
prompt, clear the mark, retry the broken system, crash, fall back. State 2
stops that. A system known not to start is not tried again until somebody
says the situation has changed.

REACHING THE PROMPT IS A DELIBERATE THRESHOLD. It is not a claim that the
system works - a shell can be reached by something broken in every other
way. It is the point where a person can type, which is exactly what the
fallback exists to give back: anything wrong past there is fixable from the
prompt and nothing wrong before it is fixable at all.

The routines live in sbfs.asm because both the loader and the system read
and write this byte, and two pieces of code with their own idea of where a
byte lives is what this format has two implementations and a byte for byte
comparison to avoid.

And the trap this system documents in its own manual caught me anyway: the
first version handed the state back in A, which CALL restores, so every
read got whatever the caller happened to be holding. It comes back in
memory now, and the comment says why.

Three disks differing only in the state on them, so the tests read as three
consecutive starts of one machine while none depends on another running.
This commit is contained in:
Anachronaut
2026-08-27 16:51:39 -04:00
parent 546f336823
commit dc74149321
14 changed files with 368 additions and 3 deletions
+8
View File
@@ -220,6 +220,14 @@ d = open('boot.img','rb').read()
slot = d[256:256 + 32 * 256]
sys.exit(1 if b'aaaa' in slot else 0)"
# ---- How the last start went ----
check "the boot state reads" "$TOOL" bootstate boot.img
check "and can be set" "$TOOL" bootstate boot.img 2
refuses "but only to a state there is" "$TOOL" bootstate boot.img 7
check "a fresh disk is settled" python3 -c "
import sys
sys.exit(0 if open('plain.img','rb').read()[17] == 0 else 1)"
echo
if [ "$FAIL" -eq 0 ]; then
echo "All $PASS disk tool checks passed."
+1
View File
@@ -1,5 +1,6 @@
stage two
no /System/Boot/cosmos.bin
trying the fallback
nothing to start
Execution halted.
[exit 0]
+4
View File
@@ -0,0 +1,4 @@
stage two
a system that never reaches a prompt
Execution halted.
[exit 0]
+8
View File
@@ -0,0 +1,8 @@
stage two
the last start did not arrive
CosmOS
this is the fallback: what boot.cfg asks for did not start
>
halted
Execution halted.
[exit 0]
+8
View File
@@ -0,0 +1,8 @@
stage two
still on the fallback: settle it to try again
CosmOS
this is the fallback: what boot.cfg asks for did not start
>
halted
Execution halted.
[exit 0]
+21
View File
@@ -446,3 +446,24 @@ printf 'system /System/Boot/bare.bin\n' > "$WORK/bare.cfg"
printf 'fallback /System/Boot/cosmos.bin\n'
} > "$WORK/fallback.cfg"
"$TOOL" put "$DISKS/cfgfallback.img" "$WORK/fallback.cfg" /System/Boot/boot.cfg >/dev/null
# ---- A system that never reaches a prompt ----
#
# The case the boot state exists for. Pointing the configuration at something that dies
# before the shell is, without a mark on the disk, a machine that can never be told
# anything again - so the loader marks it before handing over and the system clears the
# mark on arrival, which makes "did not arrive" a thing the next start can see.
"$ROOT/Assembler" "$ROOT/Programs/Boot/wedged.asm" -o "$WORK/wedged.bin" >/dev/null
for stage in first second third; do
cp "$DISKS/selfboot.img" "$DISKS/wedge$stage.img"
"$TOOL" put "$DISKS/wedge$stage.img" "$WORK/wedged.bin" /System/Boot/wedged.bin >/dev/null
{
printf 'system /System/Boot/wedged.bin\n'
printf 'fallback /System/Boot/cosmos.bin\n'
} > "$WORK/wedge.cfg"
"$TOOL" put "$DISKS/wedge$stage.img" "$WORK/wedge.cfg" /System/Boot/boot.cfg >/dev/null
done
# Each disk begins where the one before it ended, so the three tests read as three
# consecutive starts of one machine without any of them depending on the others running.
"$TOOL" bootstate "$DISKS/wedgesecond.img" 1 >/dev/null
"$TOOL" bootstate "$DISKS/wedgethird.img" 2 >/dev/null
+14
View File
@@ -419,6 +419,20 @@ cfgBroken | Boot/stage1.asm | rom | -
cfgFallback | Boot/stage1.asm | rom | selfBoot.in | 90000000 | disks/cfgfallback.img
# And the bare image on its own, which has to keep assembling.
bareMetal | Boot/bare.asm | assemble | - | -
# ---- A system that never reaches a prompt ----
#
# Three disks that differ only in the boot state on them, so the three tests read as three
# consecutive starts of one machine while none of them depends on another having run.
#
# wedgeFirst tries it and marks the disk. wedgeSecond finds the mark still set - nothing
# came back to say the last start arrived - and uses the fallback. wedgeThird finds that
# already happened and does the same again WITHOUT retrying, which is the part worth
# pinning down: a system known not to start should not be tried every other boot for ever.
wedgeFirst | Boot/stage1.asm | rom | - | 90000000 | disks/wedgefirst.img
wedgeSecond | Boot/stage1.asm | rom | - | 90000000 | disks/wedgesecond.img
wedgeThird | Boot/stage1.asm | rom | - | 90000000 | disks/wedgethird.img
wedgedImage | Boot/wedged.asm | assemble | - | -
# Reading a disk that has directories on it. The machine can walk a path at this point but
# cannot make a directory, so the disk is built by the host tool and read here - which is
# the two implementations checking each other rather than either checking itself.