pub const PFN_NONE: u32 = u32::MAX;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum PageFlags {
Free = 0,
Allocated = 1,
Slab = 2,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct PageMeta {
pub flags: PageFlags,
pub order: u8,
pub _pad: u16,
pub prev: u32,
pub next: u32,
}
const _: () = assert!(core::mem::size_of::<PageMeta>() == 12);
impl Default for PageMeta {
fn default() -> Self {
Self::new()
}
}
impl PageMeta {
pub const fn new() -> Self {
Self {
flags: PageFlags::Free,
order: 0,
_pad: 0,
prev: PFN_NONE,
next: PFN_NONE,
}
}
}
#[inline]
pub unsafe fn free_list_push(meta: *mut PageMeta, free_lists: &mut [u32], pfn: u32, order: usize) {
unsafe {
let old_head = free_lists[order];
let m = &mut *meta.add(pfn as usize);
m.prev = PFN_NONE;
m.next = old_head;
if old_head != PFN_NONE {
(*meta.add(old_head as usize)).prev = pfn;
}
free_lists[order] = pfn;
}
}
#[inline]
pub unsafe fn free_list_pop(meta: *mut PageMeta, free_lists: &mut [u32], order: usize) -> u32 {
unsafe {
let head = free_lists[order];
if head == PFN_NONE {
return PFN_NONE;
}
let m = &mut *meta.add(head as usize);
let next = m.next;
m.prev = PFN_NONE;
m.next = PFN_NONE;
if next != PFN_NONE {
(*meta.add(next as usize)).prev = PFN_NONE;
}
free_lists[order] = next;
head
}
}
#[inline]
pub unsafe fn free_list_remove(
meta: *mut PageMeta,
free_lists: &mut [u32],
pfn: u32,
order: usize,
) {
unsafe {
let m = &*meta.add(pfn as usize);
let prev = m.prev;
let next = m.next;
if prev != PFN_NONE {
(*meta.add(prev as usize)).next = next;
} else {
free_lists[order] = next;
}
if next != PFN_NONE {
(*meta.add(next as usize)).prev = prev;
}
let m = &mut *meta.add(pfn as usize);
m.prev = PFN_NONE;
m.next = PFN_NONE;
}
}