1pub use x86defs::apic::DeliveryMode;
7
8use hvdef::HvInterruptType;
9use inspect::Inspect;
10use parking_lot::Mutex;
11use std::fmt::Debug;
12use x86defs::msi::MsiAddress;
13use x86defs::msi::MsiData;
14
15pub trait IoApicRouting: Send + Sync {
22 fn set_irq_route(&self, irq: u8, request: Option<MsiRequest>);
24
25 fn assert_irq(&self, irq: u8);
27}
28
29pub trait ControlGic: Send + Sync {
31 fn set_spi_irq(&self, irq_id: u32, high: bool);
33}
34
35pub const IRQ_LINES: usize = 24;
37
38#[derive(Debug, Copy, Clone, Inspect)]
40pub struct MsiRequest {
41 #[inspect(hex)]
43 pub address: u64,
44 #[inspect(hex)]
46 pub data: u32,
47}
48
49impl MsiRequest {
50 pub fn new_x86(
52 mode: DeliveryMode,
53 destination: u32,
54 is_logical_destination: bool,
55 vector: u8,
56 is_level_triggered: bool,
57 ) -> Self {
58 let address = MsiAddress::new()
59 .with_address(x86defs::msi::MSI_ADDRESS)
60 .with_redirection_hint(mode == DeliveryMode::LOWEST_PRIORITY)
61 .with_virt_destination(destination as u16)
62 .with_destination_mode_logical(is_logical_destination);
63
64 let data = MsiData::new()
65 .with_vector(vector)
66 .with_delivery_mode(mode.0 & 0x7)
67 .with_assert(is_level_triggered)
68 .with_trigger_mode_level(is_level_triggered);
69
70 Self {
71 address: u32::from(address).into(),
72 data: data.into(),
73 }
74 }
75
76 pub fn as_x86(&self) -> (MsiAddress, MsiData) {
78 (
79 MsiAddress::from(self.address as u32),
80 MsiData::from(self.data),
81 )
82 }
83
84 pub fn hv_x86_interrupt_control(&self) -> hvdef::HvInterruptControl {
90 let (address, data) = self.as_x86();
91 let ty = match DeliveryMode(data.delivery_mode()) {
92 DeliveryMode::FIXED => HvInterruptType::HvX64InterruptTypeFixed,
93 DeliveryMode::LOWEST_PRIORITY => HvInterruptType::HvX64InterruptTypeLowestPriority,
94 DeliveryMode::SMI => HvInterruptType::HvX64InterruptTypeSmi,
95 DeliveryMode::REMOTE_READ => HvInterruptType::HvX64InterruptTypeRemoteRead,
96 DeliveryMode::NMI => HvInterruptType::HvX64InterruptTypeNmi,
97 DeliveryMode::INIT => HvInterruptType::HvX64InterruptTypeInit,
98 DeliveryMode::SIPI => HvInterruptType::HvX64InterruptTypeSipi,
99 _ => HvInterruptType(!0),
105 };
106 hvdef::HvInterruptControl::new()
107 .with_interrupt_type(ty)
108 .with_x86_level_triggered(data.trigger_mode_level())
109 .with_x86_logical_destination_mode(address.destination_mode_logical())
110 }
111}
112
113#[derive(Debug, Inspect)]
118pub struct IrqRoutes {
119 #[inspect(
120 with = "|x| inspect::adhoc(|req| inspect::iter_by_index(x.lock().iter()).inspect(req))"
121 )]
122 routes: Mutex<Vec<Option<MsiRequest>>>,
123}
124
125impl Default for IrqRoutes {
126 fn default() -> Self {
127 Self::new()
128 }
129}
130
131impl IrqRoutes {
132 pub fn new() -> Self {
133 let routes = vec![None; IRQ_LINES];
134 Self {
135 routes: Mutex::new(routes),
136 }
137 }
138
139 pub fn set_irq_route(&self, irq: u8, request: Option<MsiRequest>) {
141 self.routes.lock()[irq as usize] = request;
142 }
143
144 pub fn assert_irq(&self, irq: u8, assert: impl FnOnce(MsiRequest)) {
148 let request = self.routes.lock()[irq as usize];
149 match request {
150 Some(request) => {
151 assert(request);
152 }
153 None => {
154 tracelimit::warn_ratelimited!(irq, "irq for masked interrupt");
155 }
156 }
157 }
158}