Update --
It turned out my PCI scan ended one device earlier than the second NIC's location.
Because my OS maxmizes use of registers over the stack, this led me to come up with a simplified PCI scan...
Code:
_pci64_scan:
;scans the PCI buses for devices and places the found bus/dev_slot/class_subclass into the PCI Map.
;inputs: none
;outputs: none
;scan can be simplified so that bus + dev are on the same 32 bit register using the mask below
; E000 0000 BBBB BBBB DDDD DFFF rrrr rr00 e=Enable Bit
; 1000 0000 0000 0000 0000 0000 0000 0000 0x80000000 <== first bus:device:function #
; 1000 0000 1111 1111 1111 1000 0000 0000 0x80FFF800 <== last bus:device:function #
; assumes function 0 on each b:d.
MOV RDI, PCI_MAP_ADDR
MOV ECX, 0x80000000 ;starting B:D:F, shifted
.loop_next_device:
MOV EAX, ECX
OR EAX, PCI_REGISTER_CLASS << 2 ;insert register to be queried
CALL pci_read_register
SHR EAX, 16 ;Move the retrieved Class/Subclass code to AX
CMP AX, 0xFFFF
JE .not_a_device
MOV [RDI + pci_map_entry.class_sub], AX
MOV [RDI + pci_map_entry.location], ECX ;Store location word as-is. Saves bit shifting when reused
MOV EAX, ECX
OR EAX, PCI_REGISTER_DEVICEID << 2
CALL pci_read_register
MOV [RDI + pci_map_entry.device_id], EAX
ADD RDI, pci_map_entry_size
CMP RDI, PCI_MAP_ADDR + (pci_map_entry_size * MAX_MAP_ENTRIES)
JNL .loop_next_device_done ;maximum map size reached, exit the loop
.not_a_device:
ADD ECX, 0x800 ;next B:D:F
CMP ECX, 0x80FFF800 ;final B:D:F
JNG .loop_next_device
.loop_next_device_done:
RET
_pci64_scan_done:
pci_read_register:
;inputs:
; EAX: BUS/DEVICE/SLOT/REGISTER
;outputs:
; EAX: register contents
; trashes:
; DX
MOV DX, PCI_CONFIG_ADDRESS
OUT DX, EAX
MOV DX, PCI_CONFIG_DATA
IN EAX, DX
RET
pci_read_register_done:
(iaw Defensive programming practice, called routines in my implementation do not save and restore registers. The calling code holds the responsibility for saving any registers it needs saved.)