@@ -13,8 +13,13 @@ use vm_memory::GuestMemoryError;
1313
1414use super :: cache_info:: { CacheEntry , read_cache_config} ;
1515use super :: gic:: GICDevice ;
16+ use crate :: arch:: {
17+ MEM_32BIT_DEVICES_SIZE , MEM_32BIT_DEVICES_START , MEM_64BIT_DEVICES_SIZE ,
18+ MEM_64BIT_DEVICES_START , PCI_MMIO_CONFIG_SIZE_PER_SEGMENT ,
19+ } ;
1620use crate :: device_manager:: DeviceManager ;
1721use crate :: device_manager:: mmio:: MMIODeviceInfo ;
22+ use crate :: device_manager:: pci_mngr:: PciDevices ;
1823use crate :: devices:: acpi:: vmgenid:: { VMGENID_MEM_SIZE , VmGenId } ;
1924use crate :: initrd:: InitrdConfig ;
2025use crate :: vstate:: memory:: { Address , GuestMemory , GuestMemoryMmap } ;
@@ -90,6 +95,7 @@ pub fn create_fdt(
9095 create_psci_node ( & mut fdt_writer) ?;
9196 create_devices_node ( & mut fdt_writer, device_manager) ?;
9297 create_vmgenid_node ( & mut fdt_writer, & device_manager. acpi_devices . vmgenid ) ?;
98+ create_pci_nodes ( & mut fdt_writer, & device_manager. pci_devices ) ?;
9399
94100 // End Header node.
95101 fdt_writer. end_node ( root) ?;
@@ -431,6 +437,63 @@ fn create_devices_node(
431437 Ok ( ( ) )
432438}
433439
440+ fn create_pci_nodes ( fdt : & mut FdtWriter , pci_devices : & PciDevices ) -> Result < ( ) , FdtError > {
441+ if pci_devices. pci_segment . is_none ( ) {
442+ return Ok ( ( ) ) ;
443+ }
444+
445+ // Fine to unwrap here, we just checked it's not `None`.
446+ let segment = pci_devices. pci_segment . as_ref ( ) . unwrap ( ) ;
447+
448+ let pci_node_name = format ! ( "pci@{:x}" , segment. mmio_config_address) ;
449+ // Each range here is a thruple of `(PCI address, CPU address, PCI size)`.
450+ //
451+ // More info about the format can be found here:
452+ // https://elinux.org/Device_Tree_Usage#PCI_Address_Translation
453+ let ranges = [
454+ // 32bit addresses
455+ 0x200_0000u32 ,
456+ ( MEM_32BIT_DEVICES_START >> 32 ) as u32 , // PCI address
457+ ( MEM_32BIT_DEVICES_START & 0xffff_ffff ) as u32 ,
458+ ( MEM_32BIT_DEVICES_START >> 32 ) as u32 , // CPU address
459+ ( MEM_32BIT_DEVICES_START & 0xffff_ffff ) as u32 ,
460+ ( MEM_32BIT_DEVICES_SIZE >> 32 ) as u32 , // Range size
461+ ( MEM_32BIT_DEVICES_SIZE & 0xffff_ffff ) as u32 ,
462+ // 64bit addresses
463+ 0x300_0000u32 ,
464+ // PCI address
465+ ( MEM_64BIT_DEVICES_START >> 32 ) as u32 , // PCI address
466+ ( MEM_64BIT_DEVICES_START & 0xffff_ffff ) as u32 ,
467+ // CPU address
468+ ( MEM_64BIT_DEVICES_START >> 32 ) as u32 , // CPU address
469+ ( MEM_64BIT_DEVICES_START & 0xffff_ffff ) as u32 ,
470+ // Range size
471+ ( MEM_64BIT_DEVICES_SIZE >> 32 ) as u32 , // Range size
472+ ( ( MEM_64BIT_DEVICES_SIZE & 0xffff_ffff ) >> 32 ) as u32 ,
473+ ] ;
474+ let pci_node = fdt. begin_node ( & pci_node_name) ?;
475+
476+ fdt. property_string ( "compatible" , "pci-host-ecam-generic" ) ?;
477+ fdt. property_string ( "device_type" , "pci" ) ?;
478+ fdt. property_array_u32 ( "ranges" , & ranges) ?;
479+ fdt. property_array_u32 ( "bus-range" , & [ 0 , 0 ] ) ?;
480+ fdt. property_u32 ( "linux,pci-domain" , segment. id . into ( ) ) ?;
481+ fdt. property_u32 ( "#address-cells" , 3 ) ?;
482+ fdt. property_u32 ( "#size-cells" , 2 ) ?;
483+ fdt. property_array_u64 (
484+ "reg" ,
485+ & [
486+ segment. mmio_config_address ,
487+ PCI_MMIO_CONFIG_SIZE_PER_SEGMENT ,
488+ ] ,
489+ ) ?;
490+ fdt. property_u32 ( "#interrupt-cells" , 1 ) ?;
491+ fdt. property_null ( "interrupt-map" ) ?;
492+ fdt. property_null ( "interrupt-map-mask" ) ?;
493+ fdt. property_null ( "dma-coherent" ) ?;
494+ Ok ( fdt. end_node ( pci_node) ?)
495+ }
496+
434497#[ cfg( test) ]
435498mod tests {
436499 use std:: ffi:: CString ;
0 commit comments