Skip to main content

proka_kernel/memory/
paging.rs

1//! Paging module for Proka Kernel
2//! Copyright (C) RainSTR Studio 2025, All Rights Reserved.
3//!
4//! This module provides paging support, including:
5//! - HHDM (Higher Half Direct Map) offset retrieval
6//! - OffsetPageTable initialization
7//! - Bitmap-based frame allocator with deallocation support
8//! - Memory statistics and protection utilities
9
10extern crate alloc;
11use crate::memory::frame_allocator::{format_bytes, FrameStats, LockedFrameAllocator};
12use crate::println;
13use limine::response::MemoryMapResponse;
14use x86_64::{
15    registers::control::Cr3,
16    structures::paging::{OffsetPageTable, PageTable},
17    VirtAddr,
18};
19
20/// Retrieve the HHDM (Higher Half Direct Map) offset from Limine
21///
22/// This offset is used to map physical memory into virtual address space.
23pub fn get_hhdm_offset() -> VirtAddr {
24    VirtAddr::new(
25        crate::HHDM_REQUEST
26            .get_response()
27            .expect("Failed to get HHDM response")
28            .offset(),
29    )
30}
31
32/// Initialize an OffsetPageTable for accessing page tables
33///
34/// # Arguments
35/// * `physical_memory_offset` - The HHDM offset returned by bootloader
36///
37/// # Safety
38/// This function is unsafe because the caller must guarantee that:
39/// - The complete physical memory is mapped to virtual memory at the passed offset
40/// - This function is only called once to avoid aliasing `&mut` references
41pub unsafe fn init_offset_page_table(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
42    unsafe {
43        let level_4_table = active_level_4_table(physical_memory_offset);
44        OffsetPageTable::new(level_4_table, physical_memory_offset)
45    }
46}
47
48/// Returns a mutable reference to the active level 4 table.
49///
50/// # Safety
51/// This function is unsafe because the caller must guarantee that:
52/// - The complete physical memory is mapped to virtual memory at the passed offset
53/// - This function is only called once to avoid aliasing `&mut` references
54unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
55    let (level_4_table_frame, _) = Cr3::read();
56
57    let phys = level_4_table_frame.start_address();
58    let virt = physical_memory_offset + phys.as_u64();
59    let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
60
61    unsafe { &mut *page_table_ptr }
62}
63
64/// Create a buddy system based frame allocator with deallocation support
65///
66/// # Arguments
67/// * `memory_map` - The memory map from Limine bootloader
68///
69/// # Safety
70/// This function is unsafe because the caller must guarantee that:
71/// - The passed memory map is valid
72/// - All frames marked as `USABLE` in it are really unused
73pub unsafe fn init_frame_allocator(memory_map: &'static MemoryMapResponse) -> LockedFrameAllocator {
74    LockedFrameAllocator::init(memory_map)
75}
76
77/// Print memory statistics
78///
79/// # Arguments
80/// * `frame_allocator` - The frame allocator to query
81pub fn print_memory_stats(frame_allocator: &LockedFrameAllocator) {
82    let stats = frame_allocator.stats();
83
84    println!("=== Memory Statistics ===");
85    println!("Total frames:    {}", stats.total_frames);
86    println!("Used frames:     {}", stats.used_frames);
87    println!("Free frames:     {}", stats.free_frames);
88    println!("Total memory:    {}", format_bytes(stats.total_memory));
89    println!("Used memory:     {}", format_bytes(stats.used_memory));
90    println!("Free memory:     {}", format_bytes(stats.free_memory));
91    println!(
92        "Usage:           {}%",
93        (stats.used_frames * 100) / stats.total_frames
94    );
95}
96
97/// Get memory statistics
98///
99/// # Arguments
100/// * `frame_allocator` - The frame allocator to query
101///
102/// # Returns
103/// * FrameStats containing memory usage information
104pub fn get_memory_stats(frame_allocator: &LockedFrameAllocator) -> FrameStats {
105    frame_allocator.stats()
106}