kernel/mm/vmm/
address_space.rs1use crate::lib::addr::VirtAddr;
7use crate::lib::panic::kernel_panic;
8use crate::lib::panic_codes::PanicCode;
9use crate::mm::pmm::FRAME_SIZE;
10use crate::mm::vmm::boot_mapping::BootMappings;
11use crate::mm::vmm::traits::VmmPaging;
12use crate::mm::vmm::vma::Vma;
13use crate::mm::vmm::{Vmm, VmmError, VmmResult};
14use crate::state::kstate::KSTATE;
15use alloc::collections::BTreeSet;
16
17pub struct AddressSpace {
19 page_ptr: VirtAddr,
20 vmas: BTreeSet<Vma>,
21}
22
23impl AddressSpace {
24 pub fn empty(page_ptr: VirtAddr) -> Self {
26 Self {
27 page_ptr,
28 vmas: BTreeSet::new()
29 }
30 }
31
32 pub unsafe fn new_user_addr_space() -> Self {
38 let frame = unsafe { KSTATE.mm.pmm() }.lock().alloc_frame().unwrap_or_else(
39 || kernel_panic(
40 PanicCode::OutOfMemory,
41 "Could not allocate a root page for the a address space, out of memory"
42 )
43 );
44
45 let page = VirtAddr::from_phys(frame);
46 unsafe {
50 core::ptr::write_bytes(page.as_mut_ptr::<u8>(), 0u8, FRAME_SIZE as usize);
51 Vmm::clone_kernel_mappings(page);
52 }
53
54 AddressSpace::empty(page)
55 }
56
57 pub fn page_ptr(&self) -> VirtAddr {
59 self.page_ptr
60 }
61
62 pub fn vmas(&self) -> &BTreeSet<Vma> {
64 &self.vmas
65 }
66
67 pub fn setup_kernel_vmas(&mut self, boot_mappings: &BootMappings) -> VmmResult {
70 for mapping in boot_mappings {
71 self.insert_vma(
72 Vma {
73 start_addr: mapping.virt,
74 end_addr: mapping.virt + mapping.size,
75 flags: mapping.flags,
76 }
77 )?;
78 }
79
80 Ok(())
81 }
82
83 pub fn insert_vma(&mut self, vma: Vma) -> VmmResult {
85 for vma_other in &self.vmas {
86 if vma_other.overlaps(&vma) {
87 return Err(VmmError::VmaOverlap);
88 }
89 }
90 self.vmas.insert(vma);
91 Ok(())
92 }
93
94 pub fn remove_vma(&mut self, vma_start_addr: VirtAddr) -> Option<Vma> {
97 self.vmas.take(&vma_start_addr)
98 }
99
100 pub fn find_vma(&self, addr: VirtAddr) -> Option<&Vma> {
103 self.vmas.range(..=addr).next_back().filter(|vma| vma.contains(addr))
104 }
105
106 pub fn find_free_range(&self, from: VirtAddr, to: VirtAddr, size: u64) -> Option<VirtAddr> {
110 let mut candidate = from;
111
112 for vma in self.vmas.range(from..) {
113 if vma.start_addr >= to {
114 break;
115 }
116
117 if vma.start_addr.as_u64() - candidate.as_u64() >= size {
118 return Some(candidate);
119 }
120
121 if vma.end_addr > candidate {
122 candidate = vma.end_addr;
123 }
124 }
125
126 if to.as_u64() - candidate.as_u64() >= size {
127 Some(candidate)
128 } else {
129 None
130 }
131 }
132}