ipi.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. use alloc::sync::Arc;
  2. use log::error;
  3. use system_error::SystemError;
  4. use x86::apic::ApicId;
  5. use crate::{
  6. arch::{
  7. driver::apic::{lapic_vector::local_apic_chip, CurrentApic, LocalAPIC},
  8. smp::SMP_BOOT_DATA,
  9. },
  10. exception::{
  11. ipi::{FlushTLBIpiHandler, IpiKind, IpiTarget, KickCpuIpiHandler},
  12. irqdata::{IrqData, IrqLineStatus},
  13. irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandler},
  14. HardwareIrqNumber, IrqNumber,
  15. },
  16. smp::cpu::ProcessorId,
  17. };
  18. use super::TrapFrame;
  19. pub const IPI_NUM_KICK_CPU: IrqNumber = IrqNumber::new(200);
  20. pub const IPI_NUM_FLUSH_TLB: IrqNumber = IrqNumber::new(201);
  21. /// IPI的种类(架构相关,指定了向量号)
  22. #[derive(Debug, Copy, Clone, Eq, PartialEq)]
  23. #[repr(u32)]
  24. pub enum ArchIpiKind {
  25. KickCpu = IPI_NUM_KICK_CPU.data(),
  26. FlushTLB = IPI_NUM_FLUSH_TLB.data(),
  27. SpecVector(HardwareIrqNumber),
  28. }
  29. impl From<IpiKind> for ArchIpiKind {
  30. fn from(kind: IpiKind) -> Self {
  31. match kind {
  32. IpiKind::KickCpu => ArchIpiKind::KickCpu,
  33. IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
  34. IpiKind::SpecVector(vec) => ArchIpiKind::SpecVector(vec),
  35. }
  36. }
  37. }
  38. impl From<ArchIpiKind> for u8 {
  39. fn from(value: ArchIpiKind) -> Self {
  40. match value {
  41. ArchIpiKind::KickCpu => IPI_NUM_KICK_CPU.data() as u8,
  42. ArchIpiKind::FlushTLB => IPI_NUM_FLUSH_TLB.data() as u8,
  43. ArchIpiKind::SpecVector(vec) => (vec.data() & 0xFF) as u8,
  44. }
  45. }
  46. }
  47. /// IPI投递目标
  48. #[derive(Debug, Copy, Clone, Eq, PartialEq)]
  49. pub enum ArchIpiTarget {
  50. /// 当前CPU
  51. Current,
  52. /// 所有CPU
  53. All,
  54. /// 除了当前CPU以外的所有CPU
  55. Other,
  56. /// 指定的CPU
  57. Specified(x86::apic::ApicId),
  58. }
  59. impl From<IpiTarget> for ArchIpiTarget {
  60. fn from(target: IpiTarget) -> Self {
  61. match target {
  62. IpiTarget::Current => ArchIpiTarget::Current,
  63. IpiTarget::All => ArchIpiTarget::All,
  64. IpiTarget::Other => ArchIpiTarget::Other,
  65. IpiTarget::Specified(cpu_id) => {
  66. ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id))
  67. }
  68. }
  69. }
  70. }
  71. impl From<ArchIpiTarget> for ApicId {
  72. fn from(val: ArchIpiTarget) -> Self {
  73. if let ArchIpiTarget::Specified(id) = val {
  74. return id;
  75. } else if CurrentApic.x2apic_enabled() {
  76. return x86::apic::ApicId::X2Apic(0);
  77. } else {
  78. return x86::apic::ApicId::XApic(0);
  79. }
  80. }
  81. }
  82. impl ArchIpiTarget {
  83. #[allow(dead_code)]
  84. pub fn shorthand(&self) -> u8 {
  85. match self {
  86. ArchIpiTarget::Specified(_) => 0,
  87. ArchIpiTarget::Current => 1,
  88. ArchIpiTarget::All => 2,
  89. ArchIpiTarget::Other => 3,
  90. }
  91. }
  92. #[inline(always)]
  93. fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId {
  94. if CurrentApic.x2apic_enabled() {
  95. x86::apic::ApicId::X2Apic(cpu_id.data())
  96. } else {
  97. x86::apic::ApicId::XApic(cpu_id.data() as u8)
  98. }
  99. }
  100. }
  101. impl From<ArchIpiTarget> for x86::apic::DestinationShorthand {
  102. fn from(val: ArchIpiTarget) -> Self {
  103. match val {
  104. ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
  105. ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
  106. ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
  107. ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
  108. }
  109. }
  110. }
  111. #[inline(always)]
  112. pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
  113. // debug!("send_ipi: {:?} {:?}", kind, target);
  114. let ipi_vec = ArchIpiKind::from(kind).into();
  115. let target = ArchIpiTarget::from(target);
  116. let shorthand: x86::apic::DestinationShorthand = target.into();
  117. let destination: x86::apic::ApicId = target.into();
  118. let icr = if CurrentApic.x2apic_enabled() {
  119. // debug!("send_ipi: x2apic");
  120. x86::apic::Icr::for_x2apic(
  121. ipi_vec,
  122. destination,
  123. shorthand,
  124. x86::apic::DeliveryMode::Fixed,
  125. x86::apic::DestinationMode::Physical,
  126. x86::apic::DeliveryStatus::Idle,
  127. x86::apic::Level::Assert,
  128. x86::apic::TriggerMode::Edge,
  129. )
  130. } else {
  131. // debug!("send_ipi: xapic");
  132. x86::apic::Icr::for_xapic(
  133. ipi_vec,
  134. destination,
  135. shorthand,
  136. x86::apic::DeliveryMode::Fixed,
  137. x86::apic::DestinationMode::Physical,
  138. x86::apic::DeliveryStatus::Idle,
  139. x86::apic::Level::Assert,
  140. x86::apic::TriggerMode::Edge,
  141. )
  142. };
  143. CurrentApic.write_icr(icr);
  144. }
  145. /// 发送smp初始化IPI
  146. pub fn ipi_send_smp_init() {
  147. let target = ArchIpiTarget::Other;
  148. let icr = if CurrentApic.x2apic_enabled() {
  149. x86::apic::Icr::for_x2apic(
  150. 0,
  151. target.into(),
  152. x86::apic::DestinationShorthand::AllExcludingSelf,
  153. x86::apic::DeliveryMode::Init,
  154. x86::apic::DestinationMode::Physical,
  155. x86::apic::DeliveryStatus::Idle,
  156. x86::apic::Level::Deassert,
  157. x86::apic::TriggerMode::Edge,
  158. )
  159. } else {
  160. x86::apic::Icr::for_xapic(
  161. 0,
  162. target.into(),
  163. x86::apic::DestinationShorthand::AllExcludingSelf,
  164. x86::apic::DeliveryMode::Init,
  165. x86::apic::DestinationMode::Physical,
  166. x86::apic::DeliveryStatus::Idle,
  167. x86::apic::Level::Deassert,
  168. x86::apic::TriggerMode::Edge,
  169. )
  170. };
  171. CurrentApic.write_icr(icr);
  172. }
  173. /// 发送smp启动IPI
  174. ///
  175. /// ## 参数
  176. ///
  177. /// * `target_cpu` - 目标CPU
  178. pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
  179. if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
  180. return Err(SystemError::EINVAL);
  181. }
  182. let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
  183. let icr = if CurrentApic.x2apic_enabled() {
  184. x86::apic::Icr::for_x2apic(
  185. 0x20,
  186. target.into(),
  187. x86::apic::DestinationShorthand::NoShorthand,
  188. x86::apic::DeliveryMode::StartUp,
  189. x86::apic::DestinationMode::Physical,
  190. x86::apic::DeliveryStatus::Idle,
  191. x86::apic::Level::Deassert,
  192. x86::apic::TriggerMode::Edge,
  193. )
  194. } else {
  195. x86::apic::Icr::for_xapic(
  196. 0x20,
  197. target.into(),
  198. x86::apic::DestinationShorthand::NoShorthand,
  199. x86::apic::DeliveryMode::StartUp,
  200. x86::apic::DestinationMode::Physical,
  201. x86::apic::DeliveryStatus::Idle,
  202. x86::apic::Level::Deassert,
  203. x86::apic::TriggerMode::Edge,
  204. )
  205. };
  206. CurrentApic.write_icr(icr);
  207. return Ok(());
  208. }
  209. /// 初始化IPI处理函数
  210. pub fn arch_ipi_handler_init() {
  211. do_init_irq_handler(IPI_NUM_KICK_CPU);
  212. do_init_irq_handler(IPI_NUM_FLUSH_TLB);
  213. }
  214. fn do_init_irq_handler(irq: IrqNumber) {
  215. let desc = irq_desc_manager().lookup(irq).unwrap();
  216. let irq_data: Arc<IrqData> = desc.irq_data();
  217. let mut chip_info_guard = irq_data.chip_info_write_irqsave();
  218. chip_info_guard.set_chip(Some(local_apic_chip().clone()));
  219. desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
  220. drop(chip_info_guard);
  221. desc.set_handler(&X86_64IpiIrqFlowHandler);
  222. }
  223. #[derive(Debug)]
  224. struct X86_64IpiIrqFlowHandler;
  225. impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
  226. fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
  227. let irq = irq_desc.irq_data().irq();
  228. match irq {
  229. IPI_NUM_KICK_CPU => {
  230. KickCpuIpiHandler.handle(irq, None, None).ok();
  231. }
  232. IPI_NUM_FLUSH_TLB => {
  233. FlushTLBIpiHandler.handle(irq, None, None).ok();
  234. CurrentApic.send_eoi();
  235. }
  236. _ => {
  237. error!("Unknown IPI: {}", irq.data());
  238. CurrentApic.send_eoi();
  239. }
  240. }
  241. }
  242. }