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}