Skip to content

Commit dd72f70

Browse files
committed
update dma32 test
1 parent 559f862 commit dd72f70

1 file changed

Lines changed: 362 additions & 0 deletions

File tree

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
//! Test for GlobalAllocator's alloc_dma32_pages method
2+
3+
#![no_std]
4+
5+
extern crate alloc;
6+
7+
use alloc::vec::Vec;
8+
use alloc::vec;
9+
use buddy_slab_allocator::{GlobalAllocator, AllocError, AddrTranslator};
10+
use core::alloc::Layout;
11+
12+
const PAGE_SIZE: usize = 0x1000; // 4KB pages
13+
const TEST_HEAP_SIZE: usize = 16 * 1024 * 1024; // 16MB
14+
15+
/// Mock address translator for testing
16+
/// In a real hypervisor, this would translate virtual addresses to physical addresses
17+
struct MockAddrTranslator;
18+
19+
impl AddrTranslator for MockAddrTranslator {
20+
fn virt_to_phys(&self, va: usize) -> Option<usize> {
21+
// For testing purposes, we'll map virtual addresses to physical addresses in the low-memory region
22+
// This ensures that our test memory is considered low-memory (<4GiB)
23+
// We'll simply subtract a large value to get into the low-memory range
24+
Some(va & 0x7fffffff) // Mask to get 31-bit address, which is below 2GiB
25+
}
26+
}
27+
28+
/// Static instance of the mock address translator
29+
static MOCK_TRANSLATOR: MockAddrTranslator = MockAddrTranslator;
30+
31+
/// Allocate test memory using system allocator
32+
fn alloc_test_heap(size: usize) -> (*mut u8, Layout) {
33+
let layout = Layout::from_size_align(size, PAGE_SIZE).unwrap();
34+
let ptr = unsafe { alloc::alloc::alloc(layout) };
35+
assert!(!ptr.is_null(), "Failed to allocate test heap");
36+
(ptr, layout)
37+
}
38+
39+
/// Deallocate test memory
40+
fn dealloc_test_heap(ptr: *mut u8, layout: Layout) {
41+
unsafe { alloc::alloc::dealloc(ptr, layout) };
42+
}
43+
44+
#[test]
45+
fn test_alloc_dma32_pages_uninitialized() {
46+
// Create a new allocator but don't initialize it
47+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
48+
49+
// Try to allocate pages - should fail because allocator is not initialized
50+
let result = allocator.alloc_dma32_pages(1, PAGE_SIZE);
51+
assert!(result.is_err(), "Expected error when allocating from uninitialized allocator");
52+
assert_eq!(result.unwrap_err(), AllocError::NoMemory, "Expected NoMemory error");
53+
}
54+
55+
#[test]
56+
fn test_alloc_dma32_pages_initialized() {
57+
// Allocate actual test memory
58+
let (heap_ptr, heap_layout) = alloc_test_heap(TEST_HEAP_SIZE);
59+
let heap_addr = heap_ptr as usize;
60+
61+
// Create allocator and set address translator
62+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
63+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
64+
65+
// Initialize allocator
66+
let init_result = allocator.init(heap_addr, TEST_HEAP_SIZE);
67+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
68+
69+
// Test 1: Allocate 1 page with page size alignment
70+
let result1 = allocator.alloc_dma32_pages(1, PAGE_SIZE);
71+
assert!(result1.is_ok(), "Failed to allocate 1 page: {:?}", result1);
72+
let addr1 = result1.unwrap();
73+
assert!(addr1 >= heap_addr, "Allocated address is below memory start");
74+
assert!(addr1 < heap_addr + TEST_HEAP_SIZE, "Allocated address is beyond memory end");
75+
assert_eq!(addr1 % PAGE_SIZE, 0, "Allocated address is not page-aligned");
76+
77+
// Test 2: Allocate multiple pages
78+
let result2 = allocator.alloc_dma32_pages(4, PAGE_SIZE);
79+
assert!(result2.is_ok(), "Failed to allocate 4 pages: {:?}", result2);
80+
let addr2 = result2.unwrap();
81+
assert!(addr2 >= heap_addr, "Allocated address is below memory start");
82+
assert!(addr2 < heap_addr + TEST_HEAP_SIZE, "Allocated address is beyond memory end");
83+
assert_eq!(addr2 % PAGE_SIZE, 0, "Allocated address is not page-aligned");
84+
85+
// Test 3: Allocate with different alignment
86+
let result3 = allocator.alloc_dma32_pages(1, 2 * PAGE_SIZE); // 8KB alignment
87+
assert!(result3.is_ok(), "Failed to allocate 1 page with 8KB alignment: {:?}", result3);
88+
let addr3 = result3.unwrap();
89+
assert!(addr3 >= heap_addr, "Allocated address is below memory start");
90+
assert!(addr3 < heap_addr + TEST_HEAP_SIZE, "Allocated address is beyond memory end");
91+
assert_eq!(addr3 % (2 * PAGE_SIZE), 0, "Allocated address is not 8KB-aligned");
92+
93+
// Clean up
94+
dealloc_test_heap(heap_ptr, heap_layout);
95+
}
96+
97+
#[test]
98+
fn test_alloc_dma32_pages_memory_structure() {
99+
// Allocate actual test memory
100+
let (heap_ptr, heap_layout) = alloc_test_heap(TEST_HEAP_SIZE);
101+
let heap_addr = heap_ptr as usize;
102+
103+
// Create allocator and set address translator
104+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
105+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
106+
107+
// Initialize allocator
108+
let init_result = allocator.init(heap_addr, TEST_HEAP_SIZE);
109+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
110+
111+
// Test basic memory structure by allocating and deallocating
112+
// This will exercise the internal memory management structures
113+
114+
// Allocate some DMA32 pages
115+
let alloc_results = vec![
116+
allocator.alloc_dma32_pages(1, PAGE_SIZE),
117+
allocator.alloc_dma32_pages(2, PAGE_SIZE),
118+
allocator.alloc_dma32_pages(4, PAGE_SIZE),
119+
];
120+
121+
// Verify all allocations succeeded
122+
for (i, result) in alloc_results.iter().enumerate() {
123+
assert!(result.is_ok(), "Failed to allocate DMA32 pages (iteration {}): {:?}", i, result);
124+
}
125+
126+
// Get allocated addresses
127+
let alloc_addrs: Vec<usize> = alloc_results.into_iter().map(|r| r.unwrap()).collect();
128+
129+
// Verify all addresses are valid
130+
for addr in &alloc_addrs {
131+
assert!(addr >= &heap_addr, "Allocated address is below memory start");
132+
assert!(addr < &(heap_addr + TEST_HEAP_SIZE), "Allocated address is beyond memory end");
133+
}
134+
135+
// Test memory statistics if tracking feature is enabled
136+
#[cfg(feature = "tracking")]
137+
{
138+
// Get statistics after allocations
139+
let stats_after_alloc = allocator.get_stats();
140+
assert!(stats_after_alloc.used_pages > 0, "Used pages should be greater than 0 after allocations");
141+
142+
// Get buddy allocator statistics
143+
let buddy_stats = allocator.get_buddy_stats();
144+
assert!(buddy_stats.total_pages > 0, "Buddy total pages should be greater than 0");
145+
}
146+
147+
// Deallocate all pages
148+
for (i, addr) in alloc_addrs.iter().enumerate() {
149+
let num_pages = match i {
150+
0 => 1,
151+
1 => 2,
152+
2 => 4,
153+
_ => 1,
154+
};
155+
allocator.dealloc_pages(*addr, num_pages);
156+
}
157+
158+
// Test memory statistics after deallocation if tracking feature is enabled
159+
#[cfg(feature = "tracking")]
160+
{
161+
let stats_after_dealloc = allocator.get_stats();
162+
// Note: Used pages might not be exactly 0 due to internal node pool usage
163+
// but should be significantly reduced
164+
assert!(stats_after_dealloc.used_pages < 100, "Used pages should be low after deallocation");
165+
}
166+
167+
// Clean up
168+
dealloc_test_heap(heap_ptr, heap_layout);
169+
}
170+
171+
#[test]
172+
fn test_alloc_dma32_pages_memory_stats() {
173+
// Allocate actual test memory
174+
let (heap_ptr, heap_layout) = alloc_test_heap(TEST_HEAP_SIZE);
175+
let heap_addr = heap_ptr as usize;
176+
177+
// Create allocator and set address translator
178+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
179+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
180+
181+
// Initialize allocator
182+
let init_result = allocator.init(heap_addr, TEST_HEAP_SIZE);
183+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
184+
185+
// Test memory statistics if tracking feature is enabled
186+
#[cfg(feature = "tracking")]
187+
{
188+
// Get initial statistics
189+
let stats_before = allocator.get_stats();
190+
assert!(stats_before.total_pages > 0, "Total pages should be greater than 0");
191+
assert!(stats_before.free_pages > 0, "Free pages should be greater than 0");
192+
assert_eq!(stats_before.used_pages, 0, "Used pages should be 0 initially");
193+
194+
// Allocate some DMA32 pages
195+
let result = allocator.alloc_dma32_pages(2, PAGE_SIZE);
196+
assert!(result.is_ok(), "Failed to allocate DMA32 pages: {:?}", result);
197+
let addr = result.unwrap();
198+
199+
// Get statistics after allocation
200+
let stats_after = allocator.get_stats();
201+
assert_eq!(stats_after.used_pages, stats_before.used_pages + 2, "Used pages should increase by 2");
202+
assert_eq!(stats_after.free_pages, stats_before.free_pages - 2, "Free pages should decrease by 2");
203+
204+
// Deallocate the pages
205+
allocator.dealloc_pages(addr, 2);
206+
207+
// Get statistics after deallocation
208+
let stats_final = allocator.get_stats();
209+
assert_eq!(stats_final.used_pages, stats_before.used_pages, "Used pages should return to initial value");
210+
assert_eq!(stats_final.free_pages, stats_before.free_pages, "Free pages should return to initial value");
211+
}
212+
213+
// Clean up
214+
dealloc_test_heap(heap_ptr, heap_layout);
215+
}
216+
217+
#[test]
218+
fn test_alloc_dma32_pages_multiple_zones() {
219+
// Allocate two separate memory regions for multiple zones
220+
let (heap_ptr1, heap_layout1) = alloc_test_heap(TEST_HEAP_SIZE / 2);
221+
let heap_addr1 = heap_ptr1 as usize;
222+
223+
let (heap_ptr2, heap_layout2) = alloc_test_heap(TEST_HEAP_SIZE / 2);
224+
let heap_addr2 = heap_ptr2 as usize;
225+
226+
// Create allocator and set address translator
227+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
228+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
229+
230+
// Initialize allocator with first memory region
231+
let init_result = allocator.init(heap_addr1, TEST_HEAP_SIZE / 2);
232+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
233+
234+
// Add second memory region as a new zone
235+
let add_result = allocator.add_memory(heap_addr2, TEST_HEAP_SIZE / 2);
236+
assert!(add_result.is_ok(), "Failed to add memory region: {:?}", add_result);
237+
238+
// Test allocating from multiple zones
239+
// First allocation should come from the first zone
240+
let result1 = allocator.alloc_dma32_pages(1, PAGE_SIZE);
241+
assert!(result1.is_ok(), "Failed to allocate 1 page from multiple zones: {:?}", result1);
242+
let addr1 = result1.unwrap();
243+
assert!(addr1 >= heap_addr1 || addr1 >= heap_addr2, "Allocated address is not in any zone");
244+
assert!((addr1 < heap_addr1 + TEST_HEAP_SIZE / 2) || (addr1 < heap_addr2 + TEST_HEAP_SIZE / 2), "Allocated address is beyond memory end");
245+
246+
// Second allocation should come from either zone
247+
let result2 = allocator.alloc_dma32_pages(2, PAGE_SIZE);
248+
assert!(result2.is_ok(), "Failed to allocate 2 pages from multiple zones: {:?}", result2);
249+
let addr2 = result2.unwrap();
250+
assert!(addr2 >= heap_addr1 || addr2 >= heap_addr2, "Allocated address is not in any zone");
251+
assert!((addr2 < heap_addr1 + TEST_HEAP_SIZE / 2) || (addr2 < heap_addr2 + TEST_HEAP_SIZE / 2), "Allocated address is beyond memory end");
252+
253+
// Clean up
254+
dealloc_test_heap(heap_ptr1, heap_layout1);
255+
dealloc_test_heap(heap_ptr2, heap_layout2);
256+
}
257+
258+
#[test]
259+
fn test_alloc_dma32_pages_vs_normal_pages() {
260+
// Allocate actual test memory
261+
let (heap_ptr, heap_layout) = alloc_test_heap(TEST_HEAP_SIZE);
262+
let heap_addr = heap_ptr as usize;
263+
264+
// Create allocator and set address translator
265+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
266+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
267+
268+
// Initialize allocator
269+
let init_result = allocator.init(heap_addr, TEST_HEAP_SIZE);
270+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
271+
272+
// Test 1: Allocate DMA32 pages (32-bit memory)
273+
let result_dma32 = allocator.alloc_dma32_pages(1, PAGE_SIZE);
274+
assert!(result_dma32.is_ok(), "Failed to allocate DMA32 pages: {:?}", result_dma32);
275+
let addr_dma32 = result_dma32.unwrap();
276+
assert!(addr_dma32 >= heap_addr, "Allocated DMA32 address is below memory start");
277+
assert!(addr_dma32 < heap_addr + TEST_HEAP_SIZE, "Allocated DMA32 address is beyond memory end");
278+
279+
// Test 2: Allocate normal pages
280+
let result_normal = allocator.alloc_pages(1, PAGE_SIZE);
281+
assert!(result_normal.is_ok(), "Failed to allocate normal pages: {:?}", result_normal);
282+
let addr_normal = result_normal.unwrap();
283+
assert!(addr_normal >= heap_addr, "Allocated normal address is below memory start");
284+
assert!(addr_normal < heap_addr + TEST_HEAP_SIZE, "Allocated normal address is beyond memory end");
285+
286+
// Verify both addresses are valid and different
287+
assert_ne!(addr_dma32, addr_normal, "DMA32 and normal pages should have different addresses");
288+
289+
// Test 3: Allocate multiple pages of each type
290+
let result_dma32_multi = allocator.alloc_dma32_pages(4, PAGE_SIZE);
291+
assert!(result_dma32_multi.is_ok(), "Failed to allocate multiple DMA32 pages: {:?}", result_dma32_multi);
292+
293+
let result_normal_multi = allocator.alloc_pages(4, PAGE_SIZE);
294+
assert!(result_normal_multi.is_ok(), "Failed to allocate multiple normal pages: {:?}", result_normal_multi);
295+
296+
// Clean up
297+
dealloc_test_heap(heap_ptr, heap_layout);
298+
}
299+
300+
#[test]
301+
fn test_alloc_dma32_pages_edge_cases() {
302+
// Allocate actual test memory
303+
let (heap_ptr, heap_layout) = alloc_test_heap(TEST_HEAP_SIZE);
304+
let heap_addr = heap_ptr as usize;
305+
306+
// Create allocator and set address translator
307+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
308+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
309+
310+
// Initialize allocator
311+
let init_result = allocator.init(heap_addr, TEST_HEAP_SIZE);
312+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
313+
314+
// Test: Allocate 0 pages
315+
let result = allocator.alloc_dma32_pages(0, PAGE_SIZE);
316+
// Note: The behavior for 0 pages may vary - some allocators return 0, others error
317+
// This test assumes it might succeed (returning 0) or fail, but shouldn't panic
318+
match result {
319+
Ok(addr) => assert_eq!(addr, 0, "Expected 0 for 0 pages allocation"),
320+
Err(_) => {}, // Error is also acceptable for 0 pages
321+
}
322+
323+
// Clean up
324+
dealloc_test_heap(heap_ptr, heap_layout);
325+
}
326+
327+
#[test]
328+
fn test_alloc_dma32_pages_stress() {
329+
// Allocate actual test memory
330+
let (heap_ptr, heap_layout) = alloc_test_heap(TEST_HEAP_SIZE);
331+
let heap_addr = heap_ptr as usize;
332+
333+
// Create allocator and set address translator
334+
let allocator = GlobalAllocator::<PAGE_SIZE>::new();
335+
allocator.set_addr_translator(&MOCK_TRANSLATOR);
336+
337+
// Initialize allocator
338+
let init_result = allocator.init(heap_addr, TEST_HEAP_SIZE);
339+
assert!(init_result.is_ok(), "Failed to initialize allocator: {:?}", init_result);
340+
341+
// Stress test: Allocate and free multiple times
342+
let mut allocated_addrs = Vec::new();
343+
344+
// Allocate multiple times
345+
for i in 0..10 {
346+
let num_pages = (i % 4) + 1; // 1-4 pages
347+
let alignment = if i % 2 == 0 { PAGE_SIZE } else { 2 * PAGE_SIZE };
348+
349+
let result = allocator.alloc_dma32_pages(num_pages, alignment);
350+
assert!(result.is_ok(), "Failed to allocate {} pages with alignment {}: {:?}", num_pages, alignment, result);
351+
allocated_addrs.push(result.unwrap());
352+
}
353+
354+
// Verify all addresses are valid
355+
for addr in &allocated_addrs {
356+
assert!(addr >= &heap_addr, "Allocated address is below memory start");
357+
assert!(addr < &(heap_addr + TEST_HEAP_SIZE), "Allocated address is beyond memory end");
358+
}
359+
360+
// Clean up
361+
dealloc_test_heap(heap_ptr, heap_layout);
362+
}

0 commit comments

Comments
 (0)