pub use cpu_local::CpuIndex;
pub use mmio_api::{MapError, MmioAddr, MmioOp, MmioRaw};
pub fn cpu_index(cpu_index: usize) -> Result<CpuIndex, CpuBindError> {
let raw_index = cpu_index;
let cpu_index =
CpuIndex::try_from(cpu_index).map_err(|_| CpuBindError::InvalidCpu { index: raw_index })?;
crate::smp::percpu_data_ptr(cpu_index.as_usize())
.ok_or(CpuBindError::MissingArea { cpu_index })?;
Ok(cpu_index)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
pub enum CpuBindError {
#[error("the kernel runtime does not support CPU-local register binding")]
Unsupported,
#[error("logical CPU index {index} is outside the CPU-local index range")]
InvalidCpu { index: usize },
#[error("someboot did not publish CPU-local area {cpu_index:?}")]
MissingArea { cpu_index: CpuIndex },
#[error("the final image has not installed its per-CPU layout")]
LayoutNotInstalled,
#[error("CPU {cpu_index:?} is outside per-CPU layout area count {area_count}")]
CpuOutOfRange {
cpu_index: CpuIndex,
area_count: u32,
},
#[error("CPU-local area address calculation overflowed")]
AddressOverflow,
#[error("CPU-local binding does not match the installed runtime layout")]
LayoutMismatch,
#[error(transparent)]
CpuLocal(#[from] cpu_local::CpuLocalError),
}
pub trait KernelOp: MmioOp {
fn bind_current_cpu(&self, cpu_index: CpuIndex) -> Result<(), CpuBindError> {
let _ = cpu_index;
Err(CpuBindError::Unsupported)
}
fn current_cpu_idx(&self) -> Option<usize> {
None
}
}
struct EmptyKernelOp;
impl KernelOp for EmptyKernelOp {}
impl MmioOp for EmptyKernelOp {
fn ioremap(&self, _addr: MmioAddr, _size: usize) -> Result<MmioRaw, MapError> {
unimplemented!()
}
fn iounmap(&self, _mmio: &MmioRaw) {
unimplemented!()
}
}
static mut KERNEL_OP: &'static dyn KernelOp = &EmptyKernelOp;
pub(crate) fn set_kernel_op(op: &'static dyn KernelOp) {
mmio_api::init(op);
unsafe {
KERNEL_OP = op;
}
}
pub(crate) fn kernel() -> &'static dyn KernelOp {
unsafe { KERNEL_OP }
}