1use crate::Address;
2use core::cmp;
3pub mod page;
4use mycelium_util::fmt;
5
6#[derive(Clone, Eq, PartialEq)]
8pub struct Region<A = crate::PAddr> {
9 base: A,
10 size: usize,
13 kind: RegionKind,
14}
15
16#[derive(Copy, Clone, Eq, PartialEq)]
17#[repr(transparent)]
18pub struct RegionKind(KindInner);
19
20#[derive(Copy, Clone, Debug, Eq, PartialEq)]
21#[repr(u8)]
22enum KindInner {
23 Unknown = 0,
26 Free,
28 Used,
30 BootReclaimable,
37 Boot,
40 Bad,
42 Kernel,
44 KernelStack,
46 PageTable,
48}
49
50impl<A: Address> Region<A> {
51 pub fn new(base: A, size: usize, kind: RegionKind) -> Self {
52 Self { base, size, kind }
53 }
54
55 pub fn base_addr(&self) -> A {
57 self.base
58 }
59
60 pub fn size(&self) -> usize {
62 self.size
63 }
64
65 pub fn is_aligned(&self, align: impl Into<usize>) -> bool {
66 self.base.is_aligned(align)
67 }
68
69 pub fn contains(&self, addr: impl Into<A>) -> bool {
71 let addr = addr.into();
72 addr >= self.base && addr < self.end_addr()
73 }
74
75 pub fn end_addr(&self) -> A {
79 self.base + self.size
80 }
81
82 pub fn kind(&self) -> RegionKind {
83 self.kind
84 }
85
86 pub fn split_front(&mut self, size: usize) -> Option<Self> {
87 assert!(size <= isize::MAX as usize);
88 if size > self.size {
89 return None;
90 }
91 let base = self.base;
92 tracing::trace!(size, self.size, "splitting down by");
93 self.base = self.base.offset(size as isize);
94 self.size -= size;
95 Some(Self {
96 base,
97 size,
98 kind: self.kind,
99 })
100 }
101
102 pub fn split_back(&mut self, size: usize) -> Option<Self> {
103 assert!(size <= isize::MAX as usize);
104 if size >= self.size {
105 return None;
106 }
107 let rem_size = self.size - size;
108 let base = self.base.offset(size as isize);
109 tracing::trace!(
110 size,
111 self.size,
112 ?self.base,
113 self.addr = fmt::ptr(&self),
114 rem_size,
115 ?base,
116 "split_back",
117 );
118 self.size = size;
119 tracing::trace!(?self);
120 Some(Self {
121 base,
122 size: rem_size,
123 kind: self.kind,
124 })
125 }
126
127 pub fn page_range<S: page::Size>(
128 &self,
129 size: S,
130 ) -> Result<page::PageRange<A, S>, page::NotAligned<S>> {
131 tracing::trace!(?self.base, self.size, self.end = ?self.end_addr(), "Region -> PageRange");
132 let start = page::Page::starting_at(self.base, size)?;
133 let end = page::Page::starting_at(self.end_addr(), size)?;
134 Ok(start.range_to(end))
135 }
136
137 pub fn from_page_range<S: page::Size>(range: page::PageRange<A, S>, kind: RegionKind) -> Self {
138 let base = range.start().base_addr();
139 Self {
140 base,
141 size: range.size(),
142 kind,
143 }
144 }
145
146 pub fn merge(&mut self, other: &mut Self) {
147 debug_assert_eq!(self.kind, other.kind);
148 self.base = cmp::min(self.base, other.base);
150 self.size += other.size;
151 }
152}
153
154impl<A> fmt::Debug for Region<A>
155where
156 A: fmt::Debug,
157{
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 let Self { base, size, kind } = self;
160 f.debug_struct("Region")
161 .field("base", base)
162 .field("size", size)
163 .field("kind", kind)
164 .finish()
165 }
166}
167
168impl RegionKind {
169 pub const UNKNOWN: Self = Self(KindInner::Unknown);
170
171 pub const FREE: Self = Self(KindInner::Free);
173
174 pub const USED: Self = Self(KindInner::Used);
176
177 pub const BOOT_RECLAIMABLE: Self = Self(KindInner::BootReclaimable);
184
185 pub const BOOT: Self = Self(KindInner::Boot);
188
189 pub const BAD: Self = Self(KindInner::Bad);
191
192 pub const KERNEL: Self = Self(KindInner::Kernel);
194
195 pub const KERNEL_STACK: Self = Self(KindInner::KernelStack);
197
198 pub const PAGE_TABLE: Self = Self(KindInner::PageTable);
200}
201
202impl fmt::Debug for RegionKind {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 match *self {
205 RegionKind::FREE => f.pad("FREE"),
206 RegionKind::USED => f.pad("USED"),
207 RegionKind::BOOT => f.pad("BOOT"),
208 RegionKind::BOOT_RECLAIMABLE => f.pad("BOOT_RECLAIMABLE"),
209 RegionKind::BAD => f.pad("BAD T_T"),
210 RegionKind::KERNEL => f.pad("KERNEL"),
211 RegionKind::KERNEL_STACK => f.pad("KERNEL_STACK"),
212 RegionKind::PAGE_TABLE => f.pad("PAGE_TABLE"),
213 _ => f.pad("UNKNOWN ?_?"),
214 }
215 }
216}