wip(kernel): Artemis grows to fill the stick at its first boot -- metadata only, capped at 256 GiB (#92, Task 2) [skip ci]
Not yet accepted (plan 2026-10-29-stick-5, Task 2, step 3). - gpt.c: the writer, gpt_grow_last() -- the backup entry array and header to the disk's end, the last partition to the last usable sector (whole MiB, capped), both headers' CRCs, the backup before the primary, the protective MBR's size; gpt_alternate_lba(). - sk_v4_grow.c: the volume grown to its partition -- its fence (the Artemis signature, Zuse's genesis marker) moved to the new top, the header last; the partition grown no further than the BAM tracks (the block subsystem places the fence by the device's size, so a volume must fill it). - sk_v4_identity.c: a stick of 8 GB or more whose GPT ends short of the disk is grown before its partitions are opened; "Artemis: grown to fill the stick" / "under 8 GB -- not grown" / "past 256 GiB ... left unused". - block_subsystem: blk_volume_compute_totals() (compute_totals_from_B, public) and blk_subsys_set_format_bam_for(); v3's behaviour unchanged. - mkartemis --bam-for, mkdiskimage.sh --bam-for, kernel/Makefile STICK_GROW_MIN_BYTES / STICK_ARTEMIS_CAP_GIB: the stick's and data stick's Artemis BAM sized for 256 GiB (6144 devblocks). STICK.md 5a: 256 GiB (R1). After: stick_grow PASS (16 GiB: 12129370 user blocks, 8 s POST to prompt; second boot not grown, recognised; sfdisk --verify: no errors), stick_small PASS, check_images.sh PASS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
+125
-2
@@ -7,8 +7,13 @@
|
||||
* a block device of a StarshipOS partition: its block 0 is the partition's
|
||||
* first 1 KiB, and nothing past its end can be reached through it. The
|
||||
* identity and Artemis formats inside a partition are exactly those of a raw
|
||||
* drive today. Reads only. 512-byte logical sectors only (the stick and its
|
||||
* data stick); docs/v4.0.0/plans/2026-10-26-stick-2-gpt-reader.md.
|
||||
* drive today. 512-byte logical sectors only (the stick and its data stick);
|
||||
* docs/v4.0.0/plans/2026-10-26-stick-2-gpt-reader.md.
|
||||
*
|
||||
* The writer (plan 2026-10-29-stick-5, Task 2; STICK.md 5a): the stick's last
|
||||
* partition grown to the end of a disk larger than the image written to it --
|
||||
* the backup header and entry array moved to the disk's end, both headers
|
||||
* rewritten with their CRCs, the backup before the primary.
|
||||
*/
|
||||
#include "starkernel/gpt.h"
|
||||
#include "console.h"
|
||||
@@ -51,6 +56,7 @@ static uint64_t le64(const uint8_t *p) { return (uint64_t)le32(p) | (uint64_t)le
|
||||
static uint8_t g_gpt_hdr_block[BLKIO_FORTH_BLOCK_SIZE];
|
||||
static uint8_t g_gpt_entries[GPT_ENTRIES_MAX];
|
||||
static uint8_t g_gpt_disk_guid[16]; /* the DiskGUID of the last gpt_read that gave GPT_OK */
|
||||
static uint64_t g_gpt_alternate_lba; /* and its backup header's LBA */
|
||||
|
||||
int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count)
|
||||
{
|
||||
@@ -125,6 +131,7 @@ int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count
|
||||
}
|
||||
*count = n;
|
||||
memcpy(g_gpt_disk_guid, h + 56, 16);
|
||||
g_gpt_alternate_lba = le64(h + 32);
|
||||
return GPT_OK;
|
||||
}
|
||||
|
||||
@@ -140,6 +147,122 @@ int gpt_find(const gpt_part_t *parts, unsigned count, const uint8_t type[16])
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- the writer: growing the last partition to the disk's end ---------- */
|
||||
|
||||
static void put_le32(uint8_t *p, uint32_t v) { p[0] = (uint8_t)v; p[1] = (uint8_t)(v >> 8); p[2] = (uint8_t)(v >> 16); p[3] = (uint8_t)(v >> 24); }
|
||||
static void put_le64(uint8_t *p, uint64_t v) { put_le32(p, (uint32_t)v); put_le32(p + 4, (uint32_t)(v >> 32)); }
|
||||
|
||||
static uint8_t g_gpt_rmw[BLKIO_FORTH_BLOCK_SIZE];
|
||||
|
||||
/* Write `n` 512-byte sectors from `src` at sector `lba`: each through a
|
||||
* read-modify-write of the 1 KiB block that holds it, so a sector at an odd
|
||||
* LBA (the backup header, the backup entry array) is written alone. */
|
||||
static int put_sectors(blkio_dev_t *disk, uint64_t lba, const uint8_t *src, uint32_t n)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
uint64_t s = lba + i;
|
||||
uint32_t blk = (uint32_t)(s / 2u);
|
||||
if (blkio_read(disk, blk, g_gpt_rmw) != BLKIO_OK) return -1;
|
||||
memcpy(g_gpt_rmw + (s % 2u) * GPT_SECTOR, src + (size_t)i * GPT_SECTOR, GPT_SECTOR);
|
||||
if (blkio_write(disk, blk, g_gpt_rmw) != BLKIO_OK) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t gpt_alternate_lba(void)
|
||||
{
|
||||
return g_gpt_alternate_lba;
|
||||
}
|
||||
|
||||
int gpt_grow_last(blkio_dev_t *disk, const uint8_t type[16], uint64_t max_part_sectors, uint64_t *new_last_lba)
|
||||
{
|
||||
static gpt_part_t parts[16];
|
||||
static uint8_t hdr[GPT_SECTOR], bak[GPT_SECTOR];
|
||||
const uint8_t *h = g_gpt_hdr_block + GPT_SECTOR;
|
||||
uint8_t *mbr = g_gpt_hdr_block, *e = (uint8_t *)0;
|
||||
uint64_t disk_sectors, alt, ent_lba, new_alt, new_ent, new_last_usable, first, last, want, top = 0;
|
||||
uint32_t nent, esize, ent_sectors, i;
|
||||
unsigned count;
|
||||
size_t ebytes;
|
||||
int rc;
|
||||
|
||||
rc = gpt_read(disk, parts, 16u, &count);
|
||||
if (rc != GPT_OK) return rc == GPT_NONE ? GPT_BAD : rc;
|
||||
nent = le32(h + 80);
|
||||
esize = le32(h + 84);
|
||||
ebytes = (size_t)nent * esize;
|
||||
ent_sectors = (uint32_t)((ebytes + GPT_SECTOR - 1u) / GPT_SECTOR);
|
||||
ent_lba = le64(h + 72);
|
||||
alt = le64(h + 32);
|
||||
disk_sectors = (uint64_t)disk->total_blocks * (BLKIO_FORTH_BLOCK_SIZE / GPT_SECTOR);
|
||||
|
||||
/* the partition of `type`, which must be the last on the disk */
|
||||
for (i = 0; i < nent; i++) {
|
||||
uint8_t *x = g_gpt_entries + (size_t)i * esize;
|
||||
static const uint8_t zero[16];
|
||||
if (memcmp(x, zero, 16) == 0) continue;
|
||||
if (le64(x + 40) > top) top = le64(x + 40);
|
||||
if (!e && memcmp(x, type, 16) == 0) e = x;
|
||||
}
|
||||
if (!e) return GPT_BAD;
|
||||
first = le64(e + 32);
|
||||
last = le64(e + 40);
|
||||
*new_last_lba = last;
|
||||
if (alt == disk_sectors - 1u) return GPT_OK; /* already ends at the disk's end */
|
||||
if (alt > disk_sectors - 1u || last != top) return GPT_BAD;
|
||||
|
||||
/* the backup entry array and header at the disk's end; the partition to
|
||||
* the last usable sector before them, on whole MiB, at most max sectors */
|
||||
new_alt = disk_sectors - 1u;
|
||||
new_ent = new_alt - ent_sectors;
|
||||
new_last_usable = new_ent - 1u;
|
||||
if (new_last_usable < last) return GPT_BAD;
|
||||
want = new_last_usable - first + 1u;
|
||||
if (want > max_part_sectors) want = max_part_sectors;
|
||||
want -= want % 2048u;
|
||||
if (first + want - 1u > last) {
|
||||
last = first + want - 1u;
|
||||
put_le64(e + 40, last);
|
||||
}
|
||||
|
||||
/* the primary header, then the backup: each with its own LBAs and CRC */
|
||||
memcpy(hdr, h, GPT_SECTOR);
|
||||
put_le64(hdr + 32, new_alt);
|
||||
put_le64(hdr + 48, new_last_usable);
|
||||
put_le32(hdr + 88, gpt_crc32(g_gpt_entries, ebytes));
|
||||
memcpy(bak, hdr, GPT_SECTOR);
|
||||
put_le64(bak + 24, new_alt);
|
||||
put_le64(bak + 32, 1u);
|
||||
put_le64(bak + 72, new_ent);
|
||||
put_le32(hdr + 16, 0u);
|
||||
put_le32(hdr + 16, gpt_crc32(hdr, le32(hdr + 12)));
|
||||
put_le32(bak + 16, 0u);
|
||||
put_le32(bak + 16, gpt_crc32(bak, le32(bak + 12)));
|
||||
|
||||
/* the backup before the primary: a write torn between them leaves the old
|
||||
* primary, which still checks out, and the next boot grows again */
|
||||
if (put_sectors(disk, new_ent, g_gpt_entries, ent_sectors) != 0 ||
|
||||
put_sectors(disk, new_alt, bak, 1u) != 0 || disk->vt->flush(disk) != BLKIO_OK)
|
||||
return GPT_EIO;
|
||||
if (put_sectors(disk, ent_lba, g_gpt_entries, ent_sectors) != 0 ||
|
||||
put_sectors(disk, 1u, hdr, 1u) != 0 || disk->vt->flush(disk) != BLKIO_OK)
|
||||
return GPT_EIO;
|
||||
|
||||
/* the protective MBR's partition covers the disk (as many sectors as fit) */
|
||||
for (i = 0; i < 4u; i++) {
|
||||
uint8_t *p = mbr + 446u + 16u * i;
|
||||
if (p[4] == 0xEEu) {
|
||||
put_le32(p + 12, disk_sectors - 1u > 0xFFFFFFFFu ? 0xFFFFFFFFu : (uint32_t)(disk_sectors - 1u));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (put_sectors(disk, 0u, mbr, 1u) != 0 || disk->vt->flush(disk) != BLKIO_OK) return GPT_EIO;
|
||||
|
||||
*new_last_lba = last;
|
||||
return GPT_OK;
|
||||
}
|
||||
|
||||
/* ---- a partition as a blkio device ------------------------------------- */
|
||||
|
||||
static int part_open(blkio_dev_t *dev, const blkio_params_t *p)
|
||||
|
||||
Reference in New Issue
Block a user