#![no_std]
#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::all)]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod addr;
mod allocator;
mod error;
mod frame;
mod stats;
pub use addr::PhysAddr;
pub use allocator::BuddyAllocator;
pub use error::PhysMemError;
pub use frame::{PageFrame, PageOrder};
pub use stats::AllocatorStats;
pub use ruvix_types::KernelError;
pub const PAGE_SIZE: usize = 4096;
pub const PAGE_SHIFT: usize = 12;
pub const MAX_ORDER: usize = 10;
pub const MIN_ORDER: usize = 0;
pub const MAX_BLOCK_PAGES: usize = 1 << (MAX_ORDER - 1);
pub const MAX_BLOCK_SIZE: usize = MAX_BLOCK_PAGES * PAGE_SIZE;
#[inline]
#[must_use]
pub const fn pages_to_order(pages: usize) -> usize {
if pages == 0 {
return 0;
}
let leading_zeros = (pages - 1).leading_zeros() as usize;
let bits = core::mem::size_of::<usize>() * 8;
if leading_zeros >= bits {
0
} else {
bits - leading_zeros
}
}
#[inline]
#[must_use]
pub const fn order_to_pages(order: usize) -> usize {
1 << order
}
#[inline]
#[must_use]
pub const fn order_to_bytes(order: usize) -> usize {
order_to_pages(order) * PAGE_SIZE
}
#[inline]
#[must_use]
pub const fn is_page_aligned(addr: u64) -> bool {
addr & ((PAGE_SIZE as u64) - 1) == 0
}
#[inline]
#[must_use]
pub const fn align_down(addr: u64) -> u64 {
addr & !((PAGE_SIZE as u64) - 1)
}
#[inline]
#[must_use]
pub const fn align_up(addr: u64) -> u64 {
let page_mask = (PAGE_SIZE as u64) - 1;
(addr + page_mask) & !page_mask
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pages_to_order() {
assert_eq!(pages_to_order(0), 0);
assert_eq!(pages_to_order(1), 0);
assert_eq!(pages_to_order(2), 1);
assert_eq!(pages_to_order(3), 2);
assert_eq!(pages_to_order(4), 2);
assert_eq!(pages_to_order(5), 3);
assert_eq!(pages_to_order(8), 3);
assert_eq!(pages_to_order(9), 4);
assert_eq!(pages_to_order(16), 4);
assert_eq!(pages_to_order(17), 5);
assert_eq!(pages_to_order(256), 8);
assert_eq!(pages_to_order(512), 9);
}
#[test]
fn test_order_to_pages() {
assert_eq!(order_to_pages(0), 1);
assert_eq!(order_to_pages(1), 2);
assert_eq!(order_to_pages(2), 4);
assert_eq!(order_to_pages(3), 8);
assert_eq!(order_to_pages(4), 16);
assert_eq!(order_to_pages(9), 512);
}
#[test]
fn test_order_to_bytes() {
assert_eq!(order_to_bytes(0), 4096);
assert_eq!(order_to_bytes(1), 8192);
assert_eq!(order_to_bytes(2), 16384);
assert_eq!(order_to_bytes(9), 2 * 1024 * 1024);
}
#[test]
fn test_page_alignment() {
assert!(is_page_aligned(0));
assert!(is_page_aligned(PAGE_SIZE as u64));
assert!(is_page_aligned(0x1000_0000));
assert!(!is_page_aligned(1));
assert!(!is_page_aligned(PAGE_SIZE as u64 - 1));
}
#[test]
fn test_align_down() {
assert_eq!(align_down(0), 0);
assert_eq!(align_down(1), 0);
assert_eq!(align_down(4095), 0);
assert_eq!(align_down(4096), 4096);
assert_eq!(align_down(4097), 4096);
assert_eq!(align_down(8191), 4096);
assert_eq!(align_down(8192), 8192);
}
#[test]
fn test_align_up() {
assert_eq!(align_up(0), 0);
assert_eq!(align_up(1), 4096);
assert_eq!(align_up(4095), 4096);
assert_eq!(align_up(4096), 4096);
assert_eq!(align_up(4097), 8192);
assert_eq!(align_up(8192), 8192);
}
#[test]
fn test_roundtrip_order_pages() {
for order in 0..MAX_ORDER {
let pages = order_to_pages(order);
let back = pages_to_order(pages);
assert_eq!(back, order, "Order {order} -> {pages} pages -> order {back}");
}
}
}