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