# Feature Addition Guide This guide provides a comprehensive walkthrough for adding new features to the rust-kernel project. It covers the entire development process from planning to testing. ## Table of Contents 1. [Planning](#planning) 2. [Implementation](#implementation) 3. [Testing](#testing) 4. [Documentation](#documentation) 5. [Code Review](#code-review) 6. [Common Feature Types](#common-feature-types) --- ## Planning ### 1. Understand the Scope Before starting, consider: - **What problem does this feature solve?** - **Is it aligned with project goals?** - **What are the performance implications?** - **Does it introduce security risks?** - **How complex is the implementation?** ### 2. Check Existing Code Look for similar implementations: ```bash # Search for related code grep -r "similar_feature" src/ # Check if similar functionality exists rg "pattern" src/ ``` ### 3. Design the API Plan your public interfaces: - **Function signatures** - What parameters and return types? - **Error handling** - What can go wrong? - **Thread safety** - Does it need synchronization? - **Resource management** - How are resources cleaned up? ### 4. Choose the Right Location Decide where to place your code: - **New module** - If it's a standalone feature - **Existing module** - If it's an extension - **Architecture-specific** - If it's CPU-dependent - **Driver** - If it's hardware-related --- ## Implementation ### 1. Create the Module Structure #### New Module ```bash # Create module directory mkdir -p src/implementation/kernel/new_feature # Create main module file touch src/implementation/kernel/new_feature/mod.rs # Create implementation files touch src/implementation/kernel/new_feature/lib.rs ``` #### Existing Module Add to existing module structure: ```rust // src/implementation/kernel/new_feature/mod.rs pub mod lib; pub mod utils; ``` ### 2. Implement Core Functionality #### Basic Structure ```rust // src/implementation/kernel/new_feature/lib.rs //! New feature implementation use crate::error::{KernelError, KernelResult}; /// Main feature struct pub struct NewFeature { // Internal state } impl NewFeature { /// Creates a new instance pub fn new() -> Self { Self { // Initialize state } } /// Main feature operation pub fn perform_operation(&self, input: Input) -> KernelResult { // Implementation Ok(output) } } /// Error type for this feature #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NewFeatureError { InvalidInput, OperationFailed, ResourceUnavailable, } impl From for KernelError { fn from(err: NewFeatureError) -> Self { match err { NewFeatureError::InvalidInput => KernelError::InvalidArgument, NewFeatureError::OperationFailed => KernelError::Unknown, NewFeatureError::ResourceUnavailable => KernelError::OutOfMemory, } } } ``` ### 3. Add Error Handling #### Unified Error Handling ```rust use crate::error::KernelError; impl NewFeature { pub fn perform_operation(&self, input: Input) -> KernelResult { if input.is_invalid() { return Err(KernelError::InvalidArgument); } // Operation that might fail let result = some_operation()?; Ok(result) } } ``` #### Custom Error Types If needed, create custom error types that map to `KernelError`: ```rust #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NewFeatureError { InvalidInput, OperationFailed, } impl From for KernelError { fn from(err: NewFeatureError) -> Self { match err { NewFeatureError::InvalidInput => KernelError::InvalidArgument, NewFeatureError::OperationFailed => KernelError::Unknown, } } } ``` ### 4. Implement Thread Safety #### Using Spin Locks ```rust use spin::Mutex; static FEATURE_INSTANCE: Mutex> = Mutex::new(None); pub fn get_instance() -> &'static NewFeature { let mut instance = FEATURE_INSTANCE.lock(); if instance.is_none() { *instance = Some(NewFeature::new()); } instance.as_ref().unwrap() } ``` #### Using Once For one-time initialization: ```rust use spin::Once; static INIT: Once> = Once::new(); pub fn get_instance() -> KernelResult<&'static NewFeature> { INIT.call_once(|| { Ok(NewFeature::new()) }) } ``` ### 5. Add Initialization #### Module Initialization ```rust // src/implementation/kernel/new_feature/init.rs use crate::error::KernelResult; pub fn init() -> KernelResult<()> { // Initialize feature let feature = NewFeature::new(); // Store in global state if needed let mut kernel = crate::kernel::kernel(); kernel.set_new_feature(feature); Ok(()) } ``` #### Integration with Main Kernel Add to main initialization: ```rust // src/implementation/kernel/main.rs mod new_feature; // In init_submodules() halt_on_err(new_feature::init(), "New feature init failed"); ``` --- ## Testing ### 1. Create Test Module ```rust // src/implementation/kernel/new_feature/tests.rs use crate::error::KernelResult; use super::NewFeature; #[test_case] fn test_new_feature_creation() -> KernelResult<()> { let feature = NewFeature::new(); assert!(feature.is_valid()); Ok(()) } #[test_case] fn test_feature_operation() -> KernelResult<()> { let feature = NewFeature::new(); let input = Input::valid(); let result = feature.perform_operation(input)?; assert_eq!(result, expected_output); Ok(()) } #[test_case] fn test_error_handling() -> KernelResult<()> { let feature = NewFeature::new(); let input = Input::invalid(); match feature.perform_operation(input) { Err(KernelError::InvalidArgument) -> Ok(()), _ -> Err(KernelError::Unknown), } } ``` ### 2. Add to Test Runner ```rust // src/implementation/kernel/tests/mod.rs mod new_feature; pub fn run_tests() -> KernelResult<()> { new_feature::run_tests()?; Ok(()) } ``` ### 3. Test Edge Cases Test boundary conditions: ```rust #[test_case] fn test_edge_cases() -> KernelResult<()> { let feature = NewFeature::new(); // Test with minimum valid input let min_input = Input::min(); feature.perform_operation(min_input)?; // Test with maximum valid input let max_input = Input::max(); feature.perform_operation(max_input)?; // Test with empty input let empty_input = Input::empty(); feature.perform_operation(empty_input)?; Ok(()) } ``` --- ## Documentation ### 1. Module Documentation ```rust //! New Feature Module //! //! This module provides functionality for [feature description]. //! It is used for [use cases] and integrates with [related systems]. //! //! ## Features //! - [Feature 1 description] //! - [Feature 2 description] //! - [Feature 3 description] ``` ### 2. Public API Documentation ```rust /// Main feature struct /// /// This struct provides the core functionality for the new feature. /// It manages [what it manages] and provides [what it provides]. /// /// # Examples /// /// ``` /// let feature = NewFeature::new(); /// let result = feature.perform_operation(input); /// ``` pub struct NewFeature { // Fields } impl NewFeature { /// Creates a new instance /// /// # Arguments /// /// * `param` - [parameter description] /// /// # Returns /// /// A new `NewFeature` instance /// /// # Errors /// /// Returns `KernelError::InvalidState` if [condition] pub fn new() -> Self { Self { // Implementation } } /// Performs the main operation /// /// This is the primary function that users will call. /// It [what it does] and returns [what it returns]. /// /// # Arguments /// /// * `input` - [input description] /// /// # Returns /// /// The result of the operation /// /// # Errors /// /// Returns `KernelError::InvalidArgument` if [condition] /// Returns `KernelError::OperationFailed` if [condition] pub fn perform_operation(&self, input: Input) -> KernelResult { // Implementation Ok(output) } } ``` ### 3. Inline Documentation ```rust // Good: Clear explanation of complex logic // SAFETY: We can dereference this pointer because it was allocated by our allocator // and we have exclusive access to it during this operation. let ptr = unsafe { &mut *allocated_ptr }; ``` --- ## Code Review ### Before Submitting 1. **Build passes** - `make build` should succeed 2. **Tests pass** - `make run-tests` should pass 3. **No warnings** - Fix all compiler warnings 4. **Documentation complete** - All public APIs documented 5. **Error handling complete** - All error cases handled 6. **Thread safety verified** - All shared state protected ### Common Review Issues #### Memory Safety - **Unsafe blocks** - Are they necessary and documented? - **Pointer usage** - Are raw pointers properly managed? - **Lifetime issues** - Are references valid for their entire use? #### Error Handling - **Missing error cases** - Are all failure modes handled? - **Error propagation** - Are errors properly propagated with `?`? - **Error context** - Do errors provide useful debugging information? --- ## Common Feature Types ### 1. New System Call #### Steps 1. Add syscall number to `syscall/numbers.rs` 2. Implement handler in `syscall/handler.rs` 3. Add to syscall dispatch table 4. Write tests #### Example ```rust // syscall/numbers.rs #[repr(u32)] pub enum SyscallNumber { // ... existing calls MySyscall = 60, } // syscall/handler.rs pub fn handle_syscall(num: u32, args: &[usize; 6]) -> SyscallResult { match num { // ... existing handlers SyscallNumber::MySyscall as u32 => sys_my_syscall(args), _ -> Err(KernelError::InvalidSyscall), } } ``` ### 2. New Filesystem #### Steps 1. Create module in `vfs/` directory 2. Implement `Inode` trait 3. Add to VFS mount system 4. Write tests #### Example ```rust // vfs/myfs.rs pub struct MyFsInode { // Internal state } impl Inode for MyFsInode { fn read(&self, offset: u64, buffer: &mut [u8]) -> KernelResult { // Implementation Ok(bytes_read) } // Other trait methods } ``` ### 3. Hardware Driver #### Steps 1. Create driver in `drivers/` directory 2. Implement initialization in `drivers/init.rs` 3. Add to driver initialization sequence 4. Write tests #### Example ```rust // drivers/my_device.rs pub struct MyDevice { base_addr: usize, } impl MyDevice { pub fn new(base_addr: usize) -> Self { Self { base_addr } } pub fn read(&self, reg: u8) -> u8 { // Memory-mapped I/O unsafe { &*(self.base_addr as *const u8).add(reg as usize) } } } ``` ### 4. New Scheduler Algorithm #### Steps 1. Create new scheduler in `task/scheduler/` 2. Implement scheduling algorithm 3. Add to scheduler selection 4. Write tests #### Example ```rust // task/scheduler/priority.rs pub struct PriorityScheduler { // Priority queue implementation } impl Scheduler for PriorityScheduler { fn schedule_next(&mut self) -> Option { // Priority-based scheduling self.queue.pop() } // Other scheduler methods } ``` ---