Skip to main content

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}