ruvix_physmem/frame.rs
1//! Page frame types.
2//!
3//! This module provides types for representing physical page frames
4//! and their allocation orders.
5
6use core::fmt;
7
8use crate::{order_to_bytes, order_to_pages, PhysAddr, MAX_ORDER, PAGE_SIZE};
9
10/// The order of a page frame block.
11///
12/// Order `n` represents `2^n` contiguous pages:
13/// - Order 0: 1 page (4KB)
14/// - Order 1: 2 pages (8KB)
15/// - Order 2: 4 pages (16KB)
16/// - ...
17/// - Order 9: 512 pages (2MB)
18///
19/// # Examples
20///
21/// ```rust
22/// use ruvix_physmem::PageOrder;
23///
24/// let order = PageOrder::new(2).unwrap();
25/// assert_eq!(order.pages(), 4);
26/// assert_eq!(order.bytes(), 16384);
27/// ```
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
29#[repr(transparent)]
30pub struct PageOrder(u8);
31
32impl PageOrder {
33 /// The minimum order (single page, 4KB).
34 pub const MIN: Self = Self(0);
35
36 /// The maximum order (512 pages, 2MB).
37 pub const MAX: Self = Self((MAX_ORDER - 1) as u8);
38
39 /// Creates a new page order.
40 ///
41 /// Returns `None` if the order is greater than or equal to `MAX_ORDER`.
42 ///
43 /// # Arguments
44 ///
45 /// * `order` - The order value (0 to `MAX_ORDER - 1`).
46 ///
47 /// # Examples
48 ///
49 /// ```rust
50 /// use ruvix_physmem::PageOrder;
51 ///
52 /// assert!(PageOrder::new(0).is_some());
53 /// assert!(PageOrder::new(9).is_some());
54 /// assert!(PageOrder::new(10).is_none()); // MAX_ORDER = 10
55 /// ```
56 #[inline]
57 #[must_use]
58 pub const fn new(order: usize) -> Option<Self> {
59 if order < MAX_ORDER {
60 Some(Self(order as u8))
61 } else {
62 None
63 }
64 }
65
66 /// Creates a new page order without bounds checking.
67 ///
68 /// # Safety
69 ///
70 /// This is safe because we only store a u8 and the buddy allocator
71 /// will validate the order. However, using an invalid order will
72 /// result in unexpected behavior.
73 ///
74 /// # Arguments
75 ///
76 /// * `order` - The order value.
77 #[inline]
78 #[must_use]
79 pub const fn new_unchecked(order: usize) -> Self {
80 Self(order as u8)
81 }
82
83 /// Returns the order as a `usize`.
84 #[inline]
85 #[must_use]
86 pub const fn as_usize(self) -> usize {
87 self.0 as usize
88 }
89
90 /// Returns the number of pages for this order.
91 ///
92 /// # Examples
93 ///
94 /// ```rust
95 /// use ruvix_physmem::PageOrder;
96 ///
97 /// assert_eq!(PageOrder::new(0).unwrap().pages(), 1);
98 /// assert_eq!(PageOrder::new(1).unwrap().pages(), 2);
99 /// assert_eq!(PageOrder::new(2).unwrap().pages(), 4);
100 /// assert_eq!(PageOrder::new(9).unwrap().pages(), 512);
101 /// ```
102 #[inline]
103 #[must_use]
104 pub const fn pages(self) -> usize {
105 order_to_pages(self.0 as usize)
106 }
107
108 /// Returns the block size in bytes for this order.
109 ///
110 /// # Examples
111 ///
112 /// ```rust
113 /// use ruvix_physmem::PageOrder;
114 ///
115 /// assert_eq!(PageOrder::new(0).unwrap().bytes(), 4096);
116 /// assert_eq!(PageOrder::new(1).unwrap().bytes(), 8192);
117 /// assert_eq!(PageOrder::new(9).unwrap().bytes(), 2 * 1024 * 1024);
118 /// ```
119 #[inline]
120 #[must_use]
121 pub const fn bytes(self) -> usize {
122 order_to_bytes(self.0 as usize)
123 }
124
125 /// Returns the next higher order, if it exists.
126 ///
127 /// # Examples
128 ///
129 /// ```rust
130 /// use ruvix_physmem::PageOrder;
131 ///
132 /// let order = PageOrder::new(2).unwrap();
133 /// assert_eq!(order.next().map(|o| o.as_usize()), Some(3));
134 ///
135 /// let max = PageOrder::MAX;
136 /// assert!(max.next().is_none());
137 /// ```
138 #[inline]
139 #[must_use]
140 pub const fn next(self) -> Option<Self> {
141 if (self.0 as usize) < MAX_ORDER - 1 {
142 Some(Self(self.0 + 1))
143 } else {
144 None
145 }
146 }
147
148 /// Returns the next lower order, if it exists.
149 ///
150 /// # Examples
151 ///
152 /// ```rust
153 /// use ruvix_physmem::PageOrder;
154 ///
155 /// let order = PageOrder::new(2).unwrap();
156 /// assert_eq!(order.prev().map(|o| o.as_usize()), Some(1));
157 ///
158 /// let min = PageOrder::MIN;
159 /// assert!(min.prev().is_none());
160 /// ```
161 #[inline]
162 #[must_use]
163 pub const fn prev(self) -> Option<Self> {
164 if self.0 > 0 {
165 Some(Self(self.0 - 1))
166 } else {
167 None
168 }
169 }
170
171 /// Creates an order from a page count, rounding up if necessary.
172 ///
173 /// Returns `None` if the resulting order would exceed `MAX_ORDER - 1`.
174 ///
175 /// # Arguments
176 ///
177 /// * `pages` - The number of pages needed.
178 ///
179 /// # Examples
180 ///
181 /// ```rust
182 /// use ruvix_physmem::PageOrder;
183 ///
184 /// assert_eq!(PageOrder::from_pages(1).map(|o| o.as_usize()), Some(0));
185 /// assert_eq!(PageOrder::from_pages(2).map(|o| o.as_usize()), Some(1));
186 /// assert_eq!(PageOrder::from_pages(3).map(|o| o.as_usize()), Some(2)); // rounds up
187 /// assert_eq!(PageOrder::from_pages(4).map(|o| o.as_usize()), Some(2));
188 /// assert_eq!(PageOrder::from_pages(512).map(|o| o.as_usize()), Some(9));
189 /// assert!(PageOrder::from_pages(513).is_none()); // Too large
190 /// ```
191 #[inline]
192 #[must_use]
193 pub const fn from_pages(pages: usize) -> Option<Self> {
194 if pages == 0 {
195 return None;
196 }
197
198 let order = crate::pages_to_order(pages);
199 Self::new(order)
200 }
201
202 /// Creates an order from a byte size, rounding up if necessary.
203 ///
204 /// Returns `None` if the resulting order would exceed `MAX_ORDER - 1`.
205 ///
206 /// # Arguments
207 ///
208 /// * `bytes` - The number of bytes needed.
209 ///
210 /// # Examples
211 ///
212 /// ```rust
213 /// use ruvix_physmem::PageOrder;
214 ///
215 /// assert_eq!(PageOrder::from_bytes(1).map(|o| o.as_usize()), Some(0));
216 /// assert_eq!(PageOrder::from_bytes(4096).map(|o| o.as_usize()), Some(0));
217 /// assert_eq!(PageOrder::from_bytes(4097).map(|o| o.as_usize()), Some(1));
218 /// assert_eq!(PageOrder::from_bytes(8192).map(|o| o.as_usize()), Some(1));
219 /// ```
220 #[inline]
221 #[must_use]
222 pub const fn from_bytes(bytes: usize) -> Option<Self> {
223 if bytes == 0 {
224 return None;
225 }
226
227 let pages = (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
228 Self::from_pages(pages)
229 }
230}
231
232impl fmt::Debug for PageOrder {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 write!(f, "PageOrder({})", self.0)
235 }
236}
237
238impl fmt::Display for PageOrder {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 write!(f, "order {} ({} pages, {} bytes)", self.0, self.pages(), self.bytes())
241 }
242}
243
244/// A physical page frame.
245///
246/// Represents a contiguous block of physical memory with a specific
247/// physical address and order (size).
248///
249/// # Examples
250///
251/// ```rust
252/// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
253///
254/// let frame = PageFrame::new(PhysAddr::new(0x1000), PageOrder::new(2).unwrap());
255/// assert_eq!(frame.addr().as_u64(), 0x1000);
256/// assert_eq!(frame.pages(), 4);
257/// assert_eq!(frame.bytes(), 16384);
258/// ```
259#[derive(Clone, Copy, PartialEq, Eq, Hash)]
260pub struct PageFrame {
261 /// The physical address of the frame's start.
262 addr: PhysAddr,
263 /// The order of the frame (determines size).
264 order: PageOrder,
265}
266
267impl PageFrame {
268 /// Creates a new page frame.
269 ///
270 /// # Arguments
271 ///
272 /// * `addr` - The physical address of the frame's start.
273 /// * `order` - The order determining the frame's size.
274 ///
275 /// # Examples
276 ///
277 /// ```rust
278 /// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
279 ///
280 /// let frame = PageFrame::new(
281 /// PhysAddr::new(0x1000_0000),
282 /// PageOrder::new(3).unwrap()
283 /// );
284 /// assert_eq!(frame.pages(), 8);
285 /// ```
286 #[inline]
287 #[must_use]
288 pub const fn new(addr: PhysAddr, order: PageOrder) -> Self {
289 Self { addr, order }
290 }
291
292 /// Creates a page frame for a single page.
293 ///
294 /// # Arguments
295 ///
296 /// * `addr` - The physical address of the page.
297 ///
298 /// # Examples
299 ///
300 /// ```rust
301 /// use ruvix_physmem::{PageFrame, PhysAddr};
302 ///
303 /// let frame = PageFrame::single_page(PhysAddr::new(0x1000));
304 /// assert_eq!(frame.pages(), 1);
305 /// assert_eq!(frame.order().as_usize(), 0);
306 /// ```
307 #[inline]
308 #[must_use]
309 pub const fn single_page(addr: PhysAddr) -> Self {
310 Self {
311 addr,
312 order: PageOrder::MIN,
313 }
314 }
315
316 /// Returns the physical address of the frame's start.
317 #[inline]
318 #[must_use]
319 pub const fn addr(&self) -> PhysAddr {
320 self.addr
321 }
322
323 /// Returns the order of the frame.
324 #[inline]
325 #[must_use]
326 pub const fn order(&self) -> PageOrder {
327 self.order
328 }
329
330 /// Returns the number of pages in the frame.
331 #[inline]
332 #[must_use]
333 pub const fn pages(&self) -> usize {
334 self.order.pages()
335 }
336
337 /// Returns the size of the frame in bytes.
338 #[inline]
339 #[must_use]
340 pub const fn bytes(&self) -> usize {
341 self.order.bytes()
342 }
343
344 /// Returns the physical address of the frame's end (exclusive).
345 ///
346 /// # Examples
347 ///
348 /// ```rust
349 /// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
350 ///
351 /// let frame = PageFrame::new(
352 /// PhysAddr::new(0x1000),
353 /// PageOrder::new(2).unwrap()
354 /// );
355 /// assert_eq!(frame.end_addr().as_u64(), 0x5000); // 0x1000 + 4*0x1000
356 /// ```
357 #[inline]
358 #[must_use]
359 pub const fn end_addr(&self) -> PhysAddr {
360 self.addr.add_pages(self.pages())
361 }
362
363 /// Returns the page frame number of the first page.
364 #[inline]
365 #[must_use]
366 pub const fn pfn(&self) -> u64 {
367 self.addr.pfn()
368 }
369
370 /// Checks if an address is contained within this frame.
371 ///
372 /// # Arguments
373 ///
374 /// * `addr` - The address to check.
375 ///
376 /// # Examples
377 ///
378 /// ```rust
379 /// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
380 ///
381 /// let frame = PageFrame::new(
382 /// PhysAddr::new(0x1000),
383 /// PageOrder::new(2).unwrap() // 4 pages: 0x1000..0x5000
384 /// );
385 ///
386 /// assert!(frame.contains(PhysAddr::new(0x1000)));
387 /// assert!(frame.contains(PhysAddr::new(0x2500)));
388 /// assert!(frame.contains(PhysAddr::new(0x4FFF)));
389 /// assert!(!frame.contains(PhysAddr::new(0x5000)));
390 /// assert!(!frame.contains(PhysAddr::new(0x0FFF)));
391 /// ```
392 #[inline]
393 #[must_use]
394 pub const fn contains(&self, addr: PhysAddr) -> bool {
395 addr.is_in_range(self.addr, self.end_addr())
396 }
397
398 /// Splits the frame into two buddy frames of the next lower order.
399 ///
400 /// Returns `None` if the frame is already at the minimum order.
401 ///
402 /// # Examples
403 ///
404 /// ```rust
405 /// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
406 ///
407 /// let frame = PageFrame::new(
408 /// PhysAddr::new(0x1000),
409 /// PageOrder::new(2).unwrap() // 4 pages
410 /// );
411 ///
412 /// if let Some((left, right)) = frame.split() {
413 /// assert_eq!(left.pages(), 2);
414 /// assert_eq!(right.pages(), 2);
415 /// assert_eq!(left.addr().as_u64(), 0x1000);
416 /// assert_eq!(right.addr().as_u64(), 0x3000);
417 /// }
418 /// ```
419 #[inline]
420 #[must_use]
421 pub const fn split(&self) -> Option<(Self, Self)> {
422 match self.order.prev() {
423 Some(new_order) => {
424 let left = Self {
425 addr: self.addr,
426 order: new_order,
427 };
428 let right = Self {
429 addr: self.addr.add_pages(new_order.pages()),
430 order: new_order,
431 };
432 Some((left, right))
433 }
434 None => None,
435 }
436 }
437
438 /// Returns the buddy address for this frame.
439 ///
440 /// The buddy is the adjacent block of the same size that can be
441 /// merged with this block to form a larger block.
442 ///
443 /// # Examples
444 ///
445 /// ```rust
446 /// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
447 ///
448 /// // Frame at 0x1000, order 1 (2 pages)
449 /// let frame = PageFrame::new(
450 /// PhysAddr::new(0x1000),
451 /// PageOrder::new(1).unwrap()
452 /// );
453 /// // Buddy is at 0x3000 (XOR with block size)
454 /// assert_eq!(frame.buddy_addr().as_u64(), 0x3000);
455 ///
456 /// // Frame at 0x3000, order 1 (2 pages)
457 /// let frame = PageFrame::new(
458 /// PhysAddr::new(0x3000),
459 /// PageOrder::new(1).unwrap()
460 /// );
461 /// // Buddy is at 0x1000
462 /// assert_eq!(frame.buddy_addr().as_u64(), 0x1000);
463 /// ```
464 #[inline]
465 #[must_use]
466 pub const fn buddy_addr(&self) -> PhysAddr {
467 let block_size = self.bytes() as u64;
468 PhysAddr::new(self.addr.as_u64() ^ block_size)
469 }
470
471 /// Merges this frame with its buddy to create a larger frame.
472 ///
473 /// Returns `None` if the merge would exceed the maximum order.
474 ///
475 /// # Arguments
476 ///
477 /// * `buddy` - The buddy frame to merge with.
478 ///
479 /// # Examples
480 ///
481 /// ```rust
482 /// use ruvix_physmem::{PageFrame, PhysAddr, PageOrder};
483 ///
484 /// let left = PageFrame::new(PhysAddr::new(0x1000), PageOrder::new(1).unwrap());
485 /// let right = PageFrame::new(PhysAddr::new(0x3000), PageOrder::new(1).unwrap());
486 ///
487 /// if let Some(merged) = left.merge(&right) {
488 /// assert_eq!(merged.pages(), 4);
489 /// assert_eq!(merged.addr().as_u64(), 0x1000);
490 /// }
491 /// ```
492 #[inline]
493 #[must_use]
494 pub const fn merge(&self, buddy: &Self) -> Option<Self> {
495 // Buddies must have the same order
496 if self.order.0 != buddy.order.0 {
497 return None;
498 }
499
500 // Check that they are actually buddies
501 if self.buddy_addr().as_u64() != buddy.addr.as_u64() {
502 return None;
503 }
504
505 // Get the next order
506 match self.order.next() {
507 Some(new_order) => {
508 // Use the lower address as the merged block's address
509 let addr = if self.addr.as_u64() < buddy.addr.as_u64() {
510 self.addr
511 } else {
512 buddy.addr
513 };
514 Some(Self {
515 addr,
516 order: new_order,
517 })
518 }
519 None => None,
520 }
521 }
522}
523
524impl fmt::Debug for PageFrame {
525 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526 f.debug_struct("PageFrame")
527 .field("addr", &self.addr)
528 .field("order", &self.order.0)
529 .field("pages", &self.pages())
530 .finish()
531 }
532}
533
534impl fmt::Display for PageFrame {
535 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536 write!(
537 f,
538 "PageFrame[{} - {}, {} pages]",
539 self.addr,
540 self.end_addr(),
541 self.pages()
542 )
543 }
544}
545
546#[cfg(test)]
547mod tests {
548 extern crate alloc;
549 use alloc::format;
550 use super::*;
551
552 #[test]
553 fn test_page_order_new() {
554 assert!(PageOrder::new(0).is_some());
555 assert!(PageOrder::new(9).is_some());
556 assert!(PageOrder::new(10).is_none());
557 assert!(PageOrder::new(100).is_none());
558 }
559
560 #[test]
561 fn test_page_order_pages() {
562 assert_eq!(PageOrder::new(0).unwrap().pages(), 1);
563 assert_eq!(PageOrder::new(1).unwrap().pages(), 2);
564 assert_eq!(PageOrder::new(2).unwrap().pages(), 4);
565 assert_eq!(PageOrder::new(9).unwrap().pages(), 512);
566 }
567
568 #[test]
569 fn test_page_order_bytes() {
570 assert_eq!(PageOrder::new(0).unwrap().bytes(), 4096);
571 assert_eq!(PageOrder::new(1).unwrap().bytes(), 8192);
572 assert_eq!(PageOrder::new(9).unwrap().bytes(), 2 * 1024 * 1024);
573 }
574
575 #[test]
576 fn test_page_order_next_prev() {
577 let order = PageOrder::new(5).unwrap();
578 assert_eq!(order.next().map(|o| o.as_usize()), Some(6));
579 assert_eq!(order.prev().map(|o| o.as_usize()), Some(4));
580
581 assert!(PageOrder::MIN.prev().is_none());
582 assert!(PageOrder::MAX.next().is_none());
583 }
584
585 #[test]
586 fn test_page_order_from_pages() {
587 assert_eq!(PageOrder::from_pages(0), None);
588 assert_eq!(PageOrder::from_pages(1).map(|o| o.as_usize()), Some(0));
589 assert_eq!(PageOrder::from_pages(2).map(|o| o.as_usize()), Some(1));
590 assert_eq!(PageOrder::from_pages(3).map(|o| o.as_usize()), Some(2));
591 assert_eq!(PageOrder::from_pages(4).map(|o| o.as_usize()), Some(2));
592 assert_eq!(PageOrder::from_pages(512).map(|o| o.as_usize()), Some(9));
593 assert!(PageOrder::from_pages(513).is_none());
594 }
595
596 #[test]
597 fn test_page_order_from_bytes() {
598 assert_eq!(PageOrder::from_bytes(0), None);
599 assert_eq!(PageOrder::from_bytes(1).map(|o| o.as_usize()), Some(0));
600 assert_eq!(PageOrder::from_bytes(4096).map(|o| o.as_usize()), Some(0));
601 assert_eq!(PageOrder::from_bytes(4097).map(|o| o.as_usize()), Some(1));
602 assert_eq!(PageOrder::from_bytes(8192).map(|o| o.as_usize()), Some(1));
603 }
604
605 #[test]
606 fn test_page_frame_new() {
607 let frame = PageFrame::new(
608 PhysAddr::new(0x1000_0000),
609 PageOrder::new(3).unwrap(),
610 );
611 assert_eq!(frame.addr().as_u64(), 0x1000_0000);
612 assert_eq!(frame.order().as_usize(), 3);
613 assert_eq!(frame.pages(), 8);
614 assert_eq!(frame.bytes(), 8 * 4096);
615 }
616
617 #[test]
618 fn test_page_frame_single_page() {
619 let frame = PageFrame::single_page(PhysAddr::new(0x5000));
620 assert_eq!(frame.pages(), 1);
621 assert_eq!(frame.order().as_usize(), 0);
622 }
623
624 #[test]
625 fn test_page_frame_end_addr() {
626 let frame = PageFrame::new(
627 PhysAddr::new(0x1000),
628 PageOrder::new(2).unwrap(),
629 );
630 assert_eq!(frame.end_addr().as_u64(), 0x5000);
631 }
632
633 #[test]
634 fn test_page_frame_contains() {
635 let frame = PageFrame::new(
636 PhysAddr::new(0x1000),
637 PageOrder::new(2).unwrap(),
638 );
639
640 assert!(frame.contains(PhysAddr::new(0x1000)));
641 assert!(frame.contains(PhysAddr::new(0x2000)));
642 assert!(frame.contains(PhysAddr::new(0x4FFF)));
643 assert!(!frame.contains(PhysAddr::new(0x5000)));
644 assert!(!frame.contains(PhysAddr::new(0x0FFF)));
645 }
646
647 #[test]
648 fn test_page_frame_split() {
649 let frame = PageFrame::new(
650 PhysAddr::new(0x4000),
651 PageOrder::new(2).unwrap(),
652 );
653
654 let (left, right) = frame.split().unwrap();
655 assert_eq!(left.order().as_usize(), 1);
656 assert_eq!(right.order().as_usize(), 1);
657 assert_eq!(left.addr().as_u64(), 0x4000);
658 assert_eq!(right.addr().as_u64(), 0x6000);
659 assert_eq!(left.pages(), 2);
660 assert_eq!(right.pages(), 2);
661
662 // Cannot split a single page
663 let single = PageFrame::single_page(PhysAddr::new(0x1000));
664 assert!(single.split().is_none());
665 }
666
667 #[test]
668 fn test_page_frame_buddy_addr() {
669 // Order 1 block at 0x2000 (2 pages = 0x2000 bytes)
670 let frame = PageFrame::new(
671 PhysAddr::new(0x2000),
672 PageOrder::new(1).unwrap(),
673 );
674 // XOR with 0x2000 gives 0x0
675 assert_eq!(frame.buddy_addr().as_u64(), 0x0);
676
677 // Order 1 block at 0x0
678 let frame = PageFrame::new(
679 PhysAddr::new(0x0),
680 PageOrder::new(1).unwrap(),
681 );
682 // XOR with 0x2000 gives 0x2000
683 assert_eq!(frame.buddy_addr().as_u64(), 0x2000);
684
685 // Order 2 block at 0x4000 (4 pages = 0x4000 bytes)
686 let frame = PageFrame::new(
687 PhysAddr::new(0x4000),
688 PageOrder::new(2).unwrap(),
689 );
690 // XOR with 0x4000 gives 0x0
691 assert_eq!(frame.buddy_addr().as_u64(), 0x0);
692 }
693
694 #[test]
695 fn test_page_frame_merge() {
696 let left = PageFrame::new(PhysAddr::new(0x0), PageOrder::new(1).unwrap());
697 let right = PageFrame::new(PhysAddr::new(0x2000), PageOrder::new(1).unwrap());
698
699 let merged = left.merge(&right).unwrap();
700 assert_eq!(merged.order().as_usize(), 2);
701 assert_eq!(merged.addr().as_u64(), 0x0);
702 assert_eq!(merged.pages(), 4);
703
704 // Verify merge works in both directions
705 let merged2 = right.merge(&left).unwrap();
706 assert_eq!(merged2.addr().as_u64(), 0x0);
707
708 // Cannot merge non-buddies
709 let non_buddy = PageFrame::new(PhysAddr::new(0x4000), PageOrder::new(1).unwrap());
710 assert!(left.merge(&non_buddy).is_none());
711
712 // Cannot merge different orders
713 let diff_order = PageFrame::new(PhysAddr::new(0x2000), PageOrder::new(2).unwrap());
714 assert!(left.merge(&diff_order).is_none());
715 }
716
717 #[test]
718 fn test_page_frame_display() {
719 let frame = PageFrame::new(
720 PhysAddr::new(0x1000),
721 PageOrder::new(2).unwrap(),
722 );
723 let s = format!("{frame}");
724 assert!(s.contains("0x1000"));
725 assert!(s.contains("0x5000"));
726 assert!(s.contains("4 pages"));
727 }
728}