@@ -144,40 +144,76 @@ ACPI_MCFG_ALLOCATION *mcfg_entries[PCI_MCFG_MAX_ENTRIES_LEN];
144144uint64_t mcfg_entries_len = 0 ;
145145pci_device_t * pci_devices [PCI_DEVICE_MAX ];
146146uint32_t pci_device_number = 0 ;
147+ static bool pci_use_mcfg = false;
148+ static uint64_t mcfg_virt_bases [PCI_MCFG_MAX_ENTRIES_LEN ];
149+
150+ #if defined(__x86_64__ ) || defined(__amd64__ )
151+ uint32_t pci_read0 (uint32_t b , uint32_t d , uint32_t f , uint32_t arg , uint32_t registeroffset );
152+ void pci_write0 (uint32_t b , uint32_t d , uint32_t f , uint32_t arg , uint32_t registeroffset ,
153+ uint32_t value );
154+ #endif
147155
148156void mcfg_addr_to_entries (ACPI_TABLE_MCFG * mcfg , ACPI_MCFG_ALLOCATION * * entries , uint64_t * num ) {
149157 ACPI_MCFG_ALLOCATION * entry =
150158 (ACPI_MCFG_ALLOCATION * )((uint64_t )mcfg + sizeof (ACPI_TABLE_MCFG ));
151159 int length = mcfg -> Header .Length - sizeof (ACPI_TABLE_MCFG );
152- * num = length / sizeof (ACPI_MCFG_ALLOCATION );
160+ if (length < 0 ) {
161+ * num = 0 ;
162+ return ;
163+ }
164+ * num = (uint64_t )length / sizeof (ACPI_MCFG_ALLOCATION );
165+ if (* num > PCI_MCFG_MAX_ENTRIES_LEN ) {
166+ * num = PCI_MCFG_MAX_ENTRIES_LEN ;
167+ }
153168 for (uint64_t i = 0 ; i < * num ; i ++ ) {
154169 entries [i ] = entry + i ;
155170 }
156171}
157172
158- uint64_t get_device_mmio_physical_address (uint16_t segment_group , uint8_t bus , uint8_t device ,
159- uint8_t function ) {
173+ static bool mcfg_find_entry (uint16_t segment_group , uint8_t bus , uint64_t * index_out ) {
160174 for (uint64_t i = 0 ; i < mcfg_entries_len ; i ++ ) {
161- if (mcfg_entries [i ]-> PciSegment == segment_group ) {
162- return mcfg_entries [i ]-> Address +
163- ((( uint64_t ) bus - ( uint64_t ) mcfg_entries [i ]-> StartBusNumber ) << 20 ) +
164- (( uint64_t ) device << 15 ) + (( uint64_t ) function << 12 ) ;
175+ if (mcfg_entries [i ]-> PciSegment != segment_group ) { continue ; }
176+ if ( mcfg_entries [i ]-> Address == 0 ) { continue ; }
177+ if ( bus < mcfg_entries [ i ] -> StartBusNumber || bus > mcfg_entries [i ]-> EndBusNumber ) {
178+ continue ;
165179 }
180+ if (index_out ) { * index_out = i ; }
181+ return true;
166182 }
167- return 0 ;
183+ return false;
184+ }
185+
186+ uint64_t get_device_mmio_physical_address (uint16_t segment_group , uint8_t bus , uint8_t device ,
187+ uint8_t function ) {
188+ uint64_t idx ;
189+ if (!mcfg_find_entry (segment_group , bus , & idx )) { return 0 ; }
190+ return mcfg_entries [idx ]-> Address +
191+ (((uint64_t )bus - (uint64_t )mcfg_entries [idx ]-> StartBusNumber ) << 20 ) +
192+ ((uint64_t )device << 15 ) + ((uint64_t )function << 12 );
168193}
169194
170195uint64_t get_mmio_address (uint32_t pci_address , uint16_t offset ) {
196+ if (!pci_use_mcfg ) { return 0 ; }
197+
171198 uint16_t segment = (pci_address >> 16 ) & 0xFFFF ;
172199 uint8_t bus = (pci_address >> 8 ) & 0xFF ;
173200 uint8_t device = (pci_address >> 3 ) & 0x1F ;
174201 uint8_t function = pci_address & 0x07 ;
175202
176- uint64_t phys = get_device_mmio_physical_address (segment , bus , device , function );
177- if (phys == 0 ) { return 0 ; }
203+ uint64_t idx ;
204+ if (!mcfg_find_entry (segment , bus , & idx )) { return 0 ; }
205+
206+ uint64_t bus_off =
207+ (((uint64_t )bus - (uint64_t )mcfg_entries [idx ]-> StartBusNumber ) << 20 ) +
208+ ((uint64_t )device << 15 ) + ((uint64_t )function << 12 );
209+
210+ if (mcfg_virt_bases [idx ] != 0 ) {
211+ return mcfg_virt_bases [idx ] + bus_off + offset ;
212+ }
213+
214+ uint64_t phys = mcfg_entries [idx ]-> Address + bus_off ;
178215 uint64_t virt = (uint64_t )phys_to_virt (phys );
179216 page_map_range (get_kernel_pagedir (), virt , phys , PAGE_SIZE * 4 , KERNEL_PTE_FLAGS );
180-
181217 return virt + offset ;
182218}
183219
@@ -190,14 +226,25 @@ uint32_t segment_bus_device_functon_to_pci_address(uint16_t segment, uint8_t bus
190226uint32_t pci_read (uint32_t b , uint32_t d , uint32_t f , uint32_t s , uint32_t offset ) {
191227 uint32_t pci_address = segment_bus_device_functon_to_pci_address (s , b , d , f );
192228 uint64_t mmio_address = get_mmio_address (pci_address , offset );
193- if (mmio_address == 0 ) { printk ("Cannot read pci: failed to get mmio address\n" ); }
229+ if (mmio_address == 0 ) {
230+ #if defined(__x86_64__ ) || defined(__amd64__ )
231+ return pci_read0 (b , d , f , s , offset );
232+ #else
233+ return 0xFFFFFFFFU ;
234+ #endif
235+ }
194236 return * (volatile uint32_t * )mmio_address ;
195237}
196238
197239void pci_write (uint32_t b , uint32_t d , uint32_t f , uint32_t s , uint32_t offset , uint32_t value ) {
198240 uint32_t pci_address = segment_bus_device_functon_to_pci_address (s , b , d , f );
199241 uint64_t mmio_address = get_mmio_address (pci_address , offset );
200- if (mmio_address == 0 ) { printk ("Cannot write pci: failed to get mmio address\n" ); }
242+ if (mmio_address == 0 ) {
243+ #if defined(__x86_64__ ) || defined(__amd64__ )
244+ pci_write0 (b , d , f , s , offset , value );
245+ #endif
246+ return ;
247+ }
201248 * (volatile uint32_t * )mmio_address = value ;
202249}
203250
@@ -279,22 +326,19 @@ pci_device_t *pci_find_bdfs(uint8_t bus, uint8_t slot, uint8_t func, uint16_t se
279326}
280327
281328void pci_scan_function (uint16_t segment_group , uint8_t bus , uint8_t device , uint8_t function ) {
282- uint32_t pci_address =
283- segment_bus_device_functon_to_pci_address (segment_group , bus , device , function );
284-
285- uint64_t id_mmio_addr = get_mmio_address (pci_address , 0x00 );
286- uint16_t vendor_id = * (volatile uint16_t * )id_mmio_addr ;
329+ uint32_t id_value = pci_read (bus , device , function , segment_group , 0x00 );
330+ uint16_t vendor_id = (uint16_t )(id_value & 0xFFFF );
287331 if (vendor_id == 0xFFFF ) { return ; }
288- uint16_t device_id = * ( volatile uint16_t * )( id_mmio_addr + 2 );
332+ uint16_t device_id = ( uint16_t )( id_value >> 16 );
289333
290- uint64_t field_mmio_addr = get_mmio_address ( pci_address , PCI_CONF_REVISION );
291- uint8_t device_revision = EXPORT_BYTE ( * ( volatile uint8_t * ) field_mmio_addr , true );
292- uint8_t device_class = * (( uint8_t * ) field_mmio_addr + 3 );
293- uint8_t device_subclass = * (( uint8_t * ) field_mmio_addr + 2 );
294- uint8_t device_interface = * (( uint8_t * ) field_mmio_addr + 1 );
334+ uint32_t class_reg = pci_read ( bus , device , function , segment_group , PCI_CONF_REVISION );
335+ uint8_t device_revision = ( uint8_t )( class_reg & 0xFF );
336+ uint8_t device_interface = ( uint8_t )(( class_reg >> 8 ) & 0xFF );
337+ uint8_t device_subclass = ( uint8_t )(( class_reg >> 16 ) & 0xFF );
338+ uint8_t device_class = ( uint8_t )(( class_reg >> 24 ) & 0xFF );
295339
296- uint64_t header_type_mmio_addr = get_mmio_address ( pci_address , 0x0c );
297- uint8_t header_type = (* (( uint8_t * ) header_type_mmio_addr + 2 )) & 0x7F ;
340+ uint32_t header_reg = pci_read ( bus , device , function , segment_group , 0x0c );
341+ uint8_t header_type = (uint8_t )(( header_reg >> 16 ) & 0x7F ) ;
298342
299343 pci_device_t * pci_device = (pci_device_t * )malloc (sizeof (pci_device_t ));
300344 memset (pci_device , 0 , sizeof (pci_device_t ));
@@ -462,9 +506,8 @@ void pci_scan_function(uint16_t segment_group, uint8_t bus, uint8_t device, uint
462506void pci_scan_bus (uint16_t segment_group , uint8_t bus ) {
463507 for (int i = 0 ; i < 32 ; i ++ ) {
464508 pci_scan_function (segment_group , bus , i , 0 );
465- uint32_t pci_address = segment_bus_device_functon_to_pci_address (segment_group , bus , i , 0 );
466- uint64_t mmio_addr = get_mmio_address (pci_address , 0x0c );
467- if (* (volatile uint32_t * )mmio_addr & (1UL << 23 )) {
509+ uint32_t header_reg = pci_read (bus , i , 0 , segment_group , 0x0c );
510+ if (header_reg != 0xFFFFFFFF && (header_reg & (1UL << 23 ))) {
468511 for (int j = 1 ; j < 8 ; j ++ ) {
469512 pci_scan_function (segment_group , bus , i , j );
470513 }
@@ -474,9 +517,8 @@ void pci_scan_bus(uint16_t segment_group, uint8_t bus) {
474517
475518void pci_scan_segment (uint16_t segment_group ) {
476519 pci_scan_bus (segment_group , 0 );
477- uint32_t pci_address = segment_bus_device_functon_to_pci_address (segment_group , 0 , 0 , 0 );
478- uint64_t mmio_addr = get_mmio_address (pci_address , 0x0c );
479- if (* (volatile uint32_t * )mmio_addr & (1UL << 23 )) {
520+ uint32_t header_reg = pci_read (0 , 0 , 0 , segment_group , 0x0c );
521+ if (header_reg != 0xFFFFFFFF && (header_reg & (1UL << 23 ))) {
480522 for (int i = 1 ; i < 8 ; i ++ ) {
481523 pci_scan_bus (segment_group , i );
482524 }
@@ -486,17 +528,50 @@ void pci_scan_segment(uint16_t segment_group) {
486528void pci_init () {
487529 ACPI_TABLE_MCFG * mcfg = NULL ;
488530 ACPI_STATUS status = AcpiGetTable (ACPI_SIG_MCFG , 1 , (ACPI_TABLE_HEADER * * )& mcfg );
489-
490531 if (ACPI_FAILURE (status )) {
491532 kwarn ("MCFG table not found (System switch to Legacy PCI model)." );
492533 arch_pci_legacy_enum ();
493534 return ;
494535 }
495536
496537 mcfg_addr_to_entries (mcfg , mcfg_entries , & mcfg_entries_len );
538+ pci_use_mcfg = (mcfg_entries_len != 0 );
539+ if (!pci_use_mcfg ) {
540+ kwarn ("MCFG table invalid or empty (System switch to Legacy PCI model)." );
541+ arch_pci_legacy_enum ();
542+ return ;
543+ }
544+
545+ bool has_valid_entry = false;
546+ for (uint64_t i = 0 ; i < mcfg_entries_len ; i ++ ) {
547+ if (mcfg_entries [i ]-> Address == 0 ) { continue ; }
548+ if (mcfg_entries [i ]-> EndBusNumber < mcfg_entries [i ]-> StartBusNumber ) { continue ; }
549+ has_valid_entry = true;
550+ break ;
551+ }
552+
553+ if (!has_valid_entry ) {
554+ kwarn ("MCFG entries invalid (System switch to Legacy PCI model)." );
555+ pci_use_mcfg = false;
556+ arch_pci_legacy_enum ();
557+ return ;
558+ }
497559
498560 for (uint64_t i = 0 ; i < mcfg_entries_len ; i ++ ) {
499561 uint16_t segment_group = mcfg_entries [i ]-> PciSegment ;
500- pci_scan_segment (segment_group );
562+ uint8_t start_bus = mcfg_entries [i ]-> StartBusNumber ;
563+ uint8_t end_bus = mcfg_entries [i ]-> EndBusNumber ;
564+ if (mcfg_entries [i ]-> Address == 0 ) { continue ; }
565+ if (end_bus < start_bus ) { continue ; }
566+ uint64_t size = ((uint64_t )(end_bus - start_bus + 1 )) << 20 ;
567+ uint64_t virt = (uint64_t )phys_to_virt (mcfg_entries [i ]-> Address );
568+ page_map_range (get_kernel_pagedir (), virt , mcfg_entries [i ]-> Address , size ,
569+ KERNEL_PTE_FLAGS );
570+ mcfg_virt_bases [i ] = virt ;
571+ kinfo ("MCFG map: seg=%u bus=%u-%u phys=%#llx virt=%#llx size=%#llx" ,
572+ segment_group , start_bus , end_bus , mcfg_entries [i ]-> Address , virt , size );
573+ for (uint16_t bus = start_bus ; bus <= end_bus ; bus ++ ) {
574+ pci_scan_bus (segment_group , (uint8_t )bus );
575+ }
501576 }
502577}
0 commit comments