Phase D: RUNCAP -- runtime capsule construction from thumbdrive content
capsule_runcap_birth() (new capsule_runcap.h/.c): builds a heap-only, single-entry CapsuleDirHeader + CapsuleDesc + CapsuleNameEntry + arena from a home-blocks drive's identity_src region (skipping the first devblock, reserved for MINT's user_identity_seed_t record) and hands it to the existing, unmodified capsule_birth_baby() -- no new birth mechanism, matching FABRIC-3.md §F.6's own trace. Found and closed a real gap in that trace along the way: capsule_birth_baby()'s signature check calls capsule_get_signatures(), which unconditionally returns the compile-time-baked global array -- meaningless for a heap-built directory, where index 0 would compare RUNCAP's own content against whatever real capsule happens to occupy that slot in the baked array (guaranteed-wrong, not a security check). Added an explicit skip_pki_sig flag (0 for all 4 existing call sites, 1 for RUNCAP): that content's trust comes from CERTVERIFY, a separate root, not the capsule-PKI chain. Also found live: capsule_birth_baby() never sets the registry entry's own .name (every existing caller does this itself afterward via capsule_vm_registry_set_name() -- RUNCAP now does too), and capsule_exec_payload() requires a "Block NNNN" header per chunk of content or it's silently skipped, never executed -- not a bug, but necessary context for whoever authors MINT's default personality content next. Added a small accessor pair (repl.h/.c) exposing the currently attached home-blocks device/sig -- the same gap F.9's own BINDSTEP scoping had already flagged, needed by both. Verified end-to-end live in QEMU: synthetic identity-source content written directly to a thumbdrive image's raw devblocks (no capsule build, no mkcapsule) was read, compiled, and executed by a genuinely new VM via a diagnostic RUNCAP-TEST word -- confirmed via VM-EXEC invoking a word defined only in that source. Clean 3-architecture regression boot (no RUNCAP drive attached) confirms no side effects. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZGkimpfyh63EZyRkNbkPD
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
75311967a7
commit
e1e839258d
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-28T17:01:08Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-28T18:28:25Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
@@ -127,6 +127,23 @@ CapsuleRunResult capsule_birth_mama(
|
||||
* @param descs Capsule descriptor array
|
||||
* @param names Capsule name entry array (parallel to descs)
|
||||
* @param arena Capsule payload arena
|
||||
* @param skip_pki_sig 0 for every build-time capsule (the normal case --
|
||||
* checked against the compile-time-baked signature
|
||||
* array via capsule_get_signatures()). Non-zero only
|
||||
* for RUNCAP (FABRIC-3.md §F.6/F.18): a heap-built,
|
||||
* single-entry directory sourced from a user's own
|
||||
* thumbdrive has no entry in that array at all --
|
||||
* index 0 would silently compare against whatever
|
||||
* real capsule happens to occupy slot 0, which is
|
||||
* not a security check, just a guaranteed-wrong one.
|
||||
* Trust for that content comes from CERTVERIFY (a
|
||||
* separate root, the user's own Zuse-signed cert)
|
||||
* already having run before RUNCAP is ever called,
|
||||
* not from this flag -- this only skips a check that
|
||||
* was never meaningful for that content in the first
|
||||
* place. Deliberately a plain flag, not a new entry
|
||||
* point, so the policy is one call-site decision,
|
||||
* trivially reversible.
|
||||
* @param out_vm_id Output: assigned VM ID
|
||||
* @param out_vm_ctx Output: new VM context
|
||||
* @return CAPSULE_RUN_OK on success, error code otherwise
|
||||
@@ -137,6 +154,7 @@ CapsuleRunResult capsule_birth_baby(
|
||||
const CapsuleDesc *descs,
|
||||
const CapsuleNameEntry *names,
|
||||
const uint8_t *arena,
|
||||
int skip_pki_sig,
|
||||
VMUuid *out_vm_id,
|
||||
void **out_vm_ctx
|
||||
);
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
StarForth — Steady-State Virtual Machine Runtime
|
||||
|
||||
Copyright (c) 2023–2025 Robert A. James
|
||||
All rights reserved.
|
||||
|
||||
Licensed under the StarForth License, Version 1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* capsule_runcap.h - RUNCAP: runtime capsule construction from thumbdrive
|
||||
* content (FABRIC-3.md §F.6/§F.18).
|
||||
*
|
||||
* A user's identity source (raw FORTH init/personality text, minted by
|
||||
* MINT into a home-blocks drive's identity_src region) never exists at
|
||||
* build time, so it can never appear in the compile-time-baked capsule
|
||||
* directory. This builds a heap-only, single-entry CapsuleDirHeader +
|
||||
* CapsuleDesc + CapsuleNameEntry + arena from that region and hands it to
|
||||
* the existing, unmodified capsule_birth_baby() -- no new birth mechanism,
|
||||
* per §F.6's own trace ("capsule_birth_baby() is already generic").
|
||||
*
|
||||
* Does not verify the caller has already run CERTVERIFY -- that's the
|
||||
* caller's responsibility (WIREBIND, not yet built). This function's own
|
||||
* job is narrow: read the region, construct the directory, birth it.
|
||||
*/
|
||||
|
||||
#ifndef STARKERNEL_CAPSULE_RUNCAP_H
|
||||
#define STARKERNEL_CAPSULE_RUNCAP_H
|
||||
|
||||
#ifdef __STARKERNEL__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "starkernel/capsule_run.h" /* CapsuleRunResult */
|
||||
#include "starkernel/vm_uuid.h" /* VMUuid */
|
||||
#include "starkernel/homeblocks_sig.h" /* homeblocks_sig_t */
|
||||
|
||||
struct blkio_dev;
|
||||
|
||||
/**
|
||||
* capsule_runcap_birth - Birth a VM from a home-blocks drive's own
|
||||
* identity_src region.
|
||||
*
|
||||
* Reads sig->identity_src_devblocks devblocks starting at
|
||||
* sig->identity_src_offset. The first devblock is the identity's own
|
||||
* user_identity_seed_t record (MINT, §F.8) and is skipped here -- RUNCAP
|
||||
* only cares about the FORTH source that follows it. Refuses cleanly
|
||||
* (CAPSULE_RUN_ERR_INVALID) if identity_src_offset is 0 (never minted) or
|
||||
* identity_src_devblocks < 2 (no source content beyond the seed record).
|
||||
*
|
||||
* The heap-allocated directory/descriptor/name/arena are never freed --
|
||||
* deliberate, matching kernel_main.c's own compile-time-directory-to-heap
|
||||
* copy at Mama's own birth (also never freed): a VM's IDENTITY exec reads
|
||||
* directly from this arena, and nothing in this codebase frees capsule
|
||||
* arenas after a successful birth today.
|
||||
*
|
||||
* @param dev Already-open block device for the attached drive.
|
||||
* @param sig Already-verified homeblocks_sig_t read from it.
|
||||
* @param vm_name Symbolic name for the new VM (becomes both the
|
||||
* capsule's own single directory entry name and the
|
||||
* VM registry name).
|
||||
* @param out_vm_id Output: assigned VM ID.
|
||||
* @param out_vm_ctx Output: new VM context (may be NULL if not needed).
|
||||
* @return CAPSULE_RUN_OK on success, error code otherwise.
|
||||
*/
|
||||
CapsuleRunResult capsule_runcap_birth(
|
||||
struct blkio_dev *dev,
|
||||
const homeblocks_sig_t *sig,
|
||||
const char *vm_name,
|
||||
VMUuid *out_vm_id,
|
||||
void **out_vm_ctx
|
||||
);
|
||||
|
||||
#endif /* __STARKERNEL__ */
|
||||
|
||||
#endif /* STARKERNEL_CAPSULE_RUNCAP_H */
|
||||
@@ -15,6 +15,9 @@
|
||||
#define STARKERNEL_REPL_H
|
||||
|
||||
#include "vm.h"
|
||||
#include "starkernel/homeblocks_sig.h"
|
||||
|
||||
struct blkio_dev;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -68,6 +71,16 @@ void sk_repl_set_active_vm(VM *vm);
|
||||
*/
|
||||
VM *sk_repl_get_active_vm(void);
|
||||
|
||||
/**
|
||||
* sk_repl_get_homeblocks_dev / sk_repl_get_homeblocks_sig - The currently
|
||||
* attached home-blocks USB drive, or NULL if none is attached / the
|
||||
* attached drive didn't check out as HOMEBLOCKS_SIG_OK (FABRIC-3.md
|
||||
* §F.6/§F.9/§F.18). Both return NULL together; never one without the
|
||||
* other.
|
||||
*/
|
||||
struct blkio_dev *sk_repl_get_homeblocks_dev(void);
|
||||
const homeblocks_sig_t *sk_repl_get_homeblocks_sig(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -488,6 +488,7 @@ CapsuleRunResult capsule_birth_baby(
|
||||
const CapsuleDesc *descs,
|
||||
const CapsuleNameEntry *names,
|
||||
const uint8_t *arena,
|
||||
int skip_pki_sig,
|
||||
VMUuid *out_vm_id,
|
||||
void **out_vm_ctx)
|
||||
{
|
||||
@@ -507,8 +508,14 @@ CapsuleRunResult capsule_birth_baby(
|
||||
|
||||
/* Milestone 6 (Phase 8): enforced only on INVALID -- see the fuller
|
||||
* comment in capsule_birth_mama() above for why MISSING/NO_ROOT_KEY
|
||||
* stay WARN-only. */
|
||||
{
|
||||
* stay WARN-only. Skipped entirely when skip_pki_sig is set (RUNCAP,
|
||||
* FABRIC-3.md §F.6/F.18): capsule_get_signatures() is the compile-
|
||||
* time-baked array, indexed against the build-time capsule_descriptors[]
|
||||
* -- meaningless for a heap-built directory sourced from a thumbdrive,
|
||||
* where idx 0 would just compare against whatever real capsule happens
|
||||
* to occupy that slot. That content's trust already comes from a
|
||||
* separate root (CERTVERIFY, run by the caller before this). */
|
||||
if (!skip_pki_sig) {
|
||||
int idx = (int)(cap - descs);
|
||||
CapsuleSigResult sr = capsule_verify_signature(
|
||||
descs, names, capsule_get_signatures(), arena, dir->desc_count, idx);
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
StarForth — Steady-State Virtual Machine Runtime
|
||||
|
||||
Copyright (c) 2023–2025 Robert A. James
|
||||
All rights reserved.
|
||||
|
||||
Licensed under the StarForth License, Version 1.0
|
||||
*/
|
||||
|
||||
#ifndef __STARKERNEL__
|
||||
#error "capsule_runcap.c is kernel-only"
|
||||
#endif
|
||||
|
||||
#include "starkernel/capsule_runcap.h"
|
||||
#include "starkernel/capsule.h"
|
||||
#include "starkernel/capsule_birth.h"
|
||||
#include "starkernel/xxhash64.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "blkio.h"
|
||||
#include <string.h>
|
||||
|
||||
CapsuleRunResult capsule_runcap_birth(
|
||||
struct blkio_dev *dev,
|
||||
const homeblocks_sig_t *sig,
|
||||
const char *vm_name,
|
||||
VMUuid *out_vm_id,
|
||||
void **out_vm_ctx)
|
||||
{
|
||||
if (!dev || !sig || !vm_name || !out_vm_id) return CAPSULE_RUN_ERR_INVALID;
|
||||
|
||||
/* 0 = never minted (homeblocks_sig.h's own field doc). */
|
||||
if (sig->identity_src_offset == 0) return CAPSULE_RUN_ERR_INVALID;
|
||||
|
||||
/* First devblock is the user_identity_seed_t record (MINT, §F.8);
|
||||
* everything after it is raw FORTH source. Need at least one devblock
|
||||
* of actual source beyond the seed. */
|
||||
if (sig->identity_src_devblocks < 2) return CAPSULE_RUN_ERR_INVALID;
|
||||
|
||||
uint32_t source_devblocks = sig->identity_src_devblocks - 1u;
|
||||
uint64_t source_len = (uint64_t)source_devblocks * 4096u;
|
||||
|
||||
uint8_t *arena = (uint8_t *)kmalloc((size_t)source_len);
|
||||
if (!arena) return CAPSULE_RUN_ERR_STILLBORN;
|
||||
|
||||
/* homeblocks_sig_t's own offset/devblocks fields are in 4KiB
|
||||
* devblocks; blkio_read() works in 1KiB forth-blocks (same *4
|
||||
* conversion homeblocks_sig_check() already uses for its own
|
||||
* sig_start_fblock). Skip the seed devblock (+1 devblock = +4
|
||||
* forth-blocks) before reading source content. */
|
||||
uint32_t base_fblock = (sig->identity_src_offset + 1u) * 4u;
|
||||
uint32_t source_fblocks = source_devblocks * 4u;
|
||||
uint32_t i;
|
||||
for (i = 0; i < source_fblocks; i++) {
|
||||
if (blkio_read((blkio_dev_t *)dev, base_fblock + i,
|
||||
arena + (size_t)i * BLKIO_FORTH_BLOCK_SIZE) != BLKIO_OK) {
|
||||
return CAPSULE_RUN_ERR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heap-built single-entry directory -- exact shape §F.6 traced
|
||||
* against capsule_birth_baby()'s own parameters, not a new mechanism.
|
||||
* Never freed: matches kernel_main.c's own compile-time-directory
|
||||
* heap copy at Mama's birth, which is also never freed -- the VM's
|
||||
* IDENTITY exec reads directly from this arena. */
|
||||
CapsuleNameEntry name_entry;
|
||||
memset(name_entry.name, 0, sizeof(name_entry.name));
|
||||
{
|
||||
size_t n = strlen(vm_name);
|
||||
if (n >= CAPSULE_NAME_MAX) n = CAPSULE_NAME_MAX - 1u;
|
||||
memcpy(name_entry.name, vm_name, n);
|
||||
}
|
||||
|
||||
CapsuleDesc desc;
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.magic = CAPSULE_MAGIC_PACK(CAPSULE_VERSION_0, CAPSULE_HASH_XXHASH64);
|
||||
desc.content_hash = xxhash64_capsule(arena, (size_t)source_len);
|
||||
desc.capsule_id = desc.content_hash; /* content-addressed invariant */
|
||||
desc.offset = 0;
|
||||
desc.length = source_len;
|
||||
desc.flags = CAPSULE_FLAG_ACTIVE | CAPSULE_FLAG_PRODUCTION;
|
||||
desc.owner_vm = 0;
|
||||
desc.birth_count = 0;
|
||||
desc.created_ns = 0; /* no monotonic-ns source exists anywhere in this
|
||||
* codebase yet, §F.8's own open item -- matches
|
||||
* CapsuleDesc.created_ns's existing hardcoded-0
|
||||
* precedent at mkcapsule generation time. */
|
||||
|
||||
CapsuleDirHeader dir;
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
dir.magic = CAPSULE_DIR_MAGIC;
|
||||
dir.arena_base = (uint64_t)(uintptr_t)arena;
|
||||
dir.arena_size = source_len;
|
||||
dir.desc_count = 1;
|
||||
dir.desc_capacity = 1;
|
||||
dir.name_count = 1;
|
||||
dir.dir_hash = 0; /* not verified anywhere in the birth path today */
|
||||
|
||||
CapsuleRunResult r = capsule_birth_baby(
|
||||
vm_name, &dir, &desc, &name_entry, arena,
|
||||
1 /* skip_pki_sig -- trust comes from CERTVERIFY, a separate root */,
|
||||
out_vm_id, out_vm_ctx);
|
||||
|
||||
/* capsule_birth_baby() itself never sets the registry entry's own
|
||||
* .name -- every existing caller (mama_word_birth, CONNECT-HERMES/
|
||||
* -ARTEMIS) does this as a separate step after a successful birth,
|
||||
* via capsule_vm_registry_set_name(). Found live: skipping this left
|
||||
* a freshly RUNCAP-born VM's registry name empty, which the idle-loop
|
||||
* pump (FABRIC-3.md Phase C) then read as a zero-length name and
|
||||
* refused ("VM name too long or empty") every tick. */
|
||||
if (r == CAPSULE_RUN_OK && out_vm_id) {
|
||||
capsule_vm_registry_set_name(*out_vm_id, vm_name);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "platform_alloc.h"
|
||||
#include "starkernel/capsule.h"
|
||||
#include "starkernel/capsule_birth.h"
|
||||
#include "starkernel/capsule_runcap.h"
|
||||
#include "starkernel/capsule_loader.h"
|
||||
#include "starkernel/capsule_run.h"
|
||||
#include "starkernel/capsule_loader.h"
|
||||
@@ -294,6 +295,7 @@ void mama_word_birth(VM *vm)
|
||||
capsule_get_descriptors(),
|
||||
capsule_get_names(),
|
||||
capsule_get_arena(),
|
||||
0, /* skip_pki_sig: normal build-time capsule */
|
||||
&new_vm_id,
|
||||
(void **)0
|
||||
);
|
||||
@@ -768,6 +770,51 @@ static void mama_word_vm_call(VM *vm)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RUNCAP-TEST ( caddr u -- ok? rc )
|
||||
* Diagnostic-only word (FABRIC-3.md §F.6/§F.18): calls
|
||||
* capsule_runcap_birth() against whatever drive sk_repl_get_homeblocks_
|
||||
* dev()/sig() currently report, naming the new VM from the given string.
|
||||
* Not the real RUNCAP call site -- that's WIREBIND (still unbuilt); this
|
||||
* exists to exercise capsule_runcap_birth() live before WIREBIND exists.
|
||||
* ok? is 1/0; rc is the raw CapsuleRunResult for diagnosis either way.
|
||||
*/
|
||||
static void mama_word_runcap_test(VM *vm)
|
||||
{
|
||||
char vm_name[VM_NAME_MAX];
|
||||
cell_t u, caddr;
|
||||
uint32_t i;
|
||||
|
||||
if (vm->dsp < 1) { vm->error = 1; return; }
|
||||
u = vm_pop(vm);
|
||||
caddr = vm_pop(vm);
|
||||
|
||||
if (u <= 0 || (uint32_t)u >= VM_NAME_MAX) {
|
||||
console_println("RUNCAP-TEST: name too long or empty");
|
||||
vm_push(vm, 0); vm_push(vm, (cell_t)CAPSULE_RUN_ERR_INVALID);
|
||||
return;
|
||||
}
|
||||
{
|
||||
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
|
||||
if (!p) { vm->error = 1; return; }
|
||||
for (i = 0; i < (uint32_t)u; i++) vm_name[i] = (char)p[i];
|
||||
}
|
||||
vm_name[u] = '\0';
|
||||
|
||||
struct blkio_dev *dev = sk_repl_get_homeblocks_dev();
|
||||
const homeblocks_sig_t *sig = sk_repl_get_homeblocks_sig();
|
||||
if (!dev || !sig) {
|
||||
console_println("RUNCAP-TEST: no home-blocks drive attached");
|
||||
vm_push(vm, 0); vm_push(vm, (cell_t)CAPSULE_RUN_ERR_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
VMUuid new_vm_id;
|
||||
CapsuleRunResult r = capsule_runcap_birth(dev, sig, vm_name, &new_vm_id, (void **)0);
|
||||
vm_push(vm, r == CAPSULE_RUN_OK ? 1 : 0);
|
||||
vm_push(vm, (cell_t)r);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CAPSULE-BIRTH ( capsule-id -- vm-id-hi vm-id-lo )
|
||||
* Birth a baby VM from a production (p) capsule.
|
||||
@@ -798,6 +845,7 @@ void mama_word_capsule_birth(VM *vm)
|
||||
capsule_get_descriptors(),
|
||||
capsule_get_names(),
|
||||
capsule_get_arena(),
|
||||
0, /* skip_pki_sig: normal build-time capsule */
|
||||
&new_vm_id,
|
||||
(void **)0 /* Don't need VM context back */
|
||||
);
|
||||
@@ -991,6 +1039,7 @@ static void mama_word_connect_artemis(VM *vm __attribute__((unused)))
|
||||
capsule_get_descriptors(),
|
||||
capsule_get_names(),
|
||||
capsule_get_arena(),
|
||||
0, /* skip_pki_sig: normal build-time capsule */
|
||||
&new_vm_id, (void **)0);
|
||||
console_set_vm_name(saved);
|
||||
|
||||
@@ -1062,6 +1111,7 @@ static void mama_word_connect_hermes(VM *vm __attribute__((unused)))
|
||||
capsule_get_descriptors(),
|
||||
capsule_get_names(),
|
||||
capsule_get_arena(),
|
||||
0, /* skip_pki_sig: normal build-time capsule */
|
||||
&new_vm_id, (void **)0);
|
||||
console_set_vm_name(saved);
|
||||
|
||||
@@ -1118,6 +1168,7 @@ void register_mama_forth_words(VM *vm)
|
||||
register_word(vm, "CAPSULE-LEN@", mama_word_capsule_len_fetch);
|
||||
register_word(vm, "CAPSULE-BIRTH", mama_word_capsule_birth);
|
||||
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
|
||||
register_word(vm, "RUNCAP-TEST", mama_word_runcap_test);
|
||||
register_word(vm, "MAMA-VM-ID", mama_word_mama_vm_id);
|
||||
register_word(vm, "VM-COUNT", mama_word_vm_count);
|
||||
register_word(vm, "VM-CONSERVED?", mama_word_vm_conserved);
|
||||
@@ -1147,6 +1198,7 @@ void register_mama_forth_words(VM *vm)
|
||||
register_word(vm, "CAPSULE-LEN@", mama_word_capsule_len_fetch);
|
||||
register_word(vm, "CAPSULE-BIRTH", mama_word_capsule_birth);
|
||||
register_word(vm, "CAPSULE-RUN", mama_word_capsule_run);
|
||||
register_word(vm, "RUNCAP-TEST", mama_word_runcap_test);
|
||||
register_word(vm, "MAMA-VM-ID", mama_word_mama_vm_id);
|
||||
register_word(vm, "VM-COUNT", mama_word_vm_count);
|
||||
register_word(vm, "VM-CONSERVED?", mama_word_vm_conserved);
|
||||
|
||||
@@ -67,6 +67,27 @@ static VM *g_repl_active_vm = (void *)0;
|
||||
void sk_repl_set_active_vm(VM *vm) { g_repl_active_vm = vm; }
|
||||
VM *sk_repl_get_active_vm(void) { return g_repl_active_vm; }
|
||||
|
||||
/*===========================================================================
|
||||
* Currently attached home-blocks device: mirrors g_repl_active_vm's own
|
||||
* shape (FABRIC-3.md §F.9's own precedent for this exact accessor). Set
|
||||
* once sk_repl_idle()'s own attach handling confirms HOMEBLOCKS_SIG_OK
|
||||
* below; cleared on detach. RUNCAP (§F.6/§F.18) and, later, BINDSTEP's
|
||||
* re-verify-live check (§F.9) both need this -- neither lives in this
|
||||
* file, and usb_blk_dev/xdev below are function-static, invisible outside
|
||||
* sk_repl_idle() without an accessor like this one.
|
||||
*===========================================================================*/
|
||||
|
||||
static blkio_dev_t *g_homeblocks_dev = (void *)0;
|
||||
static homeblocks_sig_t g_homeblocks_sig;
|
||||
static int g_homeblocks_sig_valid = 0;
|
||||
|
||||
blkio_dev_t *sk_repl_get_homeblocks_dev(void) {
|
||||
return g_homeblocks_sig_valid ? g_homeblocks_dev : (void *)0;
|
||||
}
|
||||
const homeblocks_sig_t *sk_repl_get_homeblocks_sig(void) {
|
||||
return g_homeblocks_sig_valid ? &g_homeblocks_sig : (void *)0;
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* Idle heartbeat service
|
||||
*
|
||||
@@ -133,6 +154,9 @@ static void sk_repl_idle(VM *active_vm)
|
||||
switch (sig_rc) {
|
||||
case HOMEBLOCKS_SIG_OK:
|
||||
console_println("xhci: USB drive recognized as a home-blocks drive");
|
||||
g_homeblocks_dev = &usb_blk_dev;
|
||||
g_homeblocks_sig = sig;
|
||||
g_homeblocks_sig_valid = 1;
|
||||
break;
|
||||
case HOMEBLOCKS_SIG_BLANK:
|
||||
console_println("xhci: USB drive not recognized (blank or foreign media) -- read-only general use only");
|
||||
@@ -165,6 +189,10 @@ static void sk_repl_idle(VM *active_vm)
|
||||
if (xdev && xdev->bot_msc_detach_pending) {
|
||||
xdev->bot_msc_detach_pending = 0;
|
||||
blk_subsys_detach_device(&usb_blk_dev);
|
||||
if (g_homeblocks_dev == &usb_blk_dev) {
|
||||
g_homeblocks_dev = (void *)0;
|
||||
g_homeblocks_sig_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FABRIC.md/FABRIC-2.md Section V item 6: "a cheap 'anything dirty?
|
||||
|
||||
Reference in New Issue
Block a user