os_bootinfo/
memory_map.rs

1use 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    // u64 instead of usize so that the structure layout is platform
10    // independent
11    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    // exclusive
106    pub end_frame_number: u64,
107}
108
109impl FrameRange {
110    /// Create a new FrameRange from the passed start_addr and end_addr.
111    ///
112    /// The end_addr is exclusive.
113    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    /// free RAM
149    Usable,
150    /// used RAM
151    InUse,
152    /// unusable
153    Reserved,
154    /// ACPI reclaimable memory
155    AcpiReclaimable,
156    /// ACPI NVS memory
157    AcpiNvs,
158    /// Area containing bad memory
159    BadMemory,
160    /// kernel memory
161    Kernel,
162    /// kernel stack memory
163    KernelStack,
164    /// memory used by page tables
165    PageTable,
166    /// memory used by the bootloader
167    Bootloader,
168    /// frame at address zero
169    ///
170    /// (shouldn't be used because it's easy to make mistakes related to null pointers)
171    FrameZero,
172    /// an empty region with size 0
173    Empty,
174    /// used for storing the boot information
175    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}