Commit 4e289b1b authored by Gonglei's avatar Gonglei Committed by Gerd Hoffmann
Browse files

ehci: fix segfault when hot-unplugging ehci 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: default avatarLidonglin <lidonglin@huawei.com>
Signed-off-by: default avatarGonglei <arei.gonglei@huawei.com>
Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 88dd1b8d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -101,6 +101,15 @@ static void usb_ehci_pci_exit(PCIDevice *dev)
    }
}

static void usb_ehci_pci_reset(DeviceState *dev)
{
    PCIDevice *pci_dev = PCI_DEVICE(dev);
    EHCIPCIState *i = PCI_EHCI(pci_dev);
    EHCIState *s = &i->ehci;

    ehci_reset(s);
}

static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr,
                                      uint32_t val, int l)
{
@@ -143,6 +152,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
    k->config_write = usb_ehci_pci_write_config;
    dc->vmsd = &vmstate_ehci_pci;
    dc->props = ehci_pci_properties;
    dc->reset = usb_ehci_pci_reset;
}

static const TypeInfo ehci_pci_type_info = {
+10 −0
Original line number Diff line number Diff line
@@ -42,6 +42,15 @@ static void usb_ehci_sysbus_realize(DeviceState *dev, Error **errp)
    sysbus_init_irq(d, &s->irq);
}

static void usb_ehci_sysbus_reset(DeviceState *dev)
{
    SysBusDevice *d = SYS_BUS_DEVICE(dev);
    EHCISysBusState *i = SYS_BUS_EHCI(d);
    EHCIState *s = &i->ehci;

    ehci_reset(s);
}

static void ehci_sysbus_init(Object *obj)
{
    SysBusDevice *d = SYS_BUS_DEVICE(obj);
@@ -70,6 +79,7 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
    dc->realize = usb_ehci_sysbus_realize;
    dc->vmsd = &vmstate_ehci_sysbus;
    dc->props = ehci_sysbus_properties;
    dc->reset = usb_ehci_sysbus_reset;
    set_bit(DEVICE_CATEGORY_USB, dc->categories);
}

+1 −2
Original line number Diff line number Diff line
@@ -839,7 +839,7 @@ static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr)
}

/* 4.1 host controller initialization */
static void ehci_reset(void *opaque)
void ehci_reset(void *opaque)
{
    EHCIState *s = opaque;
    int i;
@@ -2465,7 +2465,6 @@ void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp)
    s->async_bh = qemu_bh_new(ehci_frame_timer, s);
    s->device = dev;

    qemu_register_reset(ehci_reset, s);
    s->vmstate = qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
}

+1 −0
Original line number Diff line number Diff line
@@ -325,6 +325,7 @@ extern const VMStateDescription vmstate_ehci;
void usb_ehci_init(EHCIState *s, DeviceState *dev);
void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp);
void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp);
void ehci_reset(void *opaque);

#define TYPE_PCI_EHCI "pci-ehci-usb"
#define PCI_EHCI(obj) OBJECT_CHECK(EHCIPCIState, (obj), TYPE_PCI_EHCI)