rvf_types/
kernel_binding.rs1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25#[repr(C)]
26pub struct KernelBinding {
27 pub manifest_root_hash: [u8; 32],
29 pub policy_hash: [u8; 32],
31 pub binding_version: u16,
33 pub min_runtime_version: u16,
35 pub _pad0: u32,
37 pub allowed_segment_mask: u64,
39 pub _reserved: [u8; 48],
41}
42
43const _: () = assert!(core::mem::size_of::<KernelBinding>() == 128);
45
46impl KernelBinding {
47 pub fn to_bytes(&self) -> [u8; 128] {
49 let mut buf = [0u8; 128];
50 buf[0x00..0x20].copy_from_slice(&self.manifest_root_hash);
51 buf[0x20..0x40].copy_from_slice(&self.policy_hash);
52 buf[0x40..0x42].copy_from_slice(&self.binding_version.to_le_bytes());
53 buf[0x42..0x44].copy_from_slice(&self.min_runtime_version.to_le_bytes());
54 buf[0x44..0x48].copy_from_slice(&self._pad0.to_le_bytes());
55 buf[0x48..0x50].copy_from_slice(&self.allowed_segment_mask.to_le_bytes());
56 buf[0x50..0x80].copy_from_slice(&self._reserved);
57 buf
58 }
59
60 pub fn from_bytes(data: &[u8; 128]) -> Self {
65 Self {
66 manifest_root_hash: {
67 let mut h = [0u8; 32];
68 h.copy_from_slice(&data[0x00..0x20]);
69 h
70 },
71 policy_hash: {
72 let mut h = [0u8; 32];
73 h.copy_from_slice(&data[0x20..0x40]);
74 h
75 },
76 binding_version: u16::from_le_bytes([data[0x40], data[0x41]]),
77 min_runtime_version: u16::from_le_bytes([data[0x42], data[0x43]]),
78 _pad0: u32::from_le_bytes([data[0x44], data[0x45], data[0x46], data[0x47]]),
79 allowed_segment_mask: u64::from_le_bytes([
80 data[0x48], data[0x49], data[0x4A], data[0x4B],
81 data[0x4C], data[0x4D], data[0x4E], data[0x4F],
82 ]),
83 _reserved: {
84 let mut r = [0u8; 48];
85 r.copy_from_slice(&data[0x50..0x80]);
86 r
87 },
88 }
89 }
90
91 pub fn from_bytes_validated(data: &[u8; 128]) -> Result<Self, &'static str> {
98 let binding = Self::from_bytes(data);
99 if binding.binding_version == 0 {
100 return Err("binding_version must be > 0");
101 }
102 if binding._pad0 != 0 {
103 return Err("_pad0 must be zero");
104 }
105 if binding._reserved.iter().any(|&b| b != 0) {
106 return Err("_reserved must be all zeros");
107 }
108 Ok(binding)
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 fn sample_binding() -> KernelBinding {
117 KernelBinding {
118 manifest_root_hash: [0xAA; 32],
119 policy_hash: [0xBB; 32],
120 binding_version: 1,
121 min_runtime_version: 0,
122 _pad0: 0,
123 allowed_segment_mask: 0,
124 _reserved: [0; 48],
125 }
126 }
127
128 #[test]
129 fn binding_size_is_128() {
130 assert_eq!(core::mem::size_of::<KernelBinding>(), 128);
131 }
132
133 #[test]
134 fn round_trip_serialization() {
135 let original = sample_binding();
136 let bytes = original.to_bytes();
137 let decoded = KernelBinding::from_bytes(&bytes);
138
139 assert_eq!(decoded.manifest_root_hash, [0xAA; 32]);
140 assert_eq!(decoded.policy_hash, [0xBB; 32]);
141 assert_eq!(decoded.binding_version, 1);
142 assert_eq!(decoded.min_runtime_version, 0);
143 assert_eq!(decoded._pad0, 0);
144 assert_eq!(decoded.allowed_segment_mask, 0);
145 assert_eq!(decoded._reserved, [0; 48]);
146 }
147
148 #[test]
149 fn round_trip_with_fields() {
150 let binding = KernelBinding {
151 manifest_root_hash: [0x11; 32],
152 policy_hash: [0x22; 32],
153 binding_version: 2,
154 min_runtime_version: 3,
155 _pad0: 0,
156 allowed_segment_mask: 0x00FF_FFFF,
157 _reserved: [0; 48],
158 };
159 let bytes = binding.to_bytes();
160 let decoded = KernelBinding::from_bytes(&bytes);
161 assert_eq!(decoded.binding_version, 2);
162 assert_eq!(decoded.min_runtime_version, 3);
163 assert_eq!(decoded.allowed_segment_mask, 0x00FF_FFFF);
164 }
165
166 #[test]
167 fn field_offsets() {
168 let b = sample_binding();
169 let base = &b as *const _ as usize;
170
171 assert_eq!(&b.manifest_root_hash as *const _ as usize - base, 0x00);
172 assert_eq!(&b.policy_hash as *const _ as usize - base, 0x20);
173 assert_eq!(&b.binding_version as *const _ as usize - base, 0x40);
174 assert_eq!(&b.min_runtime_version as *const _ as usize - base, 0x42);
175 assert_eq!(&b._pad0 as *const _ as usize - base, 0x44);
176 assert_eq!(&b.allowed_segment_mask as *const _ as usize - base, 0x48);
177 assert_eq!(&b._reserved as *const _ as usize - base, 0x50);
178 }
179
180 #[test]
181 fn reserved_must_be_zero_in_new_bindings() {
182 let b = sample_binding();
183 assert!(b._reserved.iter().all(|&x| x == 0));
184 assert_eq!(b._pad0, 0);
185 }
186}