Skip to main content

kernel/mm/
heap.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Kernel heap allocator: a fixed-size [`linked_list_allocator::LockedHeap`] set as
3//! the `#[global_allocator]`. Does not grow after [`init`].
4//!
5//! Authors: MarioS271
6
7use crate::arch::x86_64::mm::vmm::page_type::PageType;
8use crate::lib::addr::VirtAddr;
9use crate::lib::panic::kernel_panic;
10use crate::lib::panic_codes::PanicCode;
11use crate::mm::vmm::{traits::VmmPaging, Vmm};
12use crate::state::kstate::KSTATE;
13use linked_list_allocator::LockedHeap;
14use x86_64::structures::paging::PageTableFlags;
15
16// TODO: redo heap allocator properly
17
18/// First virtual address of the heap region (higher-half kernel space).
19const HEAP_BASE_ADDRESS: VirtAddr = VirtAddr::new(0xffff_f800_0000_0000);
20
21/// Total heap size in bytes (4 MiB).
22const HEAP_SIZE: usize = 0x400_000;
23
24/// The global allocator instance; empty until [`init`].
25#[global_allocator]
26static ALLOCATOR: LockedHeap = LockedHeap::empty();
27
28/// Map the heap virtual address range to physical frames and initialize the allocator.
29///
30/// # Panics
31/// Panics with [`PanicCode::OutOfMemory`] if the PMM cannot satisfy any frame allocation.
32pub fn init(kernel_root_page: VirtAddr) {
33    // Safety: the PMM gets initialized before the heap in mm_init
34    let mut pmm = unsafe { KSTATE.mm.pmm().lock() };
35
36    const HUGE_PAGE_SIZE: usize = 0x200_000; // 2 MiB
37    const NUM_HUGE_PAGES: usize = HEAP_SIZE / HUGE_PAGE_SIZE; // 2
38
39    for page in 0..NUM_HUGE_PAGES {
40        let phys = pmm.alloc(9).unwrap_or_else(
41            || kernel_panic(
42                PanicCode::OutOfMemory,
43                "Out of memory for heap"
44            )
45        );
46
47        // Safety: kernel_root_page is the valid kernel PML4, phys is a valid frame that was
48        // just mapped
49        unsafe {
50            if Vmm::map_page(
51                &mut pmm,
52                kernel_root_page,
53                HEAP_BASE_ADDRESS + (page * HUGE_PAGE_SIZE) as u64,
54                phys,
55                PageType::HugePage2MiB,   // TODO: no arch specific page type here
56                PageTableFlags::WRITABLE,
57            ).is_err() {
58                kernel_panic(
59                    PanicCode::OutOfMemory,
60                    "Could not map one or more kernel heap pages, out of memory"
61                )
62            }
63        }
64    }
65
66    // Safety: boot was never called before, the given heap base addr is valid, static and not
67    // used for anything else
68    unsafe {
69        ALLOCATOR.lock().init(HEAP_BASE_ADDRESS.as_mut_ptr::<u8>(), HEAP_SIZE);
70    }
71}