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