use alloc::{borrow::Cow, sync::Arc, vec::Vec};
use core::ops::{Deref, DerefMut};
use ax_errno::{AxError, AxResult};
use ax_memory_addr::{PAGE_SIZE_4K, PhysAddr};
use axpoll::{PollSet, Pollable};
use kbpf_basic::{
PollWaker,
map::{BpfMapMeta, UnifiedMap, bpf_map_create},
};
use crate::{
ebpf::transform::{EbpfKernelAuxiliary, PerCpuImpl},
file::{FileLike, Kstat},
kprobe::KernelRawMutex,
pseudofs::DeviceMmap,
};
pub struct BpfMap {
unified_map: Arc<UnifiedMap<KernelRawMutex>>,
poll_ready: Arc<PollSetWrapper>,
}
impl core::fmt::Debug for BpfMap {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BpfMap").finish()
}
}
impl BpfMap {
pub fn new(unified_map: UnifiedMap<KernelRawMutex>, poll_ready: Arc<PollSetWrapper>) -> Self {
BpfMap {
unified_map: Arc::new(unified_map),
poll_ready,
}
}
pub fn unified_map(&self) -> &UnifiedMap<KernelRawMutex> {
self.unified_map.as_ref()
}
}
impl Pollable for BpfMap {
fn poll(&self) -> axpoll::IoEvents {
let map = self.unified_map();
let mut events = axpoll::IoEvents::empty();
if map.map().readable() {
events |= axpoll::IoEvents::IN;
}
if map.map().writable() {
events |= axpoll::IoEvents::OUT;
}
events
}
fn register(&self, context: &mut core::task::Context<'_>, _events: axpoll::IoEvents) {
self.poll_ready.register(context.waker());
}
}
impl FileLike for BpfMap {
fn read(&self, _dst: &mut crate::file::IoDst) -> AxResult<usize> {
Err(AxError::Unsupported)
}
fn write(&self, _src: &mut crate::file::IoSrc) -> AxResult<usize> {
Err(AxError::Unsupported)
}
fn stat(&self) -> AxResult<Kstat> {
Ok(Kstat::default())
}
fn path(&self) -> Cow<'_, str> {
"anon_inode:[bpf_map]".into()
}
fn device_mmap(&self, offset: u64, length: u64) -> AxResult<crate::pseudofs::DeviceMmap> {
if !offset.is_multiple_of(PAGE_SIZE_4K as u64)
|| !length.is_multiple_of(PAGE_SIZE_4K as u64)
{
return Err(AxError::InvalidInput);
}
let unified_map = self.unified_map();
let map = unified_map.map();
let phy_addrs = map
.map_mmap(offset as usize, length as usize)
.map_err(|_| AxError::InvalidInput)?
.iter()
.map(|&phys_addr| PhysAddr::from_usize(phys_addr))
.collect::<Vec<_>>();
let retain: Arc<dyn core::any::Any + Send + Sync> = self.unified_map.clone();
Ok(DeviceMmap::PhysicalPages(phy_addrs, Some(retain)))
}
}
pub struct PollSetWrapper(PollSet);
impl PollSetWrapper {
pub fn new() -> Self {
Self(PollSet::new())
}
}
impl Default for PollSetWrapper {
fn default() -> Self {
Self::new()
}
}
impl Deref for PollSetWrapper {
type Target = PollSet;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PollSetWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl PollWaker for PollSetWrapper {
fn wake_up(&self) {
self.0.wake();
}
}
pub fn create_map(meta: BpfMapMeta) -> kbpf_basic::BpfResult<BpfMap> {
let waker = Arc::new(PollSetWrapper::new());
let waker_dyn: Arc<dyn PollWaker> = waker.clone();
let map = bpf_map_create::<EbpfKernelAuxiliary, PerCpuImpl>(meta, Some(waker_dyn))?;
Ok(BpfMap::new(map, waker))
}