Skip to main content

ax_alloc/
page.rs

1use ax_errno::AxResult;
2use ax_memory_addr::{PhysAddr, VirtAddr};
3
4use crate::{PAGE_SIZE, UsageKind, global_allocator};
5
6/// A RAII wrapper of contiguous 4K-sized pages.
7///
8/// It will automatically deallocate the pages when dropped.
9#[derive(Debug)]
10pub struct GlobalPage {
11    start_vaddr: VirtAddr,
12    num_pages: usize,
13}
14
15impl GlobalPage {
16    /// Allocate one 4K-sized page.
17    pub fn alloc() -> AxResult<Self> {
18        let vaddr = global_allocator()
19            .alloc_pages(1, PAGE_SIZE, UsageKind::Global)
20            .map_err(|_| ax_errno::AxError::NoMemory)?;
21        Ok(Self {
22            start_vaddr: vaddr.into(),
23            num_pages: 1,
24        })
25    }
26
27    /// Allocate one 4K-sized page and fill with zero.
28    pub fn alloc_zero() -> AxResult<Self> {
29        let mut p = Self::alloc()?;
30        p.zero();
31        Ok(p)
32    }
33
34    /// Allocate contiguous 4K-sized pages.
35    pub fn alloc_contiguous(num_pages: usize, alignment: usize) -> AxResult<Self> {
36        let vaddr = global_allocator()
37            .alloc_pages(num_pages, alignment, UsageKind::Global)
38            .map_err(|_| ax_errno::AxError::NoMemory)?;
39        Ok(Self {
40            start_vaddr: vaddr.into(),
41            num_pages,
42        })
43    }
44
45    /// Get the start virtual address of this page.
46    pub fn start_vaddr(&self) -> VirtAddr {
47        self.start_vaddr
48    }
49
50    /// Get the start physical address of this page.
51    pub fn start_paddr<F>(&self, virt_to_phys: F) -> PhysAddr
52    where
53        F: FnOnce(VirtAddr) -> PhysAddr,
54    {
55        virt_to_phys(self.start_vaddr)
56    }
57
58    /// Get the total size (in bytes) of these page(s).
59    pub fn size(&self) -> usize {
60        self.num_pages * PAGE_SIZE
61    }
62
63    /// Convert to a raw pointer.
64    pub fn as_ptr(&self) -> *const u8 {
65        self.start_vaddr.as_ptr()
66    }
67
68    /// Convert to a mutable raw pointer.
69    pub fn as_mut_ptr(&mut self) -> *mut u8 {
70        self.start_vaddr.as_mut_ptr()
71    }
72
73    /// Fill `self` with `byte`.
74    pub fn fill(&mut self, byte: u8) {
75        unsafe { core::ptr::write_bytes(self.as_mut_ptr(), byte, self.size()) }
76    }
77
78    /// Fill `self` with zero.
79    pub fn zero(&mut self) {
80        self.fill(0)
81    }
82
83    /// Forms a slice that can read data.
84    pub fn as_slice(&self) -> &[u8] {
85        unsafe { core::slice::from_raw_parts(self.as_ptr(), self.size()) }
86    }
87
88    /// Forms a mutable slice that can write data.
89    pub fn as_slice_mut(&mut self) -> &mut [u8] {
90        unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), self.size()) }
91    }
92}
93
94impl Drop for GlobalPage {
95    fn drop(&mut self) {
96        global_allocator().dealloc_pages(
97            self.start_vaddr.into(),
98            self.num_pages,
99            UsageKind::Global,
100        );
101    }
102}