@@ -72,9 +72,16 @@ impl<'a> Fdt<'a> {
72
72
73
73
#[ cfg( all( target_arch = "x86_64" , not( target_os = "uefi" ) , not( feature = "fc" ) ) ) ]
74
74
mod x86_64 {
75
+ use alloc:: format;
76
+ use alloc:: vec:: Vec ;
77
+
78
+ use log:: info;
75
79
use multiboot:: information:: { MemoryMapIter , MemoryType } ;
80
+ use pci_types:: { Bar , EndpointHeader , PciAddress , PciHeader , MAX_BARS } ;
76
81
use vm_fdt:: FdtWriterResult ;
77
82
83
+ use crate :: arch:: pci:: { PciConfigRegion , PCI_MAX_BUS_NUMBER , PCI_MAX_DEVICE_NUMBER } ;
84
+
78
85
impl super :: Fdt < ' _ > {
79
86
pub fn memory_regions (
80
87
mut self ,
@@ -92,6 +99,132 @@ mod x86_64 {
92
99
93
100
Ok ( self )
94
101
}
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
+ }
95
228
}
96
229
}
97
230
0 commit comments