#![deny(missing_docs)]
#![allow(static_mut_refs)]
use core::slice;
use core::{
fmt::Debug,
hint::spin_loop,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, Ordering},
};
use sel4::{CapRights, VmAttributes, cap::Granule, init_thread::slot};
use sel4_kit::slot_manager::LeafSlot;
use spin::Lazy;
use crate::config::PAGE_SIZE;
use crate::slot::alloc_slot;
#[repr(C, align(4096))]
pub struct FreePagePlaceHolder([u8; PAGE_SIZE]);
impl FreePagePlaceHolder {
fn addr(&self) -> usize {
self.0.as_ptr() as usize
}
}
static mut FREE_PAGE_PLACEHOLDER: FreePagePlaceHolder = FreePagePlaceHolder([0; PAGE_SIZE]);
static PAGE_MAP_LOCK: AtomicBool = AtomicBool::new(false);
#[derive(Clone)]
pub struct PhysPage {
cap: Granule,
}
impl PhysPage {
pub const fn new(cap: Granule) -> Self {
Self { cap }
}
#[inline]
pub fn addr(&self) -> usize {
self.cap
.frame_get_address()
.expect("can't get address of the physical page")
}
pub const fn cap(&self) -> Granule {
self.cap
}
pub fn lock(&self) -> PhysPageLocker {
static PLACE_HOLDER_SLOT: Lazy<LeafSlot> = Lazy::new(alloc_slot);
while PAGE_MAP_LOCK.load(Ordering::SeqCst) {
spin_loop();
}
PAGE_MAP_LOCK.store(true, Ordering::SeqCst);
let slot = *PLACE_HOLDER_SLOT;
slot.copy_from(&self.cap.into(), CapRights::all()).unwrap();
let addr = unsafe { FREE_PAGE_PLACEHOLDER.addr() };
let cap: Granule = slot.cap();
cap.frame_map(
slot::VSPACE.cap(),
addr,
CapRights::all(),
VmAttributes::DEFAULT,
)
.unwrap();
PhysPageLocker {
cap,
data: unsafe { slice::from_raw_parts_mut(addr as _, PAGE_SIZE) },
}
}
}
pub struct PhysPageLocker<'a> {
cap: Granule,
data: &'a mut [u8],
}
impl PhysPageLocker<'_> {
#[inline]
pub fn write_usize(&mut self, mut offset: usize, data: usize) {
offset %= PAGE_SIZE;
let len = core::mem::size_of::<usize>();
self.data[offset..offset + len].copy_from_slice(&data.to_le_bytes());
}
#[inline]
pub fn write_bytes(&mut self, mut offset: usize, data: &[u8]) {
offset %= PAGE_SIZE;
self.data[offset..offset + data.len()].copy_from_slice(data);
}
#[inline]
pub fn write_u8(&mut self, mut offset: usize, data: u8) {
offset %= PAGE_SIZE;
self.data[offset] = data;
}
pub fn read_usize(&self, mut offset: usize) -> usize {
offset %= PAGE_SIZE;
unsafe { (self.data.as_ptr().add(offset) as *const usize).read() }
}
}
impl Deref for PhysPageLocker<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.data
}
}
impl DerefMut for PhysPageLocker<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data
}
}
impl Drop for PhysPageLocker<'_> {
fn drop(&mut self) {
self.cap.frame_unmap().unwrap();
LeafSlot::from(self.cap).delete().unwrap();
PAGE_MAP_LOCK.store(false, Ordering::SeqCst);
}
}
impl Debug for PhysPage {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PhysPage")
.field("cap", &(self.cap.frame_get_address()))
.finish()
}
}