1 // Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // 3 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE-BSD-3-Clause file. 6 // 7 // Copyright © 2019 - 2021 Intel Corporation 8 // 9 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 10 // 11 12 use crate::device_manager::{AddressManager, DeviceManagerError, DeviceManagerResult}; 13 use acpi_tables::{aml, Aml}; 14 use arch::layout; 15 use pci::{DeviceRelocation, PciBdf, PciBus, PciConfigMmio, PciRoot}; 16 #[cfg(target_arch = "x86_64")] 17 use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE}; 18 use std::sync::{Arc, Mutex}; 19 use uuid::Uuid; 20 use vm_allocator::AddressAllocator; 21 use vm_device::BusDeviceSync; 22 23 pub(crate) struct PciSegment { 24 pub(crate) id: u16, 25 pub(crate) pci_bus: Arc<Mutex<PciBus>>, 26 pub(crate) pci_config_mmio: Arc<Mutex<PciConfigMmio>>, 27 pub(crate) mmio_config_address: u64, 28 pub(crate) proximity_domain: u32, 29 30 #[cfg(target_arch = "x86_64")] 31 pub(crate) pci_config_io: Option<Arc<Mutex<PciConfigIo>>>, 32 33 // Bitmap of PCI devices to hotplug. 34 pub(crate) pci_devices_up: u32, 35 // Bitmap of PCI devices to hotunplug. 36 pub(crate) pci_devices_down: u32, 37 // List of allocated IRQs for each PCI slot. 38 pub(crate) pci_irq_slots: [u8; 32], 39 40 // Device memory covered by this segment 41 pub(crate) start_of_mem32_area: u64, 42 pub(crate) end_of_mem32_area: u64, 43 44 pub(crate) start_of_mem64_area: u64, 45 pub(crate) end_of_mem64_area: u64, 46 47 pub(crate) mem32_allocator: Arc<Mutex<AddressAllocator>>, 48 pub(crate) mem64_allocator: Arc<Mutex<AddressAllocator>>, 49 } 50 51 impl PciSegment { 52 pub(crate) fn new( 53 id: u16, 54 numa_node: u32, 55 address_manager: &Arc<AddressManager>, 56 mem32_allocator: Arc<Mutex<AddressAllocator>>, 57 mem64_allocator: Arc<Mutex<AddressAllocator>>, 58 pci_irq_slots: &[u8; 32], 59 ) -> DeviceManagerResult<PciSegment> { 60 let pci_root = PciRoot::new(None); 61 let pci_bus = Arc::new(Mutex::new(PciBus::new( 62 pci_root, 63 Arc::clone(address_manager) as Arc<dyn DeviceRelocation>, 64 ))); 65 66 let pci_config_mmio = Arc::new(Mutex::new(PciConfigMmio::new(Arc::clone(&pci_bus)))); 67 let mmio_config_address = 68 layout::PCI_MMCONFIG_START.0 + layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT * id as u64; 69 70 address_manager 71 .mmio_bus 72 .insert( 73 Arc::clone(&pci_config_mmio) as Arc<dyn BusDeviceSync>, 74 mmio_config_address, 75 layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT, 76 ) 77 .map_err(DeviceManagerError::BusError)?; 78 79 let start_of_mem32_area = mem32_allocator.lock().unwrap().base().0; 80 let end_of_mem32_area = mem32_allocator.lock().unwrap().end().0; 81 82 let start_of_mem64_area = mem64_allocator.lock().unwrap().base().0; 83 let end_of_mem64_area = mem64_allocator.lock().unwrap().end().0; 84 85 let segment = PciSegment { 86 id, 87 pci_bus, 88 pci_config_mmio, 89 mmio_config_address, 90 proximity_domain: numa_node, 91 pci_devices_up: 0, 92 pci_devices_down: 0, 93 #[cfg(target_arch = "x86_64")] 94 pci_config_io: None, 95 mem32_allocator, 96 mem64_allocator, 97 start_of_mem32_area, 98 end_of_mem32_area, 99 start_of_mem64_area, 100 end_of_mem64_area, 101 pci_irq_slots: *pci_irq_slots, 102 }; 103 104 info!( 105 "Adding PCI segment: id={}, PCI MMIO config address: 0x{:x}, mem32 area [0x{:x}-0x{:x}, mem64 area [0x{:x}-0x{:x}", 106 segment.id, segment.mmio_config_address, segment.start_of_mem32_area, segment.end_of_mem32_area, segment.start_of_mem64_area, segment.end_of_mem64_area 107 ); 108 Ok(segment) 109 } 110 111 #[cfg(target_arch = "x86_64")] 112 pub(crate) fn new_default_segment( 113 address_manager: &Arc<AddressManager>, 114 mem32_allocator: Arc<Mutex<AddressAllocator>>, 115 mem64_allocator: Arc<Mutex<AddressAllocator>>, 116 pci_irq_slots: &[u8; 32], 117 ) -> DeviceManagerResult<PciSegment> { 118 let mut segment = Self::new( 119 0, 120 0, 121 address_manager, 122 mem32_allocator, 123 mem64_allocator, 124 pci_irq_slots, 125 )?; 126 let pci_config_io = Arc::new(Mutex::new(PciConfigIo::new(Arc::clone(&segment.pci_bus)))); 127 128 address_manager 129 .io_bus 130 .insert( 131 pci_config_io.clone(), 132 PCI_CONFIG_IO_PORT, 133 PCI_CONFIG_IO_PORT_SIZE, 134 ) 135 .map_err(DeviceManagerError::BusError)?; 136 137 segment.pci_config_io = Some(pci_config_io); 138 139 Ok(segment) 140 } 141 142 #[cfg(target_arch = "aarch64")] 143 pub(crate) fn new_default_segment( 144 address_manager: &Arc<AddressManager>, 145 mem32_allocator: Arc<Mutex<AddressAllocator>>, 146 mem64_allocator: Arc<Mutex<AddressAllocator>>, 147 pci_irq_slots: &[u8; 32], 148 ) -> DeviceManagerResult<PciSegment> { 149 Self::new( 150 0, 151 0, 152 address_manager, 153 mem32_allocator, 154 mem64_allocator, 155 pci_irq_slots, 156 ) 157 } 158 159 pub(crate) fn next_device_bdf(&self) -> DeviceManagerResult<PciBdf> { 160 Ok(PciBdf::new( 161 self.id, 162 0, 163 self.pci_bus 164 .lock() 165 .unwrap() 166 .next_device_id() 167 .map_err(DeviceManagerError::NextPciDeviceId)? as u8, 168 0, 169 )) 170 } 171 172 pub fn reserve_legacy_interrupts_for_pci_devices( 173 address_manager: &Arc<AddressManager>, 174 pci_irq_slots: &mut [u8; 32], 175 ) -> DeviceManagerResult<()> { 176 // Reserve 8 IRQs which will be shared across all PCI devices. 177 let num_irqs = 8; 178 let mut irqs: Vec<u8> = Vec::new(); 179 for _ in 0..num_irqs { 180 irqs.push( 181 address_manager 182 .allocator 183 .lock() 184 .unwrap() 185 .allocate_irq() 186 .ok_or(DeviceManagerError::AllocateIrq)? as u8, 187 ); 188 } 189 190 // There are 32 devices on the PCI bus, let's assign them an IRQ. 191 for i in 0..32 { 192 pci_irq_slots[i] = irqs[i % num_irqs]; 193 } 194 195 Ok(()) 196 } 197 } 198 199 struct PciDevSlot { 200 device_id: u8, 201 } 202 203 impl Aml for PciDevSlot { 204 fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) { 205 let sun = self.device_id; 206 let adr: u32 = (self.device_id as u32) << 16; 207 aml::Device::new( 208 format!("S{:03}", self.device_id).as_str().into(), 209 vec![ 210 &aml::Name::new("_SUN".into(), &sun), 211 &aml::Name::new("_ADR".into(), &adr), 212 &aml::Method::new( 213 "_EJ0".into(), 214 1, 215 true, 216 vec![&aml::MethodCall::new( 217 "\\_SB_.PHPR.PCEJ".into(), 218 vec![&aml::Path::new("_SUN"), &aml::Path::new("_SEG")], 219 )], 220 ), 221 ], 222 ) 223 .to_aml_bytes(sink) 224 } 225 } 226 227 struct PciDevSlotNotify { 228 device_id: u8, 229 } 230 231 impl Aml for PciDevSlotNotify { 232 fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) { 233 let device_id_mask: u32 = 1 << self.device_id; 234 let object = aml::Path::new(&format!("S{:03}", self.device_id)); 235 aml::And::new(&aml::Local(0), &aml::Arg(0), &device_id_mask).to_aml_bytes(sink); 236 aml::If::new( 237 &aml::Equal::new(&aml::Local(0), &device_id_mask), 238 vec![&aml::Notify::new(&object, &aml::Arg(1))], 239 ) 240 .to_aml_bytes(sink); 241 } 242 } 243 244 struct PciDevSlotMethods {} 245 246 impl Aml for PciDevSlotMethods { 247 fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) { 248 let mut device_notifies = Vec::new(); 249 for device_id in 0..32 { 250 device_notifies.push(PciDevSlotNotify { device_id }); 251 } 252 253 let mut device_notifies_refs: Vec<&dyn Aml> = Vec::new(); 254 for device_notify in device_notifies.iter() { 255 device_notifies_refs.push(device_notify); 256 } 257 258 aml::Method::new("DVNT".into(), 2, true, device_notifies_refs).to_aml_bytes(sink); 259 aml::Method::new( 260 "PCNT".into(), 261 0, 262 true, 263 vec![ 264 &aml::Acquire::new("\\_SB_.PHPR.BLCK".into(), 0xffff), 265 &aml::Store::new(&aml::Path::new("\\_SB_.PHPR.PSEG"), &aml::Path::new("_SEG")), 266 &aml::MethodCall::new( 267 "DVNT".into(), 268 vec![&aml::Path::new("\\_SB_.PHPR.PCIU"), &aml::ONE], 269 ), 270 &aml::MethodCall::new( 271 "DVNT".into(), 272 vec![&aml::Path::new("\\_SB_.PHPR.PCID"), &3usize], 273 ), 274 &aml::Release::new("\\_SB_.PHPR.BLCK".into()), 275 ], 276 ) 277 .to_aml_bytes(sink) 278 } 279 } 280 281 struct PciDsmMethod {} 282 283 impl Aml for PciDsmMethod { 284 fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) { 285 // Refer to ACPI spec v6.3 Ch 9.1.1 and PCI Firmware spec v3.3 Ch 4.6.1 286 // _DSM (Device Specific Method), the following is the implementation in ASL. 287 /* 288 Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method 289 { 290 If ((Arg0 == ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) 291 { 292 If ((Arg2 == Zero)) 293 { 294 Return (Buffer (One) { 0x21 }) 295 } 296 If ((Arg2 == 0x05)) 297 { 298 Return (Zero) 299 } 300 } 301 302 Return (Buffer (One) { 0x00 }) 303 } 304 */ 305 /* 306 * As per ACPI v6.3 Ch 19.6.142, the UUID is required to be in mixed endian: 307 * Among the fields of a UUID: 308 * {d1 (8 digits)} - {d2 (4 digits)} - {d3 (4 digits)} - {d4 (16 digits)} 309 * d1 ~ d3 need to be little endian, d4 be big endian. 310 * See https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding . 311 */ 312 let uuid = Uuid::parse_str("E5C937D0-3553-4D7A-9117-EA4D19C3434D").unwrap(); 313 let (uuid_d1, uuid_d2, uuid_d3, uuid_d4) = uuid.as_fields(); 314 let mut uuid_buf = vec![]; 315 uuid_buf.extend(uuid_d1.to_le_bytes()); 316 uuid_buf.extend(uuid_d2.to_le_bytes()); 317 uuid_buf.extend(uuid_d3.to_le_bytes()); 318 uuid_buf.extend(uuid_d4); 319 aml::Method::new( 320 "_DSM".into(), 321 4, 322 false, 323 vec![ 324 &aml::If::new( 325 &aml::Equal::new(&aml::Arg(0), &aml::BufferData::new(uuid_buf)), 326 vec![ 327 &aml::If::new( 328 &aml::Equal::new(&aml::Arg(2), &aml::ZERO), 329 vec![&aml::Return::new(&aml::BufferData::new(vec![0x21]))], 330 ), 331 &aml::If::new( 332 &aml::Equal::new(&aml::Arg(2), &0x05u8), 333 vec![&aml::Return::new(&aml::ZERO)], 334 ), 335 ], 336 ), 337 &aml::Return::new(&aml::BufferData::new(vec![0])), 338 ], 339 ) 340 .to_aml_bytes(sink) 341 } 342 } 343 344 impl Aml for PciSegment { 345 fn to_aml_bytes(&self, sink: &mut dyn acpi_tables::AmlSink) { 346 let mut pci_dsdt_inner_data: Vec<&dyn Aml> = Vec::new(); 347 let hid = aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A08")); 348 pci_dsdt_inner_data.push(&hid); 349 let cid = aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0A03")); 350 pci_dsdt_inner_data.push(&cid); 351 let adr = aml::Name::new("_ADR".into(), &aml::ZERO); 352 pci_dsdt_inner_data.push(&adr); 353 let seg = aml::Name::new("_SEG".into(), &self.id); 354 pci_dsdt_inner_data.push(&seg); 355 let uid = aml::Name::new("_UID".into(), &aml::ZERO); 356 pci_dsdt_inner_data.push(&uid); 357 let cca = aml::Name::new("_CCA".into(), &aml::ONE); 358 pci_dsdt_inner_data.push(&cca); 359 let supp = aml::Name::new("SUPP".into(), &aml::ZERO); 360 pci_dsdt_inner_data.push(&supp); 361 362 let proximity_domain = self.proximity_domain; 363 let pxm_return = aml::Return::new(&proximity_domain); 364 let pxm = aml::Method::new("_PXM".into(), 0, false, vec![&pxm_return]); 365 pci_dsdt_inner_data.push(&pxm); 366 367 let pci_dsm = PciDsmMethod {}; 368 pci_dsdt_inner_data.push(&pci_dsm); 369 370 #[allow(clippy::if_same_then_else)] 371 let crs = if self.id == 0 { 372 aml::Name::new( 373 "_CRS".into(), 374 &aml::ResourceTemplate::new(vec![ 375 &aml::AddressSpace::new_bus_number(0x0u16, 0x0u16), 376 #[cfg(target_arch = "x86_64")] 377 &aml::IO::new(0xcf8, 0xcf8, 1, 0x8), 378 &aml::Memory32Fixed::new( 379 true, 380 self.mmio_config_address as u32, 381 layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT as u32, 382 ), 383 &aml::AddressSpace::new_memory( 384 aml::AddressSpaceCacheable::NotCacheable, 385 true, 386 self.start_of_mem32_area, 387 self.end_of_mem32_area, 388 None, 389 ), 390 &aml::AddressSpace::new_memory( 391 aml::AddressSpaceCacheable::NotCacheable, 392 true, 393 self.start_of_mem64_area, 394 self.end_of_mem64_area, 395 None, 396 ), 397 #[cfg(target_arch = "x86_64")] 398 &aml::AddressSpace::new_io(0u16, 0x0cf7u16, None), 399 #[cfg(target_arch = "x86_64")] 400 &aml::AddressSpace::new_io(0x0d00u16, 0xffffu16, None), 401 ]), 402 ) 403 } else { 404 aml::Name::new( 405 "_CRS".into(), 406 &aml::ResourceTemplate::new(vec![ 407 &aml::AddressSpace::new_bus_number(0x0u16, 0x0u16), 408 &aml::Memory32Fixed::new( 409 true, 410 self.mmio_config_address as u32, 411 layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT as u32, 412 ), 413 &aml::AddressSpace::new_memory( 414 aml::AddressSpaceCacheable::NotCacheable, 415 true, 416 self.start_of_mem32_area, 417 self.end_of_mem32_area, 418 None, 419 ), 420 &aml::AddressSpace::new_memory( 421 aml::AddressSpaceCacheable::NotCacheable, 422 true, 423 self.start_of_mem64_area, 424 self.end_of_mem64_area, 425 None, 426 ), 427 ]), 428 ) 429 }; 430 pci_dsdt_inner_data.push(&crs); 431 432 let mut pci_devices = Vec::new(); 433 for device_id in 0..32 { 434 let pci_device = PciDevSlot { device_id }; 435 pci_devices.push(pci_device); 436 } 437 for pci_device in pci_devices.iter() { 438 pci_dsdt_inner_data.push(pci_device); 439 } 440 441 let pci_device_methods = PciDevSlotMethods {}; 442 pci_dsdt_inner_data.push(&pci_device_methods); 443 444 // Build PCI routing table, listing IRQs assigned to PCI devices. 445 let prt_package_list: Vec<(u32, u32)> = self 446 .pci_irq_slots 447 .iter() 448 .enumerate() 449 .map(|(i, irq)| (((((i as u32) & 0x1fu32) << 16) | 0xffffu32), *irq as u32)) 450 .collect(); 451 let prt_package_list: Vec<aml::Package> = prt_package_list 452 .iter() 453 .map(|(bdf, irq)| aml::Package::new(vec![bdf, &0u8, &0u8, irq])) 454 .collect(); 455 let prt_package_list: Vec<&dyn Aml> = prt_package_list 456 .iter() 457 .map(|item| item as &dyn Aml) 458 .collect(); 459 let prt = aml::Name::new("_PRT".into(), &aml::Package::new(prt_package_list)); 460 pci_dsdt_inner_data.push(&prt); 461 462 aml::Device::new( 463 format!("_SB_.PC{:02X}", self.id).as_str().into(), 464 pci_dsdt_inner_data, 465 ) 466 .to_aml_bytes(sink) 467 } 468 } 469