Skip to main content

ruvix_boot/
mount.rs

1//! RVF package mounting (rvf_mount syscall implementation).
2//!
3//! The rvf_mount operation:
4//! 1. Verifies package signature
5//! 2. Parses manifest
6//! 3. Creates regions per memory schema
7//! 4. Mounts WASM components
8//! 5. Distributes capabilities per manifest
9//! 6. Connects queues per wiring
10//! 7. Spawns initial tasks per WIT entry points
11
12use crate::manifest::RvfManifest;
13use crate::signature::SignatureVerifier;
14use ruvix_types::{
15    KernelError, RvfMountHandle, RvfVerifyStatus, RegionHandle,
16    TaskHandle, TaskPriority,
17};
18
19#[cfg(feature = "alloc")]
20use alloc::vec::Vec;
21
22/// Configuration for RVF mount operations.
23#[derive(Debug, Clone)]
24pub struct MountConfig {
25    /// Maximum components per package.
26    pub max_components: usize,
27
28    /// Maximum regions per package.
29    pub max_regions: usize,
30
31    /// Maximum queues per package.
32    pub max_queues: usize,
33
34    /// Default task priority for spawned tasks.
35    pub default_task_priority: TaskPriority,
36
37    /// Whether to verify signatures (should always be true in production).
38    pub verify_signatures: bool,
39}
40
41impl Default for MountConfig {
42    fn default() -> Self {
43        Self {
44            max_components: 256,
45            max_regions: 256,
46            max_queues: 1024,
47            default_task_priority: TaskPriority::Normal,
48            verify_signatures: true,
49        }
50    }
51}
52
53/// Result of an RVF mount operation.
54#[derive(Debug, Clone)]
55pub struct MountResult {
56    /// Handle to the mounted RVF package.
57    pub mount_handle: RvfMountHandle,
58
59    /// Verification status.
60    pub verify_status: RvfVerifyStatus,
61
62    /// Number of components mounted.
63    pub components_mounted: usize,
64
65    /// Number of regions created.
66    pub regions_created: usize,
67
68    /// Number of queues connected.
69    pub queues_connected: usize,
70
71    /// Number of tasks spawned.
72    pub tasks_spawned: usize,
73
74    /// Created region handles.
75    pub region_handles: [Option<RegionHandle>; 256],
76    /// Number of region handles in the array.
77    pub region_handle_count: usize,
78
79    /// Spawned task handles.
80    pub task_handles: [Option<TaskHandle>; 64],
81    /// Number of task handles in the array.
82    pub task_handle_count: usize,
83}
84
85impl MountResult {
86    /// Creates a successful mount result.
87    #[must_use]
88    pub fn success(mount_handle: RvfMountHandle) -> Self {
89        Self {
90            mount_handle,
91            verify_status: RvfVerifyStatus::SignatureValid,
92            components_mounted: 0,
93            regions_created: 0,
94            queues_connected: 0,
95            tasks_spawned: 0,
96            region_handles: [None; 256],
97            region_handle_count: 0,
98            task_handles: [None; 64],
99            task_handle_count: 0,
100        }
101    }
102
103    /// Creates a failed mount result.
104    #[must_use]
105    pub fn failure(status: RvfVerifyStatus) -> Self {
106        Self {
107            mount_handle: RvfMountHandle::null(),
108            verify_status: status,
109            components_mounted: 0,
110            regions_created: 0,
111            queues_connected: 0,
112            tasks_spawned: 0,
113            region_handles: [None; 256],
114            region_handle_count: 0,
115            task_handles: [None; 64],
116            task_handle_count: 0,
117        }
118    }
119
120    /// Adds a created region handle.
121    pub fn add_region(&mut self, handle: RegionHandle) -> Result<(), KernelError> {
122        if self.region_handle_count >= 256 {
123            return Err(KernelError::LimitExceeded);
124        }
125        self.region_handles[self.region_handle_count] = Some(handle);
126        self.region_handle_count += 1;
127        self.regions_created += 1;
128        Ok(())
129    }
130
131    /// Adds a spawned task handle.
132    pub fn add_task(&mut self, handle: TaskHandle) -> Result<(), KernelError> {
133        if self.task_handle_count >= 64 {
134            return Err(KernelError::LimitExceeded);
135        }
136        self.task_handles[self.task_handle_count] = Some(handle);
137        self.task_handle_count += 1;
138        self.tasks_spawned += 1;
139        Ok(())
140    }
141}
142
143/// RVF mount operation handler.
144///
145/// Implements the rvf_mount syscall per ADR-087.
146pub struct RvfMount {
147    /// Configuration.
148    config: MountConfig,
149
150    /// Signature verifier.
151    verifier: Option<SignatureVerifier>,
152
153    /// Next mount handle ID.
154    next_mount_id: u32,
155
156    /// Next region handle ID.
157    next_region_id: u32,
158
159    /// Next task handle ID.
160    next_task_id: u32,
161}
162
163impl RvfMount {
164    /// Creates a new RVF mount handler.
165    #[must_use]
166    pub fn new(config: MountConfig) -> Self {
167        Self {
168            config,
169            verifier: None,
170            next_mount_id: 1,
171            next_region_id: 0x1000,
172            next_task_id: 0x100,
173        }
174    }
175
176    /// Sets the signature verification public key.
177    pub fn set_public_key(&mut self, public_key: &[u8]) {
178        self.verifier = Some(SignatureVerifier::new(public_key));
179    }
180
181    /// Mounts an RVF package.
182    ///
183    /// # Steps
184    ///
185    /// 1. Verify package signature
186    /// 2. Parse manifest
187    /// 3. Create regions per memory schema
188    /// 4. Mount WASM components
189    /// 5. Distribute capabilities per manifest
190    /// 6. Connect queues per wiring
191    /// 7. Spawn initial tasks per WIT entry points
192    ///
193    /// # Errors
194    ///
195    /// - `InvalidSignature` if signature verification fails
196    /// - `InvalidManifest` if manifest parsing fails
197    /// - `OutOfMemory` if region creation fails
198    /// - `LimitExceeded` if max components/regions/queues exceeded
199    pub fn mount(
200        &mut self,
201        manifest_bytes: &[u8],
202        signature: &[u8],
203        _package_bytes: &[u8], // WASM components - not used in Phase A
204    ) -> Result<MountResult, KernelError> {
205        // Step 1: Verify signature
206        if self.config.verify_signatures {
207            self.verify_signature(manifest_bytes, signature)?;
208        }
209
210        // Step 2: Parse manifest
211        let manifest = RvfManifest::parse(manifest_bytes)?;
212
213        // Validate manifest
214        if !manifest.validate() {
215            return Ok(MountResult::failure(RvfVerifyStatus::ManifestInvalid));
216        }
217
218        // Check limits
219        if manifest.component_graph.component_count() > self.config.max_components {
220            return Err(KernelError::LimitExceeded);
221        }
222        if manifest.memory_schema.region_count() > self.config.max_regions {
223            return Err(KernelError::LimitExceeded);
224        }
225        if manifest.component_graph.wiring_count() > self.config.max_queues {
226            return Err(KernelError::LimitExceeded);
227        }
228
229        // Allocate mount handle
230        let mount_handle = RvfMountHandle::new(self.next_mount_id, 0);
231        self.next_mount_id += 1;
232
233        let mut result = MountResult::success(mount_handle);
234
235        // Step 3: Create regions
236        self.create_regions(&manifest, &mut result)?;
237
238        // Step 4: Mount components (Phase A: mock)
239        result.components_mounted = manifest.component_graph.component_count();
240
241        // Step 5: Distribute capabilities (Phase A: mock)
242        // In production, this creates actual capability entries
243
244        // Step 6: Connect queues (Phase A: mock)
245        result.queues_connected = manifest.component_graph.wiring_count();
246
247        // Step 7: Spawn tasks
248        self.spawn_initial_tasks(&manifest, &mut result)?;
249
250        Ok(result)
251    }
252
253    fn verify_signature(&self, manifest: &[u8], signature: &[u8]) -> Result<(), KernelError> {
254        match &self.verifier {
255            Some(verifier) => {
256                let result = verifier.verify(manifest, signature);
257                if result.is_valid() {
258                    Ok(())
259                } else {
260                    Err(KernelError::InvalidSignature)
261                }
262            }
263            None => {
264                // No verifier configured - require signature verification
265                Err(KernelError::InternalError)
266            }
267        }
268    }
269
270    fn create_regions(
271        &mut self,
272        manifest: &RvfManifest,
273        result: &mut MountResult,
274    ) -> Result<(), KernelError> {
275        let region_count = manifest.memory_schema.region_count();
276
277        for _ in 0..region_count {
278            let handle = RegionHandle::new(self.next_region_id, 0);
279            self.next_region_id += 1;
280            result.add_region(handle)?;
281        }
282
283        Ok(())
284    }
285
286    fn spawn_initial_tasks(
287        &mut self,
288        manifest: &RvfManifest,
289        result: &mut MountResult,
290    ) -> Result<(), KernelError> {
291        let component_count = manifest.component_graph.component_count();
292
293        // In production, we would check each component's entry point
294        // and spawn a task if it has one. For Phase A, spawn one task
295        // per component with an entry point.
296
297        // Phase A: Spawn one task for the root component
298        if component_count > 0 {
299            let handle = TaskHandle::new(self.next_task_id, 0);
300            self.next_task_id += 1;
301            result.add_task(handle)?;
302        }
303
304        Ok(())
305    }
306
307    /// Unmounts an RVF package.
308    ///
309    /// # Steps
310    ///
311    /// 1. Stop all tasks
312    /// 2. Disconnect queues
313    /// 3. Revoke capabilities
314    /// 4. Destroy regions
315    /// 5. Free mount handle
316    pub fn unmount(&mut self, _handle: RvfMountHandle) -> Result<(), KernelError> {
317        // Phase A: Mock implementation
318        // In production, this would perform the full unmount sequence
319        Ok(())
320    }
321}
322
323impl Default for RvfMount {
324    fn default() -> Self {
325        Self::new(MountConfig::default())
326    }
327}
328
329#[cfg(test)]
330mod tests {
331    use super::*;
332    use crate::signature::SIGNATURE_SIZE;
333
334    fn create_test_manifest() -> Vec<u8> {
335        let mut manifest = vec![0u8; 100];
336        manifest[0..4].copy_from_slice(b"RVF1");
337        manifest[4..6].copy_from_slice(&1u16.to_le_bytes()); // major
338        manifest[6..8].copy_from_slice(&0u16.to_le_bytes()); // minor
339        manifest
340    }
341
342    fn create_test_signature(manifest: &[u8]) -> Vec<u8> {
343        use sha2::{Sha256, Digest};
344
345        let mut sig = vec![0u8; SIGNATURE_SIZE];
346        sig[0..4].copy_from_slice(b"TEST");
347
348        let mut hasher = Sha256::new();
349        hasher.update(manifest);
350        let hash = hasher.finalize();
351        sig[4..36].copy_from_slice(&hash);
352
353        sig
354    }
355
356    #[test]
357    fn test_mount_config_default() {
358        let config = MountConfig::default();
359        assert_eq!(config.max_components, 256);
360        assert_eq!(config.max_regions, 256);
361        assert!(config.verify_signatures);
362    }
363
364    #[test]
365    fn test_mount_result_success() {
366        let handle = RvfMountHandle::new(1, 0);
367        let result = MountResult::success(handle);
368
369        assert_eq!(result.verify_status, RvfVerifyStatus::SignatureValid);
370        assert!(!result.mount_handle.is_null());
371    }
372
373    #[test]
374    fn test_mount_result_add_region() {
375        let mut result = MountResult::success(RvfMountHandle::new(1, 0));
376
377        result.add_region(RegionHandle::new(1, 0)).unwrap();
378        result.add_region(RegionHandle::new(2, 0)).unwrap();
379
380        assert_eq!(result.regions_created, 2);
381        assert_eq!(result.region_handle_count, 2);
382    }
383
384    #[test]
385    fn test_mount_result_add_task() {
386        let mut result = MountResult::success(RvfMountHandle::new(1, 0));
387
388        result.add_task(TaskHandle::new(1, 0)).unwrap();
389
390        assert_eq!(result.tasks_spawned, 1);
391        assert_eq!(result.task_handle_count, 1);
392    }
393
394    #[test]
395    fn test_rvf_mount_basic() {
396        let mut mount = RvfMount::new(MountConfig::default());
397        mount.set_public_key(&[0u8; 1952]); // Test key
398
399        let manifest = create_test_manifest();
400        let signature = create_test_signature(&manifest);
401
402        let result = mount.mount(&manifest, &signature, &[]).unwrap();
403
404        assert_eq!(result.verify_status, RvfVerifyStatus::SignatureValid);
405        assert!(!result.mount_handle.is_null());
406    }
407
408    #[test]
409    fn test_rvf_mount_invalid_signature() {
410        let mut mount = RvfMount::new(MountConfig::default());
411        mount.set_public_key(&[0u8; 1952]);
412
413        let manifest = create_test_manifest();
414        let wrong_manifest = b"wrong manifest";
415        let signature = create_test_signature(wrong_manifest);
416
417        let result = mount.mount(&manifest, &signature, &[]);
418
419        assert!(result.is_err());
420        assert_eq!(result.unwrap_err(), KernelError::InvalidSignature);
421    }
422
423    #[test]
424    fn test_rvf_mount_skip_verification() {
425        let mut config = MountConfig::default();
426        config.verify_signatures = false;
427
428        let mut mount = RvfMount::new(config);
429
430        let manifest = create_test_manifest();
431        let bad_signature = [0u8; 100]; // Wrong size, but we skip verification
432
433        let result = mount.mount(&manifest, &bad_signature, &[]).unwrap();
434
435        assert_eq!(result.verify_status, RvfVerifyStatus::SignatureValid);
436    }
437
438    #[test]
439    fn test_rvf_unmount() {
440        let mut mount = RvfMount::default();
441        let handle = RvfMountHandle::new(1, 0);
442
443        // Should not fail
444        mount.unmount(handle).unwrap();
445    }
446}