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