From 217a4f30ae4b9297fc7887787dde1260eeb52821 Mon Sep 17 00:00:00 2001 From: Yu Duan Date: Tue, 26 Nov 2024 16:11:59 +0000 Subject: [PATCH 1/2] Scan PCI bus in loader and save the information of network devices in deivcetree --- Cargo.lock | 12 ++++ Cargo.toml | 2 + src/arch/x86_64/devicetree.rs | 122 ++++++++++++++++++++++++++++++++++ src/arch/x86_64/mod.rs | 2 + src/arch/x86_64/multiboot.rs | 28 +------- src/arch/x86_64/pci.rs | 50 ++++++++++++++ 6 files changed, 191 insertions(+), 25 deletions(-) create mode 100644 src/arch/x86_64/devicetree.rs create mode 100644 src/arch/x86_64/pci.rs diff --git a/Cargo.lock b/Cargo.lock index 4cea6b47..94704f85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -296,12 +296,14 @@ dependencies = [ "multiboot", "naked-function", "one-shot-mutex", + "pci_types", "sbi-rt", "sptr", "take-static", "uart_16550", "uefi", "vm-fdt", + "x86", "x86_64", ] @@ -411,6 +413,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pci_types" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebac2b2ee11791f721a51184b632a916b3044f2ee7b2374e7fdcfdf3eaf29c79" +dependencies = [ + "bit_field", + "bitflags 2.6.0", +] + [[package]] name = "plain" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index 3474611e..145ad96a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ cfg-if = "1" hermit-entry = { version = "0.10", features = ["loader"] } log = "0.4" one-shot-mutex = "0.1" +pci_types = { version = "0.6" } sptr = "0.3" take-static = "0.1" vm-fdt = { version = "0.3", default-features = false, features = ["alloc"] } @@ -27,6 +28,7 @@ multiboot = "0.8" [target.'cfg(target_arch = "x86_64")'.dependencies] uart_16550 = "0.3" +x86 = { version = "0.52", default-features = false } x86_64 = { version = "0.15", default-features = false, features = ["instructions"] } [target.'cfg(target_arch = "aarch64")'.dependencies] diff --git a/src/arch/x86_64/devicetree.rs b/src/arch/x86_64/devicetree.rs new file mode 100644 index 00000000..9104cf11 --- /dev/null +++ b/src/arch/x86_64/devicetree.rs @@ -0,0 +1,122 @@ +use alloc::format; +use alloc::vec::Vec; + +use log::debug; +use log::info; +use multiboot::information::{Multiboot, MemoryType}; +use pci_types::{EndpointHeader, PciAddress, PciHeader, MAX_BARS, Bar}; +use vm_fdt::{FdtWriter, FdtWriterResult}; + +use super::pci::{PciConfigRegion, PCI_MAX_BUS_NUMBER, PCI_MAX_DEVICE_NUMBER}; +use super::multiboot::{mb_info, Mem}; + +pub struct DeviceTree; + +impl DeviceTree { + pub fn create() -> FdtWriterResult<&'static [u8]> { + let mut mem = Mem; + let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; + + let all_regions = multiboot + .memory_regions() + .expect("Could not find a memory map in the Multiboot information"); + let ram_regions = all_regions.filter(|m| m.memory_type() == MemoryType::Available); + + let mut fdt = FdtWriter::new()?; + + let root_node = fdt.begin_node("")?; + fdt.property_string("compatible", "linux,dummy-virt")?; + fdt.property_u32("#address-cells", 0x2)?; + fdt.property_u32("#size-cells", 0x2)?; + fdt.property_u32("#interrupt-cells", 0x1)?; + + if let Some(cmdline) = multiboot.command_line() { + let chosen_node = fdt.begin_node("chosen")?; + fdt.property_string("bootargs", cmdline)?; + fdt.end_node(chosen_node)?; + } + + for m in ram_regions { + let start_address = m.base_address(); + let length = m.length(); + + let memory_node = fdt.begin_node(format!("memory@{:x}", start_address).as_str())?; + fdt.property_string("device_type", "memory")?; + fdt.property_array_u64("reg", &[start_address, length])?; + fdt.end_node(memory_node)?; + } + + debug!("Scanning PCI Busses 0 to {}", PCI_MAX_BUS_NUMBER - 1); + + let pci_node = fdt.begin_node("pci")?; + fdt.property_string("device_type", "pci")?; + + // TODO: Address cells and size cells should be 3 and 2 respectively. + fdt.property_u32("#address-cells", 0x1)?; + fdt.property_u32("#size-cells", 0x1)?; + + // Hermit only uses PCI for network devices. + // Therefore, multifunction devices as well as additional bridges are not scanned. + // We also limit scanning to the first 32 buses. + let pci_config = PciConfigRegion::new(); + for bus in 0..PCI_MAX_BUS_NUMBER { + for device in 0..PCI_MAX_DEVICE_NUMBER { + let pci_address = PciAddress::new(0, bus, device, 0); + let header = PciHeader::new(pci_address); + + let (vendor_id, device_id) = header.id(&pci_config); + if device_id != u16::MAX && vendor_id != u16::MAX { + let addr = (pci_address.bus() as u32) << 16 | (pci_address.device() as u32) << 11; + info!("Addr: {:#x}", addr); + let endpoint = EndpointHeader::from_header(header, &pci_config).unwrap(); + let (_pin, line) = endpoint.interrupt(&pci_config); + + info!("Device ID: {:#x} Vendor ID: {:#x}", device_id, vendor_id); + + if vendor_id == 0x10ec && (0x8138..=0x8139).contains(&device_id) { + info!("Network card found."); + let net_node = fdt.begin_node(format!("virtio_net@{:x}", addr).as_str())?; + + fdt.property_string("compatible", "realtek,rtl8139")?; + fdt.property_u32("vendor-id", vendor_id as u32)?; + fdt.property_u32("device-id", device_id as u32)?; + fdt.property_u32("interrupts", line as u32)?; + fdt.property_u32("pci-address", addr)?; + fdt.property_array_u32("reg", &[addr, 0, 0, 0, 0, (0x02000010 | addr), 0, 0, 0, 0x100, (0x01000014 | addr), 0, 0, 0, 0x100])?; + + let mut assigned_addresses: Vec = Vec::new(); + for i in 0..MAX_BARS { + if let Some(bar) = endpoint.bar(i.try_into().unwrap(), &pci_config) { + match bar { + Bar::Io { port } => { + info!("BAR{:x} IO {{port: {:#X}}}", i, port); + assigned_addresses.extend(alloc::vec![(0x81000014 | addr), 0, port, 0, 0x100]); + } + Bar::Memory32 { address , size, prefetchable } => { + info!("BAR{:x} Memory32 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}", i, address, size, prefetchable); + assigned_addresses.extend(alloc::vec![(0x82000010 | addr), 0, address, 0, size]); + } + Bar::Memory64 { address , size, prefetchable } => { + info!("BAR{:x} Memory64 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}", i, address, size, prefetchable); + assigned_addresses.extend(alloc::vec![(0x82000010 | addr), (address >> 32) as u32, address as u32, (size >> 32) as u32, size as u32]); + } + } + } + } + fdt.property_array_u32("assigned-addresses", assigned_addresses.as_slice())?; + + fdt.end_node(net_node)?; + } + } + } + } + + fdt.end_node(pci_node)?; + + fdt.end_node(root_node)?; + + let fdt = fdt.finish()?; + + Ok(fdt.leak()) + } +} diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 90acc585..9fe32f42 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -8,6 +8,8 @@ cfg_if::cfg_if! { } } +mod devicetree; +mod pci; mod console; #[cfg(target_os = "none")] mod paging; diff --git a/src/arch/x86_64/multiboot.rs b/src/arch/x86_64/multiboot.rs index 4840ae34..3d975bc8 100644 --- a/src/arch/x86_64/multiboot.rs +++ b/src/arch/x86_64/multiboot.rs @@ -16,11 +16,12 @@ use super::paging; use super::physicalmem::PhysAlloc; use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT}; use crate::fdt::Fdt; +use crate::arch::x86_64::devicetree::DeviceTree; use crate::BootInfoExt; extern "C" { static mut loader_end: u8; - static mb_info: usize; + pub(crate) static mb_info: usize; } #[allow(bad_asm_style)] @@ -28,7 +29,7 @@ mod entry { core::arch::global_asm!(include_str!("entry.s")); } -struct Mem; +pub(crate) struct Mem; impl MemoryManagement for Mem { unsafe fn paddr_to_slice<'a>(&self, p: PAddr, sz: usize) -> Option<&'static [u8]> { @@ -48,29 +49,6 @@ impl MemoryManagement for Mem { } } -pub struct DeviceTree; - -impl DeviceTree { - pub fn create() -> FdtWriterResult<&'static [u8]> { - let mut mem = Mem; - let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; - - let memory_regions = multiboot - .memory_regions() - .expect("Could not find a memory map in the Multiboot information"); - - let mut fdt = Fdt::new("multiboot")?.memory_regions(memory_regions)?; - - if let Some(cmdline) = multiboot.command_line() { - fdt = fdt.bootargs(cmdline)?; - } - - let fdt = fdt.finish()?; - - Ok(fdt.leak()) - } -} - pub fn find_kernel() -> &'static [u8] { use core::cmp; diff --git a/src/arch/x86_64/pci.rs b/src/arch/x86_64/pci.rs new file mode 100644 index 00000000..b6c13ca7 --- /dev/null +++ b/src/arch/x86_64/pci.rs @@ -0,0 +1,50 @@ +use pci_types::{ConfigRegionAccess, PciAddress}; +use x86::io::*; + +pub(crate) const PCI_MAX_BUS_NUMBER: u8 = 32; +pub(crate) const PCI_MAX_DEVICE_NUMBER: u8 = 32; + +pub(crate) const PCI_CONFIG_ADDRESS_PORT: u16 = 0xCF8; +const PCI_CONFIG_ADDRESS_ENABLE: u32 = 1 << 31; + +const PCI_CONFIG_DATA_PORT: u16 = 0xCFC; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct PciConfigRegion; + +impl PciConfigRegion { + pub const fn new() -> Self { + Self {} + } +} + +impl ConfigRegionAccess for PciConfigRegion { + #[inline] + fn function_exists(&self, _address: PciAddress) -> bool { + true + } + + #[inline] + unsafe fn read(&self, pci_addr: PciAddress, register: u16) -> u32 { + let address = PCI_CONFIG_ADDRESS_ENABLE + | u32::from(pci_addr.bus()) << 16 + | u32::from(pci_addr.device()) << 11 + | u32::from(register); + unsafe { + outl(PCI_CONFIG_ADDRESS_PORT, address); + u32::from_le(inl(PCI_CONFIG_DATA_PORT)) + } + } + + #[inline] + unsafe fn write(&self, pci_addr: PciAddress, register: u16, value: u32) { + let address = PCI_CONFIG_ADDRESS_ENABLE + | u32::from(pci_addr.bus()) << 16 + | u32::from(pci_addr.device()) << 11 + | u32::from(register); + unsafe { + outl(PCI_CONFIG_ADDRESS_PORT, address); + outl(PCI_CONFIG_DATA_PORT, value.to_le()); + } + } +} From 8caf2d275cd82a359ee0b4387ebc91aac81b78ef Mon Sep 17 00:00:00 2001 From: Yu Duan Date: Thu, 9 Jan 2025 08:11:11 +0000 Subject: [PATCH 2/2] Add PCI scanning process into FDT creation structure --- Cargo.lock | 12 +-- src/arch/x86_64/devicetree.rs | 104 +++----------------------- src/arch/x86_64/mod.rs | 4 +- src/arch/x86_64/multiboot.rs | 2 +- src/arch/x86_64/pci.rs | 2 +- src/fdt.rs | 137 +++++++++++++++++++++++++++++++++- 6 files changed, 155 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94704f85..3b9648c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,9 +180,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "deranged" @@ -315,9 +315,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "libc" -version = "0.2.168" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "llvm-tools" diff --git a/src/arch/x86_64/devicetree.rs b/src/arch/x86_64/devicetree.rs index 9104cf11..d0923fcd 100644 --- a/src/arch/x86_64/devicetree.rs +++ b/src/arch/x86_64/devicetree.rs @@ -1,14 +1,14 @@ use alloc::format; use alloc::vec::Vec; -use log::debug; -use log::info; -use multiboot::information::{Multiboot, MemoryType}; -use pci_types::{EndpointHeader, PciAddress, PciHeader, MAX_BARS, Bar}; +use log::{debug, info}; +use multiboot::information::{MemoryType, Multiboot}; +use pci_types::{Bar, EndpointHeader, PciAddress, PciHeader, MAX_BARS}; use vm_fdt::{FdtWriter, FdtWriterResult}; -use super::pci::{PciConfigRegion, PCI_MAX_BUS_NUMBER, PCI_MAX_DEVICE_NUMBER}; use super::multiboot::{mb_info, Mem}; +use super::pci::{PciConfigRegion, PCI_MAX_BUS_NUMBER, PCI_MAX_DEVICE_NUMBER}; +use crate::fdt::Fdt; pub struct DeviceTree; @@ -17,103 +17,17 @@ impl DeviceTree { let mut mem = Mem; let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() }; - let all_regions = multiboot + let memory_regions = multiboot .memory_regions() .expect("Could not find a memory map in the Multiboot information"); - let ram_regions = all_regions.filter(|m| m.memory_type() == MemoryType::Available); - - let mut fdt = FdtWriter::new()?; - let root_node = fdt.begin_node("")?; - fdt.property_string("compatible", "linux,dummy-virt")?; - fdt.property_u32("#address-cells", 0x2)?; - fdt.property_u32("#size-cells", 0x2)?; - fdt.property_u32("#interrupt-cells", 0x1)?; + let mut fdt = Fdt::new("multiboot")?.memory_regions(memory_regions)?; if let Some(cmdline) = multiboot.command_line() { - let chosen_node = fdt.begin_node("chosen")?; - fdt.property_string("bootargs", cmdline)?; - fdt.end_node(chosen_node)?; - } - - for m in ram_regions { - let start_address = m.base_address(); - let length = m.length(); - - let memory_node = fdt.begin_node(format!("memory@{:x}", start_address).as_str())?; - fdt.property_string("device_type", "memory")?; - fdt.property_array_u64("reg", &[start_address, length])?; - fdt.end_node(memory_node)?; - } - - debug!("Scanning PCI Busses 0 to {}", PCI_MAX_BUS_NUMBER - 1); - - let pci_node = fdt.begin_node("pci")?; - fdt.property_string("device_type", "pci")?; - - // TODO: Address cells and size cells should be 3 and 2 respectively. - fdt.property_u32("#address-cells", 0x1)?; - fdt.property_u32("#size-cells", 0x1)?; - - // Hermit only uses PCI for network devices. - // Therefore, multifunction devices as well as additional bridges are not scanned. - // We also limit scanning to the first 32 buses. - let pci_config = PciConfigRegion::new(); - for bus in 0..PCI_MAX_BUS_NUMBER { - for device in 0..PCI_MAX_DEVICE_NUMBER { - let pci_address = PciAddress::new(0, bus, device, 0); - let header = PciHeader::new(pci_address); - - let (vendor_id, device_id) = header.id(&pci_config); - if device_id != u16::MAX && vendor_id != u16::MAX { - let addr = (pci_address.bus() as u32) << 16 | (pci_address.device() as u32) << 11; - info!("Addr: {:#x}", addr); - let endpoint = EndpointHeader::from_header(header, &pci_config).unwrap(); - let (_pin, line) = endpoint.interrupt(&pci_config); - - info!("Device ID: {:#x} Vendor ID: {:#x}", device_id, vendor_id); - - if vendor_id == 0x10ec && (0x8138..=0x8139).contains(&device_id) { - info!("Network card found."); - let net_node = fdt.begin_node(format!("virtio_net@{:x}", addr).as_str())?; - - fdt.property_string("compatible", "realtek,rtl8139")?; - fdt.property_u32("vendor-id", vendor_id as u32)?; - fdt.property_u32("device-id", device_id as u32)?; - fdt.property_u32("interrupts", line as u32)?; - fdt.property_u32("pci-address", addr)?; - fdt.property_array_u32("reg", &[addr, 0, 0, 0, 0, (0x02000010 | addr), 0, 0, 0, 0x100, (0x01000014 | addr), 0, 0, 0, 0x100])?; - - let mut assigned_addresses: Vec = Vec::new(); - for i in 0..MAX_BARS { - if let Some(bar) = endpoint.bar(i.try_into().unwrap(), &pci_config) { - match bar { - Bar::Io { port } => { - info!("BAR{:x} IO {{port: {:#X}}}", i, port); - assigned_addresses.extend(alloc::vec![(0x81000014 | addr), 0, port, 0, 0x100]); - } - Bar::Memory32 { address , size, prefetchable } => { - info!("BAR{:x} Memory32 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}", i, address, size, prefetchable); - assigned_addresses.extend(alloc::vec![(0x82000010 | addr), 0, address, 0, size]); - } - Bar::Memory64 { address , size, prefetchable } => { - info!("BAR{:x} Memory64 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}", i, address, size, prefetchable); - assigned_addresses.extend(alloc::vec![(0x82000010 | addr), (address >> 32) as u32, address as u32, (size >> 32) as u32, size as u32]); - } - } - } - } - fdt.property_array_u32("assigned-addresses", assigned_addresses.as_slice())?; - - fdt.end_node(net_node)?; - } - } - } + fdt = fdt.bootargs(cmdline)?; } - fdt.end_node(pci_node)?; - - fdt.end_node(root_node)?; + fdt = fdt.pci()?; let fdt = fdt.finish()?; diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index 9fe32f42..55ec2b13 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -8,11 +8,11 @@ cfg_if::cfg_if! { } } -mod devicetree; -mod pci; mod console; +mod devicetree; #[cfg(target_os = "none")] mod paging; +pub(crate) mod pci; #[cfg(target_os = "none")] mod physicalmem; diff --git a/src/arch/x86_64/multiboot.rs b/src/arch/x86_64/multiboot.rs index 3d975bc8..39f4758d 100644 --- a/src/arch/x86_64/multiboot.rs +++ b/src/arch/x86_64/multiboot.rs @@ -14,9 +14,9 @@ use x86_64::structures::paging::{PageSize, PageTableFlags, Size2MiB, Size4KiB}; use super::paging; use super::physicalmem::PhysAlloc; +use crate::arch::x86_64::devicetree::DeviceTree; use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT}; use crate::fdt::Fdt; -use crate::arch::x86_64::devicetree::DeviceTree; use crate::BootInfoExt; extern "C" { diff --git a/src/arch/x86_64/pci.rs b/src/arch/x86_64/pci.rs index b6c13ca7..e47f986f 100644 --- a/src/arch/x86_64/pci.rs +++ b/src/arch/x86_64/pci.rs @@ -23,7 +23,7 @@ impl ConfigRegionAccess for PciConfigRegion { fn function_exists(&self, _address: PciAddress) -> bool { true } - + #[inline] unsafe fn read(&self, pci_addr: PciAddress, register: u16) -> u32 { let address = PCI_CONFIG_ADDRESS_ENABLE diff --git a/src/fdt.rs b/src/fdt.rs index 320e8c14..4f939791 100644 --- a/src/fdt.rs +++ b/src/fdt.rs @@ -2,10 +2,14 @@ use alloc::format; use alloc::vec::Vec; use core::ops::Range; +use log::info; +use pci_types::{Bar, EndpointHeader, PciAddress, PciHeader, MAX_BARS}; use vm_fdt::{FdtWriter, FdtWriterNode, FdtWriterResult}; +use crate::arch::pci::{PciConfigRegion, PCI_MAX_BUS_NUMBER, PCI_MAX_DEVICE_NUMBER}; + pub struct Fdt<'a> { - writer: FdtWriter, + pub(crate) writer: FdtWriter, root_node: FdtWriterNode, bootargs: Option<&'a str>, } @@ -72,9 +76,16 @@ impl<'a> Fdt<'a> { #[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(feature = "fc")))] mod x86_64 { + use alloc::format; + use alloc::vec::Vec; + + use log::info; use multiboot::information::{MemoryMapIter, MemoryType}; + use pci_types::{Bar, EndpointHeader, PciAddress, PciHeader, MAX_BARS}; use vm_fdt::FdtWriterResult; + use crate::arch::pci::{PciConfigRegion, PCI_MAX_BUS_NUMBER, PCI_MAX_DEVICE_NUMBER}; + impl super::Fdt<'_> { pub fn memory_regions( mut self, @@ -92,6 +103,130 @@ mod x86_64 { Ok(self) } + + pub fn pci(mut self) -> FdtWriterResult { + let fdt = &mut self.writer; + + let pci_node = fdt.begin_node("pci")?; + fdt.property_string("device_type", "pci")?; + + // TODO: Address cells and size cells should be 3 and 2 respectively. + fdt.property_u32("#address-cells", 0x1)?; + fdt.property_u32("#size-cells", 0x1)?; + + info!("Scanning PCI Busses 0 to {}", PCI_MAX_BUS_NUMBER - 1); + + // Hermit only uses PCI for network devices. + // Therefore, multifunction devices as well as additional bridges are not scanned. + // We also limit scanning to the first 32 buses. + let pci_config = PciConfigRegion::new(); + for bus in 0..PCI_MAX_BUS_NUMBER { + for device in 0..PCI_MAX_DEVICE_NUMBER { + let pci_address = PciAddress::new(0, bus, device, 0); + let header = PciHeader::new(pci_address); + + let (vendor_id, device_id) = header.id(&pci_config); + if device_id != u16::MAX && vendor_id != u16::MAX { + let addr = + (pci_address.bus() as u32) << 16 | (pci_address.device() as u32) << 11; + info!("Addr: {:#x}", addr); + let endpoint = EndpointHeader::from_header(header, &pci_config).unwrap(); + let (_pin, line) = endpoint.interrupt(&pci_config); + + info!("Device ID: {:#x} Vendor ID: {:#x}", device_id, vendor_id); + + if vendor_id == 0x10ec && (0x8138..=0x8139).contains(&device_id) { + info!("Network card found."); + let net_node = + fdt.begin_node(format!("virtio_net@{:x}", addr).as_str())?; + + fdt.property_string("compatible", "realtek,rtl8139")?; + fdt.property_u32("vendor-id", vendor_id as u32)?; + fdt.property_u32("device-id", device_id as u32)?; + fdt.property_u32("interrupts", line as u32)?; + fdt.property_u32("pci-address", addr)?; + fdt.property_array_u32( + "reg", + &[ + addr, + 0, + 0, + 0, + 0, + (0x02000010 | addr), + 0, + 0, + 0, + 0x100, + (0x01000014 | addr), + 0, + 0, + 0, + 0x100, + ], + )?; + + let mut assigned_addresses: Vec = Vec::new(); + for i in 0..MAX_BARS { + if let Some(bar) = endpoint.bar(i.try_into().unwrap(), &pci_config) + { + match bar { + Bar::Io { port } => { + info!("BAR{:x} IO {{port: {:#X}}}", i, port); + assigned_addresses.extend(alloc::vec![ + (0x81000014 | addr), + 0, + port, + 0, + 0x100 + ]); + } + Bar::Memory32 { + address, + size, + prefetchable, + } => { + info!("BAR{:x} Memory32 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}", i, address, size, prefetchable); + assigned_addresses.extend(alloc::vec![ + (0x82000010 | addr), + 0, + address, + 0, + size + ]); + } + Bar::Memory64 { + address, + size, + prefetchable, + } => { + info!("BAR{:x} Memory64 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}", i, address, size, prefetchable); + assigned_addresses.extend(alloc::vec![ + (0x82000010 | addr), + (address >> 32) as u32, + address as u32, + (size >> 32) as u32, + size as u32 + ]); + } + } + } + } + fdt.property_array_u32( + "assigned-addresses", + assigned_addresses.as_slice(), + )?; + + fdt.end_node(net_node)?; + } + } + } + } + + fdt.end_node(pci_node)?; + + Ok(self) + } } }