feat(boot): the loader tells the kernel its boot disk; system=v3 is refused on a stick
uefi.h: the UEFI device path and Block I/O protocols, a typed LocateDevicePath, and BootDisk
{gpt, is_stick, disk_guid[16]} appended to BootInfo after args (boot_info_offsets.h unchanged).
The loader, before ExitBootServices, cuts its image's device path at the partition's HardDrive
node, locates the whole disk's Block I/O (whole path consumed, not a logical partition, 512-byte
blocks), reads it as 1 KiB blocks through a loader-side blkio adapter, and runs the kernel's own
gpt_read: is it a StarshipOS stick (identity and Artemis partitions), and its DiskGUID
(gpt_disk_guid, new). No HardDrive node (an ISO/CD boot), no GPT, or any failure: not a stick.
Monolithic builds only (the non-monolithic loader does not link gpt.c, and does not build today:
kernel/src/vm/vm_core.c -- reported, not fixed).
The kernel prints 'Boot disk: a StarshipOS stick' or '... not a StarshipOS stick', and on a stick
system=v3 gives 'System: v3 is not on this stick -- StarForth v4' and boots v4.
Tests: stick_v3 (new), stick_boot and zuse x3 failed on the new lines before, pass after; v3_keys
still boots v3 off a stick. Acceptance: amd64, aarch64, riscv64 to [zuse@Hera] ok>, POST 538/538,
dict_hash 0xfec8c47cfc6f437f; v4 suite and test-32 0 failures.
Plan: docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a321c537f7
commit
1b45f5f85f
@@ -55,6 +55,9 @@
|
||||
#include "starkernel/boot_info_offsets.h"
|
||||
#include "starkernel/fdt.h"
|
||||
#include "starkernel/fdt_uart.h"
|
||||
#ifdef MONOLITHIC_BUILD
|
||||
#include "starkernel/gpt.h"
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
/* Verify BootInfo field offsets match boot_info_offsets.h (BOOT_INFO_OFFSETS) */
|
||||
@@ -508,6 +511,100 @@ static int load_cfg_from_esp(EFI_HANDLE ImageHandle, EFI_BOOT_SERVICES *BS,
|
||||
return read_size > 0;
|
||||
}
|
||||
|
||||
#ifdef MONOLITHIC_BUILD
|
||||
/* The boot disk (docs/v4.0.0/plans/2026-10-27-stick-4-one-disk.md, Task 3).
|
||||
* The firmware's Block I/O for the whole disk the loader was read from,
|
||||
* seen as a 1 KiB-block device (block n = LBAs 2n and 2n+1), so the kernel's
|
||||
* own gpt.c reads its GPT: the kernel is then told whether it booted from a
|
||||
* StarshipOS stick, and which one (the header's DiskGUID). Reads only, before
|
||||
* ExitBootServices. Monolithic builds only: the non-monolithic loader does
|
||||
* not link gpt.c (and does not build, 2026-10-28: kernel/src/vm/vm_core.c). */
|
||||
static EFI_BLOCK_IO_PROTOCOL *g_boot_bio;
|
||||
static uint8_t g_boot_bounce[BLKIO_FORTH_BLOCK_SIZE] __attribute__((aligned(4096)));
|
||||
|
||||
static int bootdisk_open(blkio_dev_t *dev, const blkio_params_t *p) { (void)dev; (void)p; return BLKIO_OK; }
|
||||
static int bootdisk_close(blkio_dev_t *dev) { (void)dev; return BLKIO_OK; }
|
||||
static int bootdisk_read(blkio_dev_t *dev, uint32_t fblock, void *dst)
|
||||
{
|
||||
uint8_t *d = (uint8_t *)dst;
|
||||
unsigned i;
|
||||
(void)dev;
|
||||
if (g_boot_bio->ReadBlocks(g_boot_bio, g_boot_bio->Media->MediaId, (UINT64)fblock * 2u,
|
||||
BLKIO_FORTH_BLOCK_SIZE, g_boot_bounce) != EFI_SUCCESS)
|
||||
return BLKIO_EIO;
|
||||
for (i = 0; i < BLKIO_FORTH_BLOCK_SIZE; i++) d[i] = g_boot_bounce[i];
|
||||
return BLKIO_OK;
|
||||
}
|
||||
static int bootdisk_write(blkio_dev_t *dev, uint32_t fblock, const void *src) { (void)dev; (void)fblock; (void)src; return BLKIO_ENOSUP; }
|
||||
static int bootdisk_flush(blkio_dev_t *dev) { (void)dev; return BLKIO_OK; }
|
||||
static int bootdisk_info(blkio_dev_t *dev, blkio_info_t *out)
|
||||
{
|
||||
out->forth_block_size = BLKIO_FORTH_BLOCK_SIZE;
|
||||
out->total_blocks = dev->total_blocks;
|
||||
out->phys_sector_size = 512u;
|
||||
out->phys_size_bytes = (uint64_t)dev->total_blocks * BLKIO_FORTH_BLOCK_SIZE;
|
||||
out->read_only = 1u;
|
||||
return BLKIO_OK;
|
||||
}
|
||||
static const blkio_vtable_t g_bootdisk_vt = {
|
||||
bootdisk_open, bootdisk_close, bootdisk_read, bootdisk_write, bootdisk_flush, bootdisk_info
|
||||
};
|
||||
|
||||
static void probe_boot_disk(EFI_HANDLE ImageHandle, EFI_BOOT_SERVICES *BS, BootDisk *out)
|
||||
{
|
||||
static uint8_t path[512]; /* the boot device's path, up to its HardDrive node */
|
||||
EFI_LOADED_IMAGE_PROTOCOL *li = NULL;
|
||||
EFI_DEVICE_PATH_PROTOCOL *dp = NULL, *rest;
|
||||
EFI_HANDLE disk = NULL;
|
||||
blkio_dev_t dev;
|
||||
blkio_params_t prm;
|
||||
gpt_part_t parts[16];
|
||||
unsigned n = 0, used = 0, len, i;
|
||||
const uint8_t *node;
|
||||
UINT64 blocks;
|
||||
|
||||
for (i = 0; i < sizeof *out; i++) ((uint8_t *)out)[i] = 0;
|
||||
if (BS->HandleProtocol(ImageHandle, (EFI_GUID *)&EFI_LOADED_IMAGE_PROTOCOL_GUID, (void **)&li) != EFI_SUCCESS || !li)
|
||||
return;
|
||||
if (BS->HandleProtocol(li->DeviceHandle, (EFI_GUID *)&EFI_DEVICE_PATH_PROTOCOL_GUID, (void **)&dp) != EFI_SUCCESS || !dp)
|
||||
return;
|
||||
/* copy the path up to (not including) its first Media/HardDrive node --
|
||||
* the partition -- and end it there: what is left names the whole disk.
|
||||
* No HardDrive node (a CD/ISO boot): not a disk with a GPT to read. */
|
||||
for (node = (const uint8_t *)dp; ; node += len) {
|
||||
len = (unsigned)node[2] | (unsigned)node[3] << 8;
|
||||
if (node[0] == EFI_DEVICE_PATH_TYPE_END || len < 4u) return;
|
||||
if (node[0] == EFI_DEVICE_PATH_TYPE_MEDIA && node[1] == EFI_DEVICE_PATH_SUBTYPE_HARDDRIVE) break;
|
||||
if (used + len + 4u > sizeof path) return;
|
||||
for (i = 0; i < len; i++) path[used + i] = node[i];
|
||||
used += len;
|
||||
}
|
||||
path[used] = EFI_DEVICE_PATH_TYPE_END; path[used + 1] = EFI_DEVICE_PATH_SUBTYPE_END_ENTIRE;
|
||||
path[used + 2] = 4; path[used + 3] = 0;
|
||||
|
||||
rest = (EFI_DEVICE_PATH_PROTOCOL *)path;
|
||||
if (BS->LocateDevicePath((EFI_GUID *)&EFI_BLOCK_IO_PROTOCOL_GUID, &rest, &disk) != EFI_SUCCESS || !disk)
|
||||
return;
|
||||
if (rest->Type != EFI_DEVICE_PATH_TYPE_END) return; /* a handle for less than the whole path: not the disk */
|
||||
if (BS->HandleProtocol(disk, (EFI_GUID *)&EFI_BLOCK_IO_PROTOCOL_GUID, (void **)&g_boot_bio) != EFI_SUCCESS ||
|
||||
!g_boot_bio || !g_boot_bio->Media)
|
||||
return;
|
||||
if (g_boot_bio->Media->LogicalPartition || !g_boot_bio->Media->MediaPresent ||
|
||||
g_boot_bio->Media->BlockSize != 512u || g_boot_bio->Media->IoAlign > 4096u)
|
||||
return;
|
||||
blocks = (g_boot_bio->Media->LastBlock + 1u) / 2u;
|
||||
prm.forth_block_size = BLKIO_FORTH_BLOCK_SIZE;
|
||||
prm.total_blocks = blocks > 0xFFFFFFFFu ? 0xFFFFFFFFu : (uint32_t)blocks;
|
||||
prm.opaque = NULL;
|
||||
if (blkio_open(&dev, &g_bootdisk_vt, &prm) != BLKIO_OK) return;
|
||||
if (gpt_read(&dev, parts, 16u, &n) != GPT_OK) return;
|
||||
out->gpt = 1;
|
||||
gpt_disk_guid(out->disk_guid);
|
||||
out->is_stick = gpt_find(parts, n, gpt_type_starship_identity) >= 0 &&
|
||||
gpt_find(parts, n, gpt_type_starship_artemis) >= 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MONOLITHIC_BUILD
|
||||
/* Kernel entry point signature */
|
||||
typedef void (*KernelEntry)(BootInfo *boot_info);
|
||||
@@ -866,6 +963,11 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable
|
||||
}
|
||||
debug_checkpoint(SystemTable, 5, L"Kernel stack allocation decided");
|
||||
|
||||
#ifdef MONOLITHIC_BUILD
|
||||
/* The boot disk, while the firmware's Block I/O is still there */
|
||||
probe_boot_disk(ImageHandle, BS, &g_boot_info.boot_disk);
|
||||
#endif
|
||||
|
||||
/* Fill BootInfo fields that do NOT require EBS first */
|
||||
g_boot_info.runtime_services = SystemTable->RuntimeServices;
|
||||
g_boot_info.acpi_table = NULL;
|
||||
|
||||
@@ -50,6 +50,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 */
|
||||
|
||||
int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count)
|
||||
{
|
||||
@@ -123,9 +124,15 @@ int gpt_read(blkio_dev_t *disk, gpt_part_t *parts, unsigned max, unsigned *count
|
||||
n++;
|
||||
}
|
||||
*count = n;
|
||||
memcpy(g_gpt_disk_guid, h + 56, 16);
|
||||
return GPT_OK;
|
||||
}
|
||||
|
||||
void gpt_disk_guid(uint8_t guid[16])
|
||||
{
|
||||
memcpy(guid, g_gpt_disk_guid, 16);
|
||||
}
|
||||
|
||||
int gpt_find(const gpt_part_t *parts, unsigned count, const uint8_t type[16])
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -622,10 +622,19 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* arguments (starforth.cfg on the ESP, cmdline.txt on the Pi 5) picks,
|
||||
* else the build's default (SK_V4_DEFAULT: on -- v4 -- for every build,
|
||||
* QEMU and board images alike, since 2026-10-14: v3 is being retired). */
|
||||
/* The disk the loader was booted from (uefi_loader.c's probe): a
|
||||
* StarshipOS stick carries v4 only (docs/v4.0.0/STICK.md 1, "v4 only"),
|
||||
* so system=v3 is refused on one (plan 2026-10-27-stick-4-one-disk.md,
|
||||
* Task 3). An ISO, CD or ESP-image boot is not a stick. */
|
||||
console_println(boot_info->boot_disk.is_stick ? "Boot disk: a StarshipOS stick"
|
||||
: "Boot disk: not a StarshipOS stick");
|
||||
#ifdef STARFORTH_V4
|
||||
if (boot_info->args.system == KARGS_SYSTEM_V4 ||
|
||||
{
|
||||
const int v3_refused = boot_info->boot_disk.is_stick && boot_info->args.system == KARGS_SYSTEM_V3;
|
||||
if (boot_info->args.system == KARGS_SYSTEM_V4 || v3_refused ||
|
||||
(boot_info->args.system == KARGS_SYSTEM_DEFAULT && SK_V4_DEFAULT)) {
|
||||
console_println(boot_info->args.system == KARGS_SYSTEM_V4
|
||||
console_println(v3_refused ? "System: v3 is not on this stick -- StarForth v4"
|
||||
: boot_info->args.system == KARGS_SYSTEM_V4
|
||||
? "System: StarForth v4 (system=v4)"
|
||||
: "System: StarForth v4 (this build's default)");
|
||||
/* StarForth v4 at a single prompt: one host node of the F18-derived
|
||||
@@ -634,6 +643,7 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
sk_v4_boot_info = boot_info;
|
||||
sk_v4_run(sk_v4_block_chain);
|
||||
}
|
||||
}
|
||||
console_println(boot_info->args.system == KARGS_SYSTEM_V3
|
||||
? "System: StarForth v3 (system=v3)"
|
||||
: "System: StarForth v3 (this build's default; system=v4 for v4)");
|
||||
|
||||
Reference in New Issue
Block a user