axplat_aarch64_peripherals/
gic.rs1use arm_gic_driver::v2::{Ack, Gic, IntId, SGITarget, TargetList, TrapOp, VirtAddr};
4use axplat::irq::{HandlerTable, IpiTarget, IrqHandler};
5use kspin::SpinNoIrq;
6use lazyinit::LazyInit;
7
8const MAX_IRQ_COUNT: usize = 1024;
10
11static GIC: LazyInit<SpinNoIrq<Gic>> = LazyInit::new();
12
13static TRAP_OP: LazyInit<TrapOp> = LazyInit::new();
14
15static IRQ_HANDLER_TABLE: HandlerTable<MAX_IRQ_COUNT> = HandlerTable::new();
16
17pub fn set_enable(irq_num: usize, enabled: bool) {
19 trace!("GIC set enable: {} {}", irq_num, enabled);
20 let intid = unsafe { IntId::raw(irq_num as u32) };
21 GIC.lock().set_irq_enable(intid, enabled);
22}
23
24pub fn register_handler(irq_num: usize, handler: IrqHandler) -> bool {
29 trace!("register handler IRQ {}", irq_num);
30 if IRQ_HANDLER_TABLE.register_handler(irq_num, handler) {
31 set_enable(irq_num, true);
32 return true;
33 }
34 warn!("register handler for IRQ {} failed", irq_num);
35 false
36}
37
38pub fn unregister_handler(irq_num: usize) -> Option<IrqHandler> {
43 trace!("unregister handler IRQ {}", irq_num);
44 set_enable(irq_num, false);
45 IRQ_HANDLER_TABLE.unregister_handler(irq_num)
46}
47
48pub fn handle_irq(_unused: usize) {
54 let ack = TRAP_OP.ack();
55 debug!("Handling IRQ: {ack:?}");
56
57 let irq_num = match ack {
58 Ack::Other(intid) => intid,
59 Ack::SGI { intid, cpu_id: _ } => intid,
60 };
61 if !IRQ_HANDLER_TABLE.handle(irq_num.to_u32() as _) {
62 warn!("Unhandled IRQ {:?}", irq_num);
63 }
64 if !ack.is_special() {
65 TRAP_OP.eoi(ack);
66 if TRAP_OP.eoi_mode_ns() {
67 TRAP_OP.dir(ack);
68 }
69 }
70}
71
72pub fn init_gic(gicd_base: axplat::mem::VirtAddr, gicc_base: axplat::mem::VirtAddr) {
74 info!("Initialize GICv2...");
75 let gicd_base = VirtAddr::new(gicd_base.into());
76 let gicc_base = VirtAddr::new(gicc_base.into());
77
78 let mut gic = unsafe { Gic::new(gicd_base, gicc_base, None) };
79 gic.init();
80
81 GIC.init_once(SpinNoIrq::new(gic));
82 let cpu = GIC.lock().cpu_interface();
83 TRAP_OP.init_once(cpu.trap_operations());
84}
85
86pub fn init_gicc() {
90 debug!("Initialize GIC CPU Interface...");
91 let mut cpu = GIC.lock().cpu_interface();
92 cpu.init_current_cpu();
93 cpu.set_eoi_mode_ns(false);
94}
95
96pub fn send_ipi(irq_num: usize, target: IpiTarget) {
98 match target {
99 IpiTarget::Current { cpu_id: _ } => {
100 GIC.lock()
101 .send_sgi(IntId::sgi(irq_num as u32), SGITarget::Current);
102 }
103 IpiTarget::Other { cpu_id } => {
104 let target_list = TargetList::new(&mut [cpu_id].into_iter());
105 GIC.lock().send_sgi(
106 IntId::sgi(irq_num as u32),
107 SGITarget::TargetList(target_list),
108 );
109 }
110 IpiTarget::AllExceptCurrent {
111 cpu_id: _,
112 cpu_num: _,
113 } => {
114 GIC.lock()
115 .send_sgi(IntId::sgi(irq_num as u32), SGITarget::AllOther);
116 }
117 }
118}
119
120#[macro_export]
122macro_rules! irq_if_impl {
123 ($name:ident) => {
124 struct $name;
125
126 #[impl_plat_interface]
127 impl axplat::irq::IrqIf for $name {
128 fn set_enable(irq: usize, enabled: bool) {
130 $crate::gic::set_enable(irq, enabled);
131 }
132
133 fn register(irq: usize, handler: axplat::irq::IrqHandler) -> bool {
138 $crate::gic::register_handler(irq, handler)
139 }
140
141 fn unregister(irq: usize) -> Option<axplat::irq::IrqHandler> {
146 $crate::gic::unregister_handler(irq)
147 }
148
149 fn handle(irq: usize) {
155 $crate::gic::handle_irq(irq)
156 }
157
158 fn send_ipi(irq_num: usize, target: axplat::irq::IpiTarget) {
160 $crate::gic::send_ipi(irq_num, target);
161 }
162 }
163 };
164}