cpu-local 0.4.0

Architecture CPU-local register capability for TGOSKits
Documentation
use ax_cpu::registers;

use super::*;

pub(super) const CURRENT_MODEL: ArchitectureCurrentModel = ArchitectureCurrentModel {
    linux_current: CurrentContextSource::ArchitectureRegister,
    unikernel_tls: CurrentContextSource::ArchitectureRegister,
};

pub(super) struct Backend;

impl ArchitectureRegisterBackend for Backend {}

fn current_el() -> Result<usize, CpuLocalError> {
    let level = registers::current_exception_level();
    if matches!(level, 1 | 2) {
        Ok(level)
    } else {
        Err(CpuLocalError::UnsupportedHostLevel { level })
    }
}

pub(super) fn validate_environment() -> Result<(), CpuLocalError> {
    current_el().map(|_| ())
}

pub(super) unsafe fn install_cpu_base(area_base: usize, boot_context: usize) {
    match current_el().unwrap_or_else(|_| super::fatal_register_invariant()) {
        1 => unsafe { registers::write_tpidr_el1(area_base) },
        2 => unsafe { registers::write_tpidr_el2(area_base) },
        _ => unreachable!(),
    }
    unsafe { registers::write_sp_el0(boot_context) };
}

pub(super) unsafe fn read_cpu_base() -> Result<usize, CpuLocalError> {
    Ok(match current_el()? {
        1 => registers::read_tpidr_el1(),
        2 => registers::read_tpidr_el2(),
        _ => unreachable!(),
    })
}

pub(super) unsafe fn read_current_context(_area_base: usize) -> usize {
    registers::read_sp_el0()
}

pub(super) unsafe fn write_current_context(value: usize) {
    unsafe { registers::write_sp_el0(value) };
}

#[cfg(kernel_tls)]
pub(super) unsafe fn read_kernel_tls() -> usize {
    registers::read_thread_pointer().as_usize()
}

#[cfg(kernel_tls)]
pub(super) unsafe fn write_kernel_tls(value: usize) {
    unsafe { registers::write_thread_pointer(ax_cpu::context::KernelTlsBase::new(value)) };
}