1use axalloc::global_allocator;
2use axhal::mem::{phys_to_virt, virt_to_phys};
3use axhal::paging::{MappingFlags, PageSize, PageTable};
4use memory_addr::{PAGE_SIZE_4K, PageIter4K, PhysAddr, VirtAddr};
5
6use super::Backend;
7
8fn alloc_frame(zeroed: bool) -> Option<PhysAddr> {
9 let vaddr = VirtAddr::from(global_allocator().alloc_pages(1, PAGE_SIZE_4K).ok()?);
10 if zeroed {
11 unsafe { core::ptr::write_bytes(vaddr.as_mut_ptr(), 0, PAGE_SIZE_4K) };
12 }
13 let paddr = virt_to_phys(vaddr);
14 Some(paddr)
15}
16
17fn dealloc_frame(frame: PhysAddr) {
18 let vaddr = phys_to_virt(frame);
19 global_allocator().dealloc_pages(vaddr.as_usize(), 1);
20}
21
22impl Backend {
23 pub const fn new_alloc(populate: bool) -> Self {
25 Self::Alloc { populate }
26 }
27
28 pub(crate) fn map_alloc(
29 &self,
30 start: VirtAddr,
31 size: usize,
32 flags: MappingFlags,
33 pt: &mut PageTable,
34 populate: bool,
35 ) -> bool {
36 debug!(
37 "map_alloc: [{:#x}, {:#x}) {:?} (populate={})",
38 start,
39 start + size,
40 flags,
41 populate
42 );
43 if populate {
44 let mut cursor = pt.cursor();
46 for addr in PageIter4K::new(start, start + size).unwrap() {
47 if let Some(frame) = alloc_frame(true)
48 && cursor.map(addr, frame, PageSize::Size4K, flags).is_err()
49 {
50 for rollback_addr in PageIter4K::new(start, addr).unwrap() {
53 if let Ok((mapped_frame, _, page_size)) = cursor.unmap(rollback_addr) {
54 if !page_size.is_huge() {
56 dealloc_frame(mapped_frame);
57 }
58 }
59 }
60 dealloc_frame(frame);
62 return false;
63 }
64 }
65 true
66 } else {
67 let flags = MappingFlags::empty();
69 pt.cursor()
70 .map_region(start, |_| 0.into(), size, flags, false)
71 .is_ok()
72 }
73 }
74
75 pub(crate) fn unmap_alloc(
76 &self,
77 start: VirtAddr,
78 size: usize,
79 pt: &mut PageTable,
80 _populate: bool,
81 ) -> bool {
82 debug!("unmap_alloc: [{:#x}, {:#x})", start, start + size);
83 for addr in PageIter4K::new(start, start + size).unwrap() {
84 if let Ok((frame, _, page_size)) = pt.cursor().unmap(addr) {
85 if page_size.is_huge() {
88 return false;
89 }
90 dealloc_frame(frame);
91 }
92 }
93 true
94 }
95
96 pub(crate) fn handle_page_fault_alloc(
97 &self,
98 vaddr: VirtAddr,
99 orig_flags: MappingFlags,
100 pt: &mut PageTable,
101 populate: bool,
102 ) -> bool {
103 if populate {
104 false } else if let Some(frame) = alloc_frame(true) {
106 let res = pt.cursor().remap(vaddr, frame, orig_flags);
110 if let Err(e) = &res {
111 debug!(
112 "handle_page_fault_alloc: remap failed for {:#x}: {:?}",
113 vaddr, e
114 );
115 dealloc_frame(frame);
116 }
117 res.is_ok()
118 } else {
119 false
120 }
121 }
122}