1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5
6 use std::io;
7 use std::sync::Arc;
8
9 use byteorder::{ByteOrder, LittleEndian};
10 use serde::{Deserialize, Serialize};
11 use thiserror::Error;
12 use vm_device::interrupt::{
13 InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
14 };
15 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
16
17 // MSI control masks
18 const MSI_CTL_ENABLE: u16 = 0x1;
19 const MSI_CTL_MULTI_MSG_ENABLE: u16 = 0x70;
20 const MSI_CTL_64_BITS: u16 = 0x80;
21 const MSI_CTL_PER_VECTOR: u16 = 0x100;
22
23 // MSI message offsets
24 const MSI_MSG_CTL_OFFSET: u64 = 0x2;
25 const MSI_MSG_ADDR_LO_OFFSET: u64 = 0x4;
26
27 // MSI message masks
28 const MSI_MSG_ADDR_LO_MASK: u32 = 0xffff_fffc;
29
msi_num_enabled_vectors(msg_ctl: u16) -> usize30 pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
31 let field = (msg_ctl >> 4) & 0x7;
32
33 if field > 5 {
34 return 0;
35 }
36
37 1 << field
38 }
39
40 #[derive(Error, Debug)]
41 pub enum Error {
42 #[error("Failed enabling the interrupt route")]
43 EnableInterruptRoute(#[source] io::Error),
44 #[error("Failed updating the interrupt route")]
45 UpdateInterruptRoute(#[source] io::Error),
46 }
47
48 pub const MSI_CONFIG_ID: &str = "msi_config";
49
50 #[derive(Clone, Copy, Default, Serialize, Deserialize)]
51 pub struct MsiCap {
52 // Message Control Register
53 // 0: MSI enable.
54 // 3-1; Multiple message capable.
55 // 6-4: Multiple message enable.
56 // 7: 64 bits address capable.
57 // 8: Per-vector masking capable.
58 // 15-9: Reserved.
59 pub msg_ctl: u16,
60 // Message Address (LSB)
61 // 1-0: Reserved.
62 // 31-2: Message address.
63 pub msg_addr_lo: u32,
64 // Message Upper Address (MSB)
65 // 31-0: Message address.
66 pub msg_addr_hi: u32,
67 // Message Data
68 // 15-0: Message data.
69 pub msg_data: u16,
70 // Mask Bits
71 // 31-0: Mask bits.
72 pub mask_bits: u32,
73 // Pending Bits
74 // 31-0: Pending bits.
75 pub pending_bits: u32,
76 }
77
78 impl MsiCap {
addr_64_bits(&self) -> bool79 fn addr_64_bits(&self) -> bool {
80 self.msg_ctl & MSI_CTL_64_BITS == MSI_CTL_64_BITS
81 }
82
per_vector_mask(&self) -> bool83 fn per_vector_mask(&self) -> bool {
84 self.msg_ctl & MSI_CTL_PER_VECTOR == MSI_CTL_PER_VECTOR
85 }
86
enabled(&self) -> bool87 fn enabled(&self) -> bool {
88 self.msg_ctl & MSI_CTL_ENABLE == MSI_CTL_ENABLE
89 }
90
num_enabled_vectors(&self) -> usize91 fn num_enabled_vectors(&self) -> usize {
92 msi_num_enabled_vectors(self.msg_ctl)
93 }
94
vector_masked(&self, vector: usize) -> bool95 fn vector_masked(&self, vector: usize) -> bool {
96 if !self.per_vector_mask() {
97 return false;
98 }
99
100 (self.mask_bits >> vector) & 0x1 == 0x1
101 }
102
size(&self) -> u64103 fn size(&self) -> u64 {
104 let mut size: u64 = 0xa;
105
106 if self.addr_64_bits() {
107 size += 0x4;
108 }
109 if self.per_vector_mask() {
110 size += 0xa;
111 }
112
113 size
114 }
115
update(&mut self, offset: u64, data: &[u8])116 fn update(&mut self, offset: u64, data: &[u8]) {
117 // Calculate message data offset depending on the address being 32 or
118 // 64 bits.
119 // Calculate upper address offset if the address is 64 bits.
120 // Calculate mask bits offset based on the address being 32 or 64 bits
121 // and based on the per vector masking being enabled or not.
122 let (msg_data_offset, addr_hi_offset, mask_bits_offset): (u64, Option<u64>, Option<u64>) =
123 if self.addr_64_bits() {
124 let mask_bits = if self.per_vector_mask() {
125 Some(0x10)
126 } else {
127 None
128 };
129 (0xc, Some(0x8), mask_bits)
130 } else {
131 let mask_bits = if self.per_vector_mask() {
132 Some(0xc)
133 } else {
134 None
135 };
136 (0x8, None, mask_bits)
137 };
138
139 // Update cache without overriding the read-only bits.
140 match data.len() {
141 2 => {
142 let value = LittleEndian::read_u16(data);
143 match offset {
144 MSI_MSG_CTL_OFFSET => {
145 self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
146 | (value & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
147 }
148 x if x == msg_data_offset => self.msg_data = value,
149 _ => error!("invalid offset"),
150 }
151 }
152 4 => {
153 let value = LittleEndian::read_u32(data);
154 match offset {
155 0x0 => {
156 self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
157 | ((value >> 16) as u16 & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
158 }
159 MSI_MSG_ADDR_LO_OFFSET => self.msg_addr_lo = value & MSI_MSG_ADDR_LO_MASK,
160 x if x == msg_data_offset => self.msg_data = value as u16,
161 x if addr_hi_offset.is_some() && x == addr_hi_offset.unwrap() => {
162 self.msg_addr_hi = value
163 }
164 x if mask_bits_offset.is_some() && x == mask_bits_offset.unwrap() => {
165 self.mask_bits = value
166 }
167 _ => error!("invalid offset"),
168 }
169 }
170 _ => error!("invalid data length"),
171 }
172 }
173 }
174
175 #[derive(Serialize, Deserialize)]
176 pub struct MsiConfigState {
177 cap: MsiCap,
178 }
179
180 pub struct MsiConfig {
181 pub cap: MsiCap,
182 interrupt_source_group: Arc<dyn InterruptSourceGroup>,
183 }
184
185 impl MsiConfig {
new( msg_ctl: u16, interrupt_source_group: Arc<dyn InterruptSourceGroup>, state: Option<MsiConfigState>, ) -> Result<Self, Error>186 pub fn new(
187 msg_ctl: u16,
188 interrupt_source_group: Arc<dyn InterruptSourceGroup>,
189 state: Option<MsiConfigState>,
190 ) -> Result<Self, Error> {
191 let cap = if let Some(state) = state {
192 if state.cap.enabled() {
193 for idx in 0..state.cap.num_enabled_vectors() {
194 let config = MsiIrqSourceConfig {
195 high_addr: state.cap.msg_addr_hi,
196 low_addr: state.cap.msg_addr_lo,
197 data: state.cap.msg_data as u32,
198 devid: 0,
199 };
200
201 interrupt_source_group
202 .update(
203 idx as InterruptIndex,
204 InterruptSourceConfig::MsiIrq(config),
205 state.cap.vector_masked(idx),
206 false,
207 )
208 .map_err(Error::UpdateInterruptRoute)?;
209 }
210
211 interrupt_source_group
212 .set_gsi()
213 .map_err(Error::EnableInterruptRoute)?;
214
215 interrupt_source_group
216 .enable()
217 .map_err(Error::EnableInterruptRoute)?;
218 }
219
220 state.cap
221 } else {
222 MsiCap {
223 msg_ctl,
224 ..Default::default()
225 }
226 };
227
228 Ok(MsiConfig {
229 cap,
230 interrupt_source_group,
231 })
232 }
233
state(&self) -> MsiConfigState234 fn state(&self) -> MsiConfigState {
235 MsiConfigState { cap: self.cap }
236 }
237
enabled(&self) -> bool238 pub fn enabled(&self) -> bool {
239 self.cap.enabled()
240 }
241
size(&self) -> u64242 pub fn size(&self) -> u64 {
243 self.cap.size()
244 }
245
num_enabled_vectors(&self) -> usize246 pub fn num_enabled_vectors(&self) -> usize {
247 self.cap.num_enabled_vectors()
248 }
249
update(&mut self, offset: u64, data: &[u8])250 pub fn update(&mut self, offset: u64, data: &[u8]) {
251 let old_enabled = self.cap.enabled();
252
253 self.cap.update(offset, data);
254
255 if self.cap.enabled() {
256 for idx in 0..self.num_enabled_vectors() {
257 let config = MsiIrqSourceConfig {
258 high_addr: self.cap.msg_addr_hi,
259 low_addr: self.cap.msg_addr_lo,
260 data: self.cap.msg_data as u32,
261 devid: 0,
262 };
263
264 if let Err(e) = self.interrupt_source_group.update(
265 idx as InterruptIndex,
266 InterruptSourceConfig::MsiIrq(config),
267 self.cap.vector_masked(idx),
268 true,
269 ) {
270 error!("Failed updating vector: {:?}", e);
271 }
272 }
273
274 if !old_enabled {
275 if let Err(e) = self.interrupt_source_group.enable() {
276 error!("Failed enabling irq_fd: {:?}", e);
277 }
278 }
279 } else if old_enabled {
280 if let Err(e) = self.interrupt_source_group.disable() {
281 error!("Failed disabling irq_fd: {:?}", e);
282 }
283 }
284 }
285 }
286
287 impl Pausable for MsiConfig {}
288
289 impl Snapshottable for MsiConfig {
id(&self) -> String290 fn id(&self) -> String {
291 String::from(MSI_CONFIG_ID)
292 }
293
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>294 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
295 Snapshot::new_from_state(&self.state())
296 }
297 }
298