User Tools

Site Tools


pci_configuration_space

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
pci_configuration_space [2026/02/28 11:02] – msvoelkerpci_configuration_space [2026/02/28 16:47] (current) – [VirtIO: DeviceCfg] msvoelker
Line 16: Line 16:
 </code> </code>
  
-Hier betrachte ich den VirtIO Netwerkadapter genauer.+Hier betrachte ich den VirtIO Netzwerkadapter genauer.
  
 Mit dem Parameter v gibt pciconf die Namen zu den IDs der class, device, usw. aus. Mit dem Parameter v gibt pciconf die Namen zu den IDs der class, device, usw. aus.
Line 29: Line 29:
 </code> </code>
  
-Mit dem Parameter r kann pciconf den PCI Configuration Space direkt ausgeben. Der Parameter b gibt an, dass der Configuration Space Byteweise ausgelesen werden soll und 0x0:0x32 gibt den Bereich an, der ausgelesen werden soll.+===== Standardisierter Bereich =====
  
-<code> +In der einfachen Variante zeigt pciconf nur einen kleinen Teil der Informationen an, die im Configuration Space stehen. Pro PCI-Gerät ist der Configuration Space 256 Byte groß. Die ersten 64 Byte sind standardisiert über das folgende Format.
-% sudo pciconf -rb virtio_pci0@pci0:0:10:0 0x0:0x3f +
-f4 1a 00 10 17 00 10 00  00 00 00 02 00 00 00 00  +
-01 00 00 00 00 00 00 00  00 60 85 e1 00 00 00 00  +
-00 00 00 00 00 00 00 00  00 00 00 00 f4 1a 01 00  +
-00 00 00 00 40 00 00 00  00 00 00 00 ff 01 00 00  +
-</code> +
- +
-Der PCI Configuration Space enthält mehr, als pciconf bisher ausgegeben hat. Es nutzt das folgende Format.+
  
 <code> <code>
Line 77: Line 69:
    60 |Interrupt Line | Interrupt Pin |    Min Gnt.   |    Max Lat.   |    60 |Interrupt Line | Interrupt Pin |    Min Gnt.   |    Max Lat.   |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 +</code>
 +
 +Mit dem Parameter r kann pciconf den PCI Configuration Space direkt ausgeben. Der Parameter b dahinter gibt an, dass der Configuration Space Byteweise ausgelesen werden soll und 0x0:0x3f gibt den Bereich an, der ausgelesen werden soll (also die kompletten ersten 64 Byte).
 +
 +<code>
 +% sudo pciconf -rb virtio_pci0@pci0:0:10:0 0x0:0x3f
 +f4 1a 00 10 17 00 10 00  00 00 00 02 00 00 00 00 
 +01 00 00 00 00 00 00 00  00 60 85 e1 00 00 00 00 
 +00 00 00 00 00 00 00 00  00 00 00 00 f4 1a 01 00 
 +00 00 00 00 40 00 00 00  00 00 00 00 0c 01 00 00 
 </code> </code>
  
 Die Bytes sind in Little Endian. Die ersten zwei Bytes sind also 0x1af4, die die Vendor ID angeben. Die Bytes sind in Little Endian. Die ersten zwei Bytes sind also 0x1af4, die die Vendor ID angeben.
  
-Interessant sind die Base Address Registers (BARs), über die weitere Informationen zum PCI-Gerät angegeben werden können. Das erste Bit den Typ an. Es gibt Memory (0) und I/O (1). Hauptsächlich gibt ein BAR die Base Address an, das ist die Adresse unter der die BAR Region im Speicher befindet. 
  
-Bei dem PCI-Gerät gibt es zwei BARs. +===== Base Address Register (BAR) =====
  
-01 00 00 00 00 00 00 00  00 60 85 e1 00 00 00 00  +In einer Base Address Register (BAR) Region, kann das PCI-Gerät weitere Informationen schreiben und auch der Treiber kann darin schreiben, um z. B. Informationen zurück zu geben. Das BAR in dem standardisierten Bereich ist hauptsächlich die Base Address, das ist die Adresse unter der sich die BAR Region im Speicher befindet. Darin kodiert ist z. B. der Typ des BAR. Es gibt Memory (0) und I/O (1). 
-00 00 00 00 00 00 00 00+ 
 +Bei dem PCI-Gerät gibt es zwei BARs. Hier der Abschnitt vom Configuration Space zu den BARs. 
 + 
 +<code> 
 +| BAR 1     |            | BAR 2     | 
 + 01 00 00 00 00 00 00 00  00 60 85 e1 00 00 00 00  
 + 00 00 00 00 00 00 00 00 
 +</code> 
 + 
 +BAR 1 hat Typ 1 (I/O) und Base Address 0. BAR 2 hat Typ 0 (Memory) und Base Address 0xe1856000. Die BARs lassen sich mit pciconf über den Parameter b ausgeben.
  
 <code> <code>
Line 94: Line 104:
     bar   [18] = type Memory, range 32, base 0xe1856000, size 8192, enabled     bar   [18] = type Memory, range 32, base 0xe1856000, size 8192, enabled
 </code> </code>
 +
 +Die Zahl in eckigen Klammern gibt über ein Byte-Offset hexadezimal an, wo im Configuration Space der BAR angegeben ist.
 +
 +VirtIO nutzt im Legacy Modus den BAR vom Typ I/O und im Modern Modus den BAR vom Typ Memory. Das PCI-Gerät, was VirtualBox bereistellt ist ein Transitional Device. Das heißt, es unterstützt beide Modi. FreeBSD hat einen Treiber pro Modus (src/sys/dev/virtio/pci/virtio_pci_[legacy|modern].c). Es ruft jeweils die entsprechende device_probe Methode auf und trifft die Entscheidung anhand des Rückgabewertes. Hier betrachte ich den Modern Modus.
 +
 +Mit pciconf kann über den Parameter D eine BAR Region ausgelesen werden.
 +
 +<code>
 +% sudo pciconf -D pci0:0:10:0 0x18 | hexdump -C
 +00000000  01 00 00 00 01 00 00 00  01 00 00 00 01 00 00 00  |................|
 +00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 +00000020  00 90 fa 03 01 00 00 00  00 d0 fa 03 01 00 00 00  |................|
 +00000030  00 e0 fa 03 01 00 00 00  ff ff ff ff ff ff ff ff  |................|
 +00000040  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
 +*
 +00000060  ff ff ff ff ff ff ff ff  ff ff ff ff 00 00 00 00  |................|
 +00000070  08 00 27 54 00 00 00 00  01 00 00 00 ff ff ff ff  |..'T............|
 +00000080  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
 +*
 +00002000
 +</code>
 +
 +Im Modern Mode zeigen die PCI Capabilities auf, wo sich in der BAR Region welche Informationen finden.
 +
 +
 +===== Capabilities =====
 +
 +Zu einem PCI-Gerät können eine Reihe von Capabilities angegeben werden, die z. B. angeben können, in welchen BAR Regionen und wo darin weitere Informationen zu finden sind. Der Capabilities Pointer ist in dem PCI Configuration Space von oben auf 0x40 gesetzt. Das ist ein Pointer auf des erste Element in einer linked list von Capabilities. Die Capabilities lassen sich mit pciconf über den Parameter c ausgeben.
 +
 +<code>
 +% sudo pciconf -lc virtio_pci0@pci0:0:10:0
 +virtio_pci0@pci0:0:10:0: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1af4 device=0x1000 subvendor=0x1af4 subdevice=0x0001
 +    cap 09[40] = vendor (length 16)
 +    cap 09[50] = vendor (length 20)
 +    cap 09[64] = vendor (length 16)
 +    cap 09[74] = vendor (length 20)
 +    cap 09[88] = vendor (length 16)
 +</code>
 +
 +Der erste Wert nach cap gibt die Capability ID an. Der Wert in eckigen Klammern gibt über ein Byte-Offset hexadezimal an, wo im Configuration Space die Capability beschrieben steht. Die erste Capability ist also 0x40 = 64 Byte hinter dem Start des Configuration Space zu finden, also direkt hinter dem standardisierten Bereich. Die Bytes lassen sich ebenfalls mit pciconf -rb auslesen.
 +
 +<code>
 +% sudo pciconf -rb virtio_pci0@pci0:0:10:0 0x40:0x97
 +09 50 10 01 02 00 00 00  00 00 00 00 38 00 00 00 
 +09 64 14 02 02 00 00 00  38 00 00 00 32 00 00 00 
 +02 00 00 00 09 74 10 03  02 00 00 00 6c 00 00 00 
 +01 00 00 00 09 88 14 05  02 00 00 00 00 00 00 00 
 +04 00 00 00 00 00 00 00  09 00 10 04 02 00 00 00 
 +70 00 00 00 0a 00 00 00
 +</code>
 +
 +Das jeweils erste Byte gibt die Capability ID an und das zweite Byte den Offset zur nächsten Capability.
 +Eine bessere Ausgabe zu den Capabilities bietet lspci, was sich über
 +
 +<code>
 +% sudo pkg install pciutils
 +</code>
 +
 +installieren lässt. Hier die Ausgabe zu dem PCI-Gerät von lspci.
 +
 +<code>
 +% sudo lspci -vv
 +...
 +00:0a.0 Ethernet controller: Red Hat, Inc. Virtio network device
 + Subsystem: Red Hat, Inc. Device 0001
 + Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
 + Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
 + Latency: 0
 + Interrupt: pin A routed to IRQ 12
 + Region 0: I/O ports at 0000
 + Region 2: Memory at e1856000 (32-bit, non-prefetchable)
 + Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfg
 + BAR=2 offset=00000000 size=00000038
 + Capabilities: [50] Vendor Specific Information: VirtIO: Notify
 + BAR=2 offset=00000038 size=00000032 multiplier=00000002
 + Capabilities: [64] Vendor Specific Information: VirtIO: ISR
 + BAR=2 offset=0000006c size=00000001
 + Capabilities: [74] Vendor Specific Information: VirtIO: <unknown>
 + BAR=2 offset=00000000 size=00000004
 + Capabilities: [88] Vendor Specific Information: VirtIO: DeviceCfg
 + BAR=2 offset=00000070 size=0000000a
 +...
 +</code>
 +
 +Alle Capabilities sind also VirtIO spezifische Capabilities und die Informationen befinden sich in der Region vom BAR 2, also in der vom Typ memory (die im VirtIO Modern Modus benutzt wird). Das Offset gibt an ab welcher Byte Position die Informationen in der BAR Region sind und size wie viele Bytes die Informationen umfassen.
 +
 +==== VirtIO: CommonCfg ====
 +
 +Die erste Capability vom Typ VirtIO: CommonCfg enthält VirtIO-Gerätunabhängige Einstellungen. Sie startet in der BAR Region bei Byte 0 und ist 0x38 Byte groß. Es handelt sich um den Bereich vor den ganzen 0xffff, also
 +
 +<code>
 +00000000  01 00 00 00 01 00 00 00  01 00 00 00 01 00 00 00
 +00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
 +00000020  00 90 fa 03 01 00 00 00  00 d0 fa 03 01 00 00 00
 +00000030  00 e0 fa 03 01 00 00 00
 +</code>
 +
 +Beschrieben ist das Format in der VirtIO Spezifikation im Abschnitt [[https://docs.oasis-open.org/virtio/virtio/v1.4/virtio-v1.4.html#x1-1750004|4.1.4.3 Common configuration structure layout]] mit
 +
 +<code>
 +struct virtio_pci_common_cfg { 
 +        /* About the whole device. */ 
 +        le32 device_feature_select;     /* read-write */ 
 +        le32 device_feature;            /* read-only for driver */ 
 +        le32 driver_feature_select;     /* read-write */ 
 +        le32 driver_feature;            /* read-write */ 
 +        le16 config_msix_vector;        /* read-write */ 
 +        le16 num_queues;                /* read-only for driver */ 
 +        u8 device_status;               /* read-write */ 
 +        u8 config_generation;           /* read-only for driver */ 
 + 
 +        /* About a specific virtqueue. */ 
 +        le16 queue_select;              /* read-write */ 
 +        le16 queue_size;                /* read-write */ 
 +        le16 queue_msix_vector;         /* read-write */ 
 +        le16 queue_enable;              /* read-write */ 
 +        le16 queue_notify_off;          /* read-only for driver */ 
 +        le64 queue_desc;                /* read-write */ 
 +        le64 queue_driver;              /* read-write */ 
 +        le64 queue_device;              /* read-write */ 
 +        le16 queue_notif_config_data;   /* read-only for driver */ 
 +        le16 queue_reset;               /* read-write */ 
 + 
 +        /* About the administration virtqueue. */ 
 +        le16 admin_queue_index;         /* read-only for driver */ 
 +        le16 admin_queue_num;         /* read-only for driver */ 
 +};
 +</code>
 +
 +Das VirtualBox PCI-Gerät gibt darüber also z. B. an, welche Features es unterstützt. Für die Features gibt es insgesamt 64 Bit. In device_feature_select wird geschrieben, ob device_feature die unteren 32 Bit (0) oder die oberen 32 Bit (1) anzeigt. In der Ausgabe oben ist in Little Endian gelesen device_feature_select=1, somit gibt das device_feature mit 1 die oberen oberen 32 Bit an. Auf die gleiche Weise schreibt der FreeBSD Treiber die Features, die es davon unterstützt und nutzen möchte in driver_feature_select und driver_feature. Auch hier ist in der Ausgabe oben in Little Endian gelesen driver_feature_select=1, somit gibt das driver_feature mit 1 die oberen oberen 32 Bit an.
 +
 +Mit device_feature_select=0 und driver_feature_select=0 sieht die erste Zeile der Ausgabe so aus.
 +
 +<code>
 +00000000  00 00 00 00 dd a3 00 2f  00 00 00 00 23 98 0f 00
 +</code>
 +
 +In Little Endian gelesen sind device_feature=0x1002fdda3, d. h. das PCI-Gerät unterstützt die folgenden Features
 +
 +Version1,GuestAnnounce,CtrlVLANFilter,CtrlRxMode,CtrlVq,Status,MrgRxBuf,TxUFO,TxTSOv6,TxTSOv4,RxUFO,RxLROv6,RxLROv4,MAC,RxChecksum,TxChecksum
 +
 +und driver_feature=0x1000f9823, d. h. ausgehandelt wurden die folgenden Features
 +
 +Version1,CtrlVLANFilter,CtrlRxMode,CtrlVq,Status,MrgRxBuf,TxTSOv6,TxTSOv4,MAC,RxChecksum,TxChecksum
 +
 +==== VirtIO: DeviceCfg ====
 +
 +Die Capability VirtIO: DeviceCfg gibt VirtIO-Gerätspezifische Einstellungen an. In der BAR Region startet sie bei Byte-Offset 0x70 und ist 0xa = 10 Byte lang, was diesem Abschnitt entspricht:
 +
 +<code>
 +00000070  08 00 27 54 00 00 00 00  01 00
 +</code>
 +
 +Beschrieben ist das Format in der VirtIO Spezifikation im Abschnitt [[https://docs.oasis-open.org/virtio/virtio/v1.4/virtio-v1.4.html#x1-2760004|5.1.4 Device configuration layout]] mit:
 +
 +<code>
 +struct virtio_net_config { 
 +        u8 mac[6]; 
 +        le16 status; 
 +        le16 max_virtqueue_pairs; 
 +        le16 mtu; 
 +        le32 speed; 
 +        u8 duplex; 
 +        u8 rss_max_key_size; 
 +        le16 rss_max_indirection_table_length; 
 +        le32 supported_hash_types; 
 +        le32 supported_tunnel_types; 
 +};
 +</code>
 +
 +Es sind jedoch nicht immer alle Werte angegeben. Welche Werte angegeben sind, hängt von den ausgehandelten Features ab. Hier sind lediglich die MAC-Adresse=08:00:27:54:00:00, der Status=0 und max_virtqueue_pairs=1 angegeben. Die MTU fehlt z. B., weil das Feature VIRTIO_NET_F_MTU nicht ausgehandelt wurde.
pci_configuration_space.1772276572.txt.gz · Last modified: by msvoelker