1 use crate::exception::ipi::{IpiKind, IpiTarget};
2 
3 extern "C" {
apic_write_icr(value: u64)4     pub fn apic_write_icr(value: u64);
apic_x2apic_enabled() -> bool5     pub fn apic_x2apic_enabled() -> bool;
6 }
7 
8 /// IPI的种类(架构相关,指定了向量号)
9 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
10 #[repr(u8)]
11 pub enum ArchIpiKind {
12     KickCpu = 200,
13     FlushTLB = 201,
14 }
15 
16 impl From<IpiKind> for ArchIpiKind {
from(kind: IpiKind) -> Self17     fn from(kind: IpiKind) -> Self {
18         match kind {
19             IpiKind::KickCpu => ArchIpiKind::KickCpu,
20             IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
21         }
22     }
23 }
24 
25 /// IPI投递目标
26 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
27 pub enum ArchIpiTarget {
28     /// 当前CPU
29     Current,
30     /// 所有CPU
31     All,
32     /// 除了当前CPU以外的所有CPU
33     Other,
34     /// 指定的CPU
35     Specified(usize),
36 }
37 
38 impl From<IpiTarget> for ArchIpiTarget {
from(target: IpiTarget) -> Self39     fn from(target: IpiTarget) -> Self {
40         match target {
41             IpiTarget::Current => ArchIpiTarget::Current,
42             IpiTarget::All => ArchIpiTarget::All,
43             IpiTarget::Other => ArchIpiTarget::Other,
44             IpiTarget::Specified(cpu_id) => ArchIpiTarget::Specified(cpu_id),
45         }
46     }
47 }
48 
49 impl ArchIpiTarget {
shorthand(&self) -> u850     pub fn shorthand(&self) -> u8 {
51         match self {
52             ArchIpiTarget::Specified(_) => 0,
53             ArchIpiTarget::Current => 1,
54             ArchIpiTarget::All => 2,
55             ArchIpiTarget::Other => 3,
56         }
57     }
58 }
59 
60 impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
into(self) -> x86::apic::DestinationShorthand61     fn into(self) -> x86::apic::DestinationShorthand {
62         match self {
63             ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
64             ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
65             ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
66             ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
67         }
68     }
69 }
70 
71 impl Into<x86::apic::ApicId> for ArchIpiTarget {
into(self) -> x86::apic::ApicId72     fn into(self) -> x86::apic::ApicId {
73         let id = match self {
74             ArchIpiTarget::Specified(cpu_id) => cpu_id,
75             _ => 0,
76         };
77 
78         if unsafe { apic_x2apic_enabled() } {
79             return x86::apic::ApicId::X2Apic(id as u32);
80         } else {
81             return x86::apic::ApicId::XApic(id as u8);
82         }
83     }
84 }
85 
86 #[inline(always)]
send_ipi(kind: IpiKind, target: IpiTarget)87 pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
88     // kdebug!("send_ipi: {:?} {:?}", kind, target);
89 
90     let ipi_vec = ArchIpiKind::from(kind) as u8;
91     let target = ArchIpiTarget::from(target);
92     let shorthand: x86::apic::DestinationShorthand = target.into();
93     let destination: x86::apic::ApicId = target.into();
94     if unsafe { apic_x2apic_enabled() } {
95         // kdebug!("send_ipi: x2apic");
96         let icr = x86::apic::Icr::for_x2apic(
97             ipi_vec,
98             destination,
99             shorthand,
100             x86::apic::DeliveryMode::Fixed,
101             x86::apic::DestinationMode::Physical,
102             x86::apic::DeliveryStatus::Idle,
103             x86::apic::Level::Assert,
104             x86::apic::TriggerMode::Edge,
105         );
106 
107         unsafe {
108             apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
109         }
110     } else {
111         // kdebug!("send_ipi: xapic");
112         let icr = x86::apic::Icr::for_xapic(
113             ipi_vec,
114             destination,
115             shorthand,
116             x86::apic::DeliveryMode::Fixed,
117             x86::apic::DestinationMode::Physical,
118             x86::apic::DeliveryStatus::Idle,
119             x86::apic::Level::Assert,
120             x86::apic::TriggerMode::Edge,
121         );
122 
123         unsafe {
124             apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
125         }
126     }
127 }
128