lib/machine/src/instance/owner.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

   1 const std = @import("std");
   2 const accelerator = @import("machine_accelerator");
   3 const checkpoint = @import("../checkpoint/root.zig");
   4 const core = @import("machine_instance_core");
   5 const reference = @import("machine_reference");
   6 const os = @import("os");
   7 const delivery = @import("delivery.zig");
   8 const image_admission = @import("admission.zig");
   9 const input_admission = @import("../admission/root.zig");
  10 const profile = @import("../profile/root.zig");
  11 const quiescence_receipt = @import("receipt/root.zig");
  12 const types = @import("types.zig");
  13 
  14 const backend = core.backend;
  15 const layout = core.layout;
  16 const manifest = os.boot.kernel.manifest;
  17 const protection = core.protection;
  18 
  19 const BackendKind = enum(u8) {
  20     none,
  21     accelerator,
  22     reference,
  23 };
  24 
  25 const MemoryKind = enum(u8) {
  26     none,
  27     linear,
  28     branch,
  29 };
  30 
  31 const backend_storage_alignment = @max(
  32     accelerator.storage_alignment,
  33     reference.storage_alignment,
  34 );
  35 const backend_storage_bytes = @max(
  36     accelerator.storage_bytes,
  37     reference.storage_bytes,
  38 );
  39 pub const run_stutter_limit: usize = 128;
  40 
  41 var next_session_identity = std.atomic.Value(u64).init(1);
  42 
  43 const ActivationStage = enum(u8) {
  44     ready,
  45     prompt,
  46     complete,
  47 };
  48 
  49 const InputStage = enum(u8) {
  50     semantic,
  51     terminal,
  52     block_root,
  53     quiescence,
  54     complete,
  55 };
  56 
  57 const Pending = struct {
  58     delivery: input_admission.Delivery,
  59     request_frontiers: os.abi.ring.Frontiers,
  60     event_frontiers: os.abi.ring.Frontiers,
  61     request_sequence: u64,
  62     final_event_sequence: u64,
  63     stage: InputStage,
  64     block_root: ?os.abi.BlockRoot,
  65     quiescence: ?os.abi.Quiescence,
  66     event_transcript_digest: os.abi.Digest,
  67     semantic_transcript_digest: os.abi.Digest,
  68 };
  69 
  70 const CommittedTurn = struct {
  71     basis: input_admission.Basis,
  72     block_root: os.abi.BlockRoot,
  73     terminal_offset: u64,
  74     semantic_frontier: u64,
  75     root_generation: u32,
  76     terminal_count: u8,
  77     receipt: types.QuiescenceReceipt,
  78 };
  79 
  80 const RestoreTargetPreparation = union(enum) {
  81     accelerator,
  82     reference: reference.PreparedRestore,
  83 };
  84 
  85 const RestorePreparation = struct {
  86     backend: backend.Prepared,
  87     target: RestoreTargetPreparation,
  88 };
  89 
  90 const ExpectedSemantic = struct {
  91     interface: [16]u8,
  92     event: u32,
  93     position: u64,
  94     bytes: []const u8,
  95 };
  96 
  97 const OwnerState = struct {
  98     session_identity: u64 = 0,
  99     ram_address: usize = 0,
 100     memory_identity: usize = 0,
 101     memory_kind: MemoryKind = .none,
 102     phase: types.RunPhase = .closed,
 103     active_backend: BackendKind = .none,
 104     manifest_bytes: u32 = 0,
 105     manifest: [os.boot.kernel.manifest.encoded_bytes_max]u8 = undefined,
 106     contract: profile.ContractFingerprint = undefined,
 107     profile_fingerprint: profile.ProfileFingerprint = undefined,
 108     execution_fingerprint: types.ExecutionFingerprint = undefined,
 109     initial: manifest.InitialState = undefined,
 110     immutable_image: core.provenance.ImmutableImage = undefined,
 111     fence: os.abi.ActivationFence = undefined,
 112     image_digest: os.abi.Digest = undefined,
 113     source_root: os.abi.Digest = undefined,
 114     frontiers: input_admission.Frontiers = undefined,
 115     outstanding_effect: ?input_admission.EffectRequest = null,
 116     block_root: os.abi.Digest = undefined,
 117     terminal_offset: u64 = 0,
 118     semantic_frontier: u64 = 0,
 119     root_generation: u32 = 0,
 120     terminal_count: u8 = 0,
 121     activation_stage: ActivationStage = .ready,
 122     pending: ?Pending = null,
 123     quiescence_receipt: ?types.QuiescenceReceipt = null,
 124     branch: checkpoint.roots.branch.Branch = undefined,
 125     backend: [backend_storage_bytes]u8 align(backend_storage_alignment) = undefined,
 126 };
 127 
 128 pub const storage_alignment: usize = @alignOf(OwnerState);
 129 pub const storage_bytes: usize = @sizeOf(OwnerState);
 130 
 131 /// Holds the bytes a caller sets aside for one running instance, so the caller
 132 /// supplies the storage and holds it still. The address has to stay put from
 133 /// the moment it is built until `deinit`. Once a lifecycle closes, the same
 134 /// bytes serve the next one.
 135 pub const Storage = struct {
 136     bytes: [storage_bytes]u8 align(storage_alignment),
 137 
 138     /// Hands back closed storage waiting for a first start or restore, so a
 139     /// caller starts storage setup here. The call invokes no allocator.
 140     pub fn init() Storage {
 141         var result: Storage = undefined;
 142         ownerState(&result).* = .{};
 143         return result;
 144     }
 145 };
 146 
 147 const OwnerError = error{
 148     StorageInUse,
 149     StorageBytesMismatch,
 150     StorageAliasesRam,
 151     UnsupportedBackend,
 152     ImageAliasesRam,
 153     OutputAliasesInstance,
 154     OutputAliasesOwner,
 155     OutputAliasesRam,
 156     StateCapacityExceeded,
 157 };
 158 
 159 const RestoreOwnerError = error{
 160     CheckpointContractMismatch,
 161     ManifestAliasesCheckpoint,
 162     ManifestAliasesRam,
 163     ManifestAliasesStorage,
 164     RamAliasesCheckpoint,
 165     StorageAliasesCheckpoint,
 166 };
 167 
 168 const ProtocolError = error{
 169     AcknowledgementRequired,
 170     ActivationGenerationStale,
 171     ActivationEventsPending,
 172     ActivationTokenStale,
 173     ActivationWorldMismatch,
 174     Closed,
 175     DeliveryReceiptMismatch,
 176     EventDrainRequired,
 177     EventReceiptMismatch,
 178     InputAlreadyDelivered,
 179     InputRequired,
 180     InputUnavailable,
 181     ReactivationRequired,
 182     UnexpectedDoorbell,
 183     UnexpectedEvent,
 184     QuiescenceUnavailable,
 185 };
 186 
 187 const QuiescenceProtocolError = error{
 188     Closed,
 189     EventReceiptMismatch,
 190     QuiescenceUnavailable,
 191 };
 192 
 193 const MachineError = OwnerError || backend.InitFailure;
 194 
 195 pub const InitError = MachineError ||
 196     profile.Error ||
 197     image_admission.Error ||
 198     input_admission.Error ||
 199     os.abi.boot.Error ||
 200     os.abi.ring.Error ||
 201     layout.Error;
 202 
 203 pub const RunError = backend.RunFailure || ProtocolError;
 204 pub const MemoryError = core.memory.Error || error{Closed};
 205 pub const DeliveryError = input_admission.Error ||
 206     delivery.Error || os.abi.ring.Error || ProtocolError || core.memory.Error;
 207 pub const EventError = os.abi.message.Error ||
 208     os.abi.ring.Error || ProtocolError || OwnerError || core.memory.Error;
 209 pub const AcknowledgeError = input_admission.Error ||
 210     os.abi.ring.Error || quiescence_receipt.Error || ProtocolError || OwnerError ||
 211     core.memory.Error;
 212 pub const QuiescenceReceiptError = os.abi.ring.Error ||
 213     quiescence_receipt.Error || QuiescenceProtocolError || core.memory.Error;
 214 pub const BasisError = ProtocolError || os.abi.ring.Error || core.memory.Error;
 215 pub const ReactivateError = os.abi.boot.Error ||
 216     os.abi.ring.Error || backend.RestartFailure || ProtocolError ||
 217     OwnerError || layout.Error;
 218 pub const CaptureCheckpointError = QuiescenceReceiptError || OwnerError ||
 219     checkpoint.Error || core.provenance.Error || layout.Error || core.memory.Error;
 220 pub const CaptureHotError = QuiescenceReceiptError || OwnerError ||
 221     checkpoint.Error || core.provenance.Error || layout.Error || core.memory.Error;
 222 pub const RestoreError = MachineError || RestoreOwnerError ||
 223     profile.Error || image_admission.RestoreError || checkpoint.Error ||
 224     checkpoint.roots.branch.Error || os.abi.boot.Error || os.abi.ring.Error ||
 225     layout.Error;
 226 
 227 /// Reports how a cold start turned out, so the caller learns the state of its
 228 /// buffers across the three outcomes. On ready, the instance holds the caller's
 229 /// storage and RAM until `deinit`. On unavailable, the storage stays closed and
 230 /// the RAM is untouched. On rejected, the value names the validation or backend
 231 /// failure.
 232 pub const StartResult = union(enum) {
 233     ready: Instance,
 234     unavailable: types.Unavailable,
 235     rejected: InitError,
 236 };
 237 
 238 /// Reports how a restore turned out, so the caller learns the state of the
 239 /// restored buffers across the three outcomes. On ready, the instance holds the
 240 /// caller's storage and whatever backs its memory until `deinit`. On
 241 /// unavailable, the storage stays closed and the destination RAM is untouched.
 242 /// On rejected, the value names the restore failure.
 243 pub const RestoreResult = union(enum) {
 244     ready: Instance,
 245     unavailable: types.Unavailable,
 246     rejected: RestoreError,
 247 };
 248 
 249 /// Accepts exactly one byte count, the value of `storage_bytes`, so a caller
 250 /// allocating storage knows the size is right before starting anything. Any
 251 /// other count comes back as `StorageBytesMismatch`.
 252 pub fn validateStorageBytes(bytes: usize) error{StorageBytesMismatch}!void {
 253     if (bytes != storage_bytes) return error.StorageBytesMismatch;
 254 }
 255 
 256 /// Operates one K0 guest that is running now, borrowing its storage and
 257 /// whatever backs its guest memory, so every lifecycle call goes through this
 258 /// handle. Each borrowed region keeps its address until `deinit`. Starting a
 259 /// new lifecycle in the same storage makes copied handles stale, because the
 260 /// session identity moves on.
 261 pub const Instance = struct {
 262     storage: *Storage,
 263     ram: []align(layout.page_bytes) u8,
 264     memory: core.memory.Access,
 265     session_identity: u64,
 266 
 267     /// Boots K0 from an ELF image and its execution manifest under the profile
 268     /// the input names, so a caller performs a cold start of a guest. That
 269     /// profile decides whether Linux KVM or the reference interpreter carries
 270     /// the guest. A ready outcome keeps `storage` and exactly `ram_bytes` bytes
 271     /// of RAM until `deinit`. Anything the validator turns away, and any
 272     /// backend that fails to come up, comes back as rejected. A host lacking
 273     /// the backend comes back as unavailable.
 274     pub fn init(
 275         storage: *Storage,
 276         ram: []align(layout.page_bytes) u8,
 277         input: types.Input,
 278     ) StartResult {
 279         return switch (input.profile.backend) {
 280             .linux_kvm_single_vcpu_v1 => initSelected(
 281                 storage,
 282                 ram,
 283                 input,
 284                 .accelerator,
 285                 null,
 286                 accelerator.start,
 287             ),
 288             .portable_x86_64_interpreter_v1 => initSelected(
 289                 storage,
 290                 ram,
 291                 input,
 292                 .reference,
 293                 null,
 294                 reference.start,
 295             ),
 296         };
 297     }
 298 
 299     /// Rebuilds the guest named by the expected checkpoint root inside
 300     /// caller-owned RAM, under the selected profile, so the caller brings a
 301     /// captured guest back into RAM it owns. A ready outcome keeps the storage
 302     /// and the RAM until `deinit`. A host lacking the backend comes back as
 303     /// unavailable, before anything reaches RAM. Every other failure comes back
 304     /// as rejected.
 305     pub fn restore(
 306         storage: *Storage,
 307         ram: []align(layout.page_bytes) u8,
 308         input: types.RestoreInput,
 309     ) RestoreResult {
 310         return switch (input.profile.backend) {
 311             .linux_kvm_single_vcpu_v1 => restoreSelected(
 312                 storage,
 313                 ram,
 314                 input,
 315                 .accelerator,
 316                 null,
 317                 accelerator.acquireRestore,
 318             ),
 319             .portable_x86_64_interpreter_v1 => restoreSelected(
 320                 storage,
 321                 ram,
 322                 input,
 323                 .reference,
 324                 null,
 325                 null,
 326             ),
 327         };
 328     }
 329 
 330     /// Brings the portable interpreter up over pages read from a store that
 331     /// authenticates them, so a caller restores a captured guest through store
 332     /// pages. The root provider and every buffer of branch storage have to
 333     /// outlive the instance, up to `deinit`. Each write takes a branch page
 334     /// from a fixed supply, and running out comes back as
 335     /// `MemoryCapacityExceeded`.
 336     pub fn restoreShared(
 337         storage: *Storage,
 338         root_storage: checkpoint.roots.Storage,
 339         branch_storage: checkpoint.roots.branch.Storage,
 340         input: types.SharedRestoreInput,
 341     ) RestoreResult {
 342         return restoreSharedSelected(
 343             storage,
 344             root_storage,
 345             branch_storage,
 346             input,
 347         );
 348     }
 349 
 350     /// Gives up whatever the backend holds and closes this lifecycle, so the
 351     /// caller gets its buffers back. Calling it twice, or calling it on a stale
 352     /// copied handle, does nothing. Afterward the storage and the memory
 353     /// backing are the caller's to use again.
 354     pub fn deinit(self: *@This()) void {
 355         const owner = ownerState(self.storage);
 356         if (!ownsLifecycle(self, owner)) return;
 357         if (owner.phase == .closed) return;
 358         switch (owner.active_backend) {
 359             .accelerator => accelerator.deinit(backendState(owner)),
 360             .reference => reference.deinit(backendState(owner)),
 361             .none => {},
 362         }
 363         owner.phase = .closed;
 364         owner.active_backend = .none;
 365         owner.manifest_bytes = 0;
 366         owner.ram_address = 0;
 367         owner.memory_identity = 0;
 368         owner.memory_kind = .none;
 369         owner.quiescence_receipt = null;
 370     }
 371 
 372     /// Says whether this handle is the one driving the lifecycle its storage
 373     /// currently holds, so a caller can tell whether a copied handle remains
 374     /// the live one.
 375     pub fn active(self: *const @This()) bool {
 376         const owner = ownerState(self.storage);
 377         return ownsLifecycle(self, owner) and owner.phase != .closed;
 378     }
 379 
 380     /// Names the stage the lifecycle has reached, so the caller knows which
 381     /// calls are legal right now. A closed storage and a stale handle both
 382     /// answer `closed`.
 383     pub fn phase(self: *const @This()) types.RunPhase {
 384         const owner = ownerState(self.storage);
 385         if (!ownsLifecycle(self, owner)) return .closed;
 386         return owner.phase;
 387     }
 388 
 389     /// Copies bytes out of guest memory, starting at a byte offset counted from
 390     /// zero, into a buffer the caller owns, so the caller can read guest state
 391     /// from outside the guest. A closed handle, and any failure reaching the
 392     /// memory, come back as `MemoryError`.
 393     pub fn readMemory(
 394         self: *const @This(),
 395         address: usize,
 396         output: []u8,
 397     ) MemoryError!void {
 398         const owner = ownerState(self.storage);
 399         if (!ownsLifecycle(self, owner)) return error.Closed;
 400         return self.memory.read(address, output);
 401     }
 402 
 403     /// Copies caller-owned bytes into guest memory at a byte offset counted
 404     /// from zero, so the caller can change guest state from outside the guest.
 405     /// A closed handle, a range outside the guest, a page that fails its digest
 406     /// check, and exhausted branch storage all come back as `MemoryError`.
 407     pub fn writeMemory(
 408         self: *@This(),
 409         address: usize,
 410         input: []const u8,
 411     ) MemoryError!void {
 412         const owner = ownerState(self.storage);
 413         if (!ownsLifecycle(self, owner)) return error.Closed;
 414         return self.memory.write(address, input);
 415     }
 416 
 417     /// Counts the writable guest pages this instance has resident, so the
 418     /// caller can see how many pages a shared restore has copied. A guest
 419     /// living in the caller's RAM counts every page of it. A guest restored
 420     /// from a store counts the pages copied into branch storage.
 421     pub fn privatePageCount(self: *const @This()) MemoryError!u16 {
 422         const owner = ownerState(self.storage);
 423         if (!ownsLifecycle(self, owner)) return error.Closed;
 424         return switch (owner.memory_kind) {
 425             .linear => @intCast(checkpoint.page_count),
 426             .branch => owner.branch.privatePageCount(),
 427             .none => error.Closed,
 428         };
 429     }
 430 
 431     /// Measures what this instance's guest memory holds in bytes, so the caller
 432     /// can determine what one instance is holding. A guest living in the
 433     /// caller's RAM measures `ram_bytes`. A guest restored from a store adds up
 434     /// its branch bookkeeping, the digests it has authenticated, and the pages
 435     /// it has copied.
 436     pub fn residentMemoryBytes(self: *const @This()) MemoryError!u64 {
 437         const owner = ownerState(self.storage);
 438         if (!ownsLifecycle(self, owner)) return error.Closed;
 439         return switch (owner.memory_kind) {
 440             .linear => layout.ram_bytes,
 441             .branch => owner.branch.residentBytes(),
 442             .none => error.Closed,
 443         };
 444     }
 445 
 446     /// Lets the selected backend carry the guest until it reaches one boundary
 447     /// this namespace reports, so the caller advances the guest. A doorbell
 448     /// taken while the guest is ready, and one taken while it is quiescent,
 449     /// both move the lifecycle along. Any other boundary that comes back puts
 450     /// the lifecycle into its failed stage. A boundary carrying no guest
 451     /// progress is passed over and the backend is asked again, up to a limit.
 452     /// The limit is 128 tries, and reaching it comes back as `WouldBlock`.
 453     pub fn run(self: *@This()) RunError!types.Exit {
 454         const owner = ownerState(self.storage);
 455         if (!ownsLifecycle(self, owner)) return error.Closed;
 456         const running_phase = owner.phase;
 457         switch (running_phase) {
 458             .booting, .input_delivered => {},
 459             .draining_activation => return error.EventDrainRequired,
 460             .awaiting_input => return error.InputRequired,
 461             .draining_input => return error.EventDrainRequired,
 462             .awaiting_acknowledgement => return error.AcknowledgementRequired,
 463             .awaiting_reactivation => return error.ReactivationRequired,
 464             .closed, .failed, .capturing_checkpoint, .completing_io => return error.Closed,
 465         }
 466         for (0..run_stutter_limit) |_| {
 467             const raw = runBackend(owner) catch |failure| {
 468                 owner.phase = .failed;
 469                 return mapRunFailure(failure);
 470             };
 471             if (std.meta.activeTag(raw) == .stutter) continue;
 472             const normalized = normalize(raw);
 473             if (std.meta.activeTag(raw) == .io) {
 474                 owner.phase = .completing_io;
 475                 completePendingIo(owner) catch |failure| {
 476                     owner.phase = .failed;
 477                     return mapRunFailure(failure);
 478                 };
 479                 owner.phase = running_phase;
 480             }
 481             return applyExit(owner, running_phase, normalized);
 482         }
 483         return error.WouldBlock;
 484     }
 485 
 486     /// Reports the position an input is admitted against once the events the
 487     /// activation produced have been taken, so the caller obtains the guest
 488     /// position needed to admit an input. The guest has to be waiting for
 489     /// input. Both rings have to be settled, the one carrying requests and the
 490     /// one carrying events.
 491     pub fn admissionBasis(
 492         self: *const @This(),
 493     ) BasisError!input_admission.Basis {
 494         const owner = ownerState(self.storage);
 495         if (!ownsLifecycle(self, owner)) return error.Closed;
 496         if (owner.phase != .awaiting_input) return error.InputUnavailable;
 497         if (owner.activation_stage != .complete) {
 498             return error.ActivationEventsPending;
 499         }
 500         const requests = try os.abi.RequestRing.frontiers(
 501             try layout.requestRingAccess(self.memory),
 502             owner.fence,
 503         );
 504         const events = try os.abi.EventRing.frontiers(
 505             try layout.eventRingAccess(self.memory),
 506             owner.fence,
 507         );
 508         if (requests.consumed != 0 or requests.produced != 0 or
 509             events.consumed != os.k0.events_per_activation or
 510             events.produced != os.k0.events_per_activation)
 511         {
 512             return error.EventReceiptMismatch;
 513         }
 514         return basis(owner);
 515     }
 516 
 517     /// Checks one admitted input against the position and the authority in
 518     /// force, then writes it where the guest reads, so an admitted input
 519     /// reaches the guest. The delivery value is copied during the call. A phase
 520     /// that forbids the call, a ring that will not take the input, a memory
 521     /// failure, and an admission that does not check out all leave the turn
 522     /// unacknowledged.
 523     pub fn deliverAdmitted(
 524         self: *@This(),
 525         value: *const input_admission.Delivery,
 526     ) DeliveryError!void {
 527         const owner = ownerState(self.storage);
 528         if (!ownsLifecycle(self, owner)) return error.Closed;
 529         const owned = value.*;
 530         if (owner.phase == .input_delivered or owner.phase == .draining_input) {
 531             return error.InputAlreadyDelivered;
 532         }
 533         if (owner.phase == .awaiting_acknowledgement) {
 534             return error.AcknowledgementRequired;
 535         }
 536         if (owner.phase != .awaiting_input) return error.InputUnavailable;
 537         if (owner.activation_stage != .complete) {
 538             return error.ActivationEventsPending;
 539         }
 540         try input_admission.verifyDelivery(basis(owner), owner.fence, &owned);
 541         const requests = try layout.requestRingAccess(self.memory);
 542         const events = try layout.eventRingAccess(self.memory);
 543         const request_frontiers = try os.abi.RequestRing.frontiers(
 544             requests,
 545             owner.fence,
 546         );
 547         const event_frontiers = try os.abi.EventRing.frontiers(
 548             events,
 549             owner.fence,
 550         );
 551         if (request_frontiers.consumed != 0 or
 552             request_frontiers.produced != 0 or
 553             event_frontiers.consumed != os.k0.events_per_activation or
 554             event_frontiers.produced != os.k0.events_per_activation)
 555         {
 556             return error.EventReceiptMismatch;
 557         }
 558         const request_sequence = std.math.add(
 559             u64,
 560             request_frontiers.produced,
 561             1,
 562         ) catch return error.SequenceExhausted;
 563         const event_count: u64 = switch (owned.admission.record) {
 564             .terminal => os.k0.events_per_terminal_input,
 565             else => os.k0.events_per_nonterminal_input,
 566         };
 567         const final_event_sequence = std.math.add(
 568             u64,
 569             event_frontiers.produced,
 570             event_count,
 571         ) catch return error.SequenceExhausted;
 572         var wire: os.abi.MessageWire = undefined;
 573         try delivery.encode(
 574             owner.fence,
 575             request_sequence,
 576             &owned.admission,
 577             &wire,
 578         );
 579         try os.abi.RequestRing.push(requests, owner.fence, &wire);
 580         owner.pending = .{
 581             .delivery = owned,
 582             .request_frontiers = request_frontiers,
 583             .event_frontiers = event_frontiers,
 584             .request_sequence = request_sequence,
 585             .final_event_sequence = final_event_sequence,
 586             .stage = .semantic,
 587             .block_root = null,
 588             .quiescence = null,
 589             .event_transcript_digest = @splat(0),
 590             .semantic_transcript_digest = @splat(0),
 591         };
 592         owner.phase = .input_delivered;
 593     }
 594 
 595     /// Moves every event of the current doorbell's group into a buffer the
 596     /// caller owns, for the caller has to take them before the turn can be
 597     /// acknowledged. That buffer may not overlap the handle, its storage, or
 598     /// guest memory. When validation fails, the ring keeps its entries.
 599     pub fn takeEvents(
 600         self: *@This(),
 601         output: *types.EventBatch,
 602     ) EventError!void {
 603         const owner = ownerState(self.storage);
 604         if (!ownsLifecycle(self, owner)) return error.Closed;
 605         const output_bytes = std.mem.asBytes(output);
 606         if (image_admission.buffersOverlap(output_bytes, std.mem.asBytes(self))) {
 607             return error.OutputAliasesInstance;
 608         }
 609         if (image_admission.buffersOverlap(output_bytes, &self.storage.bytes)) {
 610             return error.OutputAliasesOwner;
 611         }
 612         if (self.memory.aliases(output_bytes)) {
 613             return error.OutputAliasesRam;
 614         }
 615         if (owner.phase == .draining_activation) {
 616             return takeActivationEvents(owner, self.memory, output);
 617         }
 618         if (owner.phase != .draining_input) return error.InputUnavailable;
 619         return takeInputEvents(owner, self.memory, output);
 620     }
 621 
 622     /// Closes a turn whose events have all been taken, after the delivery
 623     /// digest matches and both ring cursors have settled, so the caller
 624     /// concludes the turn. Closing it builds the evidence for the quiescent
 625     /// turn and moves the lifecycle to `awaiting_reactivation`.
 626     pub fn acknowledge(
 627         self: *@This(),
 628         receipt: input_admission.DeliveryReceipt,
 629     ) AcknowledgeError!void {
 630         const owner = ownerState(self.storage);
 631         if (!ownsLifecycle(self, owner)) return error.Closed;
 632         if (owner.phase != .awaiting_acknowledgement) {
 633             return error.InputUnavailable;
 634         }
 635         const pending = owner.pending orelse return error.InputUnavailable;
 636         if (pending.stage != .complete) return error.EventDrainRequired;
 637         if (!std.meta.eql(receipt, pending.delivery.receipt)) {
 638             return error.DeliveryReceiptMismatch;
 639         }
 640         const settled = try settledRings(owner, self.memory, pending);
 641         const committed = try prepareCommit(owner, pending, settled);
 642         owner.source_root = committed.basis.source_root;
 643         owner.frontiers = committed.basis.frontiers;
 644         owner.outstanding_effect = committed.basis.outstanding_effect;
 645         owner.block_root = committed.block_root.digest;
 646         owner.terminal_offset = committed.terminal_offset;
 647         owner.semantic_frontier = committed.semantic_frontier;
 648         owner.root_generation = committed.root_generation;
 649         owner.terminal_count = committed.terminal_count;
 650         owner.pending = null;
 651         owner.quiescence_receipt = committed.receipt;
 652         owner.phase = .awaiting_reactivation;
 653     }
 654 
 655     /// Hands back the checked evidence for the turn that has settled, so the
 656     /// caller receives the receipt for the completed turn. The guest has to be
 657     /// waiting for reactivation. Both rings have to stand where the evidence
 658     /// says they stand.
 659     pub fn quiescenceReceipt(
 660         self: *const @This(),
 661     ) QuiescenceReceiptError!types.QuiescenceReceipt {
 662         const owner = ownerState(self.storage);
 663         if (!ownsLifecycle(self, owner)) return error.Closed;
 664         if (owner.phase != .awaiting_reactivation) {
 665             return error.QuiescenceUnavailable;
 666         }
 667         const value = owner.quiescence_receipt orelse
 668             return error.QuiescenceUnavailable;
 669         try quiescence_receipt.verifyForFence(value, owner.fence);
 670         try validateReceiptOwner(owner, value);
 671         const requests = try os.abi.RequestRing.frontiers(
 672             try layout.requestRingAccess(self.memory),
 673             owner.fence,
 674         );
 675         const events = try os.abi.EventRing.frontiers(
 676             try layout.eventRingAccess(self.memory),
 677             owner.fence,
 678         );
 679         if (requests.consumed != value.settled.request_cursor or
 680             requests.produced != value.settled.request_cursor or
 681             events.consumed != value.settled.event_cursor or
 682             events.produced != value.settled.event_cursor)
 683         {
 684             return error.EventReceiptMismatch;
 685         }
 686         return value;
 687     }
 688 
 689     /// Writes the settled guest state into checkpoint storage and destination
 690     /// RAM the caller owns, so the caller turns settled state into a retained
 691     /// checkpoint. Both have to stay alive for as long as the checkpoint is
 692     /// used. Buffers that overlap, evidence that does not check out, memory
 693     /// that cannot be read, and a checkpoint that will not build all turn the
 694     /// capture away.
 695     pub fn captureCheckpoint(
 696         self: *@This(),
 697         storage: *checkpoint.Storage,
 698         ram: []align(layout.page_bytes) u8,
 699     ) CaptureCheckpointError!checkpoint.Checkpoint {
 700         const owner = ownerState(self.storage);
 701         if (!ownsLifecycle(self, owner)) return error.Closed;
 702         try layout.validateRamBytes(ram.len);
 703         if (image_admission.buffersOverlap(ram, std.mem.asBytes(self))) {
 704             return error.OutputAliasesInstance;
 705         }
 706         if (image_admission.buffersOverlap(ram, &self.storage.bytes)) {
 707             return error.OutputAliasesOwner;
 708         }
 709         if (self.memory.aliases(ram)) {
 710             return error.OutputAliasesRam;
 711         }
 712         if (image_admission.buffersOverlap(&storage.bytes, std.mem.asBytes(self))) {
 713             return error.StorageAliasesInstance;
 714         }
 715         if (image_admission.buffersOverlap(&storage.bytes, &self.storage.bytes)) {
 716             return error.StorageAliasesOwner;
 717         }
 718         if (self.memory.aliases(&storage.bytes)) {
 719             return error.StorageAliasesRam;
 720         }
 721         if (image_admission.buffersOverlap(&storage.bytes, ram)) {
 722             return error.MemoryAliasesStorage;
 723         }
 724         try checkpoint.ensureAvailable(storage);
 725         const receipt_value = try self.quiescenceReceipt();
 726         owner.phase = .capturing_checkpoint;
 727         defer owner.phase = .awaiting_reactivation;
 728         const material = try checkpointMaterial(owner, receipt_value);
 729         if (self.memory.linearRam()) |linear| {
 730             return checkpoint.publish(material, storage, linear, ram);
 731         }
 732         try self.memory.read(0, ram);
 733         const memory = try checkpoint.validatedMemoryDigest(
 734             ram,
 735             material.immutable_image,
 736         );
 737         const identity = try checkpoint.identify(material, memory);
 738         var candidate = try checkpoint.beginMaterialization(storage, ram);
 739         return checkpoint.publishMaterialized(
 740             &candidate,
 741             material,
 742             identity.root,
 743             memory,
 744         );
 745     }
 746 
 747     /// Captures the pages that differ from a parent checkpoint the caller owns,
 748     /// so the caller records changed pages against a durable parent. What comes
 749     /// back borrows that parent and the hot storage passed in. A guest whose
 750     /// memory comes from a store answers `MemoryReadFailed`.
 751     pub fn captureHot(
 752         self: *@This(),
 753         parent: *const checkpoint.Checkpoint,
 754         storage: checkpoint.hot.Storage,
 755     ) CaptureHotError!checkpoint.hot.Snapshot {
 756         const owner = ownerState(self.storage);
 757         if (!ownsLifecycle(self, owner)) return error.Closed;
 758         const index_bytes = std.mem.sliceAsBytes(storage.indices);
 759         if (image_admission.buffersOverlap(index_bytes, std.mem.asBytes(self)) or
 760             image_admission.buffersOverlap(storage.pages, std.mem.asBytes(self)))
 761         {
 762             return error.OutputAliasesInstance;
 763         }
 764         if (image_admission.buffersOverlap(index_bytes, &self.storage.bytes) or
 765             image_admission.buffersOverlap(storage.pages, &self.storage.bytes))
 766         {
 767             return error.OutputAliasesOwner;
 768         }
 769         const receipt_value = try self.quiescenceReceipt();
 770         owner.phase = .capturing_checkpoint;
 771         defer owner.phase = .awaiting_reactivation;
 772         const linear = self.memory.linearRam() orelse
 773             return error.MemoryReadFailed;
 774         return checkpoint.hot.capture(
 775             parent,
 776             try checkpointMaterial(owner, receipt_value),
 777             linear,
 778             storage,
 779         );
 780     }
 781 
 782     /// Sets a settled instance running again under a newer authority, so the
 783     /// caller installs the authority required for the next turn. The new
 784     /// authority names the same world, counts one generation higher, and
 785     /// carries a different token. When it succeeds the lifecycle stands at
 786     /// `booting` again.
 787     pub fn reactivate(
 788         self: *@This(),
 789         fence: os.abi.ActivationFence,
 790     ) ReactivateError!void {
 791         const owner = ownerState(self.storage);
 792         if (!ownsLifecycle(self, owner)) return error.Closed;
 793         if (owner.phase != .awaiting_reactivation) {
 794             return error.InputUnavailable;
 795         }
 796         try os.abi.wire.validateFence(fence);
 797         if (!std.mem.eql(u8, &owner.fence.world, &fence.world)) {
 798             return error.ActivationWorldMismatch;
 799         }
 800         if (fence.generation <= owner.fence.generation) {
 801             return error.ActivationGenerationStale;
 802         }
 803         if (std.mem.eql(u8, &owner.fence.token, &fence.token)) {
 804             return error.ActivationTokenStale;
 805         }
 806         _ = std.math.add(u64, owner.terminal_offset, os.k0.ready_prompt.len) catch
 807             return error.StateCapacityExceeded;
 808         const frame = continuationFrame(owner, fence);
 809         var wire: os.abi.BootWire = undefined;
 810         try os.abi.encodeBootFrame(frame, &wire);
 811         restartBackend(owner, self.memory) catch |failure| {
 812             owner.phase = .failed;
 813             return failure;
 814         };
 815         try layout.reactivateAccess(self.memory, frame, &wire);
 816         owner.fence = fence;
 817         owner.activation_stage = .ready;
 818         owner.quiescence_receipt = null;
 819         owner.phase = .booting;
 820     }
 821 };
 822 
 823 /// Boots a guest with accelerator semantics through a caller-supplied callback,
 824 /// so a backend harness can supply its own start callback while keeping the
 825 /// rest of the path unchanged. The call answers with the same start outcome as
 826 /// `init`.
 827 pub fn initWithStart(
 828     storage: *Storage,
 829     ram: []align(layout.page_bytes) u8,
 830     input: types.Input,
 831     context: ?*anyopaque,
 832     start: backend.StartFunction,
 833 ) StartResult {
 834     return initSelected(
 835         storage,
 836         ram,
 837         input,
 838         .accelerator,
 839         context,
 840         start,
 841     );
 842 }
 843 
 844 /// Restores a guest with accelerator semantics through a caller-supplied
 845 /// callback, so a backend harness can substitute the backend acquire callback
 846 /// during a restore. The checkpoint and the profile are checked first, and the
 847 /// callback runs after.
 848 pub fn restoreWithAcquire(
 849     storage: *Storage,
 850     ram: []align(layout.page_bytes) u8,
 851     input: types.RestoreInput,
 852     context: ?*anyopaque,
 853     acquire: backend.RestoreAcquireFunction,
 854 ) RestoreResult {
 855     return restoreSelected(
 856         storage,
 857         ram,
 858         input,
 859         .accelerator,
 860         context,
 861         acquire,
 862     );
 863 }
 864 
 865 /// Checks whether a direct restore would work and brings no backend up, so a
 866 /// caller verifies the operation before committing resources to it. The storage
 867 /// and the destination RAM are left as they were. When the restore would work,
 868 /// the call reports the checkpoint identity it verified.
 869 pub fn validateRestore(
 870     storage: *Storage,
 871     ram: []align(layout.page_bytes) u8,
 872     input: types.RestoreInput,
 873 ) RestoreError!checkpoint.Identity {
 874     const selected: BackendKind = switch (input.profile.backend) {
 875         .linux_kvm_single_vcpu_v1 => .accelerator,
 876         .portable_x86_64_interpreter_v1 => .reference,
 877     };
 878     return validateRestoreSelected(storage, ram, input, selected);
 879 }
 880 
 881 fn initSelected(
 882     storage: *Storage,
 883     ram: []align(layout.page_bytes) u8,
 884     input: types.Input,
 885     selected: BackendKind,
 886     context: ?*anyopaque,
 887     start: backend.StartFunction,
 888 ) StartResult {
 889     if (image_admission.buffersOverlap(&storage.bytes, ram)) {
 890         return .{ .rejected = error.StorageAliasesRam };
 891     }
 892     const prepared = prepareStart(storage, ram, input, selected) catch |failure| {
 893         return .{ .rejected = failure };
 894     };
 895     const attempt = start(
 896         context,
 897         backendState(ownerState(storage)),
 898         ram,
 899         input.elf,
 900         &prepared,
 901     ) catch |failure| {
 902         ownerState(storage).manifest_bytes = 0;
 903         return .{ .rejected = mapInitFailure(failure) };
 904     };
 905     return switch (attempt) {
 906         .ready => ready(storage, ram, selected),
 907         .unavailable => |receipt| unavailable(storage, receipt),
 908     };
 909 }
 910 
 911 fn ready(
 912     storage: *Storage,
 913     ram: []align(layout.page_bytes) u8,
 914     selected: BackendKind,
 915 ) StartResult {
 916     const owner = ownerState(storage);
 917     const memory = core.memory.Access.initLinear(ram);
 918     owner.phase = .booting;
 919     owner.active_backend = selected;
 920     owner.memory_kind = .linear;
 921     owner.memory_identity = memory.identity();
 922     return .{ .ready = .{
 923         .storage = storage,
 924         .ram = ram,
 925         .memory = memory,
 926         .session_identity = owner.session_identity,
 927     } };
 928 }
 929 
 930 fn unavailable(
 931     storage: *Storage,
 932     receipt: backend.Unavailable,
 933 ) StartResult {
 934     ownerState(storage).manifest_bytes = 0;
 935     ownerState(storage).active_backend = .none;
 936     return .{ .unavailable = .{
 937         .availability = receipt.availability,
 938         .stage = receipt.stage,
 939         .code = receipt.code,
 940     } };
 941 }
 942 
 943 fn prepareStart(
 944     storage: *Storage,
 945     ram: []align(layout.page_bytes) u8,
 946     input: types.Input,
 947     selected: BackendKind,
 948 ) InitError!backend.Prepared {
 949     const owner = ownerState(storage);
 950     if (owner.phase != .closed) return error.StorageInUse;
 951     owner.manifest_bytes = 0;
 952     try profile.validate(input.profile);
 953     if (!backendMatches(input.profile.backend, selected)) {
 954         return error.UnsupportedBackend;
 955     }
 956     try layout.validateRamBytes(ram.len);
 957     try validateProfileGeometry(input.profile);
 958     if (image_admission.buffersOverlap(input.elf, ram)) {
 959         return error.ImageAliasesRam;
 960     }
 961     const admitted = try image_admission.admit(
 962         &owner.manifest,
 963         input.execution_manifest,
 964         input.expected_execution_fingerprint,
 965         input.elf,
 966     );
 967     owner.manifest_bytes = @intCast(admitted.execution.bytes.len);
 968     const protection_plan = protection.Plan.init(admitted.execution) catch
 969         return error.BackendFailure;
 970     const contract = try profile.contractFingerprint(input.profile);
 971     const profile_fingerprint = try profile.profileFingerprint(input.profile);
 972     const input_basis = inputBasis(input, contract);
 973     try input_admission.validateBasis(input_basis);
 974     try initializeProtocol(
 975         owner,
 976         input,
 977         contract,
 978         profile_fingerprint,
 979         admitted.image_digest,
 980     );
 981     owner.initial = admitted.initial;
 982     owner.immutable_image = admitted.immutable_image;
 983     const frame = bootFrame(input, contract, admitted.image_digest);
 984     var wire: os.abi.BootWire = undefined;
 985     try os.abi.encodeBootFrame(frame, &wire);
 986     owner.session_identity = claimSessionIdentity();
 987     owner.ram_address = @intFromPtr(ram.ptr);
 988     return .{
 989         .execution = admitted.execution,
 990         .protection_plan = protection_plan,
 991         .initial = admitted.initial,
 992         .frame = frame,
 993         .wire = wire,
 994     };
 995 }
 996 
 997 fn restoreSelected(
 998     storage: *Storage,
 999     ram: []align(layout.page_bytes) u8,
1000     input: types.RestoreInput,
1001     selected: BackendKind,
1002     context: ?*anyopaque,
1003     acquire: ?backend.RestoreAcquireFunction,
1004 ) RestoreResult {
1005     if (image_admission.buffersOverlap(&storage.bytes, ram)) {
1006         return .{ .rejected = error.StorageAliasesRam };
1007     }
1008     const prepared = prepareRestore(storage, ram, input, selected) catch |failure| {
1009         return .{ .rejected = failure };
1010     };
1011     return switch (selected) {
1012         .accelerator => restoreAccelerator(
1013             storage,
1014             ram,
1015             input,
1016             prepared,
1017             context,
1018             acquire orelse unreachable,
1019         ),
1020         .reference => restoreReference(storage, ram, input, prepared),
1021         .none => unreachable,
1022     };
1023 }
1024 
1025 fn restoreSharedSelected(
1026     storage: *Storage,
1027     root_storage: checkpoint.roots.Storage,
1028     branch_storage: checkpoint.roots.branch.Storage,
1029     input: types.SharedRestoreInput,
1030 ) RestoreResult {
1031     const owner = ownerState(storage);
1032     if (owner.phase != .closed) return .{ .rejected = error.StorageInUse };
1033     if (branchStorageAliases(branch_storage, &storage.bytes)) {
1034         return .{ .rejected = error.StorageAliasesRam };
1035     }
1036     if (branchStorageAliases(branch_storage, input.execution_manifest)) {
1037         return .{ .rejected = error.ManifestAliasesRam };
1038     }
1039     profile.validate(input.profile) catch |failure| {
1040         return .{ .rejected = failure };
1041     };
1042     if (input.profile.backend != .portable_x86_64_interpreter_v1) {
1043         return .{ .rejected = error.UnsupportedBackend };
1044     }
1045     validateProfileGeometry(input.profile) catch |failure| {
1046         return .{ .rejected = failure };
1047     };
1048     os.abi.wire.validateFence(input.fence) catch |failure| {
1049         return .{ .rejected = failure };
1050     };
1051     owner.branch = checkpoint.roots.branch.restore(
1052         root_storage,
1053         input.expected_root,
1054         branch_storage,
1055     ) catch |failure| return .{ .rejected = failure };
1056     const access = branchMemory(&owner.branch);
1057     const prepared = prepareSharedRestore(
1058         owner,
1059         access,
1060         input,
1061     ) catch |failure| return rejectPreparedRestore(storage, failure);
1062     const restored = switch (prepared.target) {
1063         .reference => |value| value,
1064         .accelerator => unreachable,
1065     };
1066     const attempt = reference.startFromAccess(
1067         backendState(owner),
1068         access,
1069         &prepared.backend,
1070         restored,
1071     ) catch |failure| return rejectPreparedRestore(storage, failure);
1072     return switch (attempt) {
1073         .ready => restoreSharedReady(storage, access),
1074         .unavailable => |receipt| restoreUnavailable(storage, receipt),
1075     };
1076 }
1077 
1078 fn prepareSharedRestore(
1079     owner: *OwnerState,
1080     access: core.memory.Access,
1081     input: types.SharedRestoreInput,
1082 ) RestoreError!RestorePreparation {
1083     owner.manifest_bytes = 0;
1084     const material = owner.branch.manifest.material;
1085     const contract = try profile.contractFingerprint(input.profile);
1086     const profile_fingerprint = try profile.profileFingerprint(input.profile);
1087     if (!std.meta.eql(contract, material.receipt.basis.contract)) {
1088         return error.CheckpointContractMismatch;
1089     }
1090     const admitted = try image_admission.admitRestoredAccess(
1091         &owner.manifest,
1092         input.execution_manifest,
1093         material.receipt.execution_fingerprint,
1094         material.receipt.image_digest,
1095         material.cpu,
1096         material.immutable_image,
1097         access,
1098     );
1099     owner.manifest_bytes = @intCast(admitted.execution.bytes.len);
1100     const protection_plan = protection.Plan.init(admitted.execution) catch
1101         return error.BackendFailure;
1102     const frame = try restoreFrame(material, contract, input.fence);
1103     try initializeRestore(
1104         owner,
1105         material,
1106         contract,
1107         profile_fingerprint,
1108         input.fence,
1109     );
1110     var wire: os.abi.BootWire = undefined;
1111     try os.abi.encodeBootFrame(frame, &wire);
1112     return .{
1113         .backend = .{
1114             .execution = admitted.execution,
1115             .protection_plan = protection_plan,
1116             .initial = material.cpu,
1117             .frame = frame,
1118             .wire = wire,
1119         },
1120         .target = .{ .reference = try reference.prepareRestoreAccess(
1121             admitted.execution,
1122             &protection_plan,
1123             access,
1124         ) },
1125     };
1126 }
1127 
1128 fn restoreAccelerator(
1129     storage: *Storage,
1130     ram: []align(layout.page_bytes) u8,
1131     input: types.RestoreInput,
1132     prepared: RestorePreparation,
1133     context: ?*anyopaque,
1134     acquire: backend.RestoreAcquireFunction,
1135 ) RestoreResult {
1136     std.debug.assert(std.meta.activeTag(prepared.target) == .accelerator);
1137     const state_pointer = backendState(ownerState(storage));
1138     const attempt = acquire(context, state_pointer) catch |failure| {
1139         return rejectPreparedRestore(storage, failure);
1140     };
1141     switch (attempt) {
1142         .unavailable => |receipt| return restoreUnavailable(storage, receipt),
1143         .ready => {},
1144     }
1145     accelerator.admitRestore(
1146         state_pointer,
1147         &prepared.backend,
1148     ) catch |failure| {
1149         accelerator.deinit(state_pointer);
1150         return rejectPreparedRestore(storage, failure);
1151     };
1152     _ = input.checkpoint.materializeForRestore(
1153         input.expected_root,
1154         ram,
1155     ) catch |failure| {
1156         accelerator.deinit(state_pointer);
1157         return rejectPreparedRestore(storage, failure);
1158     };
1159     accelerator.activateRestore(
1160         state_pointer,
1161         ram,
1162         &prepared.backend,
1163     ) catch |failure| {
1164         accelerator.deinit(state_pointer);
1165         return rejectPreparedRestore(storage, failure);
1166     };
1167     return restoreReady(storage, ram, .accelerator);
1168 }
1169 
1170 fn restoreReference(
1171     storage: *Storage,
1172     ram: []align(layout.page_bytes) u8,
1173     input: types.RestoreInput,
1174     prepared: RestorePreparation,
1175 ) RestoreResult {
1176     const restored = switch (prepared.target) {
1177         .reference => |value| value,
1178         .accelerator => unreachable,
1179     };
1180     _ = input.checkpoint.materializeForRestore(
1181         input.expected_root,
1182         ram,
1183     ) catch |failure| return rejectPreparedRestore(storage, failure);
1184     const attempt = reference.startFromRam(
1185         backendState(ownerState(storage)),
1186         ram,
1187         &prepared.backend,
1188         restored,
1189     );
1190     return switch (attempt) {
1191         .ready => restoreReady(storage, ram, .reference),
1192         .unavailable => |receipt| restoreUnavailable(storage, receipt),
1193     };
1194 }
1195 
1196 fn rejectPreparedRestore(
1197     storage: *Storage,
1198     failure: RestoreError,
1199 ) RestoreResult {
1200     const owner = ownerState(storage);
1201     std.debug.assert(owner.phase == .closed);
1202     owner.manifest_bytes = 0;
1203     owner.active_backend = .none;
1204     return .{ .rejected = failure };
1205 }
1206 
1207 fn prepareRestore(
1208     storage: *Storage,
1209     ram: []align(layout.page_bytes) u8,
1210     input: types.RestoreInput,
1211     selected: BackendKind,
1212 ) RestoreError!RestorePreparation {
1213     const owner = ownerState(storage);
1214     try validateRestoreAliases(storage, ram, input);
1215     if (owner.phase != .closed) return error.StorageInUse;
1216     owner.manifest_bytes = 0;
1217     try profile.validate(input.profile);
1218     if (!backendMatches(input.profile.backend, selected)) {
1219         return error.UnsupportedBackend;
1220     }
1221     try layout.validateRamBytes(ram.len);
1222     try validateProfileGeometry(input.profile);
1223     const contract = try profile.contractFingerprint(input.profile);
1224     const profile_fingerprint = try profile.profileFingerprint(input.profile);
1225     try os.abi.wire.validateFence(input.fence);
1226     const source = try input.checkpoint.prepareForRestore(
1227         input.expected_root,
1228         ram,
1229     );
1230     const material = source.material;
1231     if (!std.meta.eql(contract, material.receipt.basis.contract)) {
1232         return error.CheckpointContractMismatch;
1233     }
1234     const admitted = try image_admission.admitRestored(
1235         &owner.manifest,
1236         input.execution_manifest,
1237         material.receipt.execution_fingerprint,
1238         material.receipt.image_digest,
1239         material.cpu,
1240         material.immutable_image,
1241         input.checkpoint.evidenceRam(),
1242     );
1243     owner.manifest_bytes = @intCast(admitted.execution.bytes.len);
1244     const protection_plan = protection.Plan.init(admitted.execution) catch
1245         return error.BackendFailure;
1246     const frame = try restoreFrame(material, contract, input.fence);
1247     try initializeRestore(
1248         owner,
1249         material,
1250         contract,
1251         profile_fingerprint,
1252         input.fence,
1253     );
1254     var wire: os.abi.BootWire = undefined;
1255     try os.abi.encodeBootFrame(frame, &wire);
1256     const target_preparation: RestoreTargetPreparation = switch (selected) {
1257         .reference => .{ .reference = try reference.prepareRestore(
1258             admitted.execution,
1259             &protection_plan,
1260             input.checkpoint.evidenceRam(),
1261         ) },
1262         .accelerator => .accelerator,
1263         .none => unreachable,
1264     };
1265     return .{
1266         .backend = .{
1267             .execution = admitted.execution,
1268             .protection_plan = protection_plan,
1269             .initial = material.cpu,
1270             .frame = frame,
1271             .wire = wire,
1272         },
1273         .target = target_preparation,
1274     };
1275 }
1276 
1277 fn validateRestoreSelected(
1278     storage: *Storage,
1279     ram: []align(layout.page_bytes) u8,
1280     input: types.RestoreInput,
1281     selected: BackendKind,
1282 ) RestoreError!checkpoint.Identity {
1283     try validateRestoreAliases(storage, ram, input);
1284     if (ownerState(storage).phase != .closed) return error.StorageInUse;
1285     try profile.validate(input.profile);
1286     if (!backendMatches(input.profile.backend, selected)) {
1287         return error.UnsupportedBackend;
1288     }
1289     try layout.validateRamBytes(ram.len);
1290     try validateProfileGeometry(input.profile);
1291     try os.abi.wire.validateFence(input.fence);
1292     const source = try input.checkpoint.prepareForRestore(
1293         input.expected_root,
1294         ram,
1295     );
1296     const material = source.material;
1297     const contract = try profile.contractFingerprint(input.profile);
1298     if (!std.meta.eql(contract, material.receipt.basis.contract)) {
1299         return error.CheckpointContractMismatch;
1300     }
1301     const admitted = try image_admission.validateRestored(
1302         input.execution_manifest,
1303         material.receipt.execution_fingerprint,
1304         material.receipt.image_digest,
1305         material.cpu,
1306         material.immutable_image,
1307         input.checkpoint.evidenceRam(),
1308     );
1309     const plan = protection.Plan.init(admitted.execution) catch
1310         return error.BackendFailure;
1311     const frame = try restoreFrame(material, contract, input.fence);
1312     var wire: os.abi.BootWire = undefined;
1313     try os.abi.encodeBootFrame(frame, &wire);
1314     if (selected == .reference) {
1315         _ = try reference.prepareRestore(
1316             admitted.execution,
1317             &plan,
1318             input.checkpoint.evidenceRam(),
1319         );
1320     }
1321     return source.identity;
1322 }
1323 
1324 fn validateProfileGeometry(value: profile.Profile) profile.Error!void {
1325     return profile.capacity.geometry(value, .{
1326         .vcpu_count = @intCast(manifest.k0_v1_vcpu_count),
1327         .page_bytes = layout.page_bytes,
1328         .ram_base = manifest.k0_v1_ram_base,
1329         .ram_bytes = layout.ram_bytes,
1330     });
1331 }
1332 
1333 fn validateRestoreAliases(
1334     storage: *Storage,
1335     ram: []align(layout.page_bytes) u8,
1336     input: types.RestoreInput,
1337 ) RestoreOwnerError!void {
1338     if (input.checkpoint.aliases(&storage.bytes)) {
1339         return error.StorageAliasesCheckpoint;
1340     }
1341     if (input.checkpoint.aliases(ram)) {
1342         return error.RamAliasesCheckpoint;
1343     }
1344     if (image_admission.buffersOverlap(input.execution_manifest, &storage.bytes)) {
1345         return error.ManifestAliasesStorage;
1346     }
1347     if (image_admission.buffersOverlap(input.execution_manifest, ram)) {
1348         return error.ManifestAliasesRam;
1349     }
1350     if (input.checkpoint.aliases(input.execution_manifest)) {
1351         return error.ManifestAliasesCheckpoint;
1352     }
1353 }
1354 
1355 fn initializeRestore(
1356     owner: *OwnerState,
1357     material: checkpoint.Material,
1358     contract: profile.ContractFingerprint,
1359     profile_fingerprint: profile.ProfileFingerprint,
1360     fence: os.abi.ActivationFence,
1361 ) RestoreError!void {
1362     const root_generation = try validateRestoreMaterial(material);
1363     owner.contract = contract;
1364     owner.profile_fingerprint = profile_fingerprint;
1365     owner.execution_fingerprint = material.receipt.execution_fingerprint;
1366     owner.initial = material.cpu;
1367     owner.immutable_image = material.immutable_image;
1368     owner.fence = fence;
1369     owner.image_digest = material.receipt.image_digest;
1370     owner.source_root = material.receipt.basis.source_root;
1371     owner.frontiers = material.receipt.basis.frontiers;
1372     owner.outstanding_effect = material.receipt.basis.outstanding_effect;
1373     owner.block_root = material.receipt.block_root.digest;
1374     owner.terminal_offset = material.receipt.boundary.terminal_offset;
1375     owner.semantic_frontier = material.receipt.boundary.semantic_frontier;
1376     owner.root_generation = root_generation;
1377     owner.terminal_count = material.receipt.k0.counter;
1378     owner.activation_stage = .ready;
1379     owner.pending = null;
1380     owner.quiescence_receipt = null;
1381 }
1382 
1383 fn restoreFrame(
1384     material: checkpoint.Material,
1385     contract: profile.ContractFingerprint,
1386     fence: os.abi.ActivationFence,
1387 ) OwnerError!os.abi.BootFrame {
1388     const root_generation = try validateRestoreMaterial(material);
1389     return .{
1390         .fence = fence,
1391         .contract_digest = contract.digest,
1392         .image_digest = material.receipt.image_digest,
1393         .ram_bytes = layout.ram_bytes,
1394         .request_ring_address = layout.request_ring_address,
1395         .event_ring_address = layout.event_ring_address,
1396         .initial_time_tick = material.receipt.basis.frontiers.virtual_time_tick,
1397         .entropy_generation = material.receipt.basis.frontiers.entropy_generation,
1398         .terminal_offset = material.receipt.boundary.terminal_offset,
1399         .effect_frontier = material.receipt.basis.frontiers.effect,
1400         .block_root = material.receipt.block_root.digest,
1401         .input_frontier = material.receipt.basis.frontiers.input,
1402         .terminal_input_offset = material.receipt.basis.frontiers.terminal_input_offset,
1403         .restart = .{
1404             .root_generation = root_generation,
1405             .counter = material.receipt.k0.counter,
1406             .semantic_frontier = material.receipt.boundary.semantic_frontier,
1407         },
1408     };
1409 }
1410 
1411 fn validateRestoreMaterial(
1412     material: checkpoint.Material,
1413 ) OwnerError!u32 {
1414     _ = std.math.add(
1415         u64,
1416         material.receipt.boundary.terminal_offset,
1417         os.k0.ready_prompt.len,
1418     ) catch return error.StateCapacityExceeded;
1419     return std.math.cast(
1420         u32,
1421         material.receipt.block_root.generation,
1422     ) orelse return error.StateCapacityExceeded;
1423 }
1424 
1425 fn restoreReady(
1426     storage: *Storage,
1427     ram: []align(layout.page_bytes) u8,
1428     selected: BackendKind,
1429 ) RestoreResult {
1430     const owner = ownerState(storage);
1431     owner.session_identity = claimSessionIdentity();
1432     owner.ram_address = @intFromPtr(ram.ptr);
1433     const memory = core.memory.Access.initLinear(ram);
1434     owner.memory_identity = memory.identity();
1435     owner.memory_kind = .linear;
1436     owner.phase = .booting;
1437     owner.active_backend = selected;
1438     return .{ .ready = .{
1439         .storage = storage,
1440         .ram = ram,
1441         .memory = memory,
1442         .session_identity = owner.session_identity,
1443     } };
1444 }
1445 
1446 fn restoreSharedReady(
1447     storage: *Storage,
1448     memory: core.memory.Access,
1449 ) RestoreResult {
1450     const owner = ownerState(storage);
1451     owner.session_identity = claimSessionIdentity();
1452     owner.ram_address = 0;
1453     owner.memory_identity = memory.identity();
1454     owner.memory_kind = .branch;
1455     owner.phase = .booting;
1456     owner.active_backend = .reference;
1457     return .{ .ready = .{
1458         .storage = storage,
1459         .ram = owner.branch.storage.pages[0..0],
1460         .memory = memory,
1461         .session_identity = owner.session_identity,
1462     } };
1463 }
1464 
1465 fn restoreUnavailable(
1466     storage: *Storage,
1467     receipt: backend.Unavailable,
1468 ) RestoreResult {
1469     ownerState(storage).manifest_bytes = 0;
1470     ownerState(storage).active_backend = .none;
1471     return .{ .unavailable = .{
1472         .availability = receipt.availability,
1473         .stage = receipt.stage,
1474         .code = receipt.code,
1475     } };
1476 }
1477 
1478 fn checkpointMaterial(
1479     owner: *const OwnerState,
1480     receipt_value: types.QuiescenceReceipt,
1481 ) quiescence_receipt.Error!checkpoint.Material {
1482     return .{
1483         .profile = owner.profile_fingerprint,
1484         .receipt = try quiescence_receipt.projectSemantic(receipt_value),
1485         .cpu = owner.initial,
1486         .immutable_image = owner.immutable_image,
1487     };
1488 }
1489 
1490 fn initializeProtocol(
1491     owner: *OwnerState,
1492     input: types.Input,
1493     contract: profile.ContractFingerprint,
1494     profile_fingerprint: profile.ProfileFingerprint,
1495     image_digest: os.abi.Digest,
1496 ) OwnerError!void {
1497     _ = std.math.add(u64, input.terminal_offset, os.k0.ready_prompt.len) catch
1498         return error.StateCapacityExceeded;
1499     owner.contract = contract;
1500     owner.profile_fingerprint = profile_fingerprint;
1501     owner.execution_fingerprint = input.expected_execution_fingerprint;
1502     owner.fence = input.fence;
1503     owner.image_digest = image_digest;
1504     owner.source_root = input.source_root;
1505     owner.frontiers = inputBasis(input, contract).frontiers;
1506     owner.outstanding_effect = input.outstanding_effect;
1507     owner.block_root = input.block_root;
1508     owner.terminal_offset = input.terminal_offset;
1509     owner.semantic_frontier = 0;
1510     owner.root_generation = os.k0.cold_root_generation;
1511     owner.terminal_count = 0;
1512     owner.activation_stage = .ready;
1513     owner.pending = null;
1514     owner.quiescence_receipt = null;
1515 }
1516 
1517 fn inputBasis(
1518     input: types.Input,
1519     contract: profile.ContractFingerprint,
1520 ) input_admission.Basis {
1521     return .{
1522         .contract = contract,
1523         .source_root = input.source_root,
1524         .frontiers = .{
1525             .input = input.input_frontier,
1526             .terminal_input_offset = input.terminal_input_offset,
1527             .virtual_time_tick = input.initial_time_tick,
1528             .entropy_generation = input.entropy_generation,
1529             .effect = input.effect_frontier,
1530         },
1531         .outstanding_effect = input.outstanding_effect,
1532     };
1533 }
1534 
1535 fn bootFrame(
1536     input: types.Input,
1537     contract: profile.ContractFingerprint,
1538     image_digest: os.abi.Digest,
1539 ) os.abi.BootFrame {
1540     return .{
1541         .fence = input.fence,
1542         .contract_digest = contract.digest,
1543         .image_digest = image_digest,
1544         .ram_bytes = layout.ram_bytes,
1545         .request_ring_address = layout.request_ring_address,
1546         .event_ring_address = layout.event_ring_address,
1547         .initial_time_tick = input.initial_time_tick,
1548         .entropy_generation = input.entropy_generation,
1549         .terminal_offset = input.terminal_offset,
1550         .effect_frontier = input.effect_frontier,
1551         .block_root = input.block_root,
1552         .input_frontier = input.input_frontier,
1553         .terminal_input_offset = input.terminal_input_offset,
1554         .restart = .cold,
1555     };
1556 }
1557 
1558 fn continuationFrame(
1559     owner: *const OwnerState,
1560     fence: os.abi.ActivationFence,
1561 ) os.abi.BootFrame {
1562     return .{
1563         .fence = fence,
1564         .contract_digest = owner.contract.digest,
1565         .image_digest = owner.image_digest,
1566         .ram_bytes = layout.ram_bytes,
1567         .request_ring_address = layout.request_ring_address,
1568         .event_ring_address = layout.event_ring_address,
1569         .initial_time_tick = owner.frontiers.virtual_time_tick,
1570         .entropy_generation = owner.frontiers.entropy_generation,
1571         .terminal_offset = owner.terminal_offset,
1572         .effect_frontier = owner.frontiers.effect,
1573         .block_root = owner.block_root,
1574         .input_frontier = owner.frontiers.input,
1575         .terminal_input_offset = owner.frontiers.terminal_input_offset,
1576         .restart = .{
1577             .root_generation = owner.root_generation,
1578             .counter = owner.terminal_count,
1579             .semantic_frontier = owner.semantic_frontier,
1580         },
1581     };
1582 }
1583 
1584 fn basis(owner: *const OwnerState) input_admission.Basis {
1585     return .{
1586         .contract = owner.contract,
1587         .source_root = owner.source_root,
1588         .frontiers = owner.frontiers,
1589         .outstanding_effect = owner.outstanding_effect,
1590     };
1591 }
1592 
1593 fn takeActivationEvents(
1594     owner: *OwnerState,
1595     memory: core.memory.Access,
1596     output: *types.EventBatch,
1597 ) EventError!void {
1598     const events = try layout.eventRingAccess(memory);
1599     const initial = try os.abi.EventRing.frontiers(events, owner.fence);
1600     if (initial.consumed != 0 or
1601         initial.produced != os.k0.events_per_activation)
1602     {
1603         return error.EventReceiptMismatch;
1604     }
1605     var working = events.*;
1606     var batch: types.EventBatch = .{
1607         .count = os.k0.events_per_activation,
1608         .storage = @splat(@splat(0)),
1609     };
1610     var stage = owner.activation_stage;
1611     var terminal_offset = owner.terminal_offset;
1612     for (0..os.k0.events_per_activation) |index| {
1613         const transaction = try os.abi.EventRing.peek(&working, owner.fence);
1614         const decoded = try os.abi.decodeEvent(&transaction.frame);
1615         try validateActivationEvent(
1616             owner,
1617             &stage,
1618             &terminal_offset,
1619             decoded,
1620         );
1621         batch.storage[index] = transaction.frame;
1622         try os.abi.EventRing.commit(&working, owner.fence, &transaction);
1623     }
1624     const final = try os.abi.EventRing.frontiers(&working, owner.fence);
1625     if (stage != .complete or final.count() != 0) {
1626         return error.EventReceiptMismatch;
1627     }
1628     events.* = working;
1629     owner.terminal_offset = terminal_offset;
1630     owner.activation_stage = stage;
1631     owner.phase = .awaiting_input;
1632     output.* = batch;
1633 }
1634 
1635 fn validateActivationEvent(
1636     owner: *const OwnerState,
1637     stage: *ActivationStage,
1638     terminal_offset: *u64,
1639     decoded: os.abi.DecodedEvent,
1640 ) EventError!void {
1641     stage.* = switch (stage.*) {
1642         .ready => ready: {
1643             if (std.meta.activeTag(decoded.value) != .ready) {
1644                 return error.UnexpectedEvent;
1645             }
1646             const value = decoded.value.ready;
1647             if (!sameDigest(value.image_digest, owner.image_digest) or
1648                 !sameDigest(value.block_root, owner.block_root) or
1649                 value.virtual_time_tick != owner.frontiers.virtual_time_tick or
1650                 value.entropy_generation != owner.frontiers.entropy_generation or
1651                 value.terminal_offset != terminal_offset.* or
1652                 value.effect_frontier != owner.frontiers.effect or
1653                 value.input_frontier != owner.frontiers.input or
1654                 value.terminal_input_offset != owner.frontiers.terminal_input_offset)
1655             {
1656                 return error.EventReceiptMismatch;
1657             }
1658             break :ready .prompt;
1659         },
1660         .prompt => prompt: {
1661             if (std.meta.activeTag(decoded.value) != .terminal_bytes) {
1662                 return error.UnexpectedEvent;
1663             }
1664             const value = decoded.value.terminal_bytes;
1665             if (value.offset != terminal_offset.* or
1666                 !std.mem.eql(u8, value.bytes, os.k0.ready_prompt))
1667             {
1668                 return error.EventReceiptMismatch;
1669             }
1670             terminal_offset.* = std.math.add(
1671                 u64,
1672                 terminal_offset.*,
1673                 os.k0.ready_prompt.len,
1674             ) catch return error.EventReceiptMismatch;
1675             break :prompt .complete;
1676         },
1677         .complete => return error.UnexpectedEvent,
1678     };
1679 }
1680 
1681 fn takeInputEvents(
1682     owner: *OwnerState,
1683     memory: core.memory.Access,
1684     output: *types.EventBatch,
1685 ) EventError!void {
1686     const events = try layout.eventRingAccess(memory);
1687     const requests = try layout.requestRingAccess(memory);
1688     const request_frontiers = try os.abi.RequestRing.frontiers(
1689         requests,
1690         owner.fence,
1691     );
1692     var pending = owner.pending orelse return error.InputUnavailable;
1693     const initial = try os.abi.EventRing.frontiers(events, owner.fence);
1694     const event_count: usize = switch (pending.delivery.admission.record) {
1695         .terminal => os.k0.events_per_terminal_input,
1696         else => os.k0.events_per_nonterminal_input,
1697     };
1698     if (initial.consumed != pending.event_frontiers.consumed or
1699         initial.produced != pending.final_event_sequence or
1700         initial.count() != event_count)
1701     {
1702         return error.EventReceiptMismatch;
1703     }
1704     var working = events.*;
1705     var batch: types.EventBatch = .{
1706         .count = @intCast(event_count),
1707         .storage = @splat(@splat(0)),
1708     };
1709     for (0..event_count) |index| {
1710         const event_frontiers = try os.abi.EventRing.frontiers(
1711             &working,
1712             owner.fence,
1713         );
1714         const transaction = try os.abi.EventRing.peek(&working, owner.fence);
1715         const decoded = try os.abi.decodeEvent(&transaction.frame);
1716         try validateInputEvent(
1717             owner,
1718             &pending,
1719             decoded,
1720             request_frontiers,
1721             event_frontiers,
1722         );
1723         batch.storage[index] = transaction.frame;
1724         try os.abi.EventRing.commit(&working, owner.fence, &transaction);
1725     }
1726     const final = try os.abi.EventRing.frontiers(&working, owner.fence);
1727     if (pending.stage != .complete or final.count() != 0) {
1728         return error.EventReceiptMismatch;
1729     }
1730     pending.event_transcript_digest = quiescence_receipt.transcriptDigest(&batch);
1731     pending.semantic_transcript_digest = try quiescence_receipt.semanticTranscriptDigest(
1732         &batch,
1733     );
1734     events.* = working;
1735     owner.pending = pending;
1736     owner.phase = .awaiting_acknowledgement;
1737     output.* = batch;
1738 }
1739 
1740 fn validateInputEvent(
1741     owner: *const OwnerState,
1742     pending: *Pending,
1743     decoded: os.abi.DecodedEvent,
1744     request_frontiers: os.abi.ring.Frontiers,
1745     event_frontiers: os.abi.ring.Frontiers,
1746 ) EventError!void {
1747     try validateEventSequence(pending.*, decoded.header.sequence);
1748     switch (pending.stage) {
1749         .semantic => {
1750             try validateSemantic(
1751                 owner,
1752                 &pending.delivery.admission,
1753                 decoded,
1754             );
1755             pending.stage = switch (pending.delivery.admission.record) {
1756                 .terminal => .terminal,
1757                 else => .block_root,
1758             };
1759         },
1760         .terminal => {
1761             if (std.meta.activeTag(decoded.value) != .terminal_bytes or
1762                 std.meta.activeTag(pending.delivery.admission.record) != .terminal)
1763             {
1764                 return error.UnexpectedEvent;
1765             }
1766             const value = decoded.value.terminal_bytes;
1767             if (value.offset != owner.terminal_offset or
1768                 !std.mem.eql(u8, value.bytes, os.k0.incremented_text))
1769             {
1770                 return error.EventReceiptMismatch;
1771             }
1772             pending.stage = .block_root;
1773         },
1774         .block_root => {
1775             if (std.meta.activeTag(decoded.value) != .block_root) {
1776                 return error.UnexpectedEvent;
1777             }
1778             const value = decoded.value.block_root;
1779             const generation = std.math.add(
1780                 u32,
1781                 owner.root_generation,
1782                 1,
1783             ) catch return error.EventReceiptMismatch;
1784             if (value.generation != generation) {
1785                 return error.EventReceiptMismatch;
1786             }
1787             pending.block_root = value;
1788             pending.stage = .quiescence;
1789         },
1790         .quiescence => {
1791             if (std.meta.activeTag(decoded.value) != .quiescent) {
1792                 return error.UnexpectedEvent;
1793             }
1794             if (event_frontiers.produced != pending.final_event_sequence) {
1795                 return error.EventReceiptMismatch;
1796             }
1797             try validateQuiescence(
1798                 owner,
1799                 pending.*,
1800                 decoded.value.quiescent,
1801                 request_frontiers,
1802             );
1803             pending.quiescence = decoded.value.quiescent;
1804             pending.stage = .complete;
1805         },
1806         .complete => return error.UnexpectedEvent,
1807     }
1808 }
1809 
1810 fn validateEventSequence(pending: Pending, actual: u64) EventError!void {
1811     if (actual != try expectedEventSequence(pending)) {
1812         return error.EventReceiptMismatch;
1813     }
1814 }
1815 
1816 fn validateSemantic(
1817     owner: *const OwnerState,
1818     value: *const input_admission.Admission,
1819     decoded: os.abi.DecodedEvent,
1820 ) EventError!void {
1821     if (std.meta.activeTag(decoded.value) != .semantic) {
1822         return error.UnexpectedEvent;
1823     }
1824     const semantic = decoded.value.semantic;
1825     const expected: ExpectedSemantic = switch (value.record) {
1826         .terminal => .{
1827             .interface = os.k0.counter_interface,
1828             .event = os.k0.counter_event,
1829             .position = @as(u64, std.math.add(
1830                 u8,
1831                 owner.terminal_count,
1832                 1,
1833             ) catch return error.EventReceiptMismatch),
1834             .bytes = os.k0.semantic_name,
1835         },
1836         .virtual_time => .{
1837             .interface = os.k0.input_interface,
1838             .event = os.k0.time_event,
1839             .position = value.expected.input,
1840             .bytes = os.k0.time_semantic_name,
1841         },
1842         .entropy => .{
1843             .interface = os.k0.input_interface,
1844             .event = os.k0.entropy_event,
1845             .position = value.expected.input,
1846             .bytes = os.k0.entropy_semantic_name,
1847         },
1848         .effect_result => .{
1849             .interface = os.k0.input_interface,
1850             .event = os.k0.effect_event,
1851             .position = value.expected.input,
1852             .bytes = os.k0.effect_semantic_name,
1853         },
1854     };
1855     if (!std.mem.eql(u8, &semantic.interface_id, &expected.interface) or
1856         semantic.event_id != expected.event or
1857         semantic.position != expected.position or
1858         !std.mem.eql(u8, semantic.bytes, expected.bytes))
1859     {
1860         return error.EventReceiptMismatch;
1861     }
1862 }
1863 
1864 fn validateQuiescence(
1865     owner: *const OwnerState,
1866     pending: Pending,
1867     value: os.abi.Quiescence,
1868     request_frontiers: os.abi.ring.Frontiers,
1869 ) EventError!void {
1870     const expected_terminal_offset = switch (pending.delivery.admission.record) {
1871         .terminal => std.math.add(
1872             u64,
1873             owner.terminal_offset,
1874             os.k0.incremented_text.len,
1875         ) catch return error.EventReceiptMismatch,
1876         else => owner.terminal_offset,
1877     };
1878     const expected_semantic_frontier = std.math.add(
1879         u64,
1880         owner.semantic_frontier,
1881         1,
1882     ) catch return error.EventReceiptMismatch;
1883     const expected = pending.delivery.admission.expected;
1884     if (value.request_sequence != pending.request_sequence or
1885         value.semantic_frontier != expected_semantic_frontier or
1886         value.effect_frontier != expected.effect or
1887         value.terminal_offset != expected_terminal_offset or
1888         value.virtual_time_tick != expected.virtual_time_tick or
1889         value.entropy_generation != expected.entropy_generation or
1890         value.request_consumed != pending.request_frontiers.consumed + 1 or
1891         value.request_produced != pending.request_frontiers.produced + 1 or
1892         request_frontiers.consumed != pending.request_frontiers.consumed + 1 or
1893         request_frontiers.produced != pending.request_frontiers.produced + 1 or
1894         value.event_consumed != pending.event_frontiers.consumed or
1895         value.event_produced != pending.final_event_sequence or
1896         value.capability_generation != owner.fence.generation or
1897         value.unresolved_effects != 0 or
1898         value.scheduler != .idle or
1899         !sameDigest(
1900             value.block_root,
1901             (pending.block_root orelse return error.EventReceiptMismatch).digest,
1902         ) or
1903         value.input_frontier != expected.input or
1904         value.terminal_input_offset != expected.terminal_input_offset)
1905     {
1906         return error.EventReceiptMismatch;
1907     }
1908 }
1909 
1910 fn prepareCommit(
1911     owner: *const OwnerState,
1912     pending: Pending,
1913     settled: types.SettledTransport,
1914 ) AcknowledgeError!CommittedTurn {
1915     const terminal = std.meta.activeTag(
1916         pending.delivery.admission.record,
1917     ) == .terminal;
1918     const terminal_offset = if (terminal)
1919         std.math.add(u64, owner.terminal_offset, os.k0.incremented_text.len) catch
1920             return error.StateCapacityExceeded
1921     else
1922         owner.terminal_offset;
1923     const semantic_frontier = std.math.add(
1924         u64,
1925         owner.semantic_frontier,
1926         1,
1927     ) catch return error.StateCapacityExceeded;
1928     const root_generation = std.math.add(
1929         u32,
1930         owner.root_generation,
1931         1,
1932     ) catch return error.StateCapacityExceeded;
1933     const terminal_count = if (terminal)
1934         std.math.add(u8, owner.terminal_count, 1) catch
1935             return error.StateCapacityExceeded
1936     else
1937         owner.terminal_count;
1938     const block_root = pending.block_root orelse
1939         return error.EventReceiptMismatch;
1940     const boundary = pending.quiescence orelse
1941         return error.EventReceiptMismatch;
1942     const next_basis: input_admission.Basis = .{
1943         .contract = owner.contract,
1944         .source_root = pending.delivery.next_source_root,
1945         .frontiers = pending.delivery.admission.expected,
1946         .outstanding_effect = pending.delivery.admission.expected_outstanding_effect,
1947     };
1948     return .{
1949         .basis = next_basis,
1950         .block_root = block_root,
1951         .terminal_offset = terminal_offset,
1952         .semantic_frontier = semantic_frontier,
1953         .root_generation = root_generation,
1954         .terminal_count = terminal_count,
1955         .receipt = try quiescence_receipt.issue(.{
1956             .fence = owner.fence,
1957             .delivery = pending.delivery.receipt,
1958             .admission_receipt = pending.delivery.admission.receipt,
1959             .basis = next_basis,
1960             .image_digest = owner.image_digest,
1961             .execution_fingerprint = owner.execution_fingerprint,
1962             .block_root = block_root,
1963             .boundary = boundary,
1964             .settled = settled,
1965             .k0 = .{ .counter = terminal_count },
1966             .event_transcript_digest = pending.event_transcript_digest,
1967             .semantic_transcript_digest = pending.semantic_transcript_digest,
1968         }),
1969     };
1970 }
1971 
1972 fn settledRings(
1973     owner: *const OwnerState,
1974     memory: core.memory.Access,
1975     pending: Pending,
1976 ) AcknowledgeError!types.SettledTransport {
1977     const requests = try os.abi.RequestRing.frontiers(
1978         try layout.requestRingAccess(memory),
1979         owner.fence,
1980     );
1981     const events = try os.abi.EventRing.frontiers(
1982         try layout.eventRingAccess(memory),
1983         owner.fence,
1984     );
1985     const request_final = pending.request_frontiers.produced + 1;
1986     if (requests.consumed != request_final or
1987         requests.produced != request_final or
1988         events.consumed != pending.final_event_sequence or
1989         events.produced != pending.final_event_sequence)
1990     {
1991         return error.EventReceiptMismatch;
1992     }
1993     return .{
1994         .request_cursor = request_final,
1995         .event_cursor = pending.final_event_sequence,
1996     };
1997 }
1998 
1999 fn validateReceiptOwner(
2000     owner: *const OwnerState,
2001     value: types.QuiescenceReceipt,
2002 ) quiescence_receipt.Error!void {
2003     if (!os.abi.wire.equalFence(value.fence, owner.fence) or
2004         !std.meta.eql(value.basis, basis(owner)) or
2005         !sameDigest(value.image_digest, owner.image_digest) or
2006         !std.meta.eql(
2007             value.execution_fingerprint,
2008             owner.execution_fingerprint,
2009         ) or
2010         value.block_root.generation != @as(u64, owner.root_generation) or
2011         !sameDigest(value.block_root.digest, owner.block_root) or
2012         value.boundary.semantic_frontier != owner.semantic_frontier or
2013         value.boundary.terminal_offset != owner.terminal_offset or
2014         value.k0.counter != owner.terminal_count)
2015     {
2016         return error.InvalidQuiescenceReceipt;
2017     }
2018 }
2019 
2020 fn expectedEventSequence(pending: Pending) EventError!u64 {
2021     const offset: u64 = switch (pending.stage) {
2022         .semantic => 1,
2023         .terminal => 2,
2024         .block_root => switch (pending.delivery.admission.record) {
2025             .terminal => 3,
2026             else => 2,
2027         },
2028         .quiescence => switch (pending.delivery.admission.record) {
2029             .terminal => 4,
2030             else => 3,
2031         },
2032         .complete => return error.UnexpectedEvent,
2033     };
2034     return std.math.add(
2035         u64,
2036         pending.event_frontiers.produced,
2037         offset,
2038     ) catch return error.EventReceiptMismatch;
2039 }
2040 
2041 fn sameDigest(a: os.abi.Digest, b: os.abi.Digest) bool {
2042     return std.mem.eql(u8, &a, &b);
2043 }
2044 
2045 const branch_memory_vtable: core.memory.Access.SharedVTable = .{
2046     .read = branchRead,
2047     .write = branchWrite,
2048     .fill = branchFill,
2049     .prepare_write = branchPrepareWrite,
2050     .prepare_pages = branchPreparePages,
2051     .writable_page = branchWritablePage,
2052     .aliases = branchAliases,
2053 };
2054 
2055 fn branchMemory(branch: *checkpoint.roots.branch.Branch) core.memory.Access {
2056     return core.memory.Access.initShared(branch, &branch_memory_vtable);
2057 }
2058 
2059 fn branchRead(
2060     context: *anyopaque,
2061     address: usize,
2062     output: []u8,
2063 ) core.memory.Error!void {
2064     branchState(context).read(address, output) catch |failure|
2065         return mapBranchFailure(failure);
2066 }
2067 
2068 fn branchWrite(
2069     context: *anyopaque,
2070     address: usize,
2071     input: []const u8,
2072 ) core.memory.Error!void {
2073     branchState(context).write(address, input) catch |failure|
2074         return mapBranchFailure(failure);
2075 }
2076 
2077 fn branchFill(
2078     context: *anyopaque,
2079     address: usize,
2080     byte_count: usize,
2081     value: u8,
2082 ) core.memory.Error!void {
2083     branchState(context).fill(address, byte_count, value) catch |failure|
2084         return mapBranchFailure(failure);
2085 }
2086 
2087 fn branchPreparePages(
2088     context: *anyopaque,
2089     pages: []const u16,
2090 ) core.memory.Error!void {
2091     branchState(context).preparePages(pages) catch |failure|
2092         return mapBranchFailure(failure);
2093 }
2094 
2095 fn branchPrepareWrite(
2096     context: *anyopaque,
2097     address: usize,
2098     byte_count: usize,
2099 ) core.memory.Error!void {
2100     branchState(context).prepareWrite(address, byte_count) catch |failure|
2101         return mapBranchFailure(failure);
2102 }
2103 
2104 fn branchWritablePage(
2105     context: *anyopaque,
2106     page_index: u16,
2107 ) core.memory.Error!*align(layout.page_bytes) [layout.page_bytes]u8 {
2108     return branchState(context).writablePage(page_index) catch |failure|
2109         return mapBranchFailure(failure);
2110 }
2111 
2112 fn branchAliases(context: *const anyopaque, bytes: []const u8) bool {
2113     const branch: *const checkpoint.roots.branch.Branch = @ptrCast(@alignCast(context));
2114     return branch.aliases(bytes);
2115 }
2116 
2117 fn branchState(context: *anyopaque) *checkpoint.roots.branch.Branch {
2118     return @ptrCast(@alignCast(context));
2119 }
2120 
2121 fn mapBranchFailure(
2122     failure: checkpoint.roots.branch.Error,
2123 ) core.memory.Error {
2124     return switch (failure) {
2125         error.BranchAddressOverflow => error.MemoryAddressOverflow,
2126         error.BranchOutOfBounds => error.MemoryOutOfBounds,
2127         error.BranchPageCapacityExceeded => error.MemoryCapacityExceeded,
2128         error.DeltaChainCapacityExceeded,
2129         error.DeltaPageCountMismatch,
2130         error.DeltaParentMismatch,
2131         error.ManifestCorrupt,
2132         error.ManifestRootMismatch,
2133         error.PageRootMismatch,
2134         error.RootObjectCorrupt,
2135         => error.MemoryAuthenticationFailed,
2136         else => error.MemoryReadFailed,
2137     };
2138 }
2139 
2140 fn branchStorageAliases(
2141     storage: checkpoint.roots.branch.Storage,
2142     bytes: []const u8,
2143 ) bool {
2144     return image_admission.buffersOverlap(
2145         std.mem.sliceAsBytes(storage.indices),
2146         bytes,
2147     ) or image_admission.buffersOverlap(storage.pages, bytes) or
2148         image_admission.buffersOverlap(
2149             std.mem.asBytes(storage.authenticated),
2150             bytes,
2151         ) or image_admission.buffersOverlap(
2152         std.mem.asBytes(storage.digests),
2153         bytes,
2154     );
2155 }
2156 
2157 fn backendMatches(value: profile.BackendSemantics, selected: BackendKind) bool {
2158     return switch (selected) {
2159         .accelerator => value == .linux_kvm_single_vcpu_v1,
2160         .reference => value == .portable_x86_64_interpreter_v1,
2161         .none => false,
2162     };
2163 }
2164 
2165 fn runBackend(owner: *OwnerState) backend.RunFailure!backend.Exit {
2166     return switch (owner.active_backend) {
2167         .accelerator => accelerator.run(backendState(owner)),
2168         .reference => reference.run(backendState(owner)),
2169         .none => error.Closed,
2170     };
2171 }
2172 
2173 fn completePendingIo(owner: *OwnerState) backend.RunFailure!void {
2174     return switch (owner.active_backend) {
2175         .accelerator => accelerator.completePendingIo(backendState(owner)),
2176         .reference => reference.completePendingIo(backendState(owner)),
2177         .none => error.Closed,
2178     };
2179 }
2180 
2181 fn restartBackend(
2182     owner: *OwnerState,
2183     memory: core.memory.Access,
2184 ) backend.RestartFailure!void {
2185     return switch (owner.active_backend) {
2186         .accelerator => accelerator.restart(
2187             backendState(owner),
2188             memory.linearRam() orelse return error.BackendInvalidState,
2189         ),
2190         .reference => reference.restart(backendState(owner)),
2191         .none => error.Closed,
2192     };
2193 }
2194 
2195 fn applyExit(
2196     owner: *OwnerState,
2197     running_phase: types.RunPhase,
2198     value: types.Exit,
2199 ) RunError!types.Exit {
2200     if (std.meta.activeTag(value) == .fault) {
2201         owner.phase = .failed;
2202         return value;
2203     }
2204     if (std.meta.activeTag(value) != .doorbell) {
2205         owner.phase = .failed;
2206         return value;
2207     }
2208     const code = value.doorbell.code;
2209     switch (running_phase) {
2210         .booting => {
2211             if (code != .ready) {
2212                 owner.phase = .failed;
2213                 return error.UnexpectedDoorbell;
2214             }
2215             owner.phase = .draining_activation;
2216         },
2217         .input_delivered => {
2218             if (code == .guest_fault) {
2219                 owner.phase = .failed;
2220                 return value;
2221             }
2222             if (code != .quiescent) {
2223                 owner.phase = .failed;
2224                 return error.UnexpectedDoorbell;
2225             }
2226             owner.phase = .draining_input;
2227         },
2228         else => unreachable,
2229     }
2230     return value;
2231 }
2232 
2233 fn normalize(raw: backend.Exit) types.Exit {
2234     return switch (raw) {
2235         .io => |io| normalizeIo(io),
2236         .halted => .halted,
2237         .shutdown => .shutdown,
2238         .stutter => unreachable,
2239         .exception => |value| fault(.exception, value.number, value.error_code),
2240         .fail_entry => |value| fault(.entry, value.hardware_reason, value.cpu),
2241         .memory_fault => |value| fault(.memory, value.flags, value.guest_physical_address),
2242         .hypercall => |value| fault(.hypercall, value.number, 0),
2243         .debug => |value| fault(.debug, value.exception, value.program_counter),
2244         .system_event => |value| fault(.system, value.kind, 0),
2245         .mmio => |value| fault(.device, @intFromBool(value.write), value.physical_address),
2246         .unknown => |value| fault(.backend, value.hardware_reason, 0),
2247         .unhandled => |value| fault(.backend, value.reason, 0),
2248         .other => fault(.backend, 0, 0),
2249     };
2250 }
2251 
2252 fn normalizeIo(io: backend.Io) types.Exit {
2253     if (io.direction != .output or
2254         io.port != os.abi.channel.doorbell_port or
2255         io.size != os.abi.channel.doorbell_bytes or
2256         io.count != 1 or
2257         io.data_bytes != os.abi.channel.doorbell_bytes)
2258     {
2259         return fault(.device, io.port, 0);
2260     }
2261     const code = std.enums.fromInt(os.abi.channel.DoorbellCode, io.first_byte) orelse {
2262         return fault(.device, io.first_byte, 0);
2263     };
2264     return .{ .doorbell = .{ .code = code } };
2265 }
2266 
2267 fn fault(kind: types.FaultKind, code: anytype, address: anytype) types.Exit {
2268     return .{ .fault = .{
2269         .kind = kind,
2270         .code = @intCast(code),
2271         .address = @intCast(address),
2272     } };
2273 }
2274 
2275 fn mapInitFailure(failure: backend.InitFailure) InitError {
2276     return failure;
2277 }
2278 
2279 fn mapRunFailure(failure: backend.RunFailure) RunError {
2280     return failure;
2281 }
2282 
2283 fn backendState(owner: *OwnerState) *anyopaque {
2284     return @ptrCast(&owner.backend);
2285 }
2286 
2287 fn ownerState(storage: *Storage) *OwnerState {
2288     return @ptrCast(@alignCast(&storage.bytes));
2289 }
2290 
2291 fn ownsLifecycle(self: *const Instance, owner: *const OwnerState) bool {
2292     return self.session_identity == owner.session_identity and
2293         owner.memory_kind != .none and
2294         self.memory.identity() == owner.memory_identity;
2295 }
2296 
2297 fn claimSessionIdentity() u64 {
2298     var current = next_session_identity.load(.monotonic);
2299     while (true) {
2300         if (current == std.math.maxInt(u64)) {
2301             @panic("machine instance session identity capacity exhausted");
2302         }
2303         if (next_session_identity.cmpxchgWeak(
2304             current,
2305             current + 1,
2306             .monotonic,
2307             .monotonic,
2308         )) |observed| {
2309             current = observed;
2310         } else {
2311             return current;
2312         }
2313     }
2314 }
2315 
2316 comptime {
2317     std.debug.assert(accelerator.storage_alignment > 0);
2318     std.debug.assert(reference.storage_alignment > 0);
2319     std.debug.assert(@alignOf(Storage) == storage_alignment);
2320     std.debug.assert(@sizeOf(Storage) == storage_bytes);
2321     std.debug.assert(@offsetOf(OwnerState, "backend") % accelerator.storage_alignment == 0);
2322     std.debug.assert(@offsetOf(OwnerState, "backend") % reference.storage_alignment == 0);
2323 }