1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE-BSD-3-Clause file. 4 // 5 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 6 7 use std::any::Any; 8 use std::collections::HashMap; 9 use std::ops::DerefMut; 10 use std::sync::{Arc, Barrier, Mutex}; 11 12 use byteorder::{ByteOrder, LittleEndian}; 13 use thiserror::Error; 14 use vm_device::{Bus, BusDevice, BusDeviceSync}; 15 16 use crate::configuration::{ 17 PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType, 18 }; 19 use crate::device::{BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice}; 20 use crate::PciBarConfiguration; 21 22 const VENDOR_ID_INTEL: u16 = 0x8086; 23 const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57; 24 const NUM_DEVICE_IDS: usize = 32; 25 26 /// Errors for device manager. 27 #[derive(Error, Debug)] 28 pub enum PciRootError { 29 /// Could not allocate device address space for the device. 30 #[error("Could not allocate device address space for the device")] 31 AllocateDeviceAddrs(#[source] PciDeviceError), 32 /// Could not allocate an IRQ number. 33 #[error("Could not allocate an IRQ number")] 34 AllocateIrq, 35 /// Could not add a device to the port io bus. 36 #[error("Could not add a device to the port io bus")] 37 PioInsert(#[source] vm_device::BusError), 38 /// Could not add a device to the mmio bus. 39 #[error("Could not add a device to the mmio bus")] 40 MmioInsert(#[source] vm_device::BusError), 41 /// Could not find an available device slot on the PCI bus. 42 #[error("Could not find an available device slot on the PCI bus")] 43 NoPciDeviceSlotAvailable, 44 /// Invalid PCI device identifier provided. 45 #[error("Invalid PCI device identifier provided")] 46 InvalidPciDeviceSlot(usize), 47 /// Valid PCI device identifier but already used. 48 #[error("Valid PCI device identifier but already used")] 49 AlreadyInUsePciDeviceSlot(usize), 50 } 51 pub type Result<T> = std::result::Result<T, PciRootError>; 52 53 /// Emulates the PCI Root bridge device. 54 pub struct PciRoot { 55 /// Configuration space. 56 config: PciConfiguration, 57 } 58 59 impl PciRoot { 60 /// Create an empty PCI root bridge. 61 pub fn new(config: Option<PciConfiguration>) -> Self { 62 if let Some(config) = config { 63 PciRoot { config } 64 } else { 65 PciRoot { 66 config: PciConfiguration::new( 67 VENDOR_ID_INTEL, 68 DEVICE_ID_INTEL_VIRT_PCIE_HOST, 69 0, 70 PciClassCode::BridgeDevice, 71 &PciBridgeSubclass::HostBridge, 72 None, 73 PciHeaderType::Device, 74 0, 75 0, 76 None, 77 None, 78 ), 79 } 80 } 81 } 82 } 83 84 impl BusDevice for PciRoot {} 85 86 impl PciDevice for PciRoot { 87 fn write_config_register( 88 &mut self, 89 reg_idx: usize, 90 offset: u64, 91 data: &[u8], 92 ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) { 93 ( 94 self.config.write_config_register(reg_idx, offset, data), 95 None, 96 ) 97 } 98 99 fn read_config_register(&mut self, reg_idx: usize) -> u32 { 100 self.config.read_reg(reg_idx) 101 } 102 103 fn as_any_mut(&mut self) -> &mut dyn Any { 104 self 105 } 106 107 fn id(&self) -> Option<String> { 108 None 109 } 110 } 111 112 pub struct PciBus { 113 /// Devices attached to this bus. 114 /// Device 0 is host bridge. 115 devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>>, 116 device_reloc: Arc<dyn DeviceRelocation>, 117 device_ids: Vec<bool>, 118 } 119 120 impl PciBus { 121 pub fn new(pci_root: PciRoot, device_reloc: Arc<dyn DeviceRelocation>) -> Self { 122 let mut devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>> = HashMap::new(); 123 let mut device_ids: Vec<bool> = vec![false; NUM_DEVICE_IDS]; 124 125 devices.insert(0, Arc::new(Mutex::new(pci_root))); 126 device_ids[0] = true; 127 128 PciBus { 129 devices, 130 device_reloc, 131 device_ids, 132 } 133 } 134 135 pub fn register_mapping( 136 &self, 137 dev: Arc<dyn BusDeviceSync>, 138 io_bus: &Bus, 139 mmio_bus: &Bus, 140 bars: Vec<PciBarConfiguration>, 141 ) -> Result<()> { 142 for bar in bars { 143 match bar.region_type() { 144 PciBarRegionType::IoRegion => { 145 io_bus 146 .insert(dev.clone(), bar.addr(), bar.size()) 147 .map_err(PciRootError::PioInsert)?; 148 } 149 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => { 150 mmio_bus 151 .insert(dev.clone(), bar.addr(), bar.size()) 152 .map_err(PciRootError::MmioInsert)?; 153 } 154 } 155 } 156 Ok(()) 157 } 158 159 pub fn add_device(&mut self, device_id: u32, device: Arc<Mutex<dyn PciDevice>>) -> Result<()> { 160 self.devices.insert(device_id, device); 161 Ok(()) 162 } 163 164 pub fn remove_by_device(&mut self, device: &Arc<Mutex<dyn PciDevice>>) -> Result<()> { 165 self.devices.retain(|_, dev| !Arc::ptr_eq(dev, device)); 166 Ok(()) 167 } 168 169 pub fn next_device_id(&mut self) -> Result<u32> { 170 for (idx, device_id) in self.device_ids.iter_mut().enumerate() { 171 if !(*device_id) { 172 *device_id = true; 173 return Ok(idx as u32); 174 } 175 } 176 177 Err(PciRootError::NoPciDeviceSlotAvailable) 178 } 179 180 pub fn get_device_id(&mut self, id: usize) -> Result<()> { 181 if id < NUM_DEVICE_IDS { 182 if !self.device_ids[id] { 183 self.device_ids[id] = true; 184 Ok(()) 185 } else { 186 Err(PciRootError::AlreadyInUsePciDeviceSlot(id)) 187 } 188 } else { 189 Err(PciRootError::InvalidPciDeviceSlot(id)) 190 } 191 } 192 193 pub fn put_device_id(&mut self, id: usize) -> Result<()> { 194 if id < NUM_DEVICE_IDS { 195 self.device_ids[id] = false; 196 Ok(()) 197 } else { 198 Err(PciRootError::InvalidPciDeviceSlot(id)) 199 } 200 } 201 } 202 203 pub struct PciConfigIo { 204 /// Config space register. 205 config_address: u32, 206 pci_bus: Arc<Mutex<PciBus>>, 207 } 208 209 impl PciConfigIo { 210 pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self { 211 PciConfigIo { 212 config_address: 0, 213 pci_bus, 214 } 215 } 216 217 pub fn config_space_read(&self) -> u32 { 218 let enabled = (self.config_address & 0x8000_0000) != 0; 219 if !enabled { 220 return 0xffff_ffff; 221 } 222 223 let (bus, device, function, register) = 224 parse_io_config_address(self.config_address & !0x8000_0000); 225 226 // Only support one bus. 227 if bus != 0 { 228 return 0xffff_ffff; 229 } 230 231 // Don't support multi-function devices. 232 if function > 0 { 233 return 0xffff_ffff; 234 } 235 236 self.pci_bus 237 .as_ref() 238 .lock() 239 .unwrap() 240 .devices 241 .get(&(device as u32)) 242 .map_or(0xffff_ffff, |d| { 243 d.lock().unwrap().read_config_register(register) 244 }) 245 } 246 247 pub fn config_space_write(&mut self, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { 248 if offset as usize + data.len() > 4 { 249 return None; 250 } 251 252 let enabled = (self.config_address & 0x8000_0000) != 0; 253 if !enabled { 254 return None; 255 } 256 257 let (bus, device, _function, register) = 258 parse_io_config_address(self.config_address & !0x8000_0000); 259 260 // Only support one bus. 261 if bus != 0 { 262 return None; 263 } 264 265 let pci_bus = self.pci_bus.as_ref().lock().unwrap(); 266 if let Some(d) = pci_bus.devices.get(&(device as u32)) { 267 let mut device = d.lock().unwrap(); 268 269 // Update the register value 270 let (bar_reprogram, ret) = device.write_config_register(register, offset, data); 271 272 // Move the device's BAR if needed 273 for params in &bar_reprogram { 274 if let Err(e) = pci_bus.device_reloc.move_bar( 275 params.old_base, 276 params.new_base, 277 params.len, 278 device.deref_mut(), 279 params.region_type, 280 ) { 281 error!( 282 "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})", 283 e, params.old_base, params.new_base, params.len 284 ); 285 } 286 } 287 288 ret 289 } else { 290 None 291 } 292 } 293 294 fn set_config_address(&mut self, offset: u64, data: &[u8]) { 295 if offset as usize + data.len() > 4 { 296 return; 297 } 298 let (mask, value): (u32, u32) = match data.len() { 299 1 => ( 300 0x0000_00ff << (offset * 8), 301 u32::from(data[0]) << (offset * 8), 302 ), 303 2 => ( 304 0x0000_ffff << (offset * 16), 305 ((u32::from(data[1]) << 8) | u32::from(data[0])) << (offset * 16), 306 ), 307 4 => (0xffff_ffff, LittleEndian::read_u32(data)), 308 _ => return, 309 }; 310 self.config_address = (self.config_address & !mask) | value; 311 } 312 } 313 314 impl BusDevice for PciConfigIo { 315 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { 316 // `offset` is relative to 0xcf8 317 let value = match offset { 318 0..=3 => self.config_address, 319 4..=7 => self.config_space_read(), 320 _ => 0xffff_ffff, 321 }; 322 323 // Only allow reads to the register boundary. 324 let start = offset as usize % 4; 325 let end = start + data.len(); 326 if end <= 4 { 327 for i in start..end { 328 data[i - start] = (value >> (i * 8)) as u8; 329 } 330 } else { 331 for d in data { 332 *d = 0xff; 333 } 334 } 335 } 336 337 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { 338 // `offset` is relative to 0xcf8 339 match offset { 340 o @ 0..=3 => { 341 self.set_config_address(o, data); 342 None 343 } 344 o @ 4..=7 => self.config_space_write(o - 4, data), 345 _ => None, 346 } 347 } 348 } 349 350 /// Emulates PCI memory-mapped configuration access mechanism. 351 pub struct PciConfigMmio { 352 pci_bus: Arc<Mutex<PciBus>>, 353 } 354 355 impl PciConfigMmio { 356 pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self { 357 PciConfigMmio { pci_bus } 358 } 359 360 fn config_space_read(&self, config_address: u32) -> u32 { 361 let (bus, device, _function, register) = parse_mmio_config_address(config_address); 362 363 // Only support one bus. 364 if bus != 0 { 365 return 0xffff_ffff; 366 } 367 368 self.pci_bus 369 .lock() 370 .unwrap() 371 .devices 372 .get(&(device as u32)) 373 .map_or(0xffff_ffff, |d| { 374 d.lock().unwrap().read_config_register(register) 375 }) 376 } 377 378 fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) { 379 if offset as usize + data.len() > 4 { 380 return; 381 } 382 383 let (bus, device, _function, register) = parse_mmio_config_address(config_address); 384 385 // Only support one bus. 386 if bus != 0 { 387 return; 388 } 389 390 let pci_bus = self.pci_bus.lock().unwrap(); 391 if let Some(d) = pci_bus.devices.get(&(device as u32)) { 392 let mut device = d.lock().unwrap(); 393 394 // Update the register value 395 let (bar_reprogram, _) = device.write_config_register(register, offset, data); 396 397 // Move the device's BAR if needed 398 for params in &bar_reprogram { 399 if let Err(e) = pci_bus.device_reloc.move_bar( 400 params.old_base, 401 params.new_base, 402 params.len, 403 device.deref_mut(), 404 params.region_type, 405 ) { 406 error!( 407 "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})", 408 e, params.old_base, params.new_base, params.len 409 ); 410 } 411 } 412 } 413 } 414 } 415 416 impl BusDevice for PciConfigMmio { 417 fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) { 418 // Only allow reads to the register boundary. 419 let start = offset as usize % 4; 420 let end = start + data.len(); 421 if end > 4 || offset > u64::from(u32::MAX) { 422 for d in data { 423 *d = 0xff; 424 } 425 return; 426 } 427 428 let value = self.config_space_read(offset as u32); 429 for i in start..end { 430 data[i - start] = (value >> (i * 8)) as u8; 431 } 432 } 433 434 fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> { 435 if offset > u64::from(u32::MAX) { 436 return None; 437 } 438 self.config_space_write(offset as u32, offset % 4, data); 439 440 None 441 } 442 } 443 444 fn shift_and_mask(value: u32, offset: usize, mask: u32) -> usize { 445 ((value >> offset) & mask) as usize 446 } 447 448 // Parse the MMIO address offset to a (bus, device, function, register) tuple. 449 // See section 7.2.2 PCI Express Enhanced Configuration Access Mechanism (ECAM) 450 // from the Pci Express Base Specification Revision 5.0 Version 1.0. 451 fn parse_mmio_config_address(config_address: u32) -> (usize, usize, usize, usize) { 452 const BUS_NUMBER_OFFSET: usize = 20; 453 const BUS_NUMBER_MASK: u32 = 0x00ff; 454 const DEVICE_NUMBER_OFFSET: usize = 15; 455 const DEVICE_NUMBER_MASK: u32 = 0x1f; 456 const FUNCTION_NUMBER_OFFSET: usize = 12; 457 const FUNCTION_NUMBER_MASK: u32 = 0x07; 458 const REGISTER_NUMBER_OFFSET: usize = 2; 459 const REGISTER_NUMBER_MASK: u32 = 0x3ff; 460 461 ( 462 shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK), 463 shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK), 464 shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK), 465 shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK), 466 ) 467 } 468 469 // Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple. 470 fn parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize) { 471 const BUS_NUMBER_OFFSET: usize = 16; 472 const BUS_NUMBER_MASK: u32 = 0x00ff; 473 const DEVICE_NUMBER_OFFSET: usize = 11; 474 const DEVICE_NUMBER_MASK: u32 = 0x1f; 475 const FUNCTION_NUMBER_OFFSET: usize = 8; 476 const FUNCTION_NUMBER_MASK: u32 = 0x07; 477 const REGISTER_NUMBER_OFFSET: usize = 2; 478 const REGISTER_NUMBER_MASK: u32 = 0x3f; 479 480 ( 481 shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK), 482 shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK), 483 shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK), 484 shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK), 485 ) 486 } 487