1#[cfg(all(test, debug_assertions))]
2mod tests {
3 use atomic::Ordering;
4
5 use crate::util::constants;
6 use crate::util::heap::layout::vm_layout;
7 use crate::util::heap::layout::vm_layout::vm_layout;
8 use crate::util::metadata::side_metadata::SideMetadataContext;
9 use crate::util::metadata::side_metadata::SideMetadataSpec;
10 use crate::util::metadata::side_metadata::*;
11 use crate::util::test_util::{serial_test, with_cleanup};
12 use crate::util::Address;
13
14 #[test]
15 fn test_side_metadata_address_to_meta_address() {
16 let mut gspec = SideMetadataSpec {
17 name: "gspec",
18 is_global: true,
19 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
20 log_num_of_bits: 0,
21 log_bytes_in_region: 0,
22 };
23 #[cfg(target_pointer_width = "64")]
24 let mut lspec = SideMetadataSpec {
25 name: "lspec",
26 is_global: false,
27 offset: SideMetadataOffset::addr(LOCAL_SIDE_METADATA_BASE_ADDRESS),
28 log_num_of_bits: 0,
29 log_bytes_in_region: 0,
30 };
31
32 #[cfg(target_pointer_width = "32")]
33 let mut lspec = SideMetadataSpec {
34 name: "lspec",
35 is_global: false,
36 offset: SideMetadataOffset::rel(0),
37 log_num_of_bits: 0,
38 log_bytes_in_region: 0,
39 };
40
41 assert_eq!(
42 address_to_meta_address(&gspec, unsafe { Address::from_usize(0) }),
43 GLOBAL_SIDE_METADATA_BASE_ADDRESS
44 );
45 assert_eq!(
46 address_to_meta_address(&lspec, unsafe { Address::from_usize(0) }),
47 LOCAL_SIDE_METADATA_BASE_ADDRESS
48 );
49
50 assert_eq!(
51 address_to_meta_address(&gspec, unsafe { Address::from_usize(7) }),
52 GLOBAL_SIDE_METADATA_BASE_ADDRESS
53 );
54 assert_eq!(
55 address_to_meta_address(&lspec, unsafe { Address::from_usize(7) }),
56 LOCAL_SIDE_METADATA_BASE_ADDRESS
57 );
58
59 assert_eq!(
60 address_to_meta_address(&gspec, unsafe { Address::from_usize(27) }),
61 GLOBAL_SIDE_METADATA_BASE_ADDRESS + 3usize
62 );
63 assert_eq!(
64 address_to_meta_address(&lspec, unsafe { Address::from_usize(129) }),
65 LOCAL_SIDE_METADATA_BASE_ADDRESS + 16usize
66 );
67
68 gspec.log_bytes_in_region = 2;
69 lspec.log_bytes_in_region = 1;
70
71 assert_eq!(
72 address_to_meta_address(&gspec, unsafe { Address::from_usize(0) }),
73 GLOBAL_SIDE_METADATA_BASE_ADDRESS
74 );
75 assert_eq!(
76 address_to_meta_address(&lspec, unsafe { Address::from_usize(0) }),
77 LOCAL_SIDE_METADATA_BASE_ADDRESS
78 );
79
80 assert_eq!(
81 address_to_meta_address(&gspec, unsafe { Address::from_usize(32) }),
82 GLOBAL_SIDE_METADATA_BASE_ADDRESS + 1usize
83 );
84 assert_eq!(
85 address_to_meta_address(&lspec, unsafe { Address::from_usize(32) }),
86 LOCAL_SIDE_METADATA_BASE_ADDRESS + 2usize
87 );
88
89 assert_eq!(
90 address_to_meta_address(&gspec, unsafe { Address::from_usize(316) }),
91 GLOBAL_SIDE_METADATA_BASE_ADDRESS + 9usize
92 );
93 assert_eq!(
94 address_to_meta_address(&lspec, unsafe { Address::from_usize(316) }),
95 LOCAL_SIDE_METADATA_BASE_ADDRESS + 19usize
96 );
97
98 gspec.log_num_of_bits = 1;
99 lspec.log_num_of_bits = 3;
100
101 assert_eq!(
102 address_to_meta_address(&gspec, unsafe { Address::from_usize(0) }),
103 GLOBAL_SIDE_METADATA_BASE_ADDRESS
104 );
105 assert_eq!(
106 address_to_meta_address(&lspec, unsafe { Address::from_usize(0) }),
107 LOCAL_SIDE_METADATA_BASE_ADDRESS
108 );
109
110 assert_eq!(
111 address_to_meta_address(&gspec, unsafe { Address::from_usize(32) }),
112 GLOBAL_SIDE_METADATA_BASE_ADDRESS + 2usize
113 );
114 assert_eq!(
115 address_to_meta_address(&lspec, unsafe { Address::from_usize(32) }),
116 LOCAL_SIDE_METADATA_BASE_ADDRESS + 16usize
117 );
118
119 assert_eq!(
120 address_to_meta_address(&gspec, unsafe { Address::from_usize(316) }),
121 GLOBAL_SIDE_METADATA_BASE_ADDRESS + 19usize
122 );
123 assert_eq!(
124 address_to_meta_address(&lspec, unsafe { Address::from_usize(318) }),
125 LOCAL_SIDE_METADATA_BASE_ADDRESS + 159usize
126 );
127 }
128
129 #[test]
130 fn test_side_metadata_meta_byte_mask() {
131 let mut spec = SideMetadataSpec {
132 name: "test_spec",
133 is_global: true,
134 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
135 log_num_of_bits: 0,
136 log_bytes_in_region: 0,
137 };
138
139 assert_eq!(meta_byte_mask(&spec), 1);
140
141 spec.log_num_of_bits = 1;
142 assert_eq!(meta_byte_mask(&spec), 3);
143 spec.log_num_of_bits = 2;
144 assert_eq!(meta_byte_mask(&spec), 15);
145 spec.log_num_of_bits = 3;
146 assert_eq!(meta_byte_mask(&spec), 255);
147 }
148
149 #[test]
150 fn test_side_metadata_meta_byte_lshift() {
151 let mut spec = SideMetadataSpec {
152 name: "test_spec",
153 is_global: true,
154 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
155 log_num_of_bits: 0,
156 log_bytes_in_region: 0,
157 };
158
159 assert_eq!(
160 meta_byte_lshift(&spec, unsafe { Address::from_usize(0) }),
161 0
162 );
163 assert_eq!(
164 meta_byte_lshift(&spec, unsafe { Address::from_usize(5) }),
165 5
166 );
167 assert_eq!(
168 meta_byte_lshift(&spec, unsafe { Address::from_usize(15) }),
169 7
170 );
171
172 spec.log_num_of_bits = 2;
173
174 assert_eq!(
175 meta_byte_lshift(&spec, unsafe { Address::from_usize(0) }),
176 0
177 );
178 assert_eq!(
179 meta_byte_lshift(&spec, unsafe { Address::from_usize(5) }),
180 4
181 );
182 assert_eq!(
183 meta_byte_lshift(&spec, unsafe { Address::from_usize(15) }),
184 4
185 );
186 assert_eq!(
187 meta_byte_lshift(&spec, unsafe { Address::from_usize(0x10010) }),
188 0
189 );
190 }
191
192 #[test]
193 fn test_side_metadata_try_mmap_metadata() {
194 let heap_start = vm_layout().heap_start;
195 serial_test(|| {
196 with_cleanup(
197 || {
198 let mut gspec = SideMetadataSpec {
201 name: "gspec",
202 is_global: true,
203 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
204 log_num_of_bits: 1,
205 log_bytes_in_region: 1,
206 };
207 #[cfg(target_pointer_width = "64")]
208 let mut lspec = SideMetadataSpec {
209 name: "lspec",
210 is_global: false,
211 offset: SideMetadataOffset::addr(LOCAL_SIDE_METADATA_BASE_ADDRESS),
212 log_num_of_bits: 1,
213 log_bytes_in_region: 1,
214 };
215 #[cfg(target_pointer_width = "32")]
216 let mut lspec = SideMetadataSpec {
217 name: "lspec",
218 is_global: false,
219 offset: SideMetadataOffset::rel(0),
220 log_num_of_bits: 1,
221 log_bytes_in_region: 1,
222 };
223
224 let metadata = SideMetadataContext {
225 global: vec![gspec],
226 local: vec![lspec],
227 };
228
229 let mut metadata_sanity = SideMetadataSanity::new();
230 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
231
232 assert!(metadata
233 .try_map_metadata_space(heap_start, constants::BYTES_IN_PAGE, "test_space")
234 .is_ok());
235
236 gspec.assert_metadata_mapped(heap_start);
237 lspec.assert_metadata_mapped(heap_start);
238 gspec.assert_metadata_mapped(heap_start + constants::BYTES_IN_PAGE - 1);
239 lspec.assert_metadata_mapped(heap_start + constants::BYTES_IN_PAGE - 1);
240
241 metadata.ensure_unmap_metadata_space(heap_start, constants::BYTES_IN_PAGE);
242
243 gspec.log_bytes_in_region = 4;
244 gspec.log_num_of_bits = 4;
245 lspec.log_bytes_in_region = 4;
246 lspec.log_num_of_bits = 4;
247
248 metadata_sanity.reset();
249
250 let metadata = SideMetadataContext {
251 global: vec![gspec],
252 local: vec![lspec],
253 };
254
255 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
256 metadata_sanity.reset();
257
258 assert!(metadata
259 .try_map_metadata_space(
260 heap_start + vm_layout::BYTES_IN_CHUNK,
261 vm_layout::BYTES_IN_CHUNK,
262 "test_space",
263 )
264 .is_ok());
265
266 gspec.assert_metadata_mapped(heap_start + vm_layout::BYTES_IN_CHUNK);
267 lspec.assert_metadata_mapped(heap_start + vm_layout::BYTES_IN_CHUNK);
268 gspec.assert_metadata_mapped(heap_start + vm_layout::BYTES_IN_CHUNK * 2 - 8);
269 lspec.assert_metadata_mapped(heap_start + vm_layout::BYTES_IN_CHUNK * 2 - 16);
270
271 metadata.ensure_unmap_metadata_space(
272 heap_start + vm_layout::BYTES_IN_CHUNK,
273 vm_layout::BYTES_IN_CHUNK,
274 );
275 },
276 || {
277 sanity::reset();
278 },
279 );
280 })
281 }
282
283 #[test]
284 fn test_side_metadata_atomic_fetch_add_sub_ge8bits() {
285 serial_test(|| {
286 with_cleanup(
287 || {
288 let data_addr = vm_layout().heap_start;
291
292 let metadata_1_spec = SideMetadataSpec {
293 name: "metadata_1_spec",
294 is_global: true,
295 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
296 log_num_of_bits: 4,
297 log_bytes_in_region: 6,
298 };
299
300 let metadata_2_spec = SideMetadataSpec {
301 name: "metadata_2_spec",
302 is_global: true,
303 offset: SideMetadataOffset::layout_after(&metadata_1_spec),
304 log_num_of_bits: 3,
305 log_bytes_in_region: 7,
306 };
307
308 let metadata = SideMetadataContext {
309 global: vec![metadata_1_spec, metadata_2_spec],
310 local: vec![],
311 };
312
313 let mut metadata_sanity = SideMetadataSanity::new();
314 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
315
316 assert!(metadata
317 .try_map_metadata_space(data_addr, constants::BYTES_IN_PAGE, "test_space",)
318 .is_ok());
319
320 let zero =
321 metadata_1_spec.fetch_add_atomic::<u16>(data_addr, 5, Ordering::SeqCst);
322 assert_eq!(zero, 0);
323
324 let five = metadata_1_spec.load_atomic::<u16>(data_addr, Ordering::SeqCst);
325 assert_eq!(five, 5);
326
327 let zero =
328 metadata_2_spec.fetch_add_atomic::<u8>(data_addr, 5, Ordering::SeqCst);
329 assert_eq!(zero, 0);
330
331 let five = metadata_2_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
332 assert_eq!(five, 5);
333
334 let another_five =
335 metadata_1_spec.fetch_sub_atomic::<u16>(data_addr, 2, Ordering::SeqCst);
336 assert_eq!(another_five, 5);
337
338 let three = metadata_1_spec.load_atomic::<u16>(data_addr, Ordering::SeqCst);
339 assert_eq!(three, 3);
340
341 let another_five =
342 metadata_2_spec.fetch_sub_atomic::<u8>(data_addr, 2, Ordering::SeqCst);
343 assert_eq!(another_five, 5);
344
345 let three = metadata_2_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
346 assert_eq!(three, 3);
347
348 metadata.ensure_unmap_metadata_space(data_addr, constants::BYTES_IN_PAGE);
349 metadata_sanity.reset();
350 },
351 || {
352 sanity::reset();
353 },
354 );
355 });
356 }
357
358 #[test]
359 fn test_side_metadata_atomic_fetch_add_sub_2bits() {
360 serial_test(|| {
361 with_cleanup(
362 || {
363 let data_addr = vm_layout().heap_start + (vm_layout::BYTES_IN_CHUNK << 1) * 2;
366
367 let metadata_1_spec = SideMetadataSpec {
368 name: "metadata_1_spec",
369 is_global: true,
370 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
371 log_num_of_bits: 1,
372 log_bytes_in_region: constants::LOG_BYTES_IN_WORD as usize,
373 };
374
375 let metadata = SideMetadataContext {
376 global: vec![metadata_1_spec],
377 local: vec![],
378 };
379
380 let mut metadata_sanity = SideMetadataSanity::new();
381 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
382
383 assert!(metadata
384 .try_map_metadata_space(data_addr, constants::BYTES_IN_PAGE, "test_space",)
385 .is_ok());
386
387 let zero =
388 metadata_1_spec.fetch_add_atomic::<u8>(data_addr, 2, Ordering::SeqCst);
389 assert_eq!(zero, 0);
390
391 let two = metadata_1_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
392 assert_eq!(two, 2);
393
394 let another_two =
395 metadata_1_spec.fetch_sub_atomic::<u8>(data_addr, 1, Ordering::SeqCst);
396 assert_eq!(another_two, 2);
397
398 let one = metadata_1_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
399 assert_eq!(one, 1);
400
401 metadata_1_spec.store_atomic::<u8>(data_addr, 0, Ordering::SeqCst);
402
403 metadata.ensure_unmap_metadata_space(data_addr, constants::BYTES_IN_PAGE);
404
405 metadata_sanity.reset();
406 },
407 || {
408 sanity::reset();
409 },
410 );
411 });
412 }
413
414 #[test]
415 fn test_side_metadata_atomic_fetch_and_or_2bits() {
416 serial_test(|| {
417 with_cleanup(
418 || {
419 let data_addr =
422 vm_layout::vm_layout().heap_start + (vm_layout::BYTES_IN_CHUNK << 1);
423
424 let metadata_1_spec = SideMetadataSpec {
425 name: "metadata_1_spec",
426 is_global: true,
427 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
428 log_num_of_bits: 1,
429 log_bytes_in_region: constants::LOG_BYTES_IN_WORD as usize,
430 };
431
432 let metadata = SideMetadataContext {
433 global: vec![metadata_1_spec],
434 local: vec![],
435 };
436
437 let mut metadata_sanity = SideMetadataSanity::new();
438 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
439
440 assert!(metadata
441 .try_map_metadata_space(data_addr, constants::BYTES_IN_PAGE, "test_space",)
442 .is_ok());
443
444 let zero =
445 metadata_1_spec.fetch_or_atomic::<u8>(data_addr, 0b11, Ordering::SeqCst);
446 assert_eq!(zero, 0);
447
448 let value_11 = metadata_1_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
449 assert_eq!(value_11, 0b11);
450
451 let another_value_11 =
452 metadata_1_spec.fetch_and_atomic::<u8>(data_addr, 0b01, Ordering::SeqCst);
453 assert_eq!(another_value_11, 0b11);
454
455 let value_01 = metadata_1_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
456 assert_eq!(value_01, 0b01);
457
458 metadata_1_spec.store_atomic::<u8>(data_addr, 0, Ordering::SeqCst);
459
460 metadata.ensure_unmap_metadata_space(data_addr, constants::BYTES_IN_PAGE);
461
462 metadata_sanity.reset();
463 },
464 || {
465 sanity::reset();
466 },
467 );
468 });
469 }
470
471 #[test]
472 fn test_side_metadata_bzero_metadata() {
473 serial_test(|| {
474 with_cleanup(
475 || {
476 let data_addr = vm_layout().heap_start + (vm_layout::BYTES_IN_CHUNK << 2);
479
480 #[cfg(target_pointer_width = "64")]
481 let metadata_1_spec = SideMetadataSpec {
482 name: "metadata_1_spec",
483 is_global: false,
484 offset: SideMetadataOffset::addr(LOCAL_SIDE_METADATA_BASE_ADDRESS),
485 log_num_of_bits: 4,
486 log_bytes_in_region: 9,
487 };
488 #[cfg(target_pointer_width = "64")]
489 let metadata_2_spec = SideMetadataSpec {
490 name: "metadata_2_spec",
491 is_global: false,
492 offset: SideMetadataOffset::layout_after(&metadata_1_spec),
493 log_num_of_bits: 3,
494 log_bytes_in_region: 7,
495 };
496
497 #[cfg(target_pointer_width = "32")]
498 let metadata_1_spec = SideMetadataSpec {
499 name: "metadata_1_spec",
500 is_global: false,
501 offset: SideMetadataOffset::rel(0),
502 log_num_of_bits: 4,
503 log_bytes_in_region: 9,
504 };
505 #[cfg(target_pointer_width = "32")]
506 let metadata_2_spec = SideMetadataSpec {
507 name: "metadata_2_spec",
508 is_global: false,
509 offset: SideMetadataOffset::layout_after(&metadata_1_spec),
510 log_num_of_bits: 3,
511 log_bytes_in_region: 7,
512 };
513
514 let metadata = SideMetadataContext {
515 global: vec![],
516 local: vec![metadata_1_spec, metadata_2_spec],
517 };
518
519 let mut metadata_sanity = SideMetadataSanity::new();
520 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
521
522 assert!(metadata
523 .try_map_metadata_space(data_addr, constants::BYTES_IN_PAGE, "test_space",)
524 .is_ok());
525
526 let zero =
527 metadata_1_spec.fetch_add_atomic::<u16>(data_addr, 5, Ordering::SeqCst);
528 assert_eq!(zero, 0);
529
530 let five = metadata_1_spec.load_atomic::<u16>(data_addr, Ordering::SeqCst);
531 assert_eq!(five, 5);
532
533 let zero =
534 metadata_2_spec.fetch_add_atomic::<u8>(data_addr, 5, Ordering::SeqCst);
535 assert_eq!(zero, 0);
536
537 let five = metadata_2_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
538 assert_eq!(five, 5);
539
540 metadata_2_spec.bzero_metadata(data_addr, constants::BYTES_IN_PAGE);
541
542 let five = metadata_1_spec.load_atomic::<u16>(data_addr, Ordering::SeqCst);
543 assert_eq!(five, 5);
544 let five = metadata_2_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
545 assert_eq!(five, 0);
546
547 metadata_1_spec.bzero_metadata(data_addr, constants::BYTES_IN_PAGE);
548
549 let five = metadata_1_spec.load_atomic::<u16>(data_addr, Ordering::SeqCst);
550 assert_eq!(five, 0);
551 let five = metadata_2_spec.load_atomic::<u8>(data_addr, Ordering::SeqCst);
552 assert_eq!(five, 0);
553
554 metadata.ensure_unmap_metadata_space(data_addr, constants::BYTES_IN_PAGE);
555
556 metadata_sanity.reset();
557 },
558 || {
559 sanity::reset();
560 },
561 );
562 });
563 }
564
565 #[test]
566 fn test_side_metadata_bzero_by_bytes() {
567 serial_test(|| {
568 with_cleanup(
569 || {
570 let data_addr = vm_layout::vm_layout().heap_start;
571
572 let spec = SideMetadataSpec {
574 name: "test spec",
575 is_global: true,
576 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
577 log_num_of_bits: 0,
578 log_bytes_in_region: 3,
579 };
580 let region_size: usize = 1 << spec.log_bytes_in_region;
581
582 let metadata = SideMetadataContext {
583 global: vec![spec],
584 local: vec![],
585 };
586
587 let mut metadata_sanity = SideMetadataSanity::new();
588 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
589
590 assert!(metadata
591 .try_map_metadata_space(data_addr, constants::BYTES_IN_PAGE, "test_space",)
592 .is_ok());
593
594 let regions = (0..9)
596 .map(|i| data_addr + (region_size * i))
597 .collect::<Vec<Address>>();
598 regions
600 .iter()
601 .for_each(|addr| unsafe { spec.store::<u8>(*addr, 1) });
602 regions
603 .iter()
604 .for_each(|addr| assert!(unsafe { spec.load::<u8>(*addr) } == 1));
605
606 spec.bzero_metadata(regions[0], region_size * 8);
608 regions[0..8]
610 .iter()
611 .for_each(|addr| assert!(unsafe { spec.load::<u8>(*addr) } == 0));
612 assert!(unsafe { spec.load::<u8>(regions[8]) } == 1);
614 },
615 || {
616 sanity::reset();
617 },
618 )
619 })
620 }
621
622 #[test]
623 fn test_side_metadata_bzero_by_fraction_of_bytes() {
624 serial_test(|| {
625 with_cleanup(
626 || {
627 let data_addr = vm_layout::vm_layout().heap_start;
628
629 let spec = SideMetadataSpec {
631 name: "test spec",
632 is_global: true,
633 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
634 log_num_of_bits: 0,
635 log_bytes_in_region: 3,
636 };
637 let region_size: usize = 1 << spec.log_bytes_in_region;
638
639 let metadata = SideMetadataContext {
640 global: vec![spec],
641 local: vec![],
642 };
643
644 let mut metadata_sanity = SideMetadataSanity::new();
645 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
646
647 assert!(metadata
648 .try_map_metadata_space(data_addr, constants::BYTES_IN_PAGE, "test_space",)
649 .is_ok());
650
651 let regions = (0..9)
653 .map(|i| data_addr + (region_size * i))
654 .collect::<Vec<Address>>();
655 regions
657 .iter()
658 .for_each(|addr| unsafe { spec.store::<u8>(*addr, 1) });
659 regions
660 .iter()
661 .for_each(|addr| assert!(unsafe { spec.load::<u8>(*addr) } == 1));
662
663 spec.bzero_metadata(regions[0], region_size * 4);
665 regions[0..4]
667 .iter()
668 .for_each(|addr| assert!(unsafe { spec.load::<u8>(*addr) } == 0));
669 regions[4..9]
671 .iter()
672 .for_each(|addr| assert!(unsafe { spec.load::<u8>(*addr) } == 1));
673 },
674 || {
675 sanity::reset();
676 },
677 )
678 })
679 }
680
681 #[test]
682 fn test_side_metadata_zero_meta_bits() {
683 let size = 4usize;
684 let allocate_u32 = || -> Address {
685 let ptr = unsafe {
686 std::alloc::alloc_zeroed(std::alloc::Layout::from_size_align(size, 4).unwrap())
687 };
688 Address::from_mut_ptr(ptr)
689 };
690 let fill_1 = |addr: Address| unsafe {
691 addr.store(u32::MAX);
692 };
693
694 let start = allocate_u32();
695 let end = start + size;
696
697 fill_1(start);
698 SideMetadataSpec::zero_meta_bits(start, 0, end, 0);
700 assert_eq!(unsafe { start.load::<u32>() }, 0);
701
702 fill_1(start);
703 SideMetadataSpec::zero_meta_bits(start, 0, start, 2);
705 assert_eq!(unsafe { start.load::<u32>() }, 0xFFFF_FFFC); fill_1(start);
708 SideMetadataSpec::zero_meta_bits(end - 1, 6, end, 0);
710 assert_eq!(unsafe { start.load::<u32>() }, 0x3FFF_FFFF); fill_1(start);
713 SideMetadataSpec::zero_meta_bits(start, 2, end - 1, 6);
715 assert_eq!(unsafe { start.load::<u32>() }, 0xC000_0003); }
717
718 #[test]
719 fn test_side_metadata_bcopy_metadata_contiguous() {
720 serial_test(|| {
721 with_cleanup(
722 || {
723 let data_addr = vm_layout().heap_start;
724
725 let log_num_of_bits = 0;
726 let log_bytes_in_region = 3;
727 let num_regions = 0x400; let bytes_per_region = 1 << log_bytes_in_region;
729 let total_size = num_regions * bytes_per_region; let metadata_1_spec = SideMetadataSpec {
732 name: "metadata_1_spec",
733 is_global: true,
734 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
735 log_num_of_bits,
736 log_bytes_in_region,
737 };
738
739 let metadata_2_spec = SideMetadataSpec {
740 name: "metadata_2_spec",
741 is_global: true,
742 offset: SideMetadataOffset::layout_after(&metadata_1_spec),
743 log_num_of_bits,
744 log_bytes_in_region,
745 };
746
747 let metadata = SideMetadataContext {
749 global: vec![metadata_1_spec, metadata_2_spec],
750 local: vec![],
751 };
752
753 let mut metadata_sanity = SideMetadataSanity::new();
754 metadata_sanity.verify_metadata_context("NoPolicy", &metadata);
755
756 metadata
757 .try_map_metadata_space(data_addr, total_size, "test_space")
758 .unwrap();
759
760 metadata_1_spec.bzero_metadata(data_addr, total_size);
761 metadata_2_spec.bzero_metadata(data_addr, total_size);
762
763 for i in 0..num_regions {
764 metadata_1_spec.store_atomic::<u8>(
765 data_addr + i * bytes_per_region,
766 (i % 2) as u8,
767 Ordering::Relaxed,
768 );
769 }
770
771 let test_copy_region = |begin: usize, end: usize| {
772 metadata_2_spec.bcopy_metadata_contiguous(
774 data_addr + begin * bytes_per_region,
775 (end - begin) * bytes_per_region,
776 &metadata_1_spec,
777 );
778
779 for i in 0..num_regions {
780 let bit = metadata_2_spec.load_atomic::<u8>(
781 data_addr + i * bytes_per_region,
782 Ordering::Relaxed,
783 );
784
785 let expected = if begin <= i && i < end {
786 (i % 2) as u8
787 } else {
788 0
789 };
790 assert_eq!(
791 bit, expected,
792 "Expected: {expected}, actual: {bit}, i: {i}, begin: {begin}, end: {end}"
793 );
794 }
795
796 metadata_2_spec.bzero_metadata(data_addr, total_size);
797 };
798
799 test_copy_region(0x100, 0x200);
801
802 test_copy_region(0x18, 0xcc);
804
805 test_copy_region(0x263, 0x3f0);
807
808 test_copy_region(0x82, 0x1fd);
810
811 metadata_1_spec.bzero_metadata(data_addr, total_size);
812 metadata_2_spec.bzero_metadata(data_addr, total_size);
813
814 metadata_sanity.reset();
815 },
816 || {
817 sanity::reset();
818 },
819 );
820 });
821 }
822}