Skip to main content

arkhe_kernel/abi/
caps.rs

1//! Capability bitmask — Mechanism/Policy boundary.
2//!
3//! The kernel *reserves* bit positions for its own invariants
4//! (SYSTEM, ADMIN_UNLOAD, OBSERVER_REGISTER, INTROSPECT). The mapping
5//! of bits to L2 roles (admin, operator, tenant) is policy owned
6//! exclusively by L2. v0.13 reserves four bits; 60 more are free for
7//! future kernel-reserved or L2-defined caps.
8
9use bitflags::bitflags;
10
11bitflags! {
12    /// 64-bit capability mask. Kernel-reserved bits are documented per
13    /// flag; remaining bits are available for L2 to assign semantics.
14    ///
15    /// Stable ABI discipline: adding a kernel-reserved bit is a schema
16    /// change (version bump); repurposing an existing bit is forbidden.
17    #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, serde::Serialize, serde::Deserialize)]
18    pub struct CapabilityMask: u64 {
19        /// Kernel-reserved: System-origin operations. Only `Principal::System`
20        /// paths and privileged operator code should hold this bit.
21        const SYSTEM = 1 << 0;
22
23        /// Kernel-reserved: Force-unload of a module that refuses to drain
24        /// (drain-refcount escape hatch).
25        const ADMIN_UNLOAD = 1 << 1;
26
27        /// Kernel-reserved: Register/remove kernel observers
28        /// (observer lifecycle).
29        const OBSERVER_REGISTER = 1 << 2;
30
31        /// Kernel-reserved: Pull-side introspection access
32        /// (`IntrospectHandle` grant).
33        const INTROSPECT = 1 << 3;
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn caps_combine_via_bitor() {
43        let c = CapabilityMask::SYSTEM | CapabilityMask::ADMIN_UNLOAD;
44        assert!(c.contains(CapabilityMask::SYSTEM));
45        assert!(c.contains(CapabilityMask::ADMIN_UNLOAD));
46        assert!(!c.contains(CapabilityMask::INTROSPECT));
47        assert!(!c.contains(CapabilityMask::OBSERVER_REGISTER));
48    }
49
50    #[test]
51    fn caps_default_is_empty() {
52        let empty = CapabilityMask::default();
53        assert!(empty.is_empty());
54        assert!(!empty.contains(CapabilityMask::SYSTEM));
55    }
56
57    #[test]
58    fn caps_all_reserved_bits_have_distinct_positions() {
59        let all = CapabilityMask::SYSTEM
60            | CapabilityMask::ADMIN_UNLOAD
61            | CapabilityMask::OBSERVER_REGISTER
62            | CapabilityMask::INTROSPECT;
63        assert_eq!(all.bits(), 0b1111);
64    }
65
66    #[test]
67    fn caps_intersection_contains() {
68        let a = CapabilityMask::SYSTEM | CapabilityMask::INTROSPECT;
69        let b = CapabilityMask::INTROSPECT | CapabilityMask::OBSERVER_REGISTER;
70        assert_eq!(a & b, CapabilityMask::INTROSPECT);
71    }
72
73    #[test]
74    fn caps_subset_relationship() {
75        let full = CapabilityMask::SYSTEM | CapabilityMask::ADMIN_UNLOAD;
76        let partial = CapabilityMask::SYSTEM;
77        assert!(full.contains(partial));
78        assert!(!partial.contains(full));
79    }
80}