@@ -46,7 +46,39 @@ static void virtio_pci_write_guest_feature(struct virtio_pci_dev *dev)
4646
4747static void virtio_pci_reset (struct virtio_pci_dev * dev )
4848{
49- /* TODO: virtio pci reset */
49+ /* Virtio 1.x §2.4: writing 0 to device_status resets the device to its
50+ * initial post-power-on state. We clear the negotiated bits the guest
51+ * is about to re-write: acked features, ISR, the per-virtq packed-ring
52+ * indices, and the common-cfg selector bytes. This is sufficient for a
53+ * driver re-probe (reload, kexec) where the guest hasn't yet enabled
54+ * any virtqueue.
55+ *
56+ * We deliberately leave info.enable, desc_ring, and the device/driver
57+ * event pointers alone, because the device-emulator workers in
58+ * virtio-blk / virtio-net poll those without locking. A full reset that
59+ * tears down enabled queues would have to write the per-device stopfd
60+ * and pthread_join the workers, which the generic virtio-pci layer has
61+ * no handle on — leaving that for a follow-up that adds a
62+ * virtio_pci_ops::reset hook.
63+ */
64+ dev -> guest_feature = 0 ;
65+ dev -> config .common_cfg .device_feature_select = 0 ;
66+ dev -> config .common_cfg .guest_feature_select = 0 ;
67+ dev -> config .common_cfg .guest_feature = 0 ;
68+ dev -> config .common_cfg .queue_select = 0 ;
69+ __atomic_store_n (& dev -> config .isr_cap .isr_status , 0 , __ATOMIC_RELEASE );
70+
71+ for (uint16_t i = 0 ; i < dev -> num_queues ; i ++ ) {
72+ struct virtq * vq = & dev -> vq [i ];
73+ if (vq -> info .enable )
74+ continue ;
75+ vq -> info .size = VIRTQ_SIZE ;
76+ vq -> info .desc_addr = 0 ;
77+ vq -> info .device_addr = 0 ;
78+ vq -> info .driver_addr = 0 ;
79+ vq -> next_avail_idx = 0 ;
80+ vq -> used_wrap_count = 1 ;
81+ }
5082}
5183
5284static void virtio_pci_write_status (struct virtio_pci_dev * dev )
@@ -62,7 +94,7 @@ static void virtio_pci_select_virtq(struct virtio_pci_dev *dev)
6294 uint16_t select = dev -> config .common_cfg .queue_select ;
6395 struct virtio_pci_common_cfg * config = & dev -> config .common_cfg ;
6496
65- if (select < config -> num_queues ) {
97+ if (select < dev -> num_queues ) {
6698 uint64_t offset = offsetof(struct virtio_pci_common_cfg , queue_size );
6799 memcpy ((void * ) ((uintptr_t ) config + offset ), & dev -> vq [select ].info ,
68100 sizeof (struct virtq_info ));
@@ -114,7 +146,7 @@ static void virtio_pci_space_write(struct virtio_pci_dev *dev,
114146 offset <= VIRTIO_PCI_COMMON_Q_USEDHI ) {
115147 uint16_t select = dev -> config .common_cfg .queue_select ;
116148 uint64_t info_offset = offset - VIRTIO_PCI_COMMON_Q_SIZE ;
117- if (select < dev -> config . common_cfg . num_queues ) {
149+ if (select < dev -> num_queues ) {
118150 memcpy ((void * ) ((uintptr_t ) & dev -> vq [select ].info +
119151 info_offset ),
120152 data , size );
@@ -251,6 +283,7 @@ void virtio_pci_set_virtq(struct virtio_pci_dev *dev,
251283 struct virtq * vq ,
252284 uint16_t num_queues )
253285{
286+ dev -> num_queues = num_queues ;
254287 dev -> config .common_cfg .num_queues = num_queues ;
255288 dev -> vq = vq ;
256289}
0 commit comments