fix: MINT-ZUSE says the stick was erased when it was (#168)

failed() printed "MINT-ZUSE: failed -- nothing changed" on every failure
after YES, though by then gpt_write_one() had rewritten the stick's partition
table and the identity partition's first blocks had been zeroed.

gpt_write_one() now tells the two apart: GPT_EIO when its first write failed
(nothing written), GPT_PART when a later write or flush failed (the disk is
changed). MINT-ZUSE keeps "failed -- nothing changed" for GPT_EIO only, and
says "failed -- the stick was erased; Zuse not minted" for every failure
after the table is written. The marker is still written last.

Tested first, seen to fail: qemu_session.py mint_part_fail (writes fail only
at the identity partition's first sector, LBA 2048) -- "nothing changed",
logs/20261112-122132. After: mint_part_fail PASS; mint_fail (every write
fails) still "nothing changed", PASS; replace (the success path) PASS. Their
logs here. FABRIC-3 XLVIII.20.

Captain Bob, 2026-11-12: "start #168".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
Claude
2026-11-12 12:41:36 +00:00
parent 7e30b4525e
commit 54311be18a
21 changed files with 102 additions and 19 deletions
+6 -2
View File
@@ -24,7 +24,8 @@ typedef struct {
#define GPT_OK 0 /* a valid GPT */
#define GPT_NONE 1 /* not a GPT disk -- no protective MBR -- (or one whose sectors are not 512 bytes): read it raw */
#define GPT_BAD 2 /* a protective MBR, but its header or entry array does not check out: not used */
#define GPT_EIO 3 /* its first block could not be read: not used */
#define GPT_EIO 3 /* its first block could not be read: not used; gpt_write_one: nothing was written */
#define GPT_PART 4 /* gpt_write_one only: a write failed after others were made -- the disk is changed (#168) */
/* Read `disk`'s protective MBR, primary GPT header and partition-entry array,
* checking both CRC-32s, the revision, the sizes and the geometry. On GPT_OK,
@@ -59,7 +60,10 @@ int gpt_grow_last(blkio_dev_t *disk, const uint8_t type[16], uint64_t max_part_s
* entries, the backup header and entries at the disk's end, the protective
* MBR written last (the old one zeroed first, so a write torn anywhere leaves
* no table). Nothing inside the partition is written. GPT_OK; GPT_BAD for a
* disk whose sectors are not 512 bytes or that is too small; GPT_EIO. */
* disk whose sectors are not 512 bytes or that is too small (nothing written);
* GPT_EIO when its first write failed (nothing written, the disk as it was);
* GPT_PART when a later write or a flush failed (the disk is changed: its old
* table is gone). The caller says which (#168). */
int gpt_write_one(blkio_dev_t *disk, const uint8_t type[16], uint64_t part_sectors, uint8_t disk_guid[16]);
/* The index of the first partition of `type`, or -1. */
+4 -2
View File
@@ -352,14 +352,16 @@ int gpt_write_one(blkio_dev_t *disk, const uint8_t type[16], uint64_t part_secto
* partition not yet written -- a used stick's old table included */
{
static const uint8_t zero[GPT_SECTOR];
if (put_sectors(disk, 0u, zero, 1u) != 0 || disk->vt->flush(disk) != BLKIO_OK) return GPT_EIO;
if (put_sectors(disk, 0u, zero, 1u) != 0) return GPT_EIO; /* nothing written yet */
if (disk->vt->flush(disk) != BLKIO_OK) return GPT_PART; /* the MBR may be gone */
}
/* from here the disk is changed: any failure says so (#168) */
if (put_sectors(disk, alt - GPT_ENT_SECTORS, g_gpt_new_entries, GPT_ENT_SECTORS) != 0 ||
put_sectors(disk, alt, bak, 1u) != 0 ||
put_sectors(disk, 2u, g_gpt_new_entries, GPT_ENT_SECTORS) != 0 ||
put_sectors(disk, 1u, hdr, 1u) != 0 || disk->vt->flush(disk) != BLKIO_OK ||
put_sectors(disk, 0u, mbr, 1u) != 0 || disk->vt->flush(disk) != BLKIO_OK)
return GPT_EIO;
return GPT_PART;
return GPT_OK;
}
+20 -9
View File
@@ -11,7 +11,9 @@
* fresh Zuse minted into it, read back -- and only then the real key written
* into the genesis marker on the system stick's Artemis. Any failure before
* the marker leaves the marker as it was: the old Zuse stick, if there is
* one, still works.
* one, still works. A failure says what happened to the stick (#168): "nothing
* changed" only while nothing has been written to it; once its partition table
* is written, "the stick was erased".
*/
#include "starkernel/v4/sk_v4_mint.h"
#include "starkernel/v4/sk_v4_identity.h"
@@ -65,13 +67,20 @@ static int read_answer(char *buf, int max)
}
}
static int failed(void)
static int failed(void) /* nothing has been written to the stick */
{
console_println("MINT-ZUSE: failed -- nothing changed");
sk_v4_identity_release_offered();
return -1;
}
static int erased(void) /* its old partition table is gone (#168) */
{
console_println("MINT-ZUSE: failed -- the stick was erased; Zuse not minted");
sk_v4_identity_release_offered();
return -1;
}
int sk_v4_mint_zuse(void)
{
static blkio_dev_t part;
@@ -115,27 +124,29 @@ int sk_v4_mint_zuse(void)
sk_v4_identity_release_offered();
return -1;
}
if (rc != GPT_OK || gpt_read(raw, parts, 4u, &n) != GPT_OK) return failed();
if (rc == GPT_EIO) return failed(); /* its first write failed: nothing written */
if (rc != GPT_OK) return erased();
if (gpt_read(raw, parts, 4u, &n) != GPT_OK) return erased();
pi = gpt_find(parts, n, gpt_type_starship_identity);
if (pi < 0 || gpt_part_open(&part, &part_state, raw, &parts[pi]) != BLKIO_OK) return failed();
if (pi < 0 || gpt_part_open(&part, &part_state, raw, &parts[pi]) != BLKIO_OK) return erased();
/* nothing of the stick's old bytes may read as an identity */
for (i = 0; i < MINT_ZERO_FBLOCKS; i++)
if (blkio_write(&part, i, zero) != BLKIO_OK) return failed();
if (blkio_write(&part, i, zero) != BLKIO_OK) return erased();
/* Zuse, minted, then read back from the stick */
if (capsule_zuse_boot_genesis_mint(&part, seed, pub) != 0) return failed();
if (capsule_zuse_boot_genesis_mint(&part, seed, pub) != 0) return erased();
sig_rc = homeblocks_sig_check(&part, HOMEBLOCKS_SIG_START_FBLOCK, &sig);
if (capsule_zuse_boot_check_key(&part, sig_rc, &sig, pub, rseed, rpub) != ZUSE_DRIVE_HERS ||
memcmp(rseed, seed, 32) != 0)
return failed();
return erased();
/* only now the marker: the proxy kept, the real Zuse named */
m = *sk_v4_identity_marker();
if (!m.present) return failed();
if (!m.present) return erased();
memcpy(m.real, pub, 32);
m.has_real = 1;
if (sk_v4_marker_write(&m) != 0) return failed();
if (sk_v4_marker_write(&m) != 0) return erased();
sk_v4_identity_set_marker(&m);
memset(seed, 0, sizeof seed);
memset(rseed, 0, sizeof rseed);