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;
|
||||
|
||||
Reference in New Issue
Block a user