os_bootinfo/
memory_map.rs1use core::fmt;
2use core::ops::{Deref, DerefMut};
3
4const PAGE_SIZE: u64 = 4096;
5
6#[repr(C)]
7pub struct MemoryMap {
8 entries: [MemoryRegion; 32],
9 next_entry_index: u64,
12}
13
14impl MemoryMap {
15 pub fn new() -> Self {
16 MemoryMap {
17 entries: [MemoryRegion::empty(); 32],
18 next_entry_index: 0,
19 }
20 }
21
22 pub fn add_region(&mut self, region: MemoryRegion) {
23 self.entries[self.next_entry_index()] = region;
24 self.next_entry_index += 1;
25 self.sort();
26 }
27
28 pub fn sort(&mut self) {
29 use core::cmp::Ordering;
30
31 self.entries.sort_unstable_by(|r1, r2| {
32 if r1.range.is_empty() {
33 Ordering::Greater
34 } else if r2.range.is_empty() {
35 Ordering::Less
36 } else {
37
38 let ordering = r1.range
39 .start_frame_number
40 .cmp(&r2.range.start_frame_number);
41
42 if ordering == Ordering::Equal {
43 r1.range
44 .end_frame_number
45 .cmp(&r2.range.end_frame_number)
46 } else {
47 ordering
48 }
49 }
50 });
51 if let Some(first_zero_index) = self.entries.iter().position(|r| r.range.is_empty()) {
52 self.next_entry_index = first_zero_index as u64;
53 }
54 }
55
56 fn next_entry_index(&self) -> usize {
57 self.next_entry_index as usize
58 }
59}
60
61impl Deref for MemoryMap {
62 type Target = [MemoryRegion];
63
64 fn deref(&self) -> &Self::Target {
65 &self.entries[0..self.next_entry_index()]
66 }
67}
68
69impl DerefMut for MemoryMap {
70 fn deref_mut(&mut self) -> &mut Self::Target {
71 let next_index = self.next_entry_index();
72 &mut self.entries[0..next_index]
73 }
74}
75
76impl fmt::Debug for MemoryMap {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 f.debug_list().entries(self.iter()).finish()
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83#[repr(C)]
84pub struct MemoryRegion {
85 pub range: FrameRange,
86 pub region_type: MemoryRegionType,
87}
88
89impl MemoryRegion {
90 pub fn empty() -> Self {
91 MemoryRegion {
92 range: FrameRange {
93 start_frame_number: 0,
94 end_frame_number: 0,
95 },
96 region_type: MemoryRegionType::Empty,
97 }
98 }
99}
100
101#[derive(Clone, Copy, PartialEq, Eq)]
102#[repr(C)]
103pub struct FrameRange {
104 pub start_frame_number: u64,
105 pub end_frame_number: u64,
107}
108
109impl FrameRange {
110 pub fn new(start_addr: u64, end_addr: u64) -> Self {
114 let last_byte = end_addr - 1;
115 FrameRange {
116 start_frame_number: start_addr / PAGE_SIZE,
117 end_frame_number: (last_byte / PAGE_SIZE) + 1,
118 }
119 }
120
121 pub fn is_empty(&self) -> bool {
122 self.start_frame_number == self.end_frame_number
123 }
124
125 pub fn start_addr(&self) -> u64 {
126 self.start_frame_number * PAGE_SIZE
127 }
128
129 pub fn end_addr(&self) -> u64 {
130 self.end_frame_number * PAGE_SIZE
131 }
132}
133
134impl fmt::Debug for FrameRange {
135 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 write!(
137 f,
138 "FrameRange({:#x}..{:#x})",
139 self.start_addr(),
140 self.end_addr()
141 )
142 }
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146#[repr(C)]
147pub enum MemoryRegionType {
148 Usable,
150 InUse,
152 Reserved,
154 AcpiReclaimable,
156 AcpiNvs,
158 BadMemory,
160 Kernel,
162 KernelStack,
164 PageTable,
166 Bootloader,
168 FrameZero,
172 Empty,
174 BootInfo,
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179#[repr(C)]
180pub struct E820MemoryRegion {
181 pub start_addr: u64,
182 pub len: u64,
183 pub region_type: u32,
184 pub acpi_extended_attributes: u32,
185}
186
187impl From<E820MemoryRegion> for MemoryRegion {
188 fn from(region: E820MemoryRegion) -> MemoryRegion {
189 let region_type = match region.region_type {
190 1 => MemoryRegionType::Usable,
191 2 => MemoryRegionType::Reserved,
192 3 => MemoryRegionType::AcpiReclaimable,
193 4 => MemoryRegionType::AcpiNvs,
194 5 => MemoryRegionType::BadMemory,
195 t => panic!("invalid region type {}", t),
196 };
197 MemoryRegion {
198 range: FrameRange::new(region.start_addr, region.start_addr + region.len),
199 region_type,
200 }
201 }
202}
203
204extern "C" {
205 fn _improper_ctypes_check(_boot_info: MemoryMap);
206}