@@ -72,9 +72,16 @@ impl<'a> Fdt<'a> {
7272
7373#[ cfg( all( target_arch = "x86_64" , not( target_os = "uefi" ) , not( feature = "fc" ) ) ) ]
7474mod x86_64 {
75+ use alloc:: format;
76+ use alloc:: vec:: Vec ;
77+
78+ use log:: info;
7579 use multiboot:: information:: { MemoryMapIter , MemoryType } ;
80+ use pci_types:: { Bar , EndpointHeader , PciAddress , PciHeader , MAX_BARS } ;
7681 use vm_fdt:: FdtWriterResult ;
7782
83+ use crate :: arch:: pci:: { PciConfigRegion , PCI_MAX_BUS_NUMBER , PCI_MAX_DEVICE_NUMBER } ;
84+
7885 impl super :: Fdt < ' _ > {
7986 pub fn memory_regions (
8087 mut self ,
@@ -92,6 +99,132 @@ mod x86_64 {
9299
93100 Ok ( self )
94101 }
102+
103+ pub fn pci ( mut self ) -> FdtWriterResult < Self > {
104+ let fdt = & mut self . writer ;
105+
106+ let pci_node = fdt. begin_node ( "pci" ) ?;
107+ fdt. property_string ( "device_type" , "pci" ) ?;
108+
109+ // TODO: Address cells and size cells should be 3 and 2 respectively. 1 and 1 are only used for compatibility with devicetree output tool.
110+ fdt. property_u32 ( "#address-cells" , 0x1 ) ?;
111+ fdt. property_u32 ( "#size-cells" , 0x1 ) ?;
112+
113+ info ! ( "Scanning PCI Busses 0 to {}" , PCI_MAX_BUS_NUMBER - 1 ) ;
114+
115+ // Hermit only uses PCI for network devices.
116+ // Therefore, multifunction devices as well as additional bridges are not scanned.
117+ // We also limit scanning to the first 32 buses.
118+ let pci_config = PciConfigRegion :: new ( ) ;
119+ for bus in 0 ..PCI_MAX_BUS_NUMBER {
120+ for device in 0 ..PCI_MAX_DEVICE_NUMBER {
121+ let pci_address = PciAddress :: new ( 0 , bus, device, 0 ) ;
122+ let header = PciHeader :: new ( pci_address) ;
123+
124+ let ( vendor_id, device_id) = header. id ( & pci_config) ;
125+ if device_id != u16:: MAX && vendor_id != u16:: MAX {
126+ let addr = ( ( pci_address. bus ( ) as u32 ) << 16 )
127+ | ( ( pci_address. device ( ) as u32 ) << 11 ) ;
128+ info ! ( "Addr: {:#x}" , addr) ;
129+ let endpoint = EndpointHeader :: from_header ( header, & pci_config) . unwrap ( ) ;
130+ let ( _pin, line) = endpoint. interrupt ( & pci_config) ;
131+
132+ info ! ( "Device ID: {:#x} Vendor ID: {:#x}" , device_id, vendor_id) ;
133+
134+ if vendor_id == 0x10ec && ( 0x8138 ..=0x8139 ) . contains ( & device_id) {
135+ info ! ( "Network card found." ) ;
136+ let net_node =
137+ fdt. begin_node ( format ! ( "ethernet@{:x}" , addr) . as_str ( ) ) ?;
138+
139+ fdt. property_string ( "compatible" , "realtek,rtl8139" ) ?;
140+ fdt. property_u32 ( "vendor-id" , vendor_id as u32 ) ?;
141+ fdt. property_u32 ( "device-id" , device_id as u32 ) ?;
142+ fdt. property_u32 ( "interrupts" , line as u32 ) ?;
143+
144+ // The creation of "reg" and "assigned-addresses" properties is based on the
145+ // PCI Bus Binding to IEEE Std 1275-1994 Revision 2.1 (https://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf)
146+ fdt. property_array_u32 (
147+ "reg" ,
148+ & [
149+ addr,
150+ 0 ,
151+ 0 ,
152+ 0 ,
153+ 0 ,
154+ ( 0x02000010 | addr) ,
155+ 0 ,
156+ 0 ,
157+ 0 ,
158+ 0x100 ,
159+ ( 0x01000014 | addr) ,
160+ 0 ,
161+ 0 ,
162+ 0 ,
163+ 0x100 ,
164+ ] ,
165+ ) ?;
166+
167+ let mut assigned_addresses: Vec < u32 > = Vec :: new ( ) ;
168+ for i in 0 ..MAX_BARS {
169+ if let Some ( bar) = endpoint. bar ( i. try_into ( ) . unwrap ( ) , & pci_config)
170+ {
171+ match bar {
172+ Bar :: Io { port } => {
173+ info ! ( "BAR{:x} IO {{port: {:#X}}}" , i, port) ;
174+ assigned_addresses. extend ( alloc:: vec![
175+ ( 0x81000014 | addr) ,
176+ 0 ,
177+ port,
178+ 0 ,
179+ 0x100
180+ ] ) ;
181+ }
182+ Bar :: Memory32 {
183+ address,
184+ size,
185+ prefetchable,
186+ } => {
187+ info ! ( "BAR{:x} Memory32 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}" , i, address, size, prefetchable) ;
188+ assigned_addresses. extend ( alloc:: vec![
189+ ( 0x82000010 | addr) ,
190+ 0 ,
191+ address,
192+ 0 ,
193+ size
194+ ] ) ;
195+ }
196+ Bar :: Memory64 {
197+ address,
198+ size,
199+ prefetchable,
200+ } => {
201+ info ! ( "BAR{:x} Memory64 {{address: {:#X}, size {:#X}, prefetchable: {:?}}}" , i, address, size, prefetchable) ;
202+ assigned_addresses. extend ( alloc:: vec![
203+ ( 0x82000010 | addr) ,
204+ ( address >> 32 ) as u32 ,
205+ address as u32 ,
206+ ( size >> 32 ) as u32 ,
207+ size as u32
208+ ] ) ;
209+ }
210+ }
211+ }
212+ }
213+ fdt. property_array_u32 (
214+ "assigned-addresses" ,
215+ assigned_addresses. as_slice ( ) ,
216+ ) ?;
217+
218+ fdt. end_node ( net_node) ?;
219+ }
220+ }
221+ }
222+ }
223+
224+ fdt. end_node ( pci_node) ?;
225+
226+ Ok ( self )
227+ }
95228 }
96229}
97230
0 commit comments