use core::time::Duration;
#[cfg(feature = "paging")]
use ax_memory_addr::MemoryAddr;
use axklib::{
AxError, AxResult, BoxedIrqHandler, ConcurrentBoxedIrqHandler, IrqCpuId, IrqCpuMask, IrqError,
IrqHandle, IrqId, Klib, PhysAddr, VirtAddr, impl_trait,
};
struct KlibImpl;
#[cfg(feature = "paging")]
fn dma_coherent_range(addr: VirtAddr, size: usize) -> Option<(VirtAddr, usize)> {
if size == 0 {
return None;
}
let start = addr.align_down_4k();
let end = (addr + size).align_up_4k();
Some((start, end - start))
}
#[cfg(feature = "irq")]
fn map_irq_error(err: IrqError) -> AxError {
match err {
IrqError::InvalidIrq | IrqError::InvalidCpu => AxError::InvalidInput,
IrqError::CpuOffline | IrqError::Unsupported => AxError::Unsupported,
IrqError::Timeout => AxError::TimedOut,
IrqError::Busy | IrqError::InIrqContext => AxError::ResourceBusy,
IrqError::NoMemory => AxError::NoMemory,
IrqError::NotFound => AxError::NotFound,
IrqError::Controller => AxError::Io,
}
}
fn dma_cache_range(op: ax_hal::mem::DCacheOp, addr: VirtAddr, size: usize) {
ax_hal::mem::dcache_range(op, addr, size);
}
impl_trait! {
impl Klib for KlibImpl {
fn mem_iomap(addr: PhysAddr, size: usize) -> AxResult<VirtAddr> {
#[cfg(feature = "paging")]
{
ax_mm::iomap(addr, size)
}
#[cfg(not(feature = "paging"))]
{
let _ = (addr, size);
Err(AxError::Unsupported)
}
}
fn mem_virt_to_phys(addr: VirtAddr) -> PhysAddr {
ax_hal::mem::virt_to_phys(addr)
}
fn dma_cache_clean(addr: VirtAddr, size: usize) {
dma_cache_range(ax_hal::mem::DCacheOp::Clean, addr, size);
}
fn dma_cache_invalidate(addr: VirtAddr, size: usize) {
dma_cache_range(ax_hal::mem::DCacheOp::Invalidate, addr, size);
}
fn dma_cache_clean_invalidate(addr: VirtAddr, size: usize) {
dma_cache_range(ax_hal::mem::DCacheOp::CleanInvalidate, addr, size);
}
fn mem_make_dma_coherent_uncached(addr: VirtAddr, size: usize) -> AxResult {
#[cfg(feature = "paging")]
{
let Some((start, size)) = dma_coherent_range(addr, size) else {
return Ok(());
};
ax_hal::mem::dma_coherent_before_make_uncached(start, size);
ax_mm::kernel_aspace().lock().protect(
start,
size,
ax_hal::paging::MappingFlags::READ
| ax_hal::paging::MappingFlags::WRITE
| ax_hal::paging::MappingFlags::UNCACHED,
)?;
ax_hal::asm::flush_tlb(None);
ax_hal::mem::dma_coherent_after_mapping_update();
Ok(())
}
#[cfg(not(feature = "paging"))]
{
let _ = (addr, size);
Err(AxError::Unsupported)
}
}
fn mem_restore_dma_cached(addr: VirtAddr, size: usize) -> AxResult {
#[cfg(feature = "paging")]
{
let Some((start, size)) = dma_coherent_range(addr, size) else {
return Ok(());
};
ax_hal::mem::dma_coherent_before_restore_cached(start, size);
ax_mm::kernel_aspace().lock().protect(
start,
size,
ax_hal::paging::MappingFlags::READ | ax_hal::paging::MappingFlags::WRITE,
)?;
ax_hal::asm::flush_tlb(None);
ax_hal::mem::dma_coherent_after_mapping_update();
Ok(())
}
#[cfg(not(feature = "paging"))]
{
let _ = (addr, size);
Err(AxError::Unsupported)
}
}
fn dma_alloc_pages(dma_mask: u64, num_pages: usize, align: usize) -> AxResult<VirtAddr> {
let addr = if dma_mask <= u32::MAX as u64 {
ax_alloc::global_allocator().alloc_dma32_pages(
num_pages,
align,
ax_alloc::UsageKind::Dma,
)
} else {
ax_alloc::global_allocator().alloc_pages(
num_pages,
align,
ax_alloc::UsageKind::Dma,
)
}?;
Ok(VirtAddr::from(addr))
}
fn dma_dealloc_pages(addr: VirtAddr, num_pages: usize) {
ax_alloc::global_allocator().dealloc_pages(
addr.as_usize(),
num_pages,
ax_alloc::UsageKind::Dma,
);
}
fn time_busy_wait(dur: Duration) {
ax_hal::time::busy_wait(dur);
}
fn time_monotonic_nanos() -> u64 {
ax_hal::time::monotonic_time_nanos()
}
fn time_try_init_epoch_offset(epoch_time_nanos: u64) -> bool {
ax_hal::time::try_init_epoch_offset(epoch_time_nanos)
}
fn irq_set_enable(_irq: IrqId, _enabled: bool) -> AxResult {
#[cfg(feature = "irq")]
{
ax_hal::irq::set_enable(_irq, _enabled).map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
fn irq_request_shared(
_irq: IrqId,
_handler: BoxedIrqHandler,
) -> AxResult<IrqHandle> {
#[cfg(feature = "irq")]
{
ax_hal::irq::request_shared_irq(_irq, _handler).map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
fn irq_request_shared_disabled(
_irq: IrqId,
_handler: BoxedIrqHandler,
) -> AxResult<IrqHandle> {
#[cfg(feature = "irq")]
{
ax_hal::irq::request_irq(
_irq,
ax_hal::irq::IrqRequest::new(_handler)
.share_mode(ax_hal::irq::ShareMode::Shared)
.auto_enable(ax_hal::irq::AutoEnable::No),
)
.map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
fn irq_request_percpu(
_irq: IrqId,
_cpus: IrqCpuMask,
_handler: ConcurrentBoxedIrqHandler,
) -> AxResult<IrqHandle> {
#[cfg(feature = "irq")]
{
ax_hal::irq::request_percpu_irq(_irq, _cpus, _handler)
.map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
fn irq_free(_handle: IrqHandle) -> AxResult {
#[cfg(feature = "irq")]
{
ax_hal::irq::free_irq(_handle).map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
fn irq_enable(_handle: IrqHandle) -> AxResult {
#[cfg(feature = "irq")]
{
ax_hal::irq::enable_irq(_handle).map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
fn irq_disable(_handle: IrqHandle) -> AxResult {
#[cfg(feature = "irq")]
{
ax_hal::irq::disable_irq(_handle).map_err(map_irq_error)
}
#[cfg(not(feature = "irq"))]
{
Err(AxError::Unsupported)
}
}
unsafe fn irq_run_on_cpu_sync(
_cpu: IrqCpuId,
_f: unsafe fn(*mut ()),
_arg: *mut (),
) -> Result<(), IrqError> {
#[cfg(feature = "irq")]
{
unsafe { ax_hal::irq::run_on_cpu_sync(_cpu, _f, _arg) }
}
#[cfg(not(feature = "irq"))]
{
let _ = (_cpu, _f, _arg);
Err(IrqError::Unsupported)
}
}
}
}