memory/trait.rs
1use core::ptr::NonNull;
2
3use crate::{Capabilities, Layout};
4
5/// Trait that defines the interface for memory allocators in the Xila system.
6///
7/// Implementors of this trait can be used to manage memory allocation and deallocation
8/// operations with specific capabilities. The trait provides the foundation for
9/// custom memory allocation strategies.
10///
11/// # Safety
12///
13/// All methods in this trait are unsafe because they deal with raw memory and can
14/// cause undefined behavior if used incorrectly, such as:
15/// - Deallocating memory that wasn't allocated with the same allocator
16/// - Using memory after it has been deallocated
17/// - Deallocating the same memory multiple times
18pub trait ManagerTrait: Send + Sync {
19 /// Allocates memory with the specified capabilities and layout.
20 ///
21 /// # Parameters
22 /// * `Capabilities` - Specific requirements for the allocation
23 /// * `Layout` - Size and alignment requirements for the allocation
24 ///
25 /// # Returns
26 /// A pointer to the allocated memory, where the protection is set to [`crate::Protection::READ`], or a null pointer if allocation failed.
27 ///
28 /// # Safety
29 /// This function is unsafe because the caller must ensure that:
30 /// - The returned memory is properly initialized before use
31 /// - The memory is properly deallocated when no longer needed
32 unsafe fn allocate(&self, capabilities: Capabilities, layout: Layout) -> Option<NonNull<u8>>;
33
34 /// Deallocates memory previously allocated by this allocator.
35 ///
36 /// # Parameters
37 /// * `Pointer` - Pointer to the memory to deallocate
38 /// * `Layout` - The layout that was used to allocate the memory
39 ///
40 /// # Safety
41 /// This function is unsafe because the caller must ensure that:
42 /// - The pointer was allocated by this allocator
43 /// - The layout matches the one used for allocation
44 /// - The memory is not used after deallocation
45 /// - The memory is not deallocated multiple times
46 unsafe fn deallocate(&self, pointer: NonNull<u8>, layout: Layout);
47
48 /// Reallocates memory with a new layout.
49 ///
50 /// This method changes the size or alignment of a previously allocated memory block.
51 /// If the pointer is `None`, this behaves like a normal allocation.
52 /// If reallocation is successful, the contents of the old memory are preserved
53 /// up to the minimum of the old and new sizes.
54 ///
55 /// # Parameters
56 /// * `Pointer` - Optional pointer to the memory to reallocate. If `None`, acts as a new allocation
57 /// * `Old_layout` - The layout that was used for the original allocation
58 /// * `New_layout` - The new layout requirements for the memory
59 ///
60 /// # Returns
61 /// A pointer to the reallocated memory with the new layout, or `None` if reallocation failed.
62 /// The protection is set to [`crate::Protection::READ`].
63 ///
64 /// # Safety
65 /// This function is unsafe because the caller must ensure that:
66 /// - If `Pointer` is `Some`, it was allocated by this allocator
67 /// - The `Old_layout` matches the one used for the original allocation
68 /// - The old memory is not used after successful reallocation
69 /// - The returned memory is properly initialized before use
70 unsafe fn reallocate(
71 &self,
72 pointer: Option<NonNull<u8>>,
73 old_layout: Layout,
74 new_layout: Layout,
75 ) -> Option<NonNull<u8>> {
76 // Default implementation simply deallocates and allocates again
77 let memory = unsafe { self.allocate(Capabilities::default(), new_layout) }?;
78
79 // Copy the old data to the new memory
80 let pointer = match pointer {
81 Some(ptr) => ptr,
82 None => return Some(memory),
83 };
84
85 let old_size = old_layout.size();
86 let new_size = new_layout.size();
87 if old_size > 0 && new_size > 0 {
88 let old_ptr = pointer.as_ptr();
89 let new_ptr = memory.as_ptr();
90 unsafe {
91 core::ptr::copy_nonoverlapping(old_ptr, new_ptr, core::cmp::min(old_size, new_size))
92 };
93 }
94 // Deallocate the old memory
95 unsafe { self.deallocate(pointer, old_layout) };
96
97 Some(memory)
98 }
99
100 /// Returns the amount of memory currently used in this allocator.
101 ///
102 /// # Returns
103 /// The number of bytes currently allocated.
104 ///
105 /// # Safety
106 /// This function is unsafe because it may rely on internal allocator state
107 /// that could be concurrently modified by other threads.
108 unsafe fn get_used(&self) -> usize;
109
110 /// Returns the amount of memory currently available in this allocator.
111 ///
112 /// # Returns
113 /// The number of bytes available for allocation.
114 ///
115 /// # Safety
116 /// This function is unsafe because it may rely on internal allocator state
117 /// that could be concurrently modified by other threads.
118 unsafe fn get_free(&self) -> usize;
119
120 /// Flushes the instruction cache for a specific memory region.
121 ///
122 /// This method ensures that any cached instructions in the specified memory
123 /// region are synchronized with main memory. This is particularly important
124 /// on architectures with separate instruction and data caches when code
125 /// has been modified at runtime.
126 ///
127 /// # Parameters
128 /// * `Address` - Pointer to the start of the memory region to flush
129 /// * `Size` - Size in bytes of the memory region to flush
130 ///
131 /// # Note
132 /// The default implementation does nothing and can be overridden by specific
133 /// allocators that need to handle instruction cache management.
134 fn flush_instruction_cache(&self, _address: NonNull<u8>, _size: usize) {
135 // Default implementation does nothing, can be overridden by specific allocators
136 }
137
138 /// Flushes the data cache to ensure memory coherency.
139 ///
140 /// This method ensures that any cached data is written back to main memory
141 /// and that the cache is synchronized. This is important for maintaining
142 /// memory coherency, especially in multi-core systems or when dealing with
143 /// memory-mapped I/O operations.
144 ///
145 /// # Note
146 /// The default implementation does nothing and can be overridden by specific
147 /// allocators that need to handle data cache management.
148 fn flush_data_cache(&self) {
149 // Default implementation does nothing, can be overridden by specific allocators
150 }
151
152 /// Returns the page size used by this memory allocator.
153 ///
154 /// The page size is the smallest unit of memory that can be allocated
155 /// by the underlying memory management system. This information is useful
156 /// for optimizing memory allocation patterns and understanding alignment
157 /// requirements.
158 ///
159 /// # Returns
160 /// The page size in bytes used by this allocator.
161 ///
162 /// # Note
163 /// The default implementation returns 4096 bytes (4 KiB), which is a common
164 /// page size on many architectures. Specific allocators can override this
165 /// to return the actual page size of their underlying memory management system.
166 fn get_page_size(&self) -> usize {
167 // Default implementation returns a common page size, can be overridden by specific allocators
168 4096 // 4 KiB is a common page size
169 }
170}