Help!
Does anybody have experience setting up multiple NICs on QEMU?
I develop on a windows environment for Intel. I have a 64 bit kernel that scans the PCI slots and will detect whichever FIRST model I specify on the QEMU command line. If I specify a second NIC, it is always ignored.
Any example command lines for multiple NICs would be greatly appreciated!
(There are several examples, but they are complicated! Using vlans, TUNs, etc -- AND they dont' work for me either).
I am running QEMU on Windows 10, eg:
This correctly detects the 8139 card on the PCI bus.
qemu-system-x86_64.exe" C:\_dev\_pet\src\makescripts\..\bin\bootable.raw -cpu qemu64,+pdpe1gb -m 256M -net nic,model=rtl8139
This correctly detects the 8254 card on the PCI bus.
qemu-system-x86_64.exe" C:\_dev\_pet\src\makescripts\..\bin\bootable.raw -cpu qemu64,+pdpe1gb -m 256M -net nic
These only show the first card specified; the second card is ignored:
qemu-system-x86_64.exe" C:\_dev\_pet\src\makescripts\..\bin\bootable.raw -cpu qemu64,+pdpe1gb -m 256M -net nic -net nic,model=rtl8139
qemu-system-x86_64.exe" C:\_dev\_pet\src\makescripts\..\bin\bootable.raw -cpu qemu64,+pdpe1gb -m 256M -net nic,model=rtl8139 -net nic
I have tried versions 2.11.0 and 2.12 of QEMU and both behave the same way.
I have tried the newer syntax for specifying network cards -- same result.
The documentation is a little sketchy, so any and all help appreciated!
Unable to detect second PCI NIC on QEMU [resolved]
Unable to detect second PCI NIC on QEMU [resolved]
Last edited by 0b1 on Sat Jun 23, 2018 6:43 am, edited 1 time in total.
Code or code not. There is no try.
Re: Unable to detect second PCI NIC on QEMU
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...
(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.)
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: Select all
_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.)
Code or code not. There is no try.
Re: Unable to detect second PCI NIC on QEMU [resolved]
Assembly? Why? Besides, your code lacks support for multi-function devices. The logic is: Start at B:D:F 0, keep increasing the device part of that, but if you find a device with the MF bit set (bit 23 in register 3), you also query each function. Although you could just change your existing code to increase ECX by 0x100 if the MF bit is set, else by 0x800 (instead of using 0x800 always).
And while we're optimizing: It is probably safe to assume that the firmware already initialized all the PCI bridges, so from your perspective the bus numbers are just a block. Then it would be better not to query all the busses that don't exist, right? Therefore, start a variable "maxbus" at 0, and whenever you see a PCI bridge (class code 6), update maxbus to its subordinate bus if that is higher than maxbus. Then break out of the loop once all devices on maxbus are queried.
And your note regarding defensive programming only works if you practice what you preach. Right now, _pci64_scan does not save its registers before calling pci_read_register. That's just another reason to use C for this.
And while we're optimizing: It is probably safe to assume that the firmware already initialized all the PCI bridges, so from your perspective the bus numbers are just a block. Then it would be better not to query all the busses that don't exist, right? Therefore, start a variable "maxbus" at 0, and whenever you see a PCI bridge (class code 6), update maxbus to its subordinate bus if that is higher than maxbus. Then break out of the loop once all devices on maxbus are queried.
And your note regarding defensive programming only works if you practice what you preach. Right now, _pci64_scan does not save its registers before calling pci_read_register. That's just another reason to use C for this.
Carpe diem!