Skip to main content

javm_cap/
kernel_image.rs

1//! Kernel-assisted Image registry.
2//!
3//! Certain `Cap::Instance` values are recognized by their `image_hash_chain`
4//! as kernel-internal (Gas/Quota unit handles, factories, yield markers). The
5//! kernel short-circuits their state access — no bytecode dispatch. From
6//! userspace they still look like ordinary `Cap::Instance` values.
7//!
8//! This registry lives in `javm-cap` (not the engine crates) so every layer —
9//! the recompiler/interpreter host, the chain genesis, the fuzz harness — agrees
10//! on the well-known `image_hash` for each kernel Image. The hashes are
11//! `Blake2b256(b"kernel:<name>")` placeholders; a later chain-genesis pass can
12//! finalize the canonical encoding (the labels are the source of truth).
13
14use crate::cap::CapHash;
15use crate::hash::{Blake2b256, Hash};
16
17/// Identifies which kernel-assisted Image a given `image_hash_chain` refers to.
18///
19/// The four kernel-assisted Instance variants of the v3 design are
20/// `Gas{meter_key}`, `Quota{quota_key}`, `YieldSender{yield_key}` (the EMIT
21/// right) and `YieldReceiver{Vec<yield_key>}` (the CATCH right), plus the two
22/// kernel-internal tables (`GasMeter`, `StorageQuota`) the unit handles index.
23/// The older per-syscall factory/marker images (set_gas_meter, mint_gas,
24/// yield_catcher, oog_marker, …) are gone: a syscall is now a `host_yield` of a
25/// `YieldSender` carrying a `kernel:*` yield_key, caught by the kernel as the
26/// root YieldReceiver — so those names are yield_keys, not Images.
27#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
28pub enum KernelImage {
29    /// Kernel-internal gas meter table (never in chain hands).
30    GasMeter,
31    /// Kernel-internal storage quota table (never in chain hands).
32    StorageQuota,
33    /// Per-Instance `Gas{meter_key}` unit handle. State: a `meter_key: Key`
34    /// packed into the handle's registers (see
35    /// [`crate::slot::key_to_regs`]).
36    Gas,
37    /// Per-Instance `Quota{quota_key}` unit handle.
38    Quota,
39    /// `YieldSender{yield_key}` — the EMIT right for a yield_key. State: the
40    /// `yield_key: Key` packed into the handle's registers.
41    YieldSender,
42    /// `YieldReceiver{Vec<yield_key>}` — the CATCH right: the set of yield_keys
43    /// an Instance catches. State (a serialized `Set<Key>`) lives in the
44    /// handle's `mem` DataCap; the kernel short-circuits it during routing.
45    YieldReceiver,
46    /// Per-Instance `File{file_id}` handle.
47    File,
48    /// Per-Instance HostOpen handle.
49    HostOpen,
50    /// Per-Instance HostSave handle.
51    HostSave,
52}
53
54/// All kernel Images, for registry iteration.
55pub const ALL_KERNEL_IMAGES: [KernelImage; 9] = [
56    KernelImage::GasMeter,
57    KernelImage::StorageQuota,
58    KernelImage::Gas,
59    KernelImage::Quota,
60    KernelImage::YieldSender,
61    KernelImage::YieldReceiver,
62    KernelImage::File,
63    KernelImage::HostOpen,
64    KernelImage::HostSave,
65];
66
67const fn const_kernel_image_label(kind: KernelImage) -> &'static [u8] {
68    match kind {
69        KernelImage::GasMeter => b"kernel:gasmeter",
70        KernelImage::StorageQuota => b"kernel:storagequota",
71        KernelImage::Gas => b"kernel:gas",
72        KernelImage::Quota => b"kernel:quota",
73        KernelImage::YieldSender => b"kernel:yieldsender",
74        KernelImage::YieldReceiver => b"kernel:yieldreceiver",
75        KernelImage::File => b"kernel:file",
76        KernelImage::HostOpen => b"kernel:host_open",
77        KernelImage::HostSave => b"kernel:host_save",
78    }
79}
80
81/// The well-known `image_hash` for a kernel-assisted Image.
82pub fn kernel_image_hash(kind: KernelImage) -> CapHash {
83    Blake2b256::hash(const_kernel_image_label(kind))
84}
85
86/// Look up a kernel-assisted Image by its `image_hash_chain`. `None` for a
87/// user Image (the common case). Linear scan over ~15 entries — only called at
88/// Instance entry / yield routing, not on the hot path.
89pub fn recognize_kernel_image(hash: CapHash) -> Option<KernelImage> {
90    ALL_KERNEL_IMAGES
91        .into_iter()
92        .find(|kind| kernel_image_hash(*kind) == hash)
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn hashes_are_deterministic_and_distinct() {
101        for (i, a) in ALL_KERNEL_IMAGES.iter().enumerate() {
102            assert_eq!(kernel_image_hash(*a), kernel_image_hash(*a));
103            for b in &ALL_KERNEL_IMAGES[i + 1..] {
104                assert_ne!(
105                    kernel_image_hash(*a),
106                    kernel_image_hash(*b),
107                    "{a:?} vs {b:?}"
108                );
109            }
110        }
111    }
112
113    #[test]
114    fn recognize_round_trips_and_rejects_unknown() {
115        assert_eq!(
116            recognize_kernel_image(kernel_image_hash(KernelImage::Gas)),
117            Some(KernelImage::Gas)
118        );
119        assert_eq!(
120            recognize_kernel_image(Blake2b256::hash(b"user:image")),
121            None
122        );
123    }
124}