kernel/vm/
manager.rs

1//! Virtual Memory Manager module.
2//! 
3//! This module provides the core functionality for managing virtual memory in the kernel.
4//! It handles address space management, memory mappings, and page table operations.
5//!
6//! # Key Components
7//!
8//! - `VirtualMemoryManager`: Main structure for managing virtual memory mappings and address spaces
9//! - Memory maps: Track mappings between virtual and physical memory areas
10//! - ASID (Address Space ID): Identifies different address spaces
11//!
12//! # Functionality
13//!
14//! The manager enables:
15//! - Creating and tracking virtual to physical memory mappings
16//! - Managing different address spaces via ASIDs
17//! - Searching for memory mappings by virtual address
18//! - Accessing the root page table for the current address space
19//!
20//! # Examples
21//!
22//! ```
23//! let mut manager = VirtualMemoryManager::new();
24//! manager.set_asid(42);
25//! 
26//! // Add a memory mapping
27//! let vma = MemoryArea { start: 0x0, end: 0x1000 };
28//! let pma = MemoryArea { start: 0x80000000, end: 0x80001000 };
29//! let map = VirtualMemoryMap { vmarea: vma, pmarea: pma };
30//! manager.add_memory_map(map);
31//! 
32//! // Search for a memory mapping
33//! if let Some(found_map) = manager.search_memory_map(0x500) {
34//!     // Found the mapping
35//! }
36//!
37
38extern crate alloc;
39use alloc::vec::Vec;
40
41use crate::{arch::vm::{get_page_table, get_root_page_table_idx, mmu::PageTable}, environment::PAGE_SIZE};
42
43use super::vmem::VirtualMemoryMap;
44
45#[derive(Debug, Clone)]
46pub struct VirtualMemoryManager {
47    memmap: Vec<VirtualMemoryMap>,
48    asid: usize,
49}
50
51impl VirtualMemoryManager {
52    /// Creates a new virtual memory manager.
53    /// 
54    /// # Returns
55    /// A new virtual memory manager with default values.
56    pub fn new() -> Self {
57        VirtualMemoryManager {
58            memmap: Vec::new(),
59            asid: 0,
60        }
61    }
62
63    /// Sets the ASID (Address Space ID) for the virtual memory manager.
64    /// 
65    /// # Arguments
66    /// * `asid` - The ASID to set
67    pub fn set_asid(&mut self, asid: usize) {
68        self.asid = asid;
69    }
70
71    /// Returns the ASID (Address Space ID) for the virtual memory manager.
72    /// 
73    /// # Returns
74    /// The ASID for the virtual memory manager.
75    pub fn get_asid(&self) -> usize {
76        self.asid
77    }
78
79    pub fn get_memmap(&self) -> &Vec<VirtualMemoryMap> {
80        &self.memmap
81    }
82
83    /// Adds a memory map to the virtual memory manager.
84    /// 
85    /// # Arguments
86    /// * `map` - The memory map to add
87    /// 
88    /// # Returns
89    /// A result indicating success or failure.
90    /// 
91    pub fn add_memory_map(&mut self, map: VirtualMemoryMap) -> Result<(), &'static str> {
92        // Check if the address and size is aligned
93        if map.vmarea.start % PAGE_SIZE != 0 || map.pmarea.start % PAGE_SIZE != 0 ||
94            map.vmarea.size() % PAGE_SIZE != 0 || map.pmarea.size() % PAGE_SIZE != 0 {
95            return Err("Address or size is not aligned to PAGE_SIZE");
96        }
97
98        self.memmap.push(map);
99        Ok(())
100    }
101
102    /// Returns the memory map at the given index.
103    /// 
104    /// # Arguments
105    /// * `idx` - The index of the memory map to retrieve
106    /// 
107    /// # Returns
108    /// The memory map at the given index, if it exists.
109    pub fn get_memory_map(&self, idx: usize) -> Option<&VirtualMemoryMap> {
110        self.memmap.get(idx)
111    }
112
113    /// Removes the memory map at the given index.
114    /// 
115    /// # Arguments
116    /// * `idx` - The index of the memory map to remove
117    /// 
118    /// # Returns
119    /// The removed memory map, if it exists.
120    pub fn remove_memory_map(&mut self, idx: usize) -> Option<VirtualMemoryMap> {
121        if idx < self.memmap.len() {
122            Some(self.memmap.remove(idx))
123        } else {
124            None
125        }
126    }
127
128    /// Removes all memory maps.
129    /// 
130    /// # Returns
131    /// The removed memory maps.
132    pub fn remove_all_memory_maps(&mut self) -> Vec<VirtualMemoryMap> {
133        let mut removed_maps = Vec::new();
134        while !self.memmap.is_empty() {
135            removed_maps.push(self.memmap.remove(0));
136        }
137        removed_maps
138    }
139
140    /// Restores the memory maps from a given vector.
141    ///
142    /// # Arguments
143    /// * `maps` - The vector of memory maps to restore
144    /// 
145    /// # Returns
146    /// A result indicating success or failure.
147    /// 
148    pub fn restore_memory_maps(&mut self, maps: Vec<VirtualMemoryMap>) -> Result<(), &'static str> {
149        for map in maps {
150            if let Err(e) = self.add_memory_map(map) {
151                return Err(e);
152            }
153        }
154        Ok(())
155    }
156
157    /// Searches for a memory map containing the given virtual address.
158    /// 
159    /// # Arguments
160    /// * `vaddr` - The virtual address to search for
161    /// 
162    /// # Returns
163    /// The memory map containing the given virtual address, if it exists.
164    pub fn search_memory_map(&self, vaddr: usize) -> Option<&VirtualMemoryMap> {
165        let mut ret = None;
166        for map in self.memmap.iter() {
167            if map.vmarea.start <= vaddr && vaddr <= map.vmarea.end {
168                ret = Some(map);
169            }
170        }
171        ret
172    }
173
174    /// Searches for the index of a memory map containing the given virtual address.
175    /// 
176    /// # Arguments
177    /// * `vaddr` - The virtual address to search for
178    /// 
179    /// # Returns
180    /// The index of the memory map containing the given virtual address, if it exists.
181    pub fn search_memory_map_idx(&self, vaddr: usize) -> Option<usize> {
182        let mut ret = None;
183        for (i, map) in self.memmap.iter().enumerate() {
184            if map.vmarea.start <= vaddr && vaddr <= map.vmarea.end {
185                ret = Some(i);
186            }
187        }
188        ret
189    }
190
191    /// Returns the root page table for the current address space.
192    /// 
193    /// # Returns
194    /// The root page table for the current address space, if it exists.
195    pub fn get_root_page_table(&self) -> Option<&mut PageTable> {
196        let idx = get_root_page_table_idx(self.asid);
197        if let Some(root_page_table_idx) = idx {
198            get_page_table(root_page_table_idx)
199        } else {
200            None
201        }
202    }
203
204    /// Translate a virtual address to physical address
205    /// 
206    /// # Arguments
207    /// 
208    /// * `vaddr` - The virtual address to translate
209    /// 
210    /// # Returns
211    /// 
212    /// The translated physical address. Returns None if no mapping exists for the address
213    pub fn translate_vaddr(&self, vaddr: usize) -> Option<usize> {
214        // Search memory mapping
215        for map in self.memmap.iter() {
216            if vaddr >= map.vmarea.start && vaddr <= map.vmarea.end {
217                // Calculate offset
218                let offset = vaddr - map.vmarea.start;
219                // Calculate physical address
220                let paddr = map.pmarea.start + offset;
221                return Some(paddr);
222            }
223        }
224        None
225    }
226}
227
228#[cfg(test)]
229mod tests {    
230    use crate::arch::vm::alloc_virtual_address_space;
231    use crate::vm::VirtualMemoryMap;
232    use crate::vm::{manager::VirtualMemoryManager, vmem::MemoryArea};
233
234    #[test_case]
235    fn test_new_virtual_memory_manager() {
236        let vmm = VirtualMemoryManager::new();
237        assert_eq!(vmm.get_asid(), 0);
238    }
239
240    #[test_case]
241    fn test_set_and_get_asid() {
242        let mut vmm = VirtualMemoryManager::new();
243        vmm.set_asid(42);
244        assert_eq!(vmm.get_asid(), 42);
245    }
246
247    #[test_case]
248    fn test_add_and_get_memory_map() {
249        let mut vmm = VirtualMemoryManager::new();
250        let vma = MemoryArea { start: 0x1000, end: 0x1fff };
251        let map = VirtualMemoryMap { vmarea: vma, pmarea: vma, permissions: 0, is_shared: false };
252        vmm.add_memory_map(map).unwrap();
253        assert_eq!(vmm.get_memory_map(0).unwrap().vmarea.start, 0x1000);
254    }
255
256    #[test_case]
257    fn test_remove_memory_map() {
258        let mut vmm = VirtualMemoryManager::new();
259        let vma = MemoryArea { start: 0x1000, end: 0x1fff };
260        let map = VirtualMemoryMap { vmarea: vma, pmarea: vma, permissions: 0, is_shared: false };
261        vmm.add_memory_map(map).unwrap();
262        let removed_map = vmm.remove_memory_map(0).unwrap();
263        assert_eq!(removed_map.vmarea.start, 0x1000);
264        assert!(vmm.get_memory_map(0).is_none());
265    }
266
267    #[test_case]
268    fn test_search_memory_map() {
269        let mut vmm = VirtualMemoryManager::new();
270        let vma1 = MemoryArea { start: 0x1000, end: 0x1fff };
271        let map1 = VirtualMemoryMap { vmarea: vma1, pmarea: vma1, permissions: 0, is_shared: false };
272        let vma2 = MemoryArea { start: 0x3000, end: 0x3fff };
273        let map2 = VirtualMemoryMap { vmarea: vma2, pmarea: vma2, permissions: 0, is_shared: false };
274        vmm.add_memory_map(map1).unwrap();
275        vmm.add_memory_map(map2).unwrap();
276        let found_map = vmm.search_memory_map(0x3500).unwrap();
277        assert_eq!(found_map.vmarea.start, 0x3000);
278    }
279
280    #[test_case]
281    fn test_get_root_page_table() {
282        let mut vmm = VirtualMemoryManager::new();
283        let asid = alloc_virtual_address_space();
284        vmm.set_asid(asid);
285        let page_table = vmm.get_root_page_table();
286        assert!(page_table.is_some());
287    }
288}