Skip to content

Commit 1631f66

Browse files
committed
[wip] add ipi for aarch64
1 parent 1b8ebc8 commit 1631f66

File tree

13 files changed

+406
-204
lines changed

13 files changed

+406
-204
lines changed

Cargo.lock

Lines changed: 242 additions & 198 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ members = [
1515
"modules/axruntime",
1616
"modules/axsync",
1717
"modules/axtask",
18+
"modules/axipi",
1819

1920
"api/axfeat",
2021
"api/arceos_api",
@@ -61,6 +62,7 @@ axruntime = { path = "modules/axruntime" }
6162
axsync = { path = "modules/axsync" }
6263
axtask = { path = "modules/axtask" }
6364
axdma = { path = "modules/axdma" }
65+
axipi = { path = "modules/axipi" }
6466

6567
[profile.release]
6668
lto = true

api/axfeat/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ fp_simd = ["axhal/fp_simd"]
2020

2121
# Interrupts
2222
irq = ["axhal/irq", "axruntime/irq", "axtask?/irq"]
23+
ipi = ["axruntime/ipi"]
2324

2425
# Memory
2526
alloc = ["axalloc", "axruntime/alloc"]

modules/axhal/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repository = "https://github.com/arceos-org/arceos/tree/main/modules/axhal"
1010
documentation = "https://arceos-org.github.io/arceos/axhal/index.html"
1111

1212
[features]
13-
smp = []
13+
smp = ["dep:cpumask"]
1414
alloc = []
1515
fp_simd = []
1616
paging = ["axalloc", "page_table_multiarch"]
@@ -39,6 +39,7 @@ axlog = { workspace = true }
3939
axconfig = { workspace = true }
4040
axalloc = { workspace = true, optional = true }
4141
cortex-a = { version = "8.1.1", optional = true }
42+
cpumask = { version = "0.1", optional = true }
4243

4344
[target.'cfg(target_arch = "x86_64")'.dependencies]
4445
x86 = "0.52"

modules/axhal/src/irq.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use handler_table::HandlerTable;
55
use crate::platform::irq::{dispatch_irq, MAX_IRQ_COUNT};
66
use crate::trap::{register_trap_handler, IRQ};
77

8-
pub use crate::platform::irq::{register_handler, set_enable};
8+
pub use crate::platform::irq::{register_handler, set_enable, IPI_IRQ_NUM};
99

1010
#[cfg(target_arch = "aarch64")]
1111
pub use crate::platform::irq::fetch_irq;

modules/axhal/src/platform/aarch64_common/gic.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ pub const TIMER_IRQ_NUM: usize = translate_irq(10, InterruptType::PPI).unwrap();
1717
/// The UART IRQ number.
1818
pub const UART_IRQ_NUM: usize = translate_irq(axconfig::UART_IRQ, InterruptType::SPI).unwrap();
1919

20+
/// The IPI IRQ number.
21+
pub const IPI_IRQ_NUM: usize = translate_irq(1, InterruptType::SGI).unwrap();
22+
2023
const GICD_BASE: PhysAddr = pa!(axconfig::GICD_PADDR);
2124
const GICC_BASE: PhysAddr = pa!(axconfig::GICC_PADDR);
2225

@@ -41,6 +44,12 @@ pub fn register_handler(irq_num: usize, handler: IrqHandler) -> bool {
4144
crate::irq::register_handler_common(irq_num, handler)
4245
}
4346

47+
/// Sends Software Generated Interrupt (SGI)(s) (usually IPI) to the given CPUs.
48+
#[cfg(feature = "smp")]
49+
pub fn send_sgi(cpu_if: usize, irq_num: usize) {
50+
GICD.lock().send_sgi(cpu_if, irq_num);
51+
}
52+
4453
/// Fetches the IRQ number.
4554
pub fn fetch_irq() -> usize {
4655
GICC.iar() as usize

modules/axhal/src/platform/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ cfg_if::cfg_if! {
2626
mod aarch64_rk3588j;
2727
pub use self::aarch64_rk3588j::*;
2828
} else {
29-
mod dummy;
30-
pub use self::dummy::*;
29+
// mod dummy;
30+
// pub use self::dummy::*;
31+
mod aarch64_qemu_virt;
32+
pub use self::aarch64_qemu_virt::*;
3133
}
3234
}

modules/axipi/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "axipi"
3+
edition = "2021"
4+
version.workspace = true
5+
authors = ["Keyang Hu <keyang.hu@qq.com>"]
6+
description = "ArceOS IPI management module"
7+
license.workspace = true
8+
homepage.workspace = true
9+
# repository = "https://github.com/arceos-org/arceos/tree/main/modules/axipi"
10+
# documentation = "https://arceos-org.github.io/arceos/axipi/index.html"
11+
12+
[features]
13+
default = []
14+
15+
[dependencies]
16+
log = "=0.4.21"
17+
lazyinit = { version = "0.2" }
18+
19+
percpu = { version = "0.1.5" }
20+
kspin = { version = "0.1" }
21+
22+
axhal = { workspace = true }

modules/axipi/src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
extern crate alloc;
2+
3+
use lazyinit::LazyInit;
4+
5+
use kspin::SpinNoIrq;
6+
7+
use axhal::cpu::this_cpu_id;
8+
use axhal::irq::IPI_IRQ_NUM;
9+
10+
mod queue;
11+
12+
use queue::IPIEventQueue;
13+
14+
pub use queue::IPIEventFn;
15+
16+
#[percpu::def_percpu]
17+
static IPI_MSG_QUEUE: LazyInit<SpinNoIrq<IPIEventQueue<IPIEventFn>>> = LazyInit::new();
18+
19+
pub fn init() {
20+
IPI_MSG_QUEUE.with_current(|ipi_queue| {
21+
ipi_queue.init_once(SpinNoIrq::new(IPIEventQueue::default()));
22+
});
23+
axhal::irq::register_handler(IPI_IRQ_NUM, ipi_handler);
24+
}
25+
26+
pub fn send_ipi_event(target_cpu: usize, event: IPIEventFn) {
27+
unsafe { IPI_MSG_QUEUE.remote_ref_raw(target_cpu) }
28+
.lock()
29+
.push(this_cpu_id(), event);
30+
}
31+
32+
fn ipi_handler() {
33+
while let Some(event) = unsafe { IPI_MSG_QUEUE.current_ref_mut_raw() }
34+
.lock()
35+
.pop_one()
36+
{
37+
event();
38+
}
39+
}

modules/axipi/src/queue.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use alloc::collections::VecDeque;
2+
3+
/// A queue of IPI events.
4+
///
5+
/// It internally uses a `VecDeque` to store the events, make it
6+
/// possible to pop these events using FIFO order.
7+
pub struct IPIEventQueue<E: IPIEvent> {
8+
events: VecDeque<IPIEventWrapper<E>>,
9+
}
10+
11+
/// A trait that all events must implement.
12+
pub trait IPIEvent: 'static {
13+
/// Callback function that will be called when the event is triggered.
14+
fn callback(self);
15+
}
16+
17+
struct IPIEventWrapper<E> {
18+
src_cpu_id: u32,
19+
event: E,
20+
}
21+
22+
impl<E: IPIEvent> IPIEventQueue<E> {
23+
/// Creates a new empty timer list.
24+
pub fn new() -> Self {
25+
Self {
26+
events: VecDeque::new(),
27+
}
28+
}
29+
30+
/// Whether there is no event.
31+
#[inline]
32+
pub fn is_empty(&self) -> bool {
33+
self.events.is_empty()
34+
}
35+
36+
pub fn push(&mut self, src_cpu_id: u32, event: E) {
37+
self.events.push_back(IPIEventWrapper { src_cpu_id, event });
38+
}
39+
40+
/// Try to pop the latest event that exists in the queue.
41+
///
42+
/// Returns `None` if no event is available.
43+
pub fn pop_one(&mut self) -> Option<E> {
44+
if let Some(e) = self.events.pop_front() {
45+
Some(e.event)
46+
} else {
47+
None
48+
}
49+
}
50+
}
51+
52+
impl<E: IPIEvent> Default for IPIEventQueue<E> {
53+
fn default() -> Self {
54+
Self::new()
55+
}
56+
}
57+
58+
/// A simple wrapper of a closure that implements the [`IPIEvent`] trait.
59+
///
60+
/// So that it can be used as in the [`IPIEventQueue`].
61+
pub struct IPIEventFn(Box<dyn FnOnce() + 'static>);
62+
63+
impl IPIEventFn {
64+
/// Constructs a new [`IPIEventFn`] from a closure.
65+
pub fn new<F>(f: F) -> Self
66+
where
67+
F: FnOnce() + 'static,
68+
{
69+
Self(Box::new(f))
70+
}
71+
}
72+
73+
impl IPIEvent for IPIEventFn {
74+
fn callback(self) {
75+
(self.0)()
76+
}
77+
}

0 commit comments

Comments
 (0)