uhci: fix segfault when hot-unplugging uhci controller
When hot-unplugging the usb controllers (ehci/uhci), we have to clean all resouce of these devices, involved registered reset handler. Otherwise, it may cause NULL pointer access and/or segmentation fault if we reboot the guest os after hot-unplugging. Let's hook up reset via DeviceClass->reset() and drop the qemu_register_reset() call. Then Qemu will register and unregister the reset handler automatically. Cc: qemu-stable <qemu-stable@nongnu.org> Reported-by: Lidonglin <lidonglin@huawei.com> Signed-off-by: Gonglei <arei.gonglei@huawei.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
		
							parent
							
								
									8ffd9f4dd4
								
							
						
					
					
						commit
						537e572a7f
					
				@ -348,9 +348,10 @@ static void uhci_update_irq(UHCIState *s)
 | 
				
			|||||||
    pci_set_irq(&s->dev, level);
 | 
					    pci_set_irq(&s->dev, level);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void uhci_reset(void *opaque)
 | 
					static void uhci_reset(DeviceState *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    UHCIState *s = opaque;
 | 
					    PCIDevice *d = PCI_DEVICE(dev);
 | 
				
			||||||
 | 
					    UHCIState *s = DO_UPCAST(UHCIState, dev, d);
 | 
				
			||||||
    uint8_t *pci_conf;
 | 
					    uint8_t *pci_conf;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
    UHCIPort *port;
 | 
					    UHCIPort *port;
 | 
				
			||||||
@ -454,11 +455,11 @@ static void uhci_port_write(void *opaque, hwaddr addr,
 | 
				
			|||||||
                port = &s->ports[i];
 | 
					                port = &s->ports[i];
 | 
				
			||||||
                usb_device_reset(port->port.dev);
 | 
					                usb_device_reset(port->port.dev);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            uhci_reset(s);
 | 
					            uhci_reset(DEVICE(s));
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (val & UHCI_CMD_HCRESET) {
 | 
					        if (val & UHCI_CMD_HCRESET) {
 | 
				
			||||||
            uhci_reset(s);
 | 
					            uhci_reset(DEVICE(s));
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        s->cmd = val;
 | 
					        s->cmd = val;
 | 
				
			||||||
@ -1230,8 +1231,6 @@ static void usb_uhci_common_realize(PCIDevice *dev, Error **errp)
 | 
				
			|||||||
    s->num_ports_vmstate = NB_PORTS;
 | 
					    s->num_ports_vmstate = NB_PORTS;
 | 
				
			||||||
    QTAILQ_INIT(&s->queues);
 | 
					    QTAILQ_INIT(&s->queues);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qemu_register_reset(uhci_reset, s);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s,
 | 
					    memory_region_init_io(&s->io_bar, OBJECT(s), &uhci_ioport_ops, s,
 | 
				
			||||||
                          "uhci", 0x20);
 | 
					                          "uhci", 0x20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1305,6 +1304,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
 | 
				
			|||||||
    k->revision  = info->revision;
 | 
					    k->revision  = info->revision;
 | 
				
			||||||
    k->class_id  = PCI_CLASS_SERIAL_USB;
 | 
					    k->class_id  = PCI_CLASS_SERIAL_USB;
 | 
				
			||||||
    dc->vmsd = &vmstate_uhci;
 | 
					    dc->vmsd = &vmstate_uhci;
 | 
				
			||||||
 | 
					    dc->reset = uhci_reset;
 | 
				
			||||||
    if (!info->unplug) {
 | 
					    if (!info->unplug) {
 | 
				
			||||||
        /* uhci controllers in companion setups can't be hotplugged */
 | 
					        /* uhci controllers in companion setups can't be hotplugged */
 | 
				
			||||||
        dc->hotpluggable = false;
 | 
					        dc->hotpluggable = false;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user