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