Skip to content

Commit 375a3e2

Browse files
committed
Supports tracepoint-based eBPF applications.
Signed-off-by: Godones <chenlinfeng25@outlook.com>
1 parent 8e666d9 commit 375a3e2

File tree

28 files changed

+1489
-67
lines changed

28 files changed

+1489
-67
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ tracepoint.workspace = true
7575
static-keys.workspace = true
7676

7777
# kbpf-basic = { path = "../../ax-project/kbpf-basic/" }
78-
kbpf-basic = { git = "https://github.com/Starry-OS/kbpf-basic" }
78+
kbpf-basic = { git = "https://github.com/Starry-OS/kbpf-basic", rev = "ef8ade5" }
7979
rbpf = { git = "https://github.com/qmonnet/rbpf.git", default-features = false, rev = "f31e471" }
8080

8181
[target.'cfg(not(target_arch = "loongarch64"))'.dependencies]

api/src/bpf/map.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ impl FileLike for BpfMap {
6363

6464
pub fn bpf_map_create(attr: &bpf_attr) -> AxResult<isize> {
6565
let map_meta = BpfMapMeta::try_from(attr).map_err(bpferror_to_axerr)?;
66+
axlog::info!("The map attr is {:#?}", map_meta);
6667
let unified_map =
6768
kbpf_basic::map::bpf_map_create::<PerCpuImpl>(map_meta).map_err(bpferror_to_axerr);
6869
if let Err(e) = &unified_map {

api/src/bpf/tansform.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ impl KernelAuxiliaryOps for EbpfKernelAuxiliary {
9696
let ret = func(&mut *unified_map);
9797
drop(unified_map);
9898
// avoid double free
99-
// log::error!("get_unified_map_from_ptr: ret: {:?}", ret);
10099
let _ = Arc::into_raw(map);
101100
ret
102101
}
@@ -105,15 +104,13 @@ impl KernelAuxiliaryOps for EbpfKernelAuxiliary {
105104
where
106105
F: FnOnce(&mut UnifiedMap) -> kbpf_basic::Result<R>,
107106
{
108-
// log::error!("get_unified_map_from_fd: map_fd: {}", map_fd);
109107
let file = get_file_like(map_fd as _).map_err(|_| BpfError::NotFound)?;
110108
let bpf_map = file.into_any().downcast::<BpfMap>().unwrap();
111109
let unified_map = &mut bpf_map.unified_map();
112110
func(unified_map)
113111
}
114112

115113
fn get_unified_map_ptr_from_fd(map_fd: u32) -> kbpf_basic::Result<*const u8> {
116-
// log::error!("get_unified_map_ptr_from_fd: map_fd: {}", map_fd);
117114
let file = get_file_like(map_fd as _).map_err(|_| BpfError::NotFound)?;
118115
let bpf_map = file.into_any().downcast::<BpfMap>().unwrap();
119116
let map_ptr = Arc::into_raw(bpf_map) as usize;
@@ -149,7 +146,6 @@ impl KernelAuxiliaryOps for EbpfKernelAuxiliary {
149146

150147
fn string_from_user_cstr(ptr: *const u8) -> kbpf_basic::Result<String> {
151148
let str = vm_load_string(ptr).map_err(|_| BpfError::InvalidArgument)?;
152-
// axlog::info!("string_from_user_cstr: string: {:?}", str);
153149
Ok(str)
154150
}
155151

api/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub fn init() {
3636

3737
tracepoint::tracepoint_init();
3838
bpf::init_bpf();
39+
perf::perf_event_init();
3940

4041
if axconfig::plat::CPU_NUM > 1 {
4142
panic!("SMP is not supported");

api/src/perf/bpf.rs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,38 @@
1-
use alloc::sync::Arc;
21
use core::{any::Any, convert::Into, fmt::Debug};
32

43
use axerrno::AxResult;
54
use axhal::paging::PageSize;
65
use axio::{IoEvents, PollSet, Pollable};
7-
use axmm::backend::SharedPages;
6+
use axmm::backend::{alloc_frames, dealloc_frames};
87
use kbpf_basic::{
98
linux_bpf::perf_event_sample_format,
109
perf::{PerfProbeArgs, bpf::BpfPerfEvent},
1110
};
11+
use memory_addr::PhysAddr;
1212

1313
use super::PerfEventOps;
1414

1515
pub struct BpfPerfEventWrapper {
1616
inner: BpfPerfEvent,
1717
poll_ready: PollSet,
18+
phys_addr: Option<(PhysAddr, usize)>,
1819
}
1920

2021
impl BpfPerfEventWrapper {
2122
pub fn new(inner: BpfPerfEvent) -> Self {
2223
BpfPerfEventWrapper {
2324
inner,
2425
poll_ready: PollSet::new(),
26+
phys_addr: None,
2527
}
2628
}
2729

2830
pub fn write_event(&mut self, data: &[u8]) -> AxResult<()> {
2931
// TODO: remove unwrap
32+
if self.phys_addr.is_none() {
33+
axlog::warn!("BpfPerfEventWrapper: first write_event, mmap not done yet");
34+
return Ok(());
35+
}
3036
self.inner.write_event(data).unwrap();
3137
if self.inner.enabled() {
3238
self.poll_ready.wake();
@@ -71,24 +77,42 @@ impl PerfEventOps for BpfPerfEventWrapper {
7177
length: usize,
7278
prot: crate::syscall::MmapProt,
7379
flags: crate::syscall::MmapFlags,
74-
_offset: usize,
80+
offset: usize,
7581
) -> AxResult<isize> {
76-
axlog::warn!(
82+
axlog::info!(
7783
"BpfPerfEventWrapper::mmap prot:{:?} flags:{:?}",
7884
prot,
7985
flags
8086
);
81-
let back = axmm::backend::Backend::new_shared(
82-
start,
83-
Arc::new(SharedPages::new(length, PageSize::Size4K)?),
84-
);
85-
aspace.map(start, length, prot.into(), true, back)?;
8687

87-
self.inner.do_mmap(start.as_usize(), length, 0).unwrap();
88+
let phys_addr = alloc_frames(
89+
true,
90+
PageSize::Size4K,
91+
length / PageSize::Size4K as usize,
92+
axalloc::UsageKind::PageCache,
93+
)?;
94+
let page_virt = axhal::mem::phys_to_virt(phys_addr);
95+
96+
aspace.map_linear(start, phys_addr, length, prot.into())?;
97+
98+
self.inner
99+
.do_mmap(page_virt.as_usize(), length, offset)
100+
.unwrap();
101+
102+
self.phys_addr = Some((phys_addr, length / PageSize::Size4K as usize));
103+
88104
Ok(start.as_usize() as isize)
89105
}
90106
}
91107

108+
impl Drop for BpfPerfEventWrapper {
109+
fn drop(&mut self) {
110+
if let Some((phys_addr, nums)) = self.phys_addr {
111+
dealloc_frames(phys_addr, nums);
112+
}
113+
}
114+
}
115+
92116
impl Pollable for BpfPerfEventWrapper {
93117
fn poll(&self) -> axio::IoEvents {
94118
if self.inner.readable() {

api/src/perf/kprobe.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ impl PerfEventOps for KprobePerfEvent {
6969
fn as_any_mut(&mut self) -> &mut dyn Any {
7070
self
7171
}
72+
73+
fn set_bpf_prog(&mut self, bpf_prog: Arc<dyn FileLike>) -> AxResult<()> {
74+
let bpf_prog = bpf_prog.into_any().downcast::<BpfProg>().unwrap();
75+
let prog = bpf_prog.insns();
76+
let prog = unsafe { core::slice::from_raw_parts_mut(prog.as_ptr() as *mut u8, prog.len()) };
77+
let mut vm = EbpfVmRaw::new(Some(prog)).unwrap();
78+
for (key, value) in BPF_HELPER_FUN_SET.iter() {
79+
vm.register_helper(*key, *value).unwrap();
80+
}
81+
vm.register_allowed_memory(0..u64::MAX);
82+
static CALLBACK_ID: AtomicU32 = AtomicU32::new(0);
83+
84+
let id = CALLBACK_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
85+
86+
// create a callback to execute the ebpf prog
87+
let callback = Box::new(KprobePerfCallBack::new(bpf_prog, vm));
88+
// update callback for kprobe
89+
self.kprobe.register_event_callback(id, callback);
90+
self.callback_list.push(id);
91+
Ok(())
92+
}
7293
}
7394

7495
pub struct KprobePerfCallBack {
@@ -100,29 +121,6 @@ impl CallBackFunc for KprobePerfCallBack {
100121
}
101122
}
102123

103-
impl KprobePerfEvent {
104-
pub fn set_bpf_prog(&mut self, bpf_prog: Arc<dyn FileLike>) -> AxResult<()> {
105-
let bpf_prog = bpf_prog.into_any().downcast::<BpfProg>().unwrap();
106-
let prog = bpf_prog.insns();
107-
let prog = unsafe { core::slice::from_raw_parts_mut(prog.as_ptr() as *mut u8, prog.len()) };
108-
let mut vm = EbpfVmRaw::new(Some(prog)).unwrap();
109-
for (key, value) in BPF_HELPER_FUN_SET.iter() {
110-
vm.register_helper(*key, *value).unwrap();
111-
}
112-
vm.register_allowed_memory(0..u64::MAX);
113-
static CALLBACK_ID: AtomicU32 = AtomicU32::new(0);
114-
115-
let id = CALLBACK_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
116-
117-
// create a callback to execute the ebpf prog
118-
let callback = Box::new(KprobePerfCallBack::new(bpf_prog, vm));
119-
// update callback for kprobe
120-
self.kprobe.register_event_callback(id, callback);
121-
self.callback_list.push(id);
122-
Ok(())
123-
}
124-
}
125-
126124
fn perf_probe_arg_to_kprobe_builder(args: &PerfProbeArgs) -> KprobeBuilder<KprobeAuxiliary> {
127125
let symbol = &args.name;
128126
let addr = ksym::addr_from_symbol(symbol).unwrap() as usize;

api/src/perf/mod.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
mod bpf;
22
mod kprobe;
3+
mod tracepoint;
34

4-
use alloc::{boxed::Box, sync::Arc};
5+
use alloc::{
6+
boxed::Box,
7+
sync::{Arc, Weak},
8+
};
59
use core::{any::Any, ffi::c_void, fmt::Debug};
610

711
use axerrno::{AxError, AxResult};
812
use axio::Pollable;
13+
use hashbrown::HashMap;
914
use kbpf_basic::{
1015
linux_bpf::{perf_event_attr, perf_type_id},
1116
perf::{PerfEventIoc, PerfProbeArgs},
1217
};
1318
use kspin::{SpinNoPreempt, SpinNoPreemptGuard};
19+
use lazyinit::LazyInit;
1420

1521
use crate::{
1622
bpf::tansform::EbpfKernelAuxiliary,
1723
file::{FileLike, Kstat, add_file_like, get_file_like},
18-
perf::{bpf::BpfPerfEventWrapper, kprobe::KprobePerfEvent},
24+
perf::bpf::BpfPerfEventWrapper,
1925
};
2026

2127
pub trait PerfEventOps: Pollable + Send + Sync + Debug {
@@ -26,7 +32,9 @@ pub trait PerfEventOps: Pollable + Send + Sync + Debug {
2632
fn custom_mmap(&self) -> bool {
2733
false
2834
}
29-
35+
fn set_bpf_prog(&mut self, _bpf_prog: Arc<dyn FileLike>) -> AxResult<()> {
36+
Err(AxError::OperationNotSupported)
37+
}
3038
fn mmap(
3139
&mut self,
3240
_aspace: &mut axmm::AddrSpace,
@@ -104,11 +112,7 @@ impl FileLike for PerfEvent {
104112
let file = get_file_like(bpf_prog_fd as _)?;
105113

106114
let mut event = self.event.lock();
107-
let kprobe_event = event
108-
.as_any_mut()
109-
.downcast_mut::<KprobePerfEvent>()
110-
.ok_or(AxError::InvalidInput)?;
111-
kprobe_event.set_bpf_prog(file)?;
115+
event.set_bpf_prog(file)?;
112116
}
113117
}
114118
Ok(0)
@@ -143,7 +147,7 @@ pub fn perf_event_open(
143147
let args =
144148
PerfProbeArgs::try_from_perf_attr::<EbpfKernelAuxiliary>(attr, pid, cpu, group_fd, flags)
145149
.unwrap();
146-
axlog::warn!("perf_event_process: {:#?}", args);
150+
axlog::info!("perf_event_process: {:#?}", args);
147151
let event: Box<dyn PerfEventOps> = match args.type_ {
148152
// Kprobe
149153
// See /sys/bus/event_source/devices/kprobe/type
@@ -155,21 +159,49 @@ pub fn perf_event_open(
155159
let bpf_event = bpf::perf_event_open_bpf(args);
156160
Box::new(bpf_event)
157161
}
162+
perf_type_id::PERF_TYPE_TRACEPOINT => {
163+
let tracepoint_event = tracepoint::perf_event_open_tracepoint(args)?;
164+
Box::new(tracepoint_event)
165+
}
158166
_ => {
159167
unimplemented!("perf_event_process: unknown type: {:?}", args);
160168
}
161169
};
162-
let event = Arc::new(PerfEvent::new(event));
163-
let fd = add_file_like(event, false).map(|fd| fd as _);
164-
fd
170+
let event = Arc::new(PerfEvent::new(event)) as Arc<dyn FileLike>;
171+
let fd = add_file_like(event.clone(), false).map(|fd| fd as _)?;
172+
173+
PERF_FILE
174+
.get()
175+
.unwrap()
176+
.lock()
177+
.insert(fd, Arc::downgrade(&event));
178+
179+
axlog::info!("perf_event_open: fd: {:?}", fd);
180+
Ok(fd as _)
181+
}
182+
183+
static PERF_FILE: LazyInit<SpinNoPreempt<HashMap<usize, Weak<dyn FileLike>>>> = LazyInit::new();
184+
185+
pub fn perf_event_init() {
186+
PERF_FILE.init_once(SpinNoPreempt::new(HashMap::new()));
165187
}
166188

167189
pub fn perf_event_output(_ctx: *mut c_void, fd: usize, _flags: u32, data: &[u8]) -> AxResult<()> {
168-
// axlog::error!("perf_event_output: fd: {}, data: {:?}", fd, data.len());
169-
let file = get_file_like(fd as _)?;
190+
let mut perf_file_map = PERF_FILE.get().unwrap().lock();
191+
let perf_file_weak = perf_file_map.get(&fd).ok_or(AxError::NotFound)?;
192+
193+
let Some(file) = perf_file_weak.upgrade() else {
194+
// The file has been dropped, remove the weak reference from the map
195+
perf_file_map.remove(&fd);
196+
return Err(AxError::NotFound);
197+
};
198+
170199
let bpf_event_file = file.into_any().downcast::<PerfEvent>().unwrap();
171200
let mut event = bpf_event_file.event();
172-
let event = event.as_any_mut().downcast_mut::<BpfPerfEventWrapper>().unwrap();
201+
let event = event
202+
.as_any_mut()
203+
.downcast_mut::<BpfPerfEventWrapper>()
204+
.unwrap();
173205
event.write_event(data).unwrap();
174206
Ok(())
175207
}

0 commit comments

Comments
 (0)