Skip to main content

kernel/arch/x86_64/boot/
mm.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! x86_64 memory boot sequence
3//!
4//! Authors: MarioS271
5
6use crate::arch::x86_64::boot::entry::LIMINE_MEMMAP_REQUEST;
7use crate::lib::addr::{PhysAddr, VirtAddr};
8use crate::lib::panic::kernel_panic;
9use crate::lib::panic_codes::PanicCode;
10use crate::lib::types::boot_info::KernelSectionInfo;
11use crate::lib::types::fmt_buffer::FmtBuffer;
12use crate::mm::pmm::FRAME_SIZE;
13use crate::mm::vmm::Vmm;
14use crate::mm::vmm::address_space::AddressSpace;
15use crate::mm::vmm::boot_mapping::BootMappings;
16use crate::mm::vmm::traits::VmmPaging;
17use crate::state::kstate::KSTATE;
18use crate::{kdebug, mm};
19use limine::memmap::MEMMAP_BOOTLOADER_RECLAIMABLE;
20use limine::request::{MemmapRespData, Response};
21
22pub fn mm_init(section_info: &KernelSectionInfo) {
23    let kernel_page: VirtAddr;
24    let boot_mappings: BootMappings;
25    
26    if let Some(memmap_response) = LIMINE_MEMMAP_REQUEST.response() {
27        // Safety: init_pmm is only called once which is here; no SMP/threading is currently active
28        unsafe { KSTATE.mm.init_pmm(mm::pmm::Pmm::init(memmap_response.entries())) };
29        (kernel_page, boot_mappings) = Vmm::setup_kernel_paging(section_info);
30
31        // TODO: reclaim only when we have our own stack
32        // reclaim_bootloader_memory(memmap_response);
33    } else {
34        kernel_panic(
35            PanicCode::InitFailure,
36            "Limine did not provide an initial memmap"
37        );
38    }
39
40    mm::heap::init(kernel_page);
41
42    // Safety: init_kernel_addr_space is only called once which is here; no SMP/threading is currently active
43    unsafe { KSTATE.mm.init_kernel_addr_space(AddressSpace::empty(kernel_page)) };
44    // Safety: kernel_addr_space was initialized one line ago, meaning it is guaranteed to exist
45    if let Err(error) = unsafe {
46        KSTATE.mm.kernel_addr_space().lock().setup_kernel_vmas(&boot_mappings)
47    } {
48        use core::fmt::Write;
49
50        let mut buffer: FmtBuffer<64> = FmtBuffer::new();
51        let _ = write!(buffer, "Failed to set up kernel VMAs ({:?})", error);
52        
53        kernel_panic(
54            PanicCode::InitFailure,
55            buffer.as_str()
56        );
57    }
58}
59
60fn reclaim_bootloader_memory(memmap_response: &Response<MemmapRespData>) {
61    // Safety: full mm kernel boot happens before this function is called in mm_init, guaranteeing
62    // that pmm is initialized
63    let mut pmm = unsafe { KSTATE.mm.pmm().lock() };
64
65    #[cfg(feature = "debug-logging")]
66    let (mut total_bytes, mut total_entries) = (0u64, 0u64);
67
68    const MAX_ENTRIES: usize = 256;
69
70    let mut entries: [(u64, u64); MAX_ENTRIES] = [(0, 0); MAX_ENTRIES];
71    let mut num_entries: usize = 0;
72
73    for entry in memmap_response.entries() {
74        if entry.type_ != MEMMAP_BOOTLOADER_RECLAIMABLE {
75            continue;
76        }
77
78        entries[num_entries] = (entry.base, entry.length);
79        num_entries += 1;
80    }
81
82    if num_entries >= MAX_ENTRIES {
83        kernel_panic(
84            PanicCode::InitFailure,
85            "Found more reclaimable bootloader entries than currently supported"
86        );
87    }
88
89    for i in 0..num_entries {
90        #[cfg(feature = "debug-logging")]
91        {
92            total_entries += 1;
93            total_bytes += entries[i].1;
94        }
95
96        let mut base_addr = entries[i].0;
97        let mut remaining = entries[i].1;
98
99        kdebug!("[reclaim] base={:#x} len={:#x}", base_addr, remaining);
100
101        while remaining >= FRAME_SIZE {
102            let mut order = 10usize;
103            while order > 0 {
104                let block_size = FRAME_SIZE << order;
105                if base_addr % block_size == 0 && remaining >= block_size {
106                    break;
107                }
108                order -= 1;
109            }
110
111            pmm.free(PhysAddr::new(base_addr), order);
112
113            let block_size = FRAME_SIZE << order;
114            base_addr += block_size;
115            remaining -= block_size;
116        }
117    }
118
119    kdebug!("reclaimed {} bootloader memory entries ({} MiB)", total_entries, total_bytes / 1024 / 1024);
120}