1 // Copyright © 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 4 // 5 6 use byteorder::{ByteOrder, LittleEndian}; 7 use std::io; 8 use std::sync::Arc; 9 use thiserror::Error; 10 use versionize::{VersionMap, Versionize, VersionizeResult}; 11 use versionize_derive::Versionize; 12 use vm_device::interrupt::{ 13 InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig, 14 }; 15 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped}; 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 30 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: {0}")] 43 EnableInterruptRoute(io::Error), 44 #[error("Failed updating the interrupt route: {0}")] 45 UpdateInterruptRoute(io::Error), 46 } 47 48 pub const MSI_CONFIG_ID: &str = "msi_config"; 49 50 #[derive(Clone, Copy, Default, Versionize)] 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 { 79 fn addr_64_bits(&self) -> bool { 80 self.msg_ctl & MSI_CTL_64_BITS == MSI_CTL_64_BITS 81 } 82 83 fn per_vector_mask(&self) -> bool { 84 self.msg_ctl & MSI_CTL_PER_VECTOR == MSI_CTL_PER_VECTOR 85 } 86 87 fn enabled(&self) -> bool { 88 self.msg_ctl & MSI_CTL_ENABLE == MSI_CTL_ENABLE 89 } 90 91 fn num_enabled_vectors(&self) -> usize { 92 msi_num_enabled_vectors(self.msg_ctl) 93 } 94 95 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 103 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 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(Versionize)] 176 pub struct MsiConfigState { 177 cap: MsiCap, 178 } 179 180 impl VersionMapped for MsiConfigState {} 181 182 pub struct MsiConfig { 183 pub cap: MsiCap, 184 interrupt_source_group: Arc<dyn InterruptSourceGroup>, 185 } 186 187 impl MsiConfig { 188 pub fn new( 189 msg_ctl: u16, 190 interrupt_source_group: Arc<dyn InterruptSourceGroup>, 191 state: Option<MsiConfigState>, 192 ) -> Result<Self, Error> { 193 let cap = if let Some(state) = state { 194 if state.cap.enabled() { 195 for idx in 0..state.cap.num_enabled_vectors() { 196 let config = MsiIrqSourceConfig { 197 high_addr: state.cap.msg_addr_hi, 198 low_addr: state.cap.msg_addr_lo, 199 data: state.cap.msg_data as u32, 200 devid: 0, 201 }; 202 203 interrupt_source_group 204 .update( 205 idx as InterruptIndex, 206 InterruptSourceConfig::MsiIrq(config), 207 state.cap.vector_masked(idx), 208 false, 209 ) 210 .map_err(Error::UpdateInterruptRoute)?; 211 } 212 213 interrupt_source_group 214 .set_gsi() 215 .map_err(Error::EnableInterruptRoute)?; 216 217 interrupt_source_group 218 .enable() 219 .map_err(Error::EnableInterruptRoute)?; 220 } 221 222 state.cap 223 } else { 224 MsiCap { 225 msg_ctl, 226 ..Default::default() 227 } 228 }; 229 230 Ok(MsiConfig { 231 cap, 232 interrupt_source_group, 233 }) 234 } 235 236 fn state(&self) -> MsiConfigState { 237 MsiConfigState { cap: self.cap } 238 } 239 240 pub fn enabled(&self) -> bool { 241 self.cap.enabled() 242 } 243 244 pub fn size(&self) -> u64 { 245 self.cap.size() 246 } 247 248 pub fn num_enabled_vectors(&self) -> usize { 249 self.cap.num_enabled_vectors() 250 } 251 252 pub fn update(&mut self, offset: u64, data: &[u8]) { 253 let old_enabled = self.cap.enabled(); 254 255 self.cap.update(offset, data); 256 257 if self.cap.enabled() { 258 for idx in 0..self.num_enabled_vectors() { 259 let config = MsiIrqSourceConfig { 260 high_addr: self.cap.msg_addr_hi, 261 low_addr: self.cap.msg_addr_lo, 262 data: self.cap.msg_data as u32, 263 devid: 0, 264 }; 265 266 if let Err(e) = self.interrupt_source_group.update( 267 idx as InterruptIndex, 268 InterruptSourceConfig::MsiIrq(config), 269 self.cap.vector_masked(idx), 270 true, 271 ) { 272 error!("Failed updating vector: {:?}", e); 273 } 274 } 275 276 if !old_enabled { 277 if let Err(e) = self.interrupt_source_group.enable() { 278 error!("Failed enabling irq_fd: {:?}", e); 279 } 280 } 281 } else if old_enabled { 282 if let Err(e) = self.interrupt_source_group.disable() { 283 error!("Failed disabling irq_fd: {:?}", e); 284 } 285 } 286 } 287 } 288 289 impl Pausable for MsiConfig {} 290 291 impl Snapshottable for MsiConfig { 292 fn id(&self) -> String { 293 String::from(MSI_CONFIG_ID) 294 } 295 296 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 297 Snapshot::new_from_versioned_state(&self.state()) 298 } 299 } 300