⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/mm/
bootloader.rs

1//! Bootloader memory map integration
2//!
3//! Handles parsing and processing of memory maps from various bootloaders
4//! (GRUB, UEFI, custom bootloader, etc.)
5
6// Bootloader memory map integration -- used during early boot
7#![allow(dead_code)]
8
9use super::{
10    frame_allocator::ReservedRegion, FrameNumber, MemoryRegion, FRAME_ALLOCATOR, FRAME_SIZE,
11};
12use crate::error::KernelError;
13
14#[cfg(feature = "alloc")]
15extern crate alloc;
16
17#[cfg(feature = "alloc")]
18use alloc::vec::Vec;
19
20/// Memory region type from bootloader
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum MemoryRegionType {
23    /// Usable RAM
24    Usable,
25    /// Reserved by firmware/BIOS
26    Reserved,
27    /// ACPI data that can be reclaimed
28    AcpiReclaimable,
29    /// ACPI NVS memory
30    AcpiNvs,
31    /// Bad memory
32    BadMemory,
33    /// Kernel and modules
34    KernelAndModules,
35    /// Bootloader reclaimable
36    BootloaderReclaimable,
37    /// Framebuffer
38    Framebuffer,
39    /// Unknown type
40    Unknown(u32),
41}
42
43/// Extended memory region with type information
44#[derive(Debug, Clone, Copy)]
45pub struct BootloaderMemoryRegion {
46    pub start: u64,
47    pub size: u64,
48    pub region_type: MemoryRegionType,
49}
50
51impl BootloaderMemoryRegion {
52    /// Create a new memory region
53    pub const fn new(start: u64, size: u64, region_type: MemoryRegionType) -> Self {
54        Self {
55            start,
56            size,
57            region_type,
58        }
59    }
60
61    /// Check if this region is usable memory
62    pub const fn is_usable(&self) -> bool {
63        matches!(self.region_type, MemoryRegionType::Usable)
64    }
65
66    /// Convert to simple memory region
67    pub const fn to_memory_region(self) -> MemoryRegion {
68        MemoryRegion {
69            start: self.start,
70            size: self.size,
71            usable: self.is_usable(),
72        }
73    }
74}
75
76/// Parse E820 memory map (x86_64 BIOS)
77#[cfg(target_arch = "x86_64")]
78pub fn parse_e820_map(entries: &[(u64, u64, u32)]) -> Vec<BootloaderMemoryRegion> {
79    let mut regions = Vec::with_capacity(entries.len());
80
81    for &(base, length, typ) in entries {
82        let region_type = match typ {
83            1 => MemoryRegionType::Usable,
84            2 => MemoryRegionType::Reserved,
85            3 => MemoryRegionType::AcpiReclaimable,
86            4 => MemoryRegionType::AcpiNvs,
87            5 => MemoryRegionType::BadMemory,
88            _ => MemoryRegionType::Unknown(typ),
89        };
90
91        regions.push(BootloaderMemoryRegion::new(base, length, region_type));
92    }
93
94    regions
95}
96
97/// Parse UEFI memory map
98pub fn parse_uefi_map(descriptors: &[UefiMemoryDescriptor]) -> Vec<BootloaderMemoryRegion> {
99    let mut regions = Vec::with_capacity(descriptors.len());
100
101    for desc in descriptors {
102        let region_type = match desc.typ {
103            0..=2 => MemoryRegionType::Reserved,
104            3 => MemoryRegionType::BootloaderReclaimable,
105            4 => MemoryRegionType::BootloaderReclaimable,
106            7 => MemoryRegionType::Usable,
107            9 => MemoryRegionType::AcpiReclaimable,
108            10 => MemoryRegionType::AcpiNvs,
109            11 => MemoryRegionType::Reserved,
110            _ => MemoryRegionType::Unknown(desc.typ),
111        };
112
113        regions.push(BootloaderMemoryRegion::new(
114            desc.phys_start,
115            desc.num_pages * 4096, // EFI page size
116            region_type,
117        ));
118    }
119
120    regions
121}
122
123/// UEFI memory descriptor
124#[repr(C)]
125pub struct UefiMemoryDescriptor {
126    pub typ: u32,
127    pub phys_start: u64,
128    pub virt_start: u64,
129    pub num_pages: u64,
130    pub attr: u64,
131}
132
133/// Process bootloader memory map and initialize frame allocator
134pub fn process_memory_map(regions: &[BootloaderMemoryRegion]) -> Result<(), KernelError> {
135    println!("[BOOT] Processing bootloader memory map...");
136
137    let mut total_memory = 0u64;
138    let mut usable_memory = 0u64;
139    let mut reserved_count = 0;
140
141    // First pass: mark reserved regions
142    for region in regions {
143        total_memory += region.size;
144
145        match region.region_type {
146            MemoryRegionType::Reserved
147            | MemoryRegionType::AcpiNvs
148            | MemoryRegionType::BadMemory
149            | MemoryRegionType::KernelAndModules
150            | MemoryRegionType::Framebuffer => {
151                // Mark as reserved in frame allocator
152                let start_frame = region.start / FRAME_SIZE as u64;
153                let end_frame = (region.start + region.size).div_ceil(FRAME_SIZE as u64);
154
155                let description = match region.region_type {
156                    MemoryRegionType::Reserved => "Reserved",
157                    MemoryRegionType::AcpiNvs => "ACPI NVS",
158                    MemoryRegionType::BadMemory => "Bad Memory",
159                    MemoryRegionType::KernelAndModules => "Kernel/Modules",
160                    MemoryRegionType::Framebuffer => "Framebuffer",
161                    _ => "Reserved",
162                };
163
164                let reserved = ReservedRegion {
165                    start: FrameNumber::new(start_frame),
166                    end: FrameNumber::new(end_frame),
167                    description,
168                };
169
170                FRAME_ALLOCATOR
171                    .lock()
172                    .add_reserved_region(reserved)
173                    .map_err(|_| KernelError::ResourceExhausted {
174                        resource: "reserved memory regions",
175                    })?;
176
177                reserved_count += 1;
178            }
179            _ => {}
180        }
181    }
182
183    // Second pass: add usable memory
184    let mut allocator = FRAME_ALLOCATOR.lock();
185    let mut region_count = 0;
186
187    for region in regions {
188        if region.is_usable() {
189            usable_memory += region.size;
190
191            let start_frame = region.start / FRAME_SIZE as u64;
192            let frame_count = region.size as usize / FRAME_SIZE;
193
194            // Skip very small regions
195            if frame_count < 16 {
196                continue;
197            }
198
199            // Use region index as NUMA node (simplified)
200            let numa_node = region_count % 8;
201
202            if let Err(_e) =
203                allocator.init_numa_node(numa_node, FrameNumber::new(start_frame), frame_count)
204            {
205                println!(
206                    "[BOOT] Warning: Failed to add memory region at 0x{:x}",
207                    region.start
208                );
209            } else {
210                println!(
211                    "[BOOT] Added {} MB at 0x{:x} (NUMA node {})",
212                    region.size / (1024 * 1024),
213                    region.start,
214                    numa_node
215                );
216                region_count += 1;
217            }
218        }
219    }
220
221    drop(allocator);
222
223    #[cfg(target_arch = "x86_64")]
224    println!(
225        "[BOOT] Memory map processed: {} MB total, {} MB usable, {} reserved regions",
226        total_memory / (1024 * 1024),
227        usable_memory / (1024 * 1024),
228        reserved_count
229    );
230
231    #[cfg(not(target_arch = "x86_64"))]
232    {
233        let _ = total_memory;
234        let _ = usable_memory;
235        let _ = reserved_count;
236        println!("[BOOT] Memory map processed");
237    }
238
239    Ok(())
240}
241
242/// Standard x86 memory regions to reserve
243pub fn reserve_standard_regions() -> Result<(), KernelError> {
244    let allocator = FRAME_ALLOCATOR.lock();
245
246    // Reserve first megabyte (BIOS, IVT, BDA, etc.)
247    let bios_region = ReservedRegion {
248        start: FrameNumber::new(0),
249        end: FrameNumber::new(256),
250        description: "BIOS/Real mode",
251    };
252    allocator
253        .add_reserved_region(bios_region)
254        .map_err(|_| KernelError::ResourceExhausted {
255            resource: "reserved memory regions",
256        })?;
257
258    // Reserve common BIOS areas
259    let video_region = ReservedRegion {
260        start: FrameNumber::new(0xA0),
261        end: FrameNumber::new(0x100),
262        description: "Video memory",
263    };
264    allocator
265        .add_reserved_region(video_region)
266        .map_err(|_| KernelError::ResourceExhausted {
267            resource: "reserved memory regions",
268        })?;
269
270    // Reserve local APIC region (typically at 0xFEE00000)
271    #[cfg(target_arch = "x86_64")]
272    {
273        let apic_frame = 0xFEE00000 / FRAME_SIZE as u64;
274        let apic_region = ReservedRegion {
275            start: FrameNumber::new(apic_frame),
276            end: FrameNumber::new(apic_frame + 1),
277            description: "Local APIC",
278        };
279        allocator
280            .add_reserved_region(apic_region)
281            .map_err(|_| KernelError::ResourceExhausted {
282                resource: "reserved memory regions",
283            })?;
284    }
285
286    Ok(())
287}