diff options
Diffstat (limited to 'hw')
137 files changed, 2840 insertions, 1358 deletions
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index f3641dbe4a..3465b1ef30 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -19,6 +19,7 @@ #include <grp.h> #include <sys/socket.h> #include <sys/un.h> +#include "qapi/error.h" #include "qemu/xattr.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -655,12 +656,13 @@ static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) warn_report("handle backend is deprecated"); if (sec_model) { - error_report("Invalid argument security_model specified with handle fsdriver"); + error_setg(errp, + "Invalid argument security_model specified with handle fsdriver"); return -1; } if (!path) { - error_report("fsdev: No path specified"); + error_setg(errp, "fsdev: No path specified"); return -1; } fse->path = g_strdup(path); diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index c30f4f26bd..08e673a79c 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1509,8 +1509,8 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) fsdev_throttle_parse_opts(opts, &fse->fst, &local_err); if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "invalid throttle configuration: "); + error_propagate_prepend(errp, local_err, + "invalid throttle configuration: "); return -1; } diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index 6026780f95..3f54a21c76 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -14,6 +14,7 @@ #include "hw/9pfs/9p.h" #include "hw/xen/xen_backend.h" #include "hw/9pfs/xen-9pfs.h" +#include "qapi/error.h" #include "qemu/config-file.h" #include "qemu/option.h" #include "fsdev/qemu-fsdev.h" @@ -355,6 +356,7 @@ static int xen_9pfs_free(struct XenDevice *xendev) static int xen_9pfs_connect(struct XenDevice *xendev) { + Error *err = NULL; int i; Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev); V9fsState *s = &xen_9pdev->state; @@ -452,7 +454,10 @@ static int xen_9pfs_connect(struct XenDevice *xendev) qemu_opt_set(fsdev, "path", xen_9pdev->path, NULL); qemu_opt_set(fsdev, "security_model", xen_9pdev->security_model, NULL); qemu_opts_set_id(fsdev, s->fsconf.fsdev_id); - qemu_fsdev_add(fsdev); + qemu_fsdev_add(fsdev, &err); + if (err) { + error_report_err(err); + } v9fs_device_realize_common(s, &xen_9p_transport, NULL); return 0; diff --git a/hw/Makefile.objs b/hw/Makefile.objs index a19c1417ed..39d882af6f 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -9,6 +9,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += cpu/ devices-dirs-$(CONFIG_SOFTMMU) += display/ devices-dirs-$(CONFIG_SOFTMMU) += dma/ devices-dirs-$(CONFIG_SOFTMMU) += gpio/ +devices-dirs-$(CONFIG_HYPERV) += hyperv/ devices-dirs-$(CONFIG_SOFTMMU) += i2c/ devices-dirs-$(CONFIG_SOFTMMU) += ide/ devices-dirs-$(CONFIG_SOFTMMU) += input/ @@ -33,7 +34,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += vfio/ devices-dirs-$(CONFIG_SOFTMMU) += virtio/ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/ devices-dirs-$(CONFIG_SOFTMMU) += xen/ -devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/ +devices-dirs-$(CONFIG_MEM_DEVICE) += mem/ devices-dirs-$(CONFIG_SOFTMMU) += smbios/ devices-dirs-y += core/ common-obj-y += $(devices-dirs-y) diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 80b987f7fb..dd62f2a405 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -150,7 +150,8 @@ static void clipper_init(MachineState *machine) } if (initrd_filename) { - long initrd_base, initrd_size; + long initrd_base; + int64_t initrd_size; initrd_size = get_image_size(initrd_filename); if (initrd_size < 0) { diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index d74b5b55e1..8004afe45b 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -932,23 +932,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, return b; } -static int typhoon_pcihost_init(SysBusDevice *dev) -{ - return 0; -} - -static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = typhoon_pcihost_init; -} - static const TypeInfo typhoon_pcihost_info = { .name = TYPE_TYPHOON_PCI_HOST_BRIDGE, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(TyphoonState), - .class_init = typhoon_pcihost_class_init, }; static void typhoon_iommu_memory_region_class_init(ObjectClass *klass, diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 20c71d7d96..586baa9b64 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -24,6 +24,7 @@ #include "qemu/config-file.h" #include "qemu/option.h" #include "exec/address-spaces.h" +#include "qemu/units.h" /* Kernel boot protocol is specified in the kernel docs * Documentation/arm/Booting and Documentation/arm64/booting.txt @@ -36,6 +37,8 @@ #define ARM64_TEXT_OFFSET_OFFSET 8 #define ARM64_MAGIC_OFFSET 56 +#define BOOTLOADER_MAX_SIZE (4 * KiB) + AddressSpace *arm_boot_address_space(ARMCPU *cpu, const struct arm_boot_info *info) { @@ -184,6 +187,8 @@ static void write_bootloader(const char *name, hwaddr addr, code[i] = tswap32(insn); } + assert((len * sizeof(uint32_t)) < BOOTLOADER_MAX_SIZE); + rom_add_blob_fixed_as(name, code, len * sizeof(uint32_t), addr, as); g_free(code); @@ -919,6 +924,19 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, memcpy(&hdrvals, buffer + ARM64_TEXT_OFFSET_OFFSET, sizeof(hdrvals)); if (hdrvals[1] != 0) { kernel_load_offset = le64_to_cpu(hdrvals[0]); + + /* + * We write our startup "bootloader" at the very bottom of RAM, + * so that bit can't be used for the image. Luckily the Image + * format specification is that the image requests only an offset + * from a 2MB boundary, not an absolute load address. So if the + * image requests an offset that might mean it overlaps with the + * bootloader, we can just load it starting at 2MB+offset rather + * than 0MB + offset. + */ + if (kernel_load_offset < BOOTLOADER_MAX_SIZE) { + kernel_load_offset += 2 * MiB; + } } } diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index c807010e83..9648b3af44 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1693,9 +1693,10 @@ static void musicpal_init(MachineState *machine) } wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR); - dev = qdev_create(NULL, "mv88w8618_audio"); + dev = qdev_create(NULL, TYPE_MV88W8618_AUDIO); s = SYS_BUS_DEVICE(dev); - qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); + object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev), + TYPE_WM8750, NULL); qdev_init_nofail(dev); sysbus_mmio_map(s, 0, MP_AUDIO_BASE); sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]); diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c index 43d6a7bb48..0e24c803a1 100644 --- a/hw/arm/sysbus-fdt.c +++ b/hw/arm/sysbus-fdt.c @@ -50,11 +50,13 @@ typedef struct PlatformBusFDTData { PlatformBusDevice *pbus; } PlatformBusFDTData; -/* struct that associates a device type name and a node creation function */ -typedef struct NodeCreationPair { +/* struct that allows to match a device and create its FDT node */ +typedef struct BindingEntry { const char *typename; - int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque); -} NodeCreationPair; + const char *compat; + int (*add_fn)(SysBusDevice *sbdev, void *opaque); + bool (*match_fn)(SysBusDevice *sbdev, const struct BindingEntry *combo); +} BindingEntry; /* helpers */ @@ -413,6 +415,27 @@ static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque) return 0; } +/* DT compatible matching */ +static bool vfio_platform_match(SysBusDevice *sbdev, + const BindingEntry *entry) +{ + VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(sbdev); + const char *compat; + unsigned int n; + + for (n = vdev->num_compat, compat = vdev->compat; n > 0; + n--, compat += strlen(compat) + 1) { + if (!strcmp(entry->compat, compat)) { + return true; + } + } + + return false; +} + +#define VFIO_PLATFORM_BINDING(compat, add_fn) \ + {TYPE_VFIO_PLATFORM, (compat), (add_fn), vfio_platform_match} + #endif /* CONFIG_LINUX */ static int no_fdt_node(SysBusDevice *sbdev, void *opaque) @@ -420,14 +443,23 @@ static int no_fdt_node(SysBusDevice *sbdev, void *opaque) return 0; } -/* list of supported dynamic sysbus devices */ -static const NodeCreationPair add_fdt_node_functions[] = { +/* Device type based matching */ +static bool type_match(SysBusDevice *sbdev, const BindingEntry *entry) +{ + return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename); +} + +#define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), type_match} + +/* list of supported dynamic sysbus bindings */ +static const BindingEntry bindings[] = { #ifdef CONFIG_LINUX - {TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node}, - {TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node}, + TYPE_BINDING(TYPE_VFIO_CALXEDA_XGMAC, add_calxeda_midway_xgmac_fdt_node), + TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node), + VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node), #endif - {TYPE_RAMFB_DEVICE, no_fdt_node}, - {"", NULL}, /* last element */ + TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), + TYPE_BINDING("", NULL), /* last element */ }; /* Generic Code */ @@ -446,10 +478,11 @@ static void add_fdt_node(SysBusDevice *sbdev, void *opaque) { int i, ret; - for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) { - if (!strcmp(object_get_typename(OBJECT(sbdev)), - add_fdt_node_functions[i].typename)) { - ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque); + for (i = 0; i < ARRAY_SIZE(bindings); i++) { + const BindingEntry *iter = &bindings[i]; + + if (iter->match_fn(sbdev, iter)) { + ret = iter->add_fn(sbdev, opaque); assert(!ret); return; } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 0b57f87abc..9f677825f9 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -712,6 +712,10 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, /* Mark as not usable by the normal world */ qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); + + qemu_fdt_add_subnode(vms->fdt, "/secure-chosen"); + qemu_fdt_setprop_string(vms->fdt, "/secure-chosen", "stdout-path", + nodename); } g_free(nodename); @@ -1758,6 +1762,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_CALXEDA_XGMAC); machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE); machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM); mc->block_default_type = IF_VIRTIO; mc->no_cdrom = 1; mc->pci_allow_0_address = true; @@ -1926,6 +1931,8 @@ static void virt_machine_2_10_options(MachineClass *mc) { virt_machine_2_11_options(mc); SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_10); + /* before 2.11 we never faulted accesses to bad addresses */ + mc->ignore_memory_transaction_failures = true; } DEFINE_VIRT_MACHINE(2, 10) diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 337402e9c6..d799533aa9 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -123,6 +123,10 @@ enum { #define MUTE_SHIFT 15 +#define TYPE_AC97 "AC97" +#define AC97(obj) \ + OBJECT_CHECK(AC97LinkState, (obj), TYPE_AC97) + #define REC_MASK 7 enum { REC_MIC = 0, @@ -1340,7 +1344,7 @@ static void ac97_on_reset (DeviceState *dev) static void ac97_realize(PCIDevice *dev, Error **errp) { - AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev); + AC97LinkState *s = AC97(dev); uint8_t *c = s->dev.config; /* TODO: no need to override */ @@ -1389,7 +1393,7 @@ static void ac97_realize(PCIDevice *dev, Error **errp) static void ac97_exit(PCIDevice *dev) { - AC97LinkState *s = DO_UPCAST(AC97LinkState, dev, dev); + AC97LinkState *s = AC97(dev); AUD_close_in(&s->card, s->voice_pi); AUD_close_out(&s->card, s->voice_po); @@ -1399,7 +1403,7 @@ static void ac97_exit(PCIDevice *dev) static int ac97_init (PCIBus *bus) { - pci_create_simple (bus, -1, "AC97"); + pci_create_simple(bus, -1, TYPE_AC97); return 0; } @@ -1427,7 +1431,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) } static const TypeInfo ac97_info = { - .name = "AC97", + .name = TYPE_AC97, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (AC97LinkState), .class_init = ac97_class_init, diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index dd75c9e8f5..97789a0771 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -506,10 +506,13 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) d - &s->chan[0], val >> 16, (val & 0xffff)); break; + case ES1370_REG_ADC_FRAMEADR: + d += 2; + goto frameadr; case ES1370_REG_DAC1_FRAMEADR: case ES1370_REG_DAC2_FRAMEADR: - case ES1370_REG_ADC_FRAMEADR: d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3; + frameadr: d->frame_addr = val; ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val); break; @@ -521,10 +524,13 @@ static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) lwarn ("writing to phantom frame address %#x\n", val); break; + case ES1370_REG_ADC_FRAMECNT: + d += 2; + goto framecnt; case ES1370_REG_DAC1_FRAMECNT: case ES1370_REG_DAC2_FRAMECNT: - case ES1370_REG_ADC_FRAMECNT: d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3; + framecnt: d->frame_cnt = val; d->leftover = 0; ldebug ("chan %td frame count %d, buffer size %d\n", @@ -579,10 +585,13 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) #endif break; + case ES1370_REG_ADC_FRAMECNT: + d += 2; + goto framecnt; case ES1370_REG_DAC1_FRAMECNT: case ES1370_REG_DAC2_FRAMECNT: - case ES1370_REG_ADC_FRAMECNT: d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3; + framecnt: val = d->frame_cnt; #ifdef DEBUG_ES1370 { @@ -596,10 +605,13 @@ static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size) #endif break; + case ES1370_REG_ADC_FRAMEADR: + d += 2; + goto frameadr; case ES1370_REG_DAC1_FRAMEADR: case ES1370_REG_DAC2_FRAMEADR: - case ES1370_REG_ADC_FRAMEADR: d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3; + frameadr: val = d->frame_addr; break; diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index e546892d3c..6600ab4851 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -15,6 +15,7 @@ #include "hw/i2c/i2c.h" #include "hw/audio/wm8750.h" #include "audio/audio.h" +#include "qapi/error.h" #define MP_AUDIO_SIZE 0x00001000 @@ -38,7 +39,6 @@ #define MP_AUDIO_CLOCK_24MHZ (1 << 9) #define MP_AUDIO_MONO (1 << 14) -#define TYPE_MV88W8618_AUDIO "mv88w8618_audio" #define MV88W8618_AUDIO(obj) \ OBJECT_CHECK(mv88w8618_audio_state, (obj), TYPE_MV88W8618_AUDIO) @@ -252,6 +252,11 @@ static void mv88w8618_audio_init(Object *obj) memory_region_init_io(&s->iomem, obj, &mv88w8618_audio_ops, s, "audio", MP_AUDIO_SIZE); sysbus_init_mmio(dev, &s->iomem); + + object_property_add_link(OBJECT(dev), "wm8750", TYPE_WM8750, + (Object **) &s->wm, + qdev_prop_allow_set_link_before_realize, + 0, &error_abort); } static void mv88w8618_audio_realize(DeviceState *dev, Error **errp) @@ -279,11 +284,6 @@ static const VMStateDescription mv88w8618_audio_vmsd = { } }; -static Property mv88w8618_audio_properties[] = { - DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm), - {/* end of list */}, -}; - static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -291,8 +291,6 @@ static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) dc->realize = mv88w8618_audio_realize; dc->reset = mv88w8618_audio_reset; dc->vmsd = &mv88w8618_audio_vmsd; - dc->props = mv88w8618_audio_properties; - /* Reason: pointer property "wm8750" */ dc->user_creatable = false; } diff --git a/hw/char/serial.c b/hw/char/serial.c index 251f40fdac..02463e3388 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -345,9 +345,9 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, default: case 0: if (s->lcr & UART_LCR_DLAB) { - if (size == 2) { + if (size == 1) { s->divider = (s->divider & 0xff00) | val; - } else if (size == 4) { + } else { s->divider = val; } serial_update_parameters(s); diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c index 373a40595f..12831561a6 100644 --- a/hw/char/sh_serial.c +++ b/hw/char/sh_serial.c @@ -29,6 +29,7 @@ #include "hw/sh4/sh.h" #include "chardev/char-fe.h" #include "qapi/error.h" +#include "qemu/timer.h" //#define DEBUG_SERIAL @@ -63,6 +64,8 @@ typedef struct { int rtrg; CharBackend chr; + QEMUTimer *fifo_timeout_timer; + uint64_t etu; /* Elementary Time Unit (ns) */ qemu_irq eri; qemu_irq rxi; @@ -314,6 +317,16 @@ static int sh_serial_can_receive1(void *opaque) return sh_serial_can_receive(s); } +static void sh_serial_timeout_int(void *opaque) +{ + sh_serial_state *s = opaque; + + s->flags |= SH_SERIAL_FLAG_RDF; + if (s->scr & (1 << 6) && s->rxi) { + qemu_set_irq(s->rxi, 1); + } +} + static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) { sh_serial_state *s = opaque; @@ -330,8 +343,12 @@ static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) if (s->rx_cnt >= s->rtrg) { s->flags |= SH_SERIAL_FLAG_RDF; if (s->scr & (1 << 6) && s->rxi) { + timer_del(s->fifo_timeout_timer); qemu_set_irq(s->rxi, 1); } + } else { + timer_mod(s->fifo_timeout_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu); } } } @@ -402,6 +419,9 @@ void sh_serial_init(MemoryRegion *sysmem, sh_serial_event, NULL, s, NULL, true); } + s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + sh_serial_timeout_int, s); + s->etu = NANOSECONDS_PER_SECOND / 9600; s->eri = eri_source; s->rxi = rxi_source; s->txi = txi_source; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index d2dd8ab502..04e3ebe352 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -667,9 +667,9 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) /* The config space (ignored on the far end in current versions) */ get_config(vdev, (uint8_t *)&config); - qemu_put_be16s(f, &config.cols); - qemu_put_be16s(f, &config.rows); - qemu_put_be32s(f, &config.max_nr_ports); + qemu_put_be16(f, config.cols); + qemu_put_be16(f, config.rows); + qemu_put_be32(f, config.max_nr_ports); /* The ports map */ max_nr_ports = s->serial.max_virtserial_ports; diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 8b4b4bf523..44f7236382 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -207,7 +207,11 @@ static int con_init(struct XenDevice *xendev) } else { snprintf(label, sizeof(label), "xencons%d", con->xendev.dev); qemu_chr_fe_init(&con->chr, - qemu_chr_new(label, output), &error_abort); + /* + * FIXME: sure we want to support implicit + * muxed monitors here? + */ + qemu_chr_new_mux_mon(label, output), &error_abort); } xenstore_store_pv_console_info(con->xendev.dev, diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index eb88ca979e..a799c83815 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -20,6 +20,5 @@ common-obj-$(CONFIG_SOFTMMU) += register.o common-obj-$(CONFIG_SOFTMMU) += or-irq.o common-obj-$(CONFIG_SOFTMMU) += split-irq.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o - -obj-$(CONFIG_SOFTMMU) += generic-loader.o -obj-$(CONFIG_SOFTMMU) += null-machine.o +common-obj-$(CONFIG_SOFTMMU) += generic-loader.o +common-obj-$(CONFIG_SOFTMMU) += null-machine.o diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index fde32cbda1..fbae05fb3b 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -130,11 +130,7 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) s->cpu = first_cpu; } -#ifdef TARGET_WORDS_BIGENDIAN - big_endian = 1; -#else - big_endian = 0; -#endif + big_endian = target_words_bigendian(); if (s->file) { AddressSpace *as = s->cpu ? s->cpu->as : NULL; @@ -204,6 +200,7 @@ static void generic_loader_class_init(ObjectClass *klass, void *data) dc->unrealize = generic_loader_unrealize; dc->props = generic_loader_props; dc->desc = "Generic Loader"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static TypeInfo generic_loader_info = { diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c index 2253072d0e..17ac986685 100644 --- a/hw/core/hotplug.c +++ b/hw/core/hotplug.c @@ -35,16 +35,6 @@ void hotplug_handler_plug(HotplugHandler *plug_handler, } } -void hotplug_handler_post_plug(HotplugHandler *plug_handler, - DeviceState *plugged_dev) -{ - HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); - - if (hdc->post_plug) { - hdc->post_plug(plug_handler, plugged_dev); - } -} - void hotplug_handler_unplug_request(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) diff --git a/hw/core/loader.c b/hw/core/loader.c index 390987a05c..aa0b3fc867 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -61,9 +61,10 @@ static int roms_loaded; /* return the size or -1 if error */ -int get_image_size(const char *filename) +int64_t get_image_size(const char *filename) { - int fd, size; + int fd; + int64_t size; fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; diff --git a/hw/core/machine.c b/hw/core/machine.c index 1987557833..da50ad6de7 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -636,7 +636,7 @@ static void machine_class_init(ObjectClass *oc, void *data) machine_get_memory_encryption, machine_set_memory_encryption, &error_abort); object_class_property_set_description(oc, "memory-encryption", - "Set memory encyption object to use", &error_abort); + "Set memory encryption object to use", &error_abort); } static void machine_class_base_init(ObjectClass *oc, void *data) diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index cde4d3eb57..76d3f8e39c 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -18,7 +18,7 @@ #include "hw/boards.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -#include "cpu.h" +#include "qom/cpu.h" static void machine_none_init(MachineState *mch) { diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 046d8f1f76..6b3cc55b27 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -832,14 +832,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp) DEVICE_LISTENER_CALL(realize, Forward, dev); - if (hotplug_ctrl) { - hotplug_handler_plug(hotplug_ctrl, dev, &local_err); - } - - if (local_err != NULL) { - goto post_realize_fail; - } - /* * always free/re-initialize here since the value cannot be cleaned up * in device_unrealize due to its usage later on in the unplug path @@ -869,8 +861,12 @@ static void device_set_realized(Object *obj, bool value, Error **errp) dev->pending_deleted_event = false; if (hotplug_ctrl) { - hotplug_handler_post_plug(hotplug_ctrl, dev); - } + hotplug_handler_plug(hotplug_ctrl, dev, &local_err); + if (local_err != NULL) { + goto child_realize_fail; + } + } + } else if (!value && dev->realized) { Error **local_errp = NULL; QLIST_FOREACH(bus, &dev->child_bus, sibling) { diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 780a76b9f0..97acd5b6cb 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -5,6 +5,7 @@ common-obj-$(CONFIG_FW_CFG_DMA) += ramfb-standalone.o common-obj-$(CONFIG_ADS7846) += ads7846.o common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o +common-obj-$(call land,$(CONFIG_VGA_CIRRUS),$(CONFIG_VGA_ISA))+=cirrus_vga_isa.o common-obj-$(CONFIG_G364FB) += g364fb.o common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o common-obj-$(CONFIG_PL110) += pl110.o @@ -14,11 +15,12 @@ common-obj-$(CONFIG_SSD0323) += ssd0323.o common-obj-$(CONFIG_XEN) += xenfb.o common-obj-$(CONFIG_VGA_PCI) += vga-pci.o -common-obj-$(CONFIG_VGA_PCI) += bochs-display.o common-obj-$(CONFIG_VGA_PCI) += edid-region.o common-obj-$(CONFIG_VGA_ISA) += vga-isa.o common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o +common-obj-$(CONFIG_BOCHS_DISPLAY) += bochs-display.o +common-obj-$(CONFIG_BOCHS_DISPLAY) += edid-region.o common-obj-$(CONFIG_BLIZZARD) += blizzard.o common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index d534d00a65..599863e4e1 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -190,7 +190,7 @@ static void fb_update_display(void *opaque) } if (s->invalidate) { - hwaddr base = s->config.base + xoff + yoff * src_width; + hwaddr base = s->config.base + xoff + (hwaddr)yoff * src_width; framebuffer_update_memory_section(&s->fbsection, s->dma_mr, base, s->config.yres, src_width); diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 09d8944a1b..3d439eb240 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -9,6 +9,7 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "hw/display/bochs-vbe.h" +#include "hw/display/edid.h" #include "qapi/error.h" @@ -35,9 +36,13 @@ typedef struct BochsDisplayState { MemoryRegion mmio; MemoryRegion vbe; MemoryRegion qext; + MemoryRegion edid; /* device config */ uint64_t vgamem; + bool enable_edid; + qemu_edid_info edid_info; + uint8_t edid_blob[256]; /* device registers */ uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; @@ -283,6 +288,12 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp) pci_register_bar(&s->pci, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); pci_register_bar(&s->pci, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); + if (s->enable_edid) { + qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info); + qemu_edid_region_io(&s->edid, obj, s->edid_blob, sizeof(s->edid_blob)); + memory_region_add_subregion(&s->mmio, 0, &s->edid); + } + if (pci_bus_is_express(pci_get_bus(dev))) { dev->cap_present |= QEMU_PCI_CAP_EXPRESS; ret = pcie_endpoint_cap_init(dev, 0x80); @@ -325,6 +336,8 @@ static void bochs_display_exit(PCIDevice *dev) static Property bochs_display_properties[] = { DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * MiB), + DEFINE_PROP_BOOL("edid", BochsDisplayState, enable_edid, false), + DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/display/cg3.c b/hw/display/cg3.c index 1c199ab369..e50d97e48c 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -307,7 +307,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) ret = load_image_mr(fcode_filename, &s->rom); g_free(fcode_filename); if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { - error_report("cg3: could not load prom '%s'", CG3_ROM_FILE); + warn_report("cg3: could not load prom '%s'", CG3_ROM_FILE); } } diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 04c87c8e8d..d9b854d74d 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -33,8 +33,8 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "ui/pixel_ops.h" -#include "vga_int.h" #include "hw/loader.h" +#include "cirrus_vga_internal.h" /* * TODO: @@ -52,16 +52,6 @@ * ***************************************/ -// ID -#define CIRRUS_ID_CLGD5422 (0x23<<2) -#define CIRRUS_ID_CLGD5426 (0x24<<2) -#define CIRRUS_ID_CLGD5424 (0x25<<2) -#define CIRRUS_ID_CLGD5428 (0x26<<2) -#define CIRRUS_ID_CLGD5430 (0x28<<2) -#define CIRRUS_ID_CLGD5434 (0x2A<<2) -#define CIRRUS_ID_CLGD5436 (0x2B<<2) -#define CIRRUS_ID_CLGD5446 (0x2E<<2) - // sequencer 0x07 #define CIRRUS_SR7_BPP_VGA 0x00 #define CIRRUS_SR7_BPP_SVGA 0x01 @@ -176,65 +166,10 @@ #define CIRRUS_PNPMMIO_SIZE 0x1000 -struct CirrusVGAState; -typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, - uint32_t dstaddr, uint32_t srcaddr, - int dstpitch, int srcpitch, - int bltwidth, int bltheight); typedef void (*cirrus_fill_t)(struct CirrusVGAState *s, uint32_t dstaddr, int dst_pitch, int width, int height); -typedef struct CirrusVGAState { - VGACommonState vga; - - MemoryRegion cirrus_vga_io; - MemoryRegion cirrus_linear_io; - MemoryRegion cirrus_linear_bitblt_io; - MemoryRegion cirrus_mmio_io; - MemoryRegion pci_bar; - bool linear_vram; /* vga.vram mapped over cirrus_linear_io */ - MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */ - MemoryRegion low_mem; /* always mapped, overridden by: */ - MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */ - uint32_t cirrus_addr_mask; - uint32_t linear_mmio_mask; - uint8_t cirrus_shadow_gr0; - uint8_t cirrus_shadow_gr1; - uint8_t cirrus_hidden_dac_lockindex; - uint8_t cirrus_hidden_dac_data; - uint32_t cirrus_bank_base[2]; - uint32_t cirrus_bank_limit[2]; - uint8_t cirrus_hidden_palette[48]; - bool enable_blitter; - int cirrus_blt_pixelwidth; - int cirrus_blt_width; - int cirrus_blt_height; - int cirrus_blt_dstpitch; - int cirrus_blt_srcpitch; - uint32_t cirrus_blt_fgcol; - uint32_t cirrus_blt_bgcol; - uint32_t cirrus_blt_dstaddr; - uint32_t cirrus_blt_srcaddr; - uint8_t cirrus_blt_mode; - uint8_t cirrus_blt_modeext; - cirrus_bitblt_rop_t cirrus_rop; -#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */ - uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE]; - uint8_t *cirrus_srcptr; - uint8_t *cirrus_srcptr_end; - uint32_t cirrus_srccounter; - /* hwcursor display state */ - int last_hw_cursor_size; - int last_hw_cursor_x; - int last_hw_cursor_y; - int last_hw_cursor_y_start; - int last_hw_cursor_y_end; - int real_vram_size; /* XXX: suppress that */ - int device_id; - int bustype; -} CirrusVGAState; - typedef struct PCICirrusVGAState { PCIDevice dev; CirrusVGAState cirrus_vga; @@ -244,16 +179,6 @@ typedef struct PCICirrusVGAState { #define PCI_CIRRUS_VGA(obj) \ OBJECT_CHECK(PCICirrusVGAState, (obj), TYPE_PCI_CIRRUS_VGA) -#define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga" -#define ISA_CIRRUS_VGA(obj) \ - OBJECT_CHECK(ISACirrusVGAState, (obj), TYPE_ISA_CIRRUS_VGA) - -typedef struct ISACirrusVGAState { - ISADevice parent_obj; - - CirrusVGAState cirrus_vga; -} ISACirrusVGAState; - static uint8_t rop_to_index[256]; /*************************************** @@ -2829,7 +2754,7 @@ static int cirrus_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_cirrus_vga = { +const VMStateDescription vmstate_cirrus_vga = { .name = "cirrus_vga", .version_id = 2, .minimum_version_id = 1, @@ -2932,10 +2857,9 @@ static const MemoryRegionOps cirrus_vga_io_ops = { }, }; -static void cirrus_init_common(CirrusVGAState *s, Object *owner, - int device_id, int is_pci, - MemoryRegion *system_memory, - MemoryRegion *system_io) +void cirrus_init_common(CirrusVGAState *s, Object *owner, + int device_id, int is_pci, + MemoryRegion *system_memory, MemoryRegion *system_io) { int i; static int inited; @@ -3031,62 +2955,6 @@ static void cirrus_init_common(CirrusVGAState *s, Object *owner, /*************************************** * - * ISA bus support - * - ***************************************/ - -static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp) -{ - ISADevice *isadev = ISA_DEVICE(dev); - ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev); - VGACommonState *s = &d->cirrus_vga.vga; - - /* follow real hardware, cirrus card emulated has 4 MB video memory. - Also accept 8 MB/16 MB for backward compatibility. */ - if (s->vram_size_mb != 4 && s->vram_size_mb != 8 && - s->vram_size_mb != 16) { - error_setg(errp, "Invalid cirrus_vga ram size '%u'", - s->vram_size_mb); - return; - } - s->global_vmstate = true; - vga_common_init(s, OBJECT(dev)); - cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0, - isa_address_space(isadev), - isa_address_space_io(isadev)); - s->con = graphic_console_init(dev, 0, s->hw_ops, s); - rom_add_vga(VGABIOS_CIRRUS_FILENAME); - /* XXX ISA-LFB support */ - /* FIXME not qdev yet */ -} - -static Property isa_cirrus_vga_properties[] = { - DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState, - cirrus_vga.vga.vram_size_mb, 4), - DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState, - cirrus_vga.enable_blitter, true), - DEFINE_PROP_END_OF_LIST(), -}; - -static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &vmstate_cirrus_vga; - dc->realize = isa_cirrus_vga_realizefn; - dc->props = isa_cirrus_vga_properties; - set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); -} - -static const TypeInfo isa_cirrus_vga_info = { - .name = TYPE_ISA_CIRRUS_VGA, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(ISACirrusVGAState), - .class_init = isa_cirrus_vga_class_init, -}; - -/*************************************** - * * PCI bus support * ***************************************/ @@ -3171,7 +3039,6 @@ static const TypeInfo cirrus_vga_info = { static void cirrus_vga_register_types(void) { - type_register_static(&isa_cirrus_vga_info); type_register_static(&cirrus_vga_info); } diff --git a/hw/display/cirrus_vga_internal.h b/hw/display/cirrus_vga_internal.h new file mode 100644 index 0000000000..a78ebbd920 --- /dev/null +++ b/hw/display/cirrus_vga_internal.h @@ -0,0 +1,103 @@ +/* + * QEMU Cirrus CLGD 54xx VGA Emulator, ISA bus support + * + * Copyright (c) 2004 Fabrice Bellard + * Copyright (c) 2004 Makoto Suzuki (suzu) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CIRRUS_VGA_INTERNAL_H +#define CIRRUS_VGA_INTERNAL_H + +#include "vga_int.h" + +/* IDs */ +#define CIRRUS_ID_CLGD5422 (0x23 << 2) +#define CIRRUS_ID_CLGD5426 (0x24 << 2) +#define CIRRUS_ID_CLGD5424 (0x25 << 2) +#define CIRRUS_ID_CLGD5428 (0x26 << 2) +#define CIRRUS_ID_CLGD5430 (0x28 << 2) +#define CIRRUS_ID_CLGD5434 (0x2A << 2) +#define CIRRUS_ID_CLGD5436 (0x2B << 2) +#define CIRRUS_ID_CLGD5446 (0x2E << 2) + +extern const VMStateDescription vmstate_cirrus_vga; + +struct CirrusVGAState; +typedef void (*cirrus_bitblt_rop_t)(struct CirrusVGAState *s, + uint32_t dstaddr, uint32_t srcaddr, + int dstpitch, int srcpitch, + int bltwidth, int bltheight); + +typedef struct CirrusVGAState { + VGACommonState vga; + + MemoryRegion cirrus_vga_io; + MemoryRegion cirrus_linear_io; + MemoryRegion cirrus_linear_bitblt_io; + MemoryRegion cirrus_mmio_io; + MemoryRegion pci_bar; + bool linear_vram; /* vga.vram mapped over cirrus_linear_io */ + MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */ + MemoryRegion low_mem; /* always mapped, overridden by: */ + MemoryRegion cirrus_bank[2]; /* aliases at 0xa0000-0xb0000 */ + uint32_t cirrus_addr_mask; + uint32_t linear_mmio_mask; + uint8_t cirrus_shadow_gr0; + uint8_t cirrus_shadow_gr1; + uint8_t cirrus_hidden_dac_lockindex; + uint8_t cirrus_hidden_dac_data; + uint32_t cirrus_bank_base[2]; + uint32_t cirrus_bank_limit[2]; + uint8_t cirrus_hidden_palette[48]; + bool enable_blitter; + int cirrus_blt_pixelwidth; + int cirrus_blt_width; + int cirrus_blt_height; + int cirrus_blt_dstpitch; + int cirrus_blt_srcpitch; + uint32_t cirrus_blt_fgcol; + uint32_t cirrus_blt_bgcol; + uint32_t cirrus_blt_dstaddr; + uint32_t cirrus_blt_srcaddr; + uint8_t cirrus_blt_mode; + uint8_t cirrus_blt_modeext; + cirrus_bitblt_rop_t cirrus_rop; +#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */ + uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE]; + uint8_t *cirrus_srcptr; + uint8_t *cirrus_srcptr_end; + uint32_t cirrus_srccounter; + /* hwcursor display state */ + int last_hw_cursor_size; + int last_hw_cursor_x; + int last_hw_cursor_y; + int last_hw_cursor_y_start; + int last_hw_cursor_y_end; + int real_vram_size; /* XXX: suppress that */ + int device_id; + int bustype; +} CirrusVGAState; + +void cirrus_init_common(CirrusVGAState *s, Object *owner, + int device_id, int is_pci, + MemoryRegion *system_memory, MemoryRegion *system_io); + +#endif diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c new file mode 100644 index 0000000000..fa10b74230 --- /dev/null +++ b/hw/display/cirrus_vga_isa.c @@ -0,0 +1,98 @@ +/* + * QEMU Cirrus CLGD 54xx VGA Emulator, ISA bus support + * + * Copyright (c) 2004 Fabrice Bellard + * Copyright (c) 2004 Makoto Suzuki (suzu) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/loader.h" +#include "hw/isa/isa.h" +#include "cirrus_vga_internal.h" + +#define TYPE_ISA_CIRRUS_VGA "isa-cirrus-vga" +#define ISA_CIRRUS_VGA(obj) \ + OBJECT_CHECK(ISACirrusVGAState, (obj), TYPE_ISA_CIRRUS_VGA) + +typedef struct ISACirrusVGAState { + ISADevice parent_obj; + + CirrusVGAState cirrus_vga; +} ISACirrusVGAState; + +static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp) +{ + ISADevice *isadev = ISA_DEVICE(dev); + ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev); + VGACommonState *s = &d->cirrus_vga.vga; + + /* follow real hardware, cirrus card emulated has 4 MB video memory. + Also accept 8 MB/16 MB for backward compatibility. */ + if (s->vram_size_mb != 4 && s->vram_size_mb != 8 && + s->vram_size_mb != 16) { + error_setg(errp, "Invalid cirrus_vga ram size '%u'", + s->vram_size_mb); + return; + } + s->global_vmstate = true; + vga_common_init(s, OBJECT(dev)); + cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0, + isa_address_space(isadev), + isa_address_space_io(isadev)); + s->con = graphic_console_init(dev, 0, s->hw_ops, s); + rom_add_vga(VGABIOS_CIRRUS_FILENAME); + /* XXX ISA-LFB support */ + /* FIXME not qdev yet */ +} + +static Property isa_cirrus_vga_properties[] = { + DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState, + cirrus_vga.vga.vram_size_mb, 4), + DEFINE_PROP_BOOL("blitter", struct ISACirrusVGAState, + cirrus_vga.enable_blitter, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_cirrus_vga; + dc->realize = isa_cirrus_vga_realizefn; + dc->props = isa_cirrus_vga_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); +} + +static const TypeInfo isa_cirrus_vga_info = { + .name = TYPE_ISA_CIRRUS_VGA, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISACirrusVGAState), + .class_init = isa_cirrus_vga_class_init, +}; + +static void cirrus_vga_isa_register_types(void) +{ + type_register_static(&isa_cirrus_vga_info); +} + +type_init(cirrus_vga_isa_register_types) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index c80397ea96..bdf5e1d4d4 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -223,7 +223,7 @@ static void edid_desc_timing(uint8_t *desc, uint32_t clock = 75 * (xres + xblank) * (yres + yblank); - *(uint32_t *)(desc) = cpu_to_le32(clock / 10000); + stl_le_p(desc, clock / 10000); desc[2] = xres & 0xff; desc[3] = xblank & 0xff; @@ -301,7 +301,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== set defaults =============== */ if (!info->vendor || strlen(info->vendor) != 3) { - info->vendor = "EMU"; + info->vendor = "RHT"; } if (!info->name) { info->name = "QEMU Monitor"; @@ -342,9 +342,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size, (((info->vendor[2] - '@') & 0x1f) << 0)); uint16_t model_nr = 0x1234; uint32_t serial_nr = info->serial ? atoi(info->serial) : 0; - *(uint16_t *)(edid + 8) = cpu_to_be16(vendor_id); - *(uint16_t *)(edid + 10) = cpu_to_le16(model_nr); - *(uint32_t *)(edid + 12) = cpu_to_le32(serial_nr); + stw_be_p(edid + 8, vendor_id); + stw_le_p(edid + 10, model_nr); + stl_le_p(edid + 12, serial_nr); /* manufacture week and year */ edid[16] = 42; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 747986478f..9087db5dee 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -290,7 +290,7 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) } cfg = qxl_phys2virt(qxl, qxl->guest_monitors_config, MEMSLOT_GROUP_GUEST); - if (cfg->count == 1) { + if (cfg != NULL && cfg->count == 1) { qxl->guest_primary.resized = 1; qxl->guest_head0_width = cfg->heads[0].width; qxl->guest_head0_height = cfg->heads[0].height; @@ -848,7 +848,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * qxl->guest_primary.commands++; qxl_track_command(qxl, ext); qxl_log_command(qxl, "csr", ext); - if (qxl->id == 0) { + if (qxl->have_vga) { qxl_render_cursor(qxl, ext); } trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode)); @@ -1255,7 +1255,7 @@ static void qxl_soft_reset(PCIQXLDevice *d) d->current_async = QXL_UNDEFINED_IO; qemu_mutex_unlock(&d->async_lock); - if (d->id == 0) { + if (d->have_vga) { qxl_enter_vga_mode(d); } else { d->mode = QXL_MODE_UNDEFINED; @@ -1893,7 +1893,31 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) trace_qxl_send_events_vm_stopped(d->id, events); return; } - old_pending = atomic_fetch_or(&d->ram->int_pending, le_events); + /* + * Older versions of Spice forgot to define the QXLRam struct + * with the '__aligned__(4)' attribute. clang 7 and newer will + * thus warn that atomic_fetch_or(&d->ram->int_pending, ...) + * might be a misaligned atomic access, and will generate an + * out-of-line call for it, which results in a link error since + * we don't currently link against libatomic. + * + * In fact we set up d->ram in init_qxl_ram() so it always starts + * at a 4K boundary, so we know that &d->ram->int_pending is + * naturally aligned for a uint32_t. Newer Spice versions + * (with Spice commit beda5ec7a6848be20c0cac2a9a8ef2a41e8069c1) + * will fix the bug directly. To deal with older versions, + * we tell the compiler to assume the address really is aligned. + * Any compiler which cares about the misalignment will have + * __builtin_assume_aligned. + */ +#ifdef HAS_ASSUME_ALIGNED +#define ALIGNED_UINT32_PTR(P) ((uint32_t *)__builtin_assume_aligned(P, 4)) +#else +#define ALIGNED_UINT32_PTR(P) ((uint32_t *)P) +#endif + + old_pending = atomic_fetch_or(ALIGNED_UINT32_PTR(&d->ram->int_pending), + le_events); if ((old_pending & le_events) == le_events) { return; } @@ -2115,7 +2139,7 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) memory_region_init_io(&qxl->io_bar, OBJECT(qxl), &qxl_io_ops, qxl, "qxl-ioports", io_size); - if (qxl->id == 0) { + if (qxl->have_vga) { vga_dirty_log_start(&qxl->vga); } memory_region_set_flush_coalesced(&qxl->io_bar); @@ -2147,7 +2171,7 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) /* print pci bar details */ dprint(qxl, 1, "ram/%s: %" PRId64 " MB [region 0]\n", - qxl->id == 0 ? "pri" : "sec", qxl->vga.vram_size / MiB); + qxl->have_vga ? "pri" : "sec", qxl->vga.vram_size / MiB); dprint(qxl, 1, "vram/32: %" PRIx64 " MB [region 1]\n", qxl->vram32_size / MiB); dprint(qxl, 1, "vram/64: %" PRIx64 " MB %s\n", @@ -2175,7 +2199,6 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp) VGACommonState *vga = &qxl->vga; Error *local_err = NULL; - qxl->id = 0; qxl_init_ramsize(qxl); vga->vbe_size = qxl->vgamem_size; vga->vram_size_mb = qxl->vga.vram_size / MiB; @@ -2186,8 +2209,15 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp) vga, "vga"); portio_list_set_flush_coalesced(&qxl->vga_port_list); portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0); + qxl->have_vga = true; vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); + qxl->id = qemu_console_get_index(vga->con); /* == channel_id */ + if (qxl->id != 0) { + error_setg(errp, "primary qxl-vga device must be console 0 " + "(first display device on the command line)"); + return; + } qxl_realize_common(qxl, &local_err); if (local_err) { @@ -2202,15 +2232,14 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp) static void qxl_realize_secondary(PCIDevice *dev, Error **errp) { - static int device_id = 1; PCIQXLDevice *qxl = PCI_QXL(dev); - qxl->id = device_id++; qxl_init_ramsize(qxl); memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram", qxl->vga.vram_size, &error_fatal); qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); + qxl->id = qemu_console_get_index(qxl->vga.con); /* == channel_id */ qxl_realize_common(qxl, errp); } diff --git a/hw/display/qxl.h b/hw/display/qxl.h index dd9c0522b7..6f9d1f21fa 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -34,6 +34,7 @@ typedef struct PCIQXLDevice { PortioList vga_port_list; SimpleSpiceDisplay ssd; int id; + bool have_vga; uint32_t debug; uint32_t guestdebug; uint32_t cmdlog; diff --git a/hw/display/tcx.c b/hw/display/tcx.c index b2786ee8d0..66f2459226 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -823,7 +823,7 @@ static void tcx_realizefn(DeviceState *dev, Error **errp) ret = load_image_mr(fcode_filename, &s->rom); g_free(fcode_filename); if (ret < 0 || ret > FCODE_MAX_ROM_SIZE) { - error_report("tcx: could not load prom '%s'", TCX_ROM_FILE); + warn_report("tcx: could not load prom '%s'", TCX_ROM_FILE); } } diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 24ca1b3e1f..a17c96e703 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -309,6 +309,14 @@ static void pci_secondary_vga_exit(PCIDevice *dev) VGACommonState *s = &d->vga; graphic_console_close(s->con); + memory_region_del_subregion(&d->mmio, &d->mrs[0]); + memory_region_del_subregion(&d->mmio, &d->mrs[1]); + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) { + memory_region_del_subregion(&d->mmio, &d->mrs[2]); + } + if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_EDID)) { + memory_region_del_subregion(&d->mmio, &d->mrs[3]); + } } static void pci_secondary_vga_init(Object *obj) diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 6e4fa48a79..55c418eab5 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -166,7 +166,6 @@ MemoryRegion *vga_init_io(VGACommonState *s, Object *obj, const MemoryRegionPortio **vbe_ports); void vga_common_reset(VGACommonState *s); -void vga_sync_dirty_bitmap(VGACommonState *s); void vga_dirty_log_start(VGACommonState *s); void vga_dirty_log_stop(VGACommonState *s); diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 564b938e3a..31e09942b5 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -488,17 +488,10 @@ PCIBus *dino_init(MemoryRegion *addr_space, return b; } -static int dino_pcihost_init(SysBusDevice *dev) -{ - return 0; -} - static void dino_pcihost_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->init = dino_pcihost_init; dc->vmsd = &vmstate_dino; } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 0fb8fb877e..ac6dd7f6ab 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -191,7 +191,7 @@ static void machine_hppa_init(MachineState *machine) if (initrd_filename) { ram_addr_t initrd_base; - long initrd_size; + int64_t initrd_size; initrd_size = get_image_size(initrd_filename); if (initrd_size < 0) { diff --git a/hw/hyperv/Makefile.objs b/hw/hyperv/Makefile.objs new file mode 100644 index 0000000000..edaca2f763 --- /dev/null +++ b/hw/hyperv/Makefile.objs @@ -0,0 +1,2 @@ +obj-y += hyperv.o +obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c new file mode 100644 index 0000000000..a28e7249d8 --- /dev/null +++ b/hw/hyperv/hyperv.c @@ -0,0 +1,654 @@ +/* + * Hyper-V guest/hypervisor interaction + * + * Copyright (c) 2015-2018 Virtuozzo International GmbH. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qapi/error.h" +#include "exec/address-spaces.h" +#include "sysemu/kvm.h" +#include "qemu/bitops.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "qemu/rcu.h" +#include "qemu/rcu_queue.h" +#include "hw/hyperv/hyperv.h" + +typedef struct SynICState { + DeviceState parent_obj; + + CPUState *cs; + + bool enabled; + hwaddr msg_page_addr; + hwaddr event_page_addr; + MemoryRegion msg_page_mr; + MemoryRegion event_page_mr; + struct hyperv_message_page *msg_page; + struct hyperv_event_flags_page *event_page; +} SynICState; + +#define TYPE_SYNIC "hyperv-synic" +#define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC) + +static SynICState *get_synic(CPUState *cs) +{ + return SYNIC(object_resolve_path_component(OBJECT(cs), "synic")); +} + +static void synic_update(SynICState *synic, bool enable, + hwaddr msg_page_addr, hwaddr event_page_addr) +{ + + synic->enabled = enable; + if (synic->msg_page_addr != msg_page_addr) { + if (synic->msg_page_addr) { + memory_region_del_subregion(get_system_memory(), + &synic->msg_page_mr); + } + if (msg_page_addr) { + memory_region_add_subregion(get_system_memory(), msg_page_addr, + &synic->msg_page_mr); + } + synic->msg_page_addr = msg_page_addr; + } + if (synic->event_page_addr != event_page_addr) { + if (synic->event_page_addr) { + memory_region_del_subregion(get_system_memory(), + &synic->event_page_mr); + } + if (event_page_addr) { + memory_region_add_subregion(get_system_memory(), event_page_addr, + &synic->event_page_mr); + } + synic->event_page_addr = event_page_addr; + } +} + +void hyperv_synic_update(CPUState *cs, bool enable, + hwaddr msg_page_addr, hwaddr event_page_addr) +{ + SynICState *synic = get_synic(cs); + + if (!synic) { + return; + } + + synic_update(synic, enable, msg_page_addr, event_page_addr); +} + +static void synic_realize(DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + SynICState *synic = SYNIC(dev); + char *msgp_name, *eventp_name; + uint32_t vp_index; + + /* memory region names have to be globally unique */ + vp_index = hyperv_vp_index(synic->cs); + msgp_name = g_strdup_printf("synic-%u-msg-page", vp_index); + eventp_name = g_strdup_printf("synic-%u-event-page", vp_index); + + memory_region_init_ram(&synic->msg_page_mr, obj, msgp_name, + sizeof(*synic->msg_page), &error_abort); + memory_region_init_ram(&synic->event_page_mr, obj, eventp_name, + sizeof(*synic->event_page), &error_abort); + synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr); + synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr); + + g_free(msgp_name); + g_free(eventp_name); +} +static void synic_reset(DeviceState *dev) +{ + SynICState *synic = SYNIC(dev); + memset(synic->msg_page, 0, sizeof(*synic->msg_page)); + memset(synic->event_page, 0, sizeof(*synic->event_page)); + synic_update(synic, false, 0, 0); +} + +static void synic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = synic_realize; + dc->reset = synic_reset; + dc->user_creatable = false; +} + +void hyperv_synic_add(CPUState *cs) +{ + Object *obj; + SynICState *synic; + + obj = object_new(TYPE_SYNIC); + synic = SYNIC(obj); + synic->cs = cs; + object_property_add_child(OBJECT(cs), "synic", obj, &error_abort); + object_unref(obj); + object_property_set_bool(obj, true, "realized", &error_abort); +} + +void hyperv_synic_reset(CPUState *cs) +{ + device_reset(DEVICE(get_synic(cs))); +} + +static const TypeInfo synic_type_info = { + .name = TYPE_SYNIC, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SynICState), + .class_init = synic_class_init, +}; + +static void synic_register_types(void) +{ + type_register_static(&synic_type_info); +} + +type_init(synic_register_types) + +/* + * KVM has its own message producers (SynIC timers). To guarantee + * serialization with both KVM vcpu and the guest cpu, the messages are first + * staged in an intermediate area and then posted to the SynIC message page in + * the vcpu thread. + */ +typedef struct HvSintStagedMessage { + /* message content staged by hyperv_post_msg */ + struct hyperv_message msg; + /* callback + data (r/o) to complete the processing in a BH */ + HvSintMsgCb cb; + void *cb_data; + /* message posting status filled by cpu_post_msg */ + int status; + /* passing the buck: */ + enum { + /* initial state */ + HV_STAGED_MSG_FREE, + /* + * hyperv_post_msg (e.g. in main loop) grabs the staged area (FREE -> + * BUSY), copies msg, and schedules cpu_post_msg on the assigned cpu + */ + HV_STAGED_MSG_BUSY, + /* + * cpu_post_msg (vcpu thread) tries to copy staged msg to msg slot, + * notify the guest, records the status, marks the posting done (BUSY + * -> POSTED), and schedules sint_msg_bh BH + */ + HV_STAGED_MSG_POSTED, + /* + * sint_msg_bh (BH) verifies that the posting is done, runs the + * callback, and starts over (POSTED -> FREE) + */ + } state; +} HvSintStagedMessage; + +struct HvSintRoute { + uint32_t sint; + SynICState *synic; + int gsi; + EventNotifier sint_set_notifier; + EventNotifier sint_ack_notifier; + + HvSintStagedMessage *staged_msg; + + unsigned refcount; +}; + +static CPUState *hyperv_find_vcpu(uint32_t vp_index) +{ + CPUState *cs = qemu_get_cpu(vp_index); + assert(hyperv_vp_index(cs) == vp_index); + return cs; +} + +/* + * BH to complete the processing of a staged message. + */ +static void sint_msg_bh(void *opaque) +{ + HvSintRoute *sint_route = opaque; + HvSintStagedMessage *staged_msg = sint_route->staged_msg; + + if (atomic_read(&staged_msg->state) != HV_STAGED_MSG_POSTED) { + /* status nor ready yet (spurious ack from guest?), ignore */ + return; + } + + staged_msg->cb(staged_msg->cb_data, staged_msg->status); + staged_msg->status = 0; + + /* staged message processing finished, ready to start over */ + atomic_set(&staged_msg->state, HV_STAGED_MSG_FREE); + /* drop the reference taken in hyperv_post_msg */ + hyperv_sint_route_unref(sint_route); +} + +/* + * Worker to transfer the message from the staging area into the SynIC message + * page in vcpu context. + */ +static void cpu_post_msg(CPUState *cs, run_on_cpu_data data) +{ + HvSintRoute *sint_route = data.host_ptr; + HvSintStagedMessage *staged_msg = sint_route->staged_msg; + SynICState *synic = sint_route->synic; + struct hyperv_message *dst_msg; + bool wait_for_sint_ack = false; + + assert(staged_msg->state == HV_STAGED_MSG_BUSY); + + if (!synic->enabled || !synic->msg_page_addr) { + staged_msg->status = -ENXIO; + goto posted; + } + + dst_msg = &synic->msg_page->slot[sint_route->sint]; + + if (dst_msg->header.message_type != HV_MESSAGE_NONE) { + dst_msg->header.message_flags |= HV_MESSAGE_FLAG_PENDING; + staged_msg->status = -EAGAIN; + wait_for_sint_ack = true; + } else { + memcpy(dst_msg, &staged_msg->msg, sizeof(*dst_msg)); + staged_msg->status = hyperv_sint_route_set_sint(sint_route); + } + + memory_region_set_dirty(&synic->msg_page_mr, 0, sizeof(*synic->msg_page)); + +posted: + atomic_set(&staged_msg->state, HV_STAGED_MSG_POSTED); + /* + * Notify the msg originator of the progress made; if the slot was busy we + * set msg_pending flag in it so it will be the guest who will do EOM and + * trigger the notification from KVM via sint_ack_notifier + */ + if (!wait_for_sint_ack) { + aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh, + sint_route); + } +} + +/* + * Post a Hyper-V message to the staging area, for delivery to guest in the + * vcpu thread. + */ +int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *src_msg) +{ + HvSintStagedMessage *staged_msg = sint_route->staged_msg; + + assert(staged_msg); + + /* grab the staging area */ + if (atomic_cmpxchg(&staged_msg->state, HV_STAGED_MSG_FREE, + HV_STAGED_MSG_BUSY) != HV_STAGED_MSG_FREE) { + return -EAGAIN; + } + + memcpy(&staged_msg->msg, src_msg, sizeof(*src_msg)); + + /* hold a reference on sint_route until the callback is finished */ + hyperv_sint_route_ref(sint_route); + + /* schedule message posting attempt in vcpu thread */ + async_run_on_cpu(sint_route->synic->cs, cpu_post_msg, + RUN_ON_CPU_HOST_PTR(sint_route)); + return 0; +} + +static void sint_ack_handler(EventNotifier *notifier) +{ + HvSintRoute *sint_route = container_of(notifier, HvSintRoute, + sint_ack_notifier); + event_notifier_test_and_clear(notifier); + + /* + * the guest consumed the previous message so complete the current one with + * -EAGAIN and let the msg originator retry + */ + aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh, sint_route); +} + +/* + * Set given event flag for a given sint on a given vcpu, and signal the sint. + */ +int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno) +{ + int ret; + SynICState *synic = sint_route->synic; + unsigned long *flags, set_mask; + unsigned set_idx; + + if (eventno > HV_EVENT_FLAGS_COUNT) { + return -EINVAL; + } + if (!synic->enabled || !synic->event_page_addr) { + return -ENXIO; + } + + set_idx = BIT_WORD(eventno); + set_mask = BIT_MASK(eventno); + flags = synic->event_page->slot[sint_route->sint].flags; + + if ((atomic_fetch_or(&flags[set_idx], set_mask) & set_mask) != set_mask) { + memory_region_set_dirty(&synic->event_page_mr, 0, + sizeof(*synic->event_page)); + ret = hyperv_sint_route_set_sint(sint_route); + } else { + ret = 0; + } + return ret; +} + +HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, + HvSintMsgCb cb, void *cb_data) +{ + HvSintRoute *sint_route; + EventNotifier *ack_notifier; + int r, gsi; + CPUState *cs; + SynICState *synic; + + cs = hyperv_find_vcpu(vp_index); + if (!cs) { + return NULL; + } + + synic = get_synic(cs); + if (!synic) { + return NULL; + } + + sint_route = g_new0(HvSintRoute, 1); + r = event_notifier_init(&sint_route->sint_set_notifier, false); + if (r) { + goto err; + } + + + ack_notifier = cb ? &sint_route->sint_ack_notifier : NULL; + if (ack_notifier) { + sint_route->staged_msg = g_new0(HvSintStagedMessage, 1); + sint_route->staged_msg->cb = cb; + sint_route->staged_msg->cb_data = cb_data; + + r = event_notifier_init(ack_notifier, false); + if (r) { + goto err_sint_set_notifier; + } + + event_notifier_set_handler(ack_notifier, sint_ack_handler); + } + + gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint); + if (gsi < 0) { + goto err_gsi; + } + + r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + ack_notifier, gsi); + if (r) { + goto err_irqfd; + } + sint_route->gsi = gsi; + sint_route->synic = synic; + sint_route->sint = sint; + sint_route->refcount = 1; + + return sint_route; + +err_irqfd: + kvm_irqchip_release_virq(kvm_state, gsi); +err_gsi: + if (ack_notifier) { + event_notifier_set_handler(ack_notifier, NULL); + event_notifier_cleanup(ack_notifier); + g_free(sint_route->staged_msg); + } +err_sint_set_notifier: + event_notifier_cleanup(&sint_route->sint_set_notifier); +err: + g_free(sint_route); + + return NULL; +} + +void hyperv_sint_route_ref(HvSintRoute *sint_route) +{ + sint_route->refcount++; +} + +void hyperv_sint_route_unref(HvSintRoute *sint_route) +{ + if (!sint_route) { + return; + } + + assert(sint_route->refcount > 0); + + if (--sint_route->refcount) { + return; + } + + kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, + &sint_route->sint_set_notifier, + sint_route->gsi); + kvm_irqchip_release_virq(kvm_state, sint_route->gsi); + if (sint_route->staged_msg) { + event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL); + event_notifier_cleanup(&sint_route->sint_ack_notifier); + g_free(sint_route->staged_msg); + } + event_notifier_cleanup(&sint_route->sint_set_notifier); + g_free(sint_route); +} + +int hyperv_sint_route_set_sint(HvSintRoute *sint_route) +{ + return event_notifier_set(&sint_route->sint_set_notifier); +} + +typedef struct MsgHandler { + struct rcu_head rcu; + QLIST_ENTRY(MsgHandler) link; + uint32_t conn_id; + HvMsgHandler handler; + void *data; +} MsgHandler; + +typedef struct EventFlagHandler { + struct rcu_head rcu; + QLIST_ENTRY(EventFlagHandler) link; + uint32_t conn_id; + EventNotifier *notifier; +} EventFlagHandler; + +static QLIST_HEAD(, MsgHandler) msg_handlers; +static QLIST_HEAD(, EventFlagHandler) event_flag_handlers; +static QemuMutex handlers_mutex; + +static void __attribute__((constructor)) hv_init(void) +{ + QLIST_INIT(&msg_handlers); + QLIST_INIT(&event_flag_handlers); + qemu_mutex_init(&handlers_mutex); +} + +int hyperv_set_msg_handler(uint32_t conn_id, HvMsgHandler handler, void *data) +{ + int ret; + MsgHandler *mh; + + qemu_mutex_lock(&handlers_mutex); + QLIST_FOREACH(mh, &msg_handlers, link) { + if (mh->conn_id == conn_id) { + if (handler) { + ret = -EEXIST; + } else { + QLIST_REMOVE_RCU(mh, link); + g_free_rcu(mh, rcu); + ret = 0; + } + goto unlock; + } + } + + if (handler) { + mh = g_new(MsgHandler, 1); + mh->conn_id = conn_id; + mh->handler = handler; + mh->data = data; + QLIST_INSERT_HEAD_RCU(&msg_handlers, mh, link); + ret = 0; + } else { + ret = -ENOENT; + } +unlock: + qemu_mutex_unlock(&handlers_mutex); + return ret; +} + +uint16_t hyperv_hcall_post_message(uint64_t param, bool fast) +{ + uint16_t ret; + hwaddr len; + struct hyperv_post_message_input *msg; + MsgHandler *mh; + + if (fast) { + return HV_STATUS_INVALID_HYPERCALL_CODE; + } + if (param & (__alignof__(*msg) - 1)) { + return HV_STATUS_INVALID_ALIGNMENT; + } + + len = sizeof(*msg); + msg = cpu_physical_memory_map(param, &len, 0); + if (len < sizeof(*msg)) { + ret = HV_STATUS_INSUFFICIENT_MEMORY; + goto unmap; + } + if (msg->payload_size > sizeof(msg->payload)) { + ret = HV_STATUS_INVALID_HYPERCALL_INPUT; + goto unmap; + } + + ret = HV_STATUS_INVALID_CONNECTION_ID; + rcu_read_lock(); + QLIST_FOREACH_RCU(mh, &msg_handlers, link) { + if (mh->conn_id == (msg->connection_id & HV_CONNECTION_ID_MASK)) { + ret = mh->handler(msg, mh->data); + break; + } + } + rcu_read_unlock(); + +unmap: + cpu_physical_memory_unmap(msg, len, 0, 0); + return ret; +} + +static int set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier) +{ + int ret; + EventFlagHandler *handler; + + qemu_mutex_lock(&handlers_mutex); + QLIST_FOREACH(handler, &event_flag_handlers, link) { + if (handler->conn_id == conn_id) { + if (notifier) { + ret = -EEXIST; + } else { + QLIST_REMOVE_RCU(handler, link); + g_free_rcu(handler, rcu); + ret = 0; + } + goto unlock; + } + } + + if (notifier) { + handler = g_new(EventFlagHandler, 1); + handler->conn_id = conn_id; + handler->notifier = notifier; + QLIST_INSERT_HEAD_RCU(&event_flag_handlers, handler, link); + ret = 0; + } else { + ret = -ENOENT; + } +unlock: + qemu_mutex_unlock(&handlers_mutex); + return ret; +} + +static bool process_event_flags_userspace; + +int hyperv_set_event_flag_handler(uint32_t conn_id, EventNotifier *notifier) +{ + if (!process_event_flags_userspace && + !kvm_check_extension(kvm_state, KVM_CAP_HYPERV_EVENTFD)) { + process_event_flags_userspace = true; + + warn_report("Hyper-V event signaling is not supported by this kernel; " + "using slower userspace hypercall processing"); + } + + if (!process_event_flags_userspace) { + struct kvm_hyperv_eventfd hvevfd = { + .conn_id = conn_id, + .fd = notifier ? event_notifier_get_fd(notifier) : -1, + .flags = notifier ? 0 : KVM_HYPERV_EVENTFD_DEASSIGN, + }; + + return kvm_vm_ioctl(kvm_state, KVM_HYPERV_EVENTFD, &hvevfd); + } + return set_event_flag_handler(conn_id, notifier); +} + +uint16_t hyperv_hcall_signal_event(uint64_t param, bool fast) +{ + uint16_t ret; + EventFlagHandler *handler; + + if (unlikely(!fast)) { + hwaddr addr = param; + + if (addr & (__alignof__(addr) - 1)) { + return HV_STATUS_INVALID_ALIGNMENT; + } + + param = ldq_phys(&address_space_memory, addr); + } + + /* + * Per spec, bits 32-47 contain the extra "flag number". However, we + * have no use for it, and in all known usecases it is zero, so just + * report lookup failure if it isn't. + */ + if (param & 0xffff00000000ULL) { + return HV_STATUS_INVALID_PORT_ID; + } + /* remaining bits are reserved-zero */ + if (param & ~HV_CONNECTION_ID_MASK) { + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } + + ret = HV_STATUS_INVALID_CONNECTION_ID; + rcu_read_lock(); + QLIST_FOREACH_RCU(handler, &event_flag_handlers, link) { + if (handler->conn_id == param) { + event_notifier_set(handler->notifier); + ret = 0; + break; + } + } + rcu_read_unlock(); + return ret; +} diff --git a/hw/hyperv/hyperv_testdev.c b/hw/hyperv/hyperv_testdev.c new file mode 100644 index 0000000000..4880333cf5 --- /dev/null +++ b/hw/hyperv/hyperv_testdev.c @@ -0,0 +1,327 @@ +/* + * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests + * + * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com> + * + * Authors: + * Andrey Smetanin <asmetanin@virtuozzo.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "qemu/queue.h" +#include "hw/qdev.h" +#include "hw/isa/isa.h" +#include "hw/hyperv/hyperv.h" + +typedef struct TestSintRoute { + QLIST_ENTRY(TestSintRoute) le; + uint8_t vp_index; + uint8_t sint; + HvSintRoute *sint_route; +} TestSintRoute; + +typedef struct TestMsgConn { + QLIST_ENTRY(TestMsgConn) le; + uint8_t conn_id; + HvSintRoute *sint_route; + struct hyperv_message msg; +} TestMsgConn; + +typedef struct TestEvtConn { + QLIST_ENTRY(TestEvtConn) le; + uint8_t conn_id; + HvSintRoute *sint_route; + EventNotifier notifier; +} TestEvtConn; + +struct HypervTestDev { + ISADevice parent_obj; + MemoryRegion sint_control; + QLIST_HEAD(, TestSintRoute) sint_routes; + QLIST_HEAD(, TestMsgConn) msg_conns; + QLIST_HEAD(, TestEvtConn) evt_conns; +}; +typedef struct HypervTestDev HypervTestDev; + +#define TYPE_HYPERV_TEST_DEV "hyperv-testdev" +#define HYPERV_TEST_DEV(obj) \ + OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV) + +enum { + HV_TEST_DEV_SINT_ROUTE_CREATE = 1, + HV_TEST_DEV_SINT_ROUTE_DESTROY, + HV_TEST_DEV_SINT_ROUTE_SET_SINT, + HV_TEST_DEV_MSG_CONN_CREATE, + HV_TEST_DEV_MSG_CONN_DESTROY, + HV_TEST_DEV_EVT_CONN_CREATE, + HV_TEST_DEV_EVT_CONN_DESTROY, +}; + +static void sint_route_create(HypervTestDev *dev, + uint8_t vp_index, uint8_t sint) +{ + TestSintRoute *sint_route; + + sint_route = g_new0(TestSintRoute, 1); + assert(sint_route); + + sint_route->vp_index = vp_index; + sint_route->sint = sint; + + sint_route->sint_route = hyperv_sint_route_new(vp_index, sint, NULL, NULL); + assert(sint_route->sint_route); + + QLIST_INSERT_HEAD(&dev->sint_routes, sint_route, le); +} + +static TestSintRoute *sint_route_find(HypervTestDev *dev, + uint8_t vp_index, uint8_t sint) +{ + TestSintRoute *sint_route; + + QLIST_FOREACH(sint_route, &dev->sint_routes, le) { + if (sint_route->vp_index == vp_index && sint_route->sint == sint) { + return sint_route; + } + } + assert(false); + return NULL; +} + +static void sint_route_destroy(HypervTestDev *dev, + uint8_t vp_index, uint8_t sint) +{ + TestSintRoute *sint_route; + + sint_route = sint_route_find(dev, vp_index, sint); + QLIST_REMOVE(sint_route, le); + hyperv_sint_route_unref(sint_route->sint_route); + g_free(sint_route); +} + +static void sint_route_set_sint(HypervTestDev *dev, + uint8_t vp_index, uint8_t sint) +{ + TestSintRoute *sint_route; + + sint_route = sint_route_find(dev, vp_index, sint); + + hyperv_sint_route_set_sint(sint_route->sint_route); +} + +static void msg_retry(void *opaque) +{ + TestMsgConn *conn = opaque; + assert(!hyperv_post_msg(conn->sint_route, &conn->msg)); +} + +static void msg_cb(void *data, int status) +{ + TestMsgConn *conn = data; + + if (!status) { + return; + } + + assert(status == -EAGAIN); + + aio_bh_schedule_oneshot(qemu_get_aio_context(), msg_retry, conn); +} + +static uint16_t msg_handler(const struct hyperv_post_message_input *msg, + void *data) +{ + int ret; + TestMsgConn *conn = data; + + /* post the same message we've got */ + conn->msg.header.message_type = msg->message_type; + assert(msg->payload_size < sizeof(conn->msg.payload)); + conn->msg.header.payload_size = msg->payload_size; + memcpy(&conn->msg.payload, msg->payload, msg->payload_size); + + ret = hyperv_post_msg(conn->sint_route, &conn->msg); + + switch (ret) { + case 0: + return HV_STATUS_SUCCESS; + case -EAGAIN: + return HV_STATUS_INSUFFICIENT_BUFFERS; + default: + return HV_STATUS_INVALID_HYPERCALL_INPUT; + } +} + +static void msg_conn_create(HypervTestDev *dev, uint8_t vp_index, + uint8_t sint, uint8_t conn_id) +{ + TestMsgConn *conn; + + conn = g_new0(TestMsgConn, 1); + assert(conn); + + conn->conn_id = conn_id; + + conn->sint_route = hyperv_sint_route_new(vp_index, sint, msg_cb, conn); + assert(conn->sint_route); + + assert(!hyperv_set_msg_handler(conn->conn_id, msg_handler, conn)); + + QLIST_INSERT_HEAD(&dev->msg_conns, conn, le); +} + +static void msg_conn_destroy(HypervTestDev *dev, uint8_t conn_id) +{ + TestMsgConn *conn; + + QLIST_FOREACH(conn, &dev->msg_conns, le) { + if (conn->conn_id == conn_id) { + QLIST_REMOVE(conn, le); + hyperv_set_msg_handler(conn->conn_id, NULL, NULL); + hyperv_sint_route_unref(conn->sint_route); + g_free(conn); + return; + } + } + assert(false); +} + +static void evt_conn_handler(EventNotifier *notifier) +{ + TestEvtConn *conn = container_of(notifier, TestEvtConn, notifier); + + event_notifier_test_and_clear(notifier); + + /* signal the same event flag we've got */ + assert(!hyperv_set_event_flag(conn->sint_route, conn->conn_id)); +} + +static void evt_conn_create(HypervTestDev *dev, uint8_t vp_index, + uint8_t sint, uint8_t conn_id) +{ + TestEvtConn *conn; + + conn = g_new0(TestEvtConn, 1); + assert(conn); + + conn->conn_id = conn_id; + + conn->sint_route = hyperv_sint_route_new(vp_index, sint, NULL, NULL); + assert(conn->sint_route); + + assert(!event_notifier_init(&conn->notifier, false)); + + event_notifier_set_handler(&conn->notifier, evt_conn_handler); + + assert(!hyperv_set_event_flag_handler(conn_id, &conn->notifier)); + + QLIST_INSERT_HEAD(&dev->evt_conns, conn, le); +} + +static void evt_conn_destroy(HypervTestDev *dev, uint8_t conn_id) +{ + TestEvtConn *conn; + + QLIST_FOREACH(conn, &dev->evt_conns, le) { + if (conn->conn_id == conn_id) { + QLIST_REMOVE(conn, le); + hyperv_set_event_flag_handler(conn->conn_id, NULL); + event_notifier_set_handler(&conn->notifier, NULL); + event_notifier_cleanup(&conn->notifier); + hyperv_sint_route_unref(conn->sint_route); + g_free(conn); + return; + } + } + assert(false); +} + +static uint64_t hv_test_dev_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void hv_test_dev_write(void *opaque, hwaddr addr, uint64_t data, + uint32_t len) +{ + HypervTestDev *dev = HYPERV_TEST_DEV(opaque); + uint8_t sint = data & 0xFF; + uint8_t vp_index = (data >> 8ULL) & 0xFF; + uint8_t ctl = (data >> 16ULL) & 0xFF; + uint8_t conn_id = (data >> 24ULL) & 0xFF; + + switch (ctl) { + case HV_TEST_DEV_SINT_ROUTE_CREATE: + sint_route_create(dev, vp_index, sint); + break; + case HV_TEST_DEV_SINT_ROUTE_DESTROY: + sint_route_destroy(dev, vp_index, sint); + break; + case HV_TEST_DEV_SINT_ROUTE_SET_SINT: + sint_route_set_sint(dev, vp_index, sint); + break; + case HV_TEST_DEV_MSG_CONN_CREATE: + msg_conn_create(dev, vp_index, sint, conn_id); + break; + case HV_TEST_DEV_MSG_CONN_DESTROY: + msg_conn_destroy(dev, conn_id); + break; + case HV_TEST_DEV_EVT_CONN_CREATE: + evt_conn_create(dev, vp_index, sint, conn_id); + break; + case HV_TEST_DEV_EVT_CONN_DESTROY: + evt_conn_destroy(dev, conn_id); + break; + default: + break; + } +} + +static const MemoryRegionOps synic_test_sint_ops = { + .read = hv_test_dev_read, + .write = hv_test_dev_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void hv_test_dev_realizefn(DeviceState *d, Error **errp) +{ + ISADevice *isa = ISA_DEVICE(d); + HypervTestDev *dev = HYPERV_TEST_DEV(d); + MemoryRegion *io = isa_address_space_io(isa); + + QLIST_INIT(&dev->sint_routes); + QLIST_INIT(&dev->msg_conns); + QLIST_INIT(&dev->evt_conns); + memory_region_init_io(&dev->sint_control, OBJECT(dev), + &synic_test_sint_ops, dev, + "hyperv-testdev-ctl", 4); + memory_region_add_subregion(io, 0x3000, &dev->sint_control); +} + +static void hv_test_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->realize = hv_test_dev_realizefn; +} + +static const TypeInfo hv_test_dev_info = { + .name = TYPE_HYPERV_TEST_DEV, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(HypervTestDev), + .class_init = hv_test_dev_class_init, +}; + +static void hv_test_dev_register_types(void) +{ + type_register_static(&hv_test_dev_info); +} +type_init(hv_test_dev_register_types); diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c index bec0c91e2d..be34fe072c 100644 --- a/hw/i2c/i2c-ddc.c +++ b/hw/i2c/i2c-ddc.c @@ -32,197 +32,6 @@ } \ } while (0) -/* Structure defining a monitor's characteristics in a - * readable format: this should be passed to build_edid_blob() - * to convert it into the 128 byte binary EDID blob. - * Not all bits of the EDID are customisable here. - */ -struct EDIDData { - char manuf_id[3]; /* three upper case letters */ - uint16_t product_id; - uint32_t serial_no; - uint8_t manuf_week; - int manuf_year; - uint8_t h_cm; - uint8_t v_cm; - uint8_t gamma; - char monitor_name[14]; - char serial_no_string[14]; - /* Range limits */ - uint8_t vmin; /* Hz */ - uint8_t vmax; /* Hz */ - uint8_t hmin; /* kHz */ - uint8_t hmax; /* kHz */ - uint8_t pixclock; /* MHz / 10 */ - uint8_t timing_data[18]; -}; - -typedef struct EDIDData EDIDData; - -/* EDID data for a simple LCD monitor */ -static const EDIDData lcd_edid = { - /* The manuf_id ought really to be an assigned EISA ID */ - .manuf_id = "QMU", - .product_id = 0, - .serial_no = 1, - .manuf_week = 1, - .manuf_year = 2011, - .h_cm = 40, - .v_cm = 30, - .gamma = 0x78, - .monitor_name = "QEMU monitor", - .serial_no_string = "1", - .vmin = 40, - .vmax = 120, - .hmin = 30, - .hmax = 100, - .pixclock = 18, - .timing_data = { - /* Borrowed from a 21" LCD */ - 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, - 0xc0, 0x13, 0x00, 0x98, 0x32, 0x11, 0x00, 0x00, 0x1e - } -}; - -static uint8_t manuf_char_to_int(char c) -{ - return (c - 'A') & 0x1f; -} - -static void write_ascii_descriptor_block(uint8_t *descblob, uint8_t blocktype, - const char *string) -{ - /* Write an EDID Descriptor Block of the "ascii string" type */ - int i; - descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0; - descblob[3] = blocktype; - /* The rest is 13 bytes of ASCII; if less then the rest must - * be filled with newline then spaces - */ - for (i = 5; i < 19; i++) { - descblob[i] = string[i - 5]; - if (!descblob[i]) { - break; - } - } - if (i < 19) { - descblob[i++] = '\n'; - } - for ( ; i < 19; i++) { - descblob[i] = ' '; - } -} - -static void write_range_limits_descriptor(const EDIDData *edid, - uint8_t *descblob) -{ - int i; - descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0; - descblob[3] = 0xfd; - descblob[5] = edid->vmin; - descblob[6] = edid->vmax; - descblob[7] = edid->hmin; - descblob[8] = edid->hmax; - descblob[9] = edid->pixclock; - descblob[10] = 0; - descblob[11] = 0xa; - for (i = 12; i < 19; i++) { - descblob[i] = 0x20; - } -} - -static void build_edid_blob(const EDIDData *edid, uint8_t *blob) -{ - /* Write an EDID 1.3 format blob (128 bytes) based - * on the EDIDData structure. - */ - int i; - uint8_t cksum; - - /* 00-07 : header */ - blob[0] = blob[7] = 0; - for (i = 1 ; i < 7; i++) { - blob[i] = 0xff; - } - /* 08-09 : manufacturer ID */ - blob[8] = (manuf_char_to_int(edid->manuf_id[0]) << 2) - | (manuf_char_to_int(edid->manuf_id[1]) >> 3); - blob[9] = (manuf_char_to_int(edid->manuf_id[1]) << 5) - | manuf_char_to_int(edid->manuf_id[2]); - /* 10-11 : product ID code */ - blob[10] = edid->product_id; - blob[11] = edid->product_id >> 8; - blob[12] = edid->serial_no; - blob[13] = edid->serial_no >> 8; - blob[14] = edid->serial_no >> 16; - blob[15] = edid->serial_no >> 24; - /* 16 : week of manufacture */ - blob[16] = edid->manuf_week; - /* 17 : year of manufacture - 1990 */ - blob[17] = edid->manuf_year - 1990; - /* 18, 19 : EDID version and revision */ - blob[18] = 1; - blob[19] = 3; - /* 20 - 24 : basic display parameters */ - /* We are always a digital display */ - blob[20] = 0x80; - /* 21, 22 : max h/v size in cm */ - blob[21] = edid->h_cm; - blob[22] = edid->v_cm; - /* 23 : gamma (divide by 100 then add 1 for actual value) */ - blob[23] = edid->gamma; - /* 24 feature support: no power management, RGB, preferred timing mode, - * standard colour space - */ - blob[24] = 0x0e; - /* 25 - 34 : chromaticity coordinates. These are the - * standard sRGB chromaticity values - */ - blob[25] = 0xee; - blob[26] = 0x91; - blob[27] = 0xa3; - blob[28] = 0x54; - blob[29] = 0x4c; - blob[30] = 0x99; - blob[31] = 0x26; - blob[32] = 0x0f; - blob[33] = 0x50; - blob[34] = 0x54; - /* 35, 36 : Established timings: claim to support everything */ - blob[35] = blob[36] = 0xff; - /* 37 : manufacturer's reserved timing: none */ - blob[37] = 0; - /* 38 - 53 : standard timing identification - * don't claim anything beyond what the 'established timings' - * already provide. Unused slots must be (0x1, 0x1) - */ - for (i = 38; i < 54; i++) { - blob[i] = 0x1; - } - /* 54 - 71 : descriptor block 1 : must be preferred timing data */ - memcpy(blob + 54, edid->timing_data, 18); - /* 72 - 89, 90 - 107, 108 - 125 : descriptor block 2, 3, 4 - * Order not important, but we must have a monitor name and a - * range limits descriptor. - */ - write_range_limits_descriptor(edid, blob + 72); - write_ascii_descriptor_block(blob + 90, 0xfc, edid->monitor_name); - write_ascii_descriptor_block(blob + 108, 0xff, edid->serial_no_string); - - /* 126 : extension flag */ - blob[126] = 0; - - cksum = 0; - for (i = 0; i < 127; i++) { - cksum += blob[i]; - } - /* 127 : checksum */ - blob[127] = -cksum; - if (DEBUG_I2CDDC) { - qemu_hexdump((char *)blob, stdout, "", 128); - } -} - static void i2c_ddc_reset(DeviceState *ds) { I2CDDCState *s = I2CDDC(ds); @@ -270,7 +79,8 @@ static int i2c_ddc_tx(I2CSlave *i2c, uint8_t data) static void i2c_ddc_init(Object *obj) { I2CDDCState *s = I2CDDC(obj); - build_edid_blob(&lcd_edid, s->edid_blob); + + qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info); } static const VMStateDescription vmstate_i2c_ddc = { @@ -283,6 +93,11 @@ static const VMStateDescription vmstate_i2c_ddc = { } }; +static Property i2c_ddc_properties[] = { + DEFINE_EDID_PROPERTIES(I2CDDCState, edid_info), + DEFINE_PROP_END_OF_LIST(), +}; + static void i2c_ddc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -290,6 +105,7 @@ static void i2c_ddc_class_init(ObjectClass *oc, void *data) dc->reset = i2c_ddc_reset; dc->vmsd = &vmstate_i2c_ddc; + dc->props = i2c_ddc_properties; isc->event = i2c_ddc_event; isc->recv = i2c_ddc_rx; isc->send = i2c_ddc_tx; diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 0bf1c60a06..25ea783bec 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -147,6 +147,15 @@ static void kvm_update_clock(KVMClockState *s) s->clock_is_reliable = kvm_has_adjust_clock_stable(); } +static void do_kvmclock_ctrl(CPUState *cpu, run_on_cpu_data data) +{ + int ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0); + + if (ret && ret != -EINVAL) { + fprintf(stderr, "%s: %s\n", __func__, strerror(-ret)); + } +} + static void kvmclock_vm_state_change(void *opaque, int running, RunState state) { @@ -183,13 +192,7 @@ static void kvmclock_vm_state_change(void *opaque, int running, return; } CPU_FOREACH(cpu) { - ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0); - if (ret) { - if (ret != -EINVAL) { - fprintf(stderr, "%s: %s\n", __func__, strerror(-ret)); - } - return; - } + run_on_cpu(cpu, do_kvmclock_ctrl, RUN_ON_CPU_NULL); } } else { diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 03148450c8..f095725dba 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -838,7 +838,8 @@ static void load_linux(PCMachineState *pcms, FWCfgState *fw_cfg) { uint16_t protocol; - int setup_size, kernel_size, initrd_size = 0, cmdline_size; + int setup_size, kernel_size, cmdline_size; + int64_t initrd_size = 0; int dtb_size, setup_data_offset; uint32_t initrd_max; uint8_t header[8192], *setup, *kernel, *initrd_data; @@ -974,6 +975,10 @@ static void load_linux(PCMachineState *pcms, fprintf(stderr, "qemu: error reading initrd %s: %s\n", initrd_filename, strerror(errno)); exit(1); + } else if (initrd_size >= initrd_max) { + fprintf(stderr, "qemu: initrd is too large, cannot support." + "(max: %"PRIu32", need %"PRId64")\n", initrd_max, initrd_size); + exit(1); } initrd_addr = (initrd_max-initrd_size) & ~4095; @@ -1699,7 +1704,7 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } - pc_dimm_pre_plug(dev, MACHINE(hotplug_dev), + pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), pcmc->enforce_aligned_dimm ? NULL : &legacy_align, errp); } @@ -1711,7 +1716,7 @@ static void pc_memory_plug(HotplugHandler *hotplug_dev, PCMachineState *pcms = PC_MACHINE(hotplug_dev); bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM); - pc_dimm_plug(dev, MACHINE(pcms), &local_err); + pc_dimm_plug(PC_DIMM(dev), MACHINE(pcms), &local_err); if (local_err) { goto out; } @@ -1771,7 +1776,7 @@ static void pc_memory_unplug(HotplugHandler *hotplug_dev, goto out; } - pc_dimm_unplug(dev, MACHINE(pcms)); + pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms)); object_unparent(OBJECT(dev)); out: @@ -2204,8 +2209,9 @@ static void pc_machine_set_nvdimm_persistence(Object *obj, const char *value, else if (strcmp(value, "mem-ctrl") == 0) nvdimm_state->persistence = 2; else { - error_report("-machine nvdimm-persistence=%s: unsupported option", value); - exit(EXIT_FAILURE); + error_setg(errp, "-machine nvdimm-persistence=%s: unsupported option", + value); + return; } g_free(nvdimm_state->persistence_string); diff --git a/hw/ide/core.c b/hw/ide/core.c index 2c62efc536..04e22e751d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -35,6 +35,7 @@ #include "sysemu/block-backend.h" #include "qapi/error.h" #include "qemu/cutils.h" +#include "sysemu/replay.h" #include "hw/ide/internal.h" #include "trace.h" @@ -479,7 +480,7 @@ static void ide_issue_trim_cb(void *opaque, int ret) done: iocb->aiocb = NULL; if (iocb->bh) { - qemu_bh_schedule(iocb->bh); + replay_bh_schedule_event(iocb->bh); } } diff --git a/hw/input/ps2.c b/hw/input/ps2.c index fdfcadf9a1..6c43fc2912 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -914,7 +914,12 @@ static void ps2_common_post_load(PS2State *s) uint8_t tmp_data[PS2_QUEUE_SIZE]; /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ - size = (q->count < 0 || q->count > PS2_QUEUE_SIZE) ? 0 : q->count; + size = q->count; + if (q->count < 0) { + size = 0; + } else if (q->count > PS2_QUEUE_SIZE) { + size = PS2_QUEUE_SIZE; + } /* move the queue elements to the start of data array */ for (i = 0; i < size; i++) { @@ -929,7 +934,6 @@ static void ps2_common_post_load(PS2State *s) q->rptr = 0; q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size; q->count = size; - s->update_irq(s->update_arg, q->count != 0); } static void ps2_kbd_reset(void *opaque) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 0d816fdd2c..0beefb05d4 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1055,17 +1055,17 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) case 0xd5c: /* MMFR3. */ return cpu->id_mmfr3; case 0xd60: /* ISAR0. */ - return cpu->id_isar0; + return cpu->isar.id_isar0; case 0xd64: /* ISAR1. */ - return cpu->id_isar1; + return cpu->isar.id_isar1; case 0xd68: /* ISAR2. */ - return cpu->id_isar2; + return cpu->isar.id_isar2; case 0xd6c: /* ISAR3. */ - return cpu->id_isar3; + return cpu->isar.id_isar3; case 0xd70: /* ISAR4. */ - return cpu->id_isar4; + return cpu->isar.id_isar4; case 0xd74: /* ISAR5. */ - return cpu->id_isar5; + return cpu->isar.id_isar5; case 0xd78: /* CLIDR */ return cpu->clidr; case 0xd7c: /* CTR */ diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index b6896ac4ce..4e529729b4 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -21,7 +21,7 @@ */ #include "qemu/osdep.h" -#include "qemu/error-report.h" +#include "qapi/error.h" #include "monitor/monitor.h" #include "hw/hw.h" #include "hw/i386/pc.h" @@ -393,9 +393,9 @@ static void ioapic_realize(DeviceState *dev, Error **errp) IOAPICCommonState *s = IOAPIC_COMMON(dev); if (s->version != 0x11 && s->version != 0x20) { - error_report("IOAPIC only supports version 0x11 or 0x20 " - "(default: 0x%x).", IOAPIC_VER_DEF); - exit(1); + error_setg(errp, "IOAPIC only supports version 0x11 or 0x20 " + "(default: 0x%x).", IOAPIC_VER_DEF); + return; } memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, diff --git a/hw/intc/xics.c b/hw/intc/xics.c index c90c893228..406efee064 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -320,8 +320,9 @@ static void icp_realize(DeviceState *dev, Error **errp) obj = object_property_get_link(OBJECT(dev), ICP_PROP_XICS, &err); if (!obj) { - error_propagate(errp, err); - error_prepend(errp, "required link '" ICP_PROP_XICS "' not found: "); + error_propagate_prepend(errp, err, + "required link '" ICP_PROP_XICS + "' not found: "); return; } @@ -329,8 +330,9 @@ static void icp_realize(DeviceState *dev, Error **errp) obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err); if (!obj) { - error_propagate(errp, err); - error_prepend(errp, "required link '" ICP_PROP_CPU "' not found: "); + error_propagate_prepend(errp, err, + "required link '" ICP_PROP_CPU + "' not found: "); return; } @@ -624,8 +626,9 @@ static void ics_base_realize(DeviceState *dev, Error **errp) obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err); if (!obj) { - error_propagate(errp, err); - error_prepend(errp, "required link '" ICS_PROP_XICS "' not found: "); + error_propagate_prepend(errp, err, + "required link '" ICS_PROP_XICS + "' not found: "); return; } ics->xics = XICS_FABRIC(obj); diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 30c3769a20..e8fa9a53ae 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -198,17 +198,12 @@ static void ics_get_kvm_state(ICSState *ics) { uint64_t state; int i; - Error *local_err = NULL; for (i = 0; i < ics->nr_irqs; i++) { ICSIRQState *irq = &ics->irqs[i]; kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, - i + ics->offset, &state, false, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } + i + ics->offset, &state, false, &error_fatal); irq->server = state & KVM_XICS_DESTINATION_MASK; irq->saved_priority = (state >> KVM_XICS_PRIORITY_SHIFT) diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs index 83e06f6c04..9e106df186 100644 --- a/hw/isa/Makefile.objs +++ b/hw/isa/Makefile.objs @@ -1,9 +1,10 @@ common-obj-$(CONFIG_ISA_BUS) += isa-bus.o -common-obj-$(CONFIG_ISA_BUS) += isa-superio.o smc37c669-superio.o +common-obj-$(CONFIG_ISA_BUS) += isa-superio.o common-obj-$(CONFIG_APM) += apm.o common-obj-$(CONFIG_I82378) += i82378.o common-obj-$(CONFIG_PC87312) += pc87312.o common-obj-$(CONFIG_PIIX4) += piix4.o common-obj-$(CONFIG_VT82C686) += vt82c686.o +common-obj-$(CONFIG_SMC37C669) += smc37c669-superio.o obj-$(CONFIG_LPC_ICH9) += lpc_ich9.o diff --git a/hw/mem/Makefile.objs b/hw/mem/Makefile.objs index 10be4df2a2..3e2f7c5ca2 100644 --- a/hw/mem/Makefile.objs +++ b/hw/mem/Makefile.objs @@ -1,3 +1,3 @@ -common-obj-$(CONFIG_MEM_HOTPLUG) += pc-dimm.o -common-obj-$(CONFIG_MEM_HOTPLUG) += memory-device.o +common-obj-$(CONFIG_DIMM) += pc-dimm.o +common-obj-$(CONFIG_MEM_DEVICE) += memory-device.o common-obj-$(CONFIG_NVDIMM) += nvdimm.o diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 6de4f70bb4..7de1ccd497 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -17,6 +17,7 @@ #include "qemu/range.h" #include "hw/virtio/vhost.h" #include "sysemu/kvm.h" +#include "trace.h" static gint memory_device_addr_sort(gconstpointer a, gconstpointer b) { @@ -57,10 +58,9 @@ static int memory_device_used_region_size(Object *obj, void *opaque) if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) { const DeviceState *dev = DEVICE(obj); const MemoryDeviceState *md = MEMORY_DEVICE(obj); - const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj); if (dev->realized) { - *size += mdc->get_region_size(md); + *size += memory_device_get_region_size(md, &error_abort); } } @@ -87,16 +87,17 @@ static void memory_device_check_addable(MachineState *ms, uint64_t size, memory_device_used_region_size(OBJECT(ms), &used_region_size); if (used_region_size + size > ms->maxram_size - ms->ram_size) { error_setg(errp, "not enough space, currently 0x%" PRIx64 - " in use of total hot pluggable 0x" RAM_ADDR_FMT, + " in use of total space for memory devices 0x" RAM_ADDR_FMT, used_region_size, ms->maxram_size - ms->ram_size); return; } } -uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, - uint64_t align, uint64_t size, - Error **errp) +static uint64_t memory_device_get_free_addr(MachineState *ms, + const uint64_t *hint, + uint64_t align, uint64_t size, + Error **errp) { uint64_t address_space_start, address_space_end; GSList *list = NULL, *item; @@ -120,7 +121,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, /* address_space_start indicates the maximum alignment we expect */ if (QEMU_ALIGN_UP(address_space_start, align) != address_space_start) { - error_setg(errp, "the alignment (0%" PRIx64 ") is not supported", + error_setg(errp, "the alignment (0x%" PRIx64 ") is not supported", align); return 0; } @@ -145,11 +146,12 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, if (hint) { new_addr = *hint; if (new_addr < address_space_start) { - error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64 - "] at 0x%" PRIx64, new_addr, size, address_space_start); + error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64 + "] before 0x%" PRIx64, new_addr, size, + address_space_start); return 0; } else if ((new_addr + size) > address_space_end) { - error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64 + error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64 "] beyond 0x%" PRIx64, new_addr, size, address_space_end); return 0; @@ -166,15 +168,13 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, uint64_t md_size, md_addr; md_addr = mdc->get_addr(md); - md_size = mdc->get_region_size(md); - if (*errp) { - goto out; - } + md_size = memory_device_get_region_size(md, &error_abort); if (ranges_overlap(md_addr, md_size, new_addr, size)) { if (hint) { const DeviceState *d = DEVICE(md); - error_setg(errp, "address range conflicts with '%s'", d->id); + error_setg(errp, "address range conflicts with memory device" + " id='%s'", d->id ? d->id : "(unnamed)"); goto out; } new_addr = QEMU_ALIGN_UP(md_addr + md_size, align); @@ -232,7 +232,7 @@ static int memory_device_plugged_size(Object *obj, void *opaque) const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj); if (dev->realized) { - *size += mdc->get_plugged_size(md); + *size += mdc->get_plugged_size(md, &error_abort); } } @@ -249,22 +249,83 @@ uint64_t get_plugged_memory_size(void) return size; } -void memory_device_plug_region(MachineState *ms, MemoryRegion *mr, - uint64_t addr) +void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms, + const uint64_t *legacy_align, Error **errp) +{ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + Error *local_err = NULL; + uint64_t addr, align; + MemoryRegion *mr; + + mr = mdc->get_memory_region(md, &local_err); + if (local_err) { + goto out; + } + + align = legacy_align ? *legacy_align : memory_region_get_alignment(mr); + addr = mdc->get_addr(md); + addr = memory_device_get_free_addr(ms, !addr ? NULL : &addr, align, + memory_region_size(mr), &local_err); + if (local_err) { + goto out; + } + mdc->set_addr(md, addr, &local_err); + if (!local_err) { + trace_memory_device_pre_plug(DEVICE(md)->id ? DEVICE(md)->id : "", + addr); + } +out: + error_propagate(errp, local_err); +} + +void memory_device_plug(MemoryDeviceState *md, MachineState *ms) { - /* we expect a previous call to memory_device_get_free_addr() */ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + const uint64_t addr = mdc->get_addr(md); + MemoryRegion *mr; + + /* + * We expect that a previous call to memory_device_pre_plug() succeeded, so + * it can't fail at this point. + */ + mr = mdc->get_memory_region(md, &error_abort); g_assert(ms->device_memory); memory_region_add_subregion(&ms->device_memory->mr, addr - ms->device_memory->base, mr); + trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "", addr); } -void memory_device_unplug_region(MachineState *ms, MemoryRegion *mr) +void memory_device_unplug(MemoryDeviceState *md, MachineState *ms) { - /* we expect a previous call to memory_device_get_free_addr() */ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + MemoryRegion *mr; + + /* + * We expect that a previous call to memory_device_pre_plug() succeeded, so + * it can't fail at this point. + */ + mr = mdc->get_memory_region(md, &error_abort); g_assert(ms->device_memory); memory_region_del_subregion(&ms->device_memory->mr, mr); + trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "", + mdc->get_addr(md)); +} + +uint64_t memory_device_get_region_size(const MemoryDeviceState *md, + Error **errp) +{ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + MemoryRegion *mr; + + /* dropping const here is fine as we don't touch the memory region */ + mr = mdc->get_memory_region((MemoryDeviceState *)md, errp); + if (!mr) { + return 0; + } + + return memory_region_size(mr); } static const TypeInfo memory_device_info = { diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 1c6674c4ed..49324f3fae 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/mem/nvdimm.h" +#include "hw/mem/memory-device.h" static void nvdimm_get_label_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -118,9 +119,10 @@ static void nvdimm_prepare_memory_region(NVDIMMDevice *nvdimm, Error **errp) nvdimm->nvdimm_mr->align = align; } -static MemoryRegion *nvdimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) +static MemoryRegion *nvdimm_md_get_memory_region(MemoryDeviceState *md, + Error **errp) { - NVDIMMDevice *nvdimm = NVDIMM(dimm); + NVDIMMDevice *nvdimm = NVDIMM(md); Error *local_err = NULL; if (!nvdimm->nvdimm_mr) { @@ -190,11 +192,12 @@ static Property nvdimm_properties[] = { static void nvdimm_class_init(ObjectClass *oc, void *data) { PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); + MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); NVDIMMClass *nvc = NVDIMM_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); ddc->realize = nvdimm_realize; - ddc->get_memory_region = nvdimm_get_memory_region; + mdc->get_memory_region = nvdimm_md_get_memory_region; dc->props = nvdimm_properties; nvc->read_label_data = nvdimm_read_label_data; diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index fb6bcaedc4..0c9b9e8292 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -29,72 +29,47 @@ static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp); -void pc_dimm_pre_plug(DeviceState *dev, MachineState *machine, +void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, const uint64_t *legacy_align, Error **errp) { - PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); Error *local_err = NULL; - MemoryRegion *mr; - uint64_t addr, align; int slot; - slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, + slot = object_property_get_int(OBJECT(dimm), PC_DIMM_SLOT_PROP, &error_abort); slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot, machine->ram_slots, &local_err); if (local_err) { goto out; } - object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &error_abort); + object_property_set_int(OBJECT(dimm), slot, PC_DIMM_SLOT_PROP, + &error_abort); trace_mhp_pc_dimm_assigned_slot(slot); - mr = ddc->get_memory_region(dimm, &local_err); - if (local_err) { - goto out; - } - - align = legacy_align ? *legacy_align : memory_region_get_alignment(mr); - addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP, - &error_abort); - addr = memory_device_get_free_addr(machine, !addr ? NULL : &addr, align, - memory_region_size(mr), &local_err); - if (local_err) { - goto out; - } - trace_mhp_pc_dimm_assigned_address(addr); - object_property_set_uint(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, - &error_abort); + memory_device_pre_plug(MEMORY_DEVICE(dimm), machine, legacy_align, + &local_err); out: error_propagate(errp, local_err); } -void pc_dimm_plug(DeviceState *dev, MachineState *machine, Error **errp) +void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine, Error **errp) { - PCDIMMDevice *dimm = PC_DIMM(dev); PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm, &error_abort); - MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort); - uint64_t addr; - - addr = object_property_get_uint(OBJECT(dev), PC_DIMM_ADDR_PROP, - &error_abort); - memory_device_plug_region(machine, mr, addr); - vmstate_register_ram(vmstate_mr, dev); + memory_device_plug(MEMORY_DEVICE(dimm), machine); + vmstate_register_ram(vmstate_mr, DEVICE(dimm)); } -void pc_dimm_unplug(DeviceState *dev, MachineState *machine) +void pc_dimm_unplug(PCDIMMDevice *dimm, MachineState *machine) { - PCDIMMDevice *dimm = PC_DIMM(dev); PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm, &error_abort); - MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort); - memory_device_unplug_region(machine, mr); - vmstate_unregister_ram(vmstate_mr, dev); + memory_device_unplug(MEMORY_DEVICE(dimm), machine); + vmstate_unregister_ram(vmstate_mr, DEVICE(dimm)); } static int pc_dimm_slot2bitmap(Object *obj, void *opaque) @@ -163,16 +138,14 @@ static Property pc_dimm_properties[] = { static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { + Error *local_err = NULL; uint64_t value; - MemoryRegion *mr; - PCDIMMDevice *dimm = PC_DIMM(obj); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(obj); - mr = ddc->get_memory_region(dimm, errp); - if (!mr) { + value = memory_device_get_region_size(MEMORY_DEVICE(obj), &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } - value = memory_region_size(mr); visit_type_uint64(v, name, &value, errp); } @@ -236,19 +209,16 @@ static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md) return dimm->addr; } -static uint64_t pc_dimm_md_get_region_size(const MemoryDeviceState *md) +static void pc_dimm_md_set_addr(MemoryDeviceState *md, uint64_t addr, + Error **errp) { - /* dropping const here is fine as we don't touch the memory region */ - PCDIMMDevice *dimm = PC_DIMM(md); - const PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(md); - MemoryRegion *mr; - - mr = ddc->get_memory_region(dimm, &error_abort); - if (!mr) { - return 0; - } + object_property_set_uint(OBJECT(md), addr, PC_DIMM_ADDR_PROP, errp); +} - return memory_region_size(mr); +static MemoryRegion *pc_dimm_md_get_memory_region(MemoryDeviceState *md, + Error **errp) +{ + return pc_dimm_get_memory_region(PC_DIMM(md), errp); } static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md, @@ -292,13 +262,13 @@ static void pc_dimm_class_init(ObjectClass *oc, void *data) dc->props = pc_dimm_properties; dc->desc = "DIMM memory module"; - ddc->get_memory_region = pc_dimm_get_memory_region; ddc->get_vmstate_memory_region = pc_dimm_get_memory_region; mdc->get_addr = pc_dimm_md_get_addr; + mdc->set_addr = pc_dimm_md_set_addr; /* for a dimm plugged_size == region_size */ - mdc->get_plugged_size = pc_dimm_md_get_region_size; - mdc->get_region_size = pc_dimm_md_get_region_size; + mdc->get_plugged_size = memory_device_get_region_size; + mdc->get_memory_region = pc_dimm_md_get_memory_region; mdc->fill_device_info = pc_dimm_md_fill_device_info; } diff --git a/hw/mem/trace-events b/hw/mem/trace-events index e150dcc497..0f2f278ff2 100644 --- a/hw/mem/trace-events +++ b/hw/mem/trace-events @@ -2,4 +2,7 @@ # hw/mem/pc-dimm.c mhp_pc_dimm_assigned_slot(int slot) "%d" -mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64 +# hw/mem/memory-device.c +memory_device_pre_plug(const char *id, uint64_t addr) "id=%s addr=0x%"PRIx64 +memory_device_plug(const char *id, uint64_t addr) "id=%s addr=0x%"PRIx64 +memory_device_unplug(const char *id, uint64_t addr) "id=%s addr=0x%"PRIx64 diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 24ad0ad024..1cd8aac658 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -992,9 +992,9 @@ static void gt64120_pci_set_irq(void *opaque, int irq_num, int level) } -static void gt64120_reset(void *opaque) +static void gt64120_reset(DeviceState *dev) { - GT64120State *s = opaque; + GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev); /* FIXME: Malta specific hw assumptions ahead */ @@ -1184,16 +1184,6 @@ PCIBus *gt64120_register(qemu_irq *pic) return phb->bus; } -static int gt64120_init(SysBusDevice *dev) -{ - GT64120State *s; - - s = GT64120_PCI_HOST_BRIDGE(dev); - - qemu_register_reset(gt64120_reset, s); - return 0; -} - static void gt64120_pci_realize(PCIDevice *d, Error **errp) { /* FIXME: Malta specific hw assumptions ahead */ @@ -1241,9 +1231,9 @@ static const TypeInfo gt64120_pci_info = { static void gt64120_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - sdc->init = gt64120_init; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->reset = gt64120_reset; dc->vmsd = &vmstate_gt64120; } diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index c1694c8254..2fbba32c48 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -104,9 +104,9 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, static int64_t load_kernel (CPUMIPSState *env) { - int64_t kernel_entry, kernel_low, kernel_high; + int64_t kernel_entry, kernel_low, kernel_high, initrd_size; int index = 0; - long kernel_size, initrd_size; + long kernel_size; ram_addr_t initrd_offset; uint32_t *prom_buf; long prom_size; @@ -150,7 +150,7 @@ static int64_t load_kernel (CPUMIPSState *env) prom_set(prom_buf, index++, "%s", loaderparams.kernel_filename); if (initrd_size > 0) { - prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", + prom_set(prom_buf, index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s", cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 40041d5ec0..c1cf0fe12e 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -995,8 +995,8 @@ static void GCC_FMT_ATTR(3, 4) prom_set(uint32_t* prom_buf, int index, /* Kernel */ static int64_t load_kernel (void) { - int64_t kernel_entry, kernel_high; - long kernel_size, initrd_size; + int64_t kernel_entry, kernel_high, initrd_size; + long kernel_size; ram_addr_t initrd_offset; int big_endian; uint32_t *prom_buf; @@ -1070,7 +1070,7 @@ static int64_t load_kernel (void) prom_set(prom_buf, prom_index++, "%s", loaderparams.kernel_filename); if (initrd_size > 0) { - prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%li %s", + prom_set(prom_buf, prom_index++, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s", xlate_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { @@ -1422,23 +1422,10 @@ void mips_malta_init(MachineState *machine) pci_vga_init(pci_bus); } -static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) -{ - return 0; -} - -static void mips_malta_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mips_malta_sysbus_device_init; -} - static const TypeInfo mips_malta_device = { .name = TYPE_MIPS_MALTA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MaltaState), - .class_init = mips_malta_class_init, }; static void mips_malta_machine_init(MachineClass *mc) diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c index 241faa1d0f..f665752a2f 100644 --- a/hw/mips/mips_mipssim.c +++ b/hw/mips/mips_mipssim.c @@ -58,9 +58,8 @@ typedef struct ResetData { static int64_t load_kernel(void) { - int64_t entry, kernel_high; + int64_t entry, kernel_high, initrd_size; long kernel_size; - long initrd_size; ram_addr_t initrd_offset; int big_endian; diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index d5725d0555..3e852e98cf 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -81,8 +81,8 @@ typedef struct ResetData { static int64_t load_kernel(void) { const size_t params_size = 264; - int64_t entry, kernel_high; - long kernel_size, initrd_size; + int64_t entry, kernel_high, initrd_size; + long kernel_size; ram_addr_t initrd_offset; uint32_t *params_buf; int big_endian; @@ -136,7 +136,7 @@ static int64_t load_kernel(void) params_buf[1] = tswap32(0x12345678); if (initrd_size > 0) { - snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%li %s", + snprintf((char *)params_buf + 8, 256, "rd_start=0x%" PRIx64 " rd_size=%" PRId64 " %s", cpu_mips_phys_to_kseg0(NULL, initrd_offset), initrd_size, loaderparams.kernel_cmdline); } else { diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 6d50b03cfd..680350b3c3 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -71,7 +71,6 @@ obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o obj-$(CONFIG_PVPANIC) += pvpanic.o -obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o obj-$(CONFIG_AUX) += auxbus.o obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o obj-$(CONFIG_MSF2) += msf2-sysreg.o diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c index 84fa1a5b9d..bed293247e 100644 --- a/hw/misc/debugexit.c +++ b/hw/misc/debugexit.c @@ -23,6 +23,11 @@ typedef struct ISADebugExitState { MemoryRegion io; } ISADebugExitState; +static uint64_t debug_exit_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, unsigned width) { @@ -30,6 +35,7 @@ static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, } static const MemoryRegionOps debug_exit_ops = { + .read = debug_exit_read, .write = debug_exit_write, .valid.min_access_size = 1, .valid.max_access_size = 4, diff --git a/hw/misc/edu.c b/hw/misc/edu.c index df26a4d046..cdcf550dd7 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -30,7 +30,8 @@ #include "qemu/main-loop.h" /* iothread mutex */ #include "qapi/visitor.h" -#define EDU(obj) OBJECT_CHECK(EduState, obj, "edu") +#define TYPE_PCI_EDU_DEVICE "edu" +#define EDU(obj) OBJECT_CHECK(EduState, obj, TYPE_PCI_EDU_DEVICE) #define FACT_IRQ 0x00000001 #define DMA_IRQ 0x00000100 @@ -341,7 +342,7 @@ static void *edu_fact_thread(void *opaque) static void pci_edu_realize(PCIDevice *pdev, Error **errp) { - EduState *edu = DO_UPCAST(EduState, pdev, pdev); + EduState *edu = EDU(pdev); uint8_t *pci_conf = pdev->config; pci_config_set_interrupt_pin(pci_conf, 1); @@ -364,7 +365,7 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp) static void pci_edu_uninit(PCIDevice *pdev) { - EduState *edu = DO_UPCAST(EduState, pdev, pdev); + EduState *edu = EDU(pdev); qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; @@ -414,7 +415,7 @@ static void pci_edu_register_types(void) { }, }; static const TypeInfo edu_info = { - .name = "edu", + .name = TYPE_PCI_EDU_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EduState), .instance_init = edu_instance_init, diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c deleted file mode 100644 index bf6bbfa8cf..0000000000 --- a/hw/misc/hyperv_testdev.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests - * - * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com> - * - * Authors: - * Andrey Smetanin <asmetanin@virtuozzo.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include <linux/kvm.h> -#include "hw/hw.h" -#include "hw/qdev.h" -#include "hw/isa/isa.h" -#include "sysemu/kvm.h" -#include "target/i386/hyperv.h" -#include "kvm_i386.h" - -#define HV_TEST_DEV_MAX_SINT_ROUTES 64 - -struct HypervTestDev { - ISADevice parent_obj; - MemoryRegion sint_control; - HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES]; -}; -typedef struct HypervTestDev HypervTestDev; - -#define TYPE_HYPERV_TEST_DEV "hyperv-testdev" -#define HYPERV_TEST_DEV(obj) \ - OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV) - -enum { - HV_TEST_DEV_SINT_ROUTE_CREATE = 1, - HV_TEST_DEV_SINT_ROUTE_DESTROY, - HV_TEST_DEV_SINT_ROUTE_SET_SINT -}; - -static int alloc_sint_route_index(HypervTestDev *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) { - if (dev->sint_route[i] == NULL) { - return i; - } - } - return -1; -} - -static void free_sint_route_index(HypervTestDev *dev, int i) -{ - assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route)); - dev->sint_route[i] = NULL; -} - -static int find_sint_route_index(HypervTestDev *dev, uint32_t vp_index, - uint32_t sint) -{ - HvSintRoute *sint_route; - int i; - - for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) { - sint_route = dev->sint_route[i]; - if (sint_route && sint_route->vp_index == vp_index && - sint_route->sint == sint) { - return i; - } - } - return -1; -} - -static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl, - uint32_t vp_index, uint32_t sint) -{ - int i; - HvSintRoute *sint_route; - - switch (ctl) { - case HV_TEST_DEV_SINT_ROUTE_CREATE: - i = alloc_sint_route_index(dev); - assert(i >= 0); - sint_route = kvm_hv_sint_route_create(vp_index, sint, NULL); - assert(sint_route); - dev->sint_route[i] = sint_route; - break; - case HV_TEST_DEV_SINT_ROUTE_DESTROY: - i = find_sint_route_index(dev, vp_index, sint); - assert(i >= 0); - sint_route = dev->sint_route[i]; - kvm_hv_sint_route_destroy(sint_route); - free_sint_route_index(dev, i); - break; - case HV_TEST_DEV_SINT_ROUTE_SET_SINT: - i = find_sint_route_index(dev, vp_index, sint); - assert(i >= 0); - sint_route = dev->sint_route[i]; - kvm_hv_sint_route_set_sint(sint_route); - break; - default: - break; - } -} - -static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data, - uint32_t len) -{ - HypervTestDev *dev = HYPERV_TEST_DEV(opaque); - uint8_t ctl; - - ctl = (data >> 16ULL) & 0xFF; - switch (ctl) { - case HV_TEST_DEV_SINT_ROUTE_CREATE: - case HV_TEST_DEV_SINT_ROUTE_DESTROY: - case HV_TEST_DEV_SINT_ROUTE_SET_SINT: { - uint8_t sint = data & 0xFF; - uint8_t vp_index = (data >> 8ULL) & 0xFF; - hv_synic_test_dev_control(dev, ctl, vp_index, sint); - break; - } - default: - break; - } -} - -static const MemoryRegionOps synic_test_sint_ops = { - .write = hv_test_dev_control, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void hv_test_dev_realizefn(DeviceState *d, Error **errp) -{ - ISADevice *isa = ISA_DEVICE(d); - HypervTestDev *dev = HYPERV_TEST_DEV(d); - MemoryRegion *io = isa_address_space_io(isa); - - memset(dev->sint_route, 0, sizeof(dev->sint_route)); - memory_region_init_io(&dev->sint_control, OBJECT(dev), - &synic_test_sint_ops, dev, - "hyperv-testdev-ctl", 4); - memory_region_add_subregion(io, 0x3000, &dev->sint_control); -} - -static void hv_test_dev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->realize = hv_test_dev_realizefn; -} - -static const TypeInfo hv_test_dev_info = { - .name = TYPE_HYPERV_TEST_DEV, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(HypervTestDev), - .class_init = hv_test_dev_class_init, -}; - -static void hv_test_dev_register_types(void) -{ - type_register_static(&hv_test_dev_info); -} -type_init(hv_test_dev_register_types); diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 6febbabcaa..f88910e55c 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -911,6 +911,7 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp) IVSHMEM_DPRINTF("using hostmem\n"); s->ivshmem_bar2 = host_memory_backend_get_memory(s->hostmem); + host_memory_backend_set_mapped(s->hostmem, true); } else { Chardev *chr = qemu_chr_fe_get_driver(&s->server_chr); assert(chr); @@ -993,6 +994,10 @@ static void ivshmem_exit(PCIDevice *dev) vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev)); } + if (s->hostmem) { + host_memory_backend_set_mapped(s->hostmem, false); + } + if (s->peers) { for (i = 0; i < s->nb_peers; i++) { close_peer_eventfds(s, i); @@ -1101,14 +1106,6 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) } ivshmem_common_realize(dev, errp); - host_memory_backend_set_mapped(s->hostmem, true); -} - -static void ivshmem_plain_exit(PCIDevice *pci_dev) -{ - IVShmemState *s = IVSHMEM_COMMON(pci_dev); - - host_memory_backend_set_mapped(s->hostmem, false); } static void ivshmem_plain_class_init(ObjectClass *klass, void *data) @@ -1117,7 +1114,6 @@ static void ivshmem_plain_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = ivshmem_plain_realize; - k->exit = ivshmem_plain_exit; dc->props = ivshmem_plain_properties; dc->vmsd = &ivshmem_plain_vmsd; } @@ -1292,8 +1288,8 @@ static void ivshmem_realize(PCIDevice *dev, Error **errp) IVShmemState *s = IVSHMEM_COMMON(dev); if (!qtest_enabled()) { - error_report("ivshmem is deprecated, please use ivshmem-plain" - " or ivshmem-doorbell instead"); + warn_report("ivshmem is deprecated, please use ivshmem-plain" + " or ivshmem-doorbell instead"); } if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) { diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c index b81d820084..697eb88c97 100644 --- a/hw/misc/pc-testdev.c +++ b/hw/misc/pc-testdev.c @@ -58,7 +58,12 @@ typedef struct PCTestdev { #define TESTDEV(obj) \ OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV) -static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, +static uint64_t test_irq_line_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void test_irq_line_write(void *opaque, hwaddr addr, uint64_t data, unsigned len) { PCTestdev *dev = opaque; @@ -68,7 +73,8 @@ static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, } static const MemoryRegionOps test_irq_ops = { - .write = test_irq_line, + .read = test_irq_line_read, + .write = test_irq_line_write, .valid.min_access_size = 1, .valid.max_access_size = 1, .endianness = DEVICE_LITTLE_ENDIAN, @@ -110,7 +116,12 @@ static const MemoryRegionOps test_ioport_byte_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, +static uint64_t test_flush_page_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + +static void test_flush_page_write(void *opaque, hwaddr addr, uint64_t data, unsigned len) { hwaddr page = 4096; @@ -126,7 +137,8 @@ static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, } static const MemoryRegionOps test_flush_ops = { - .write = test_flush_page, + .read = test_flush_page_read, + .write = test_flush_page_write, .valid.min_access_size = 4, .valid.max_access_size = 4, .endianness = DEVICE_LITTLE_ENDIAN, diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index d41247dbdc..4b0ce09c5e 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -54,8 +54,8 @@ typedef struct { static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) { uint64_t entry, kernel_low, kernel_high; + int64_t initrd_size; long kernel_size; - long initrd_size; ram_addr_t initrd_offset; kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL, diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 0fa4b0dc44..d95cc27f58 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -28,6 +28,7 @@ #include "hw/net/cadence_gem.h" #include "qapi/error.h" #include "qemu/log.h" +#include "sysemu/dma.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -141,6 +142,7 @@ #define GEM_DESCONF4 (0x0000028C/4) #define GEM_DESCONF5 (0x00000290/4) #define GEM_DESCONF6 (0x00000294/4) +#define GEM_DESCONF6_64B_MASK (1U << 23) #define GEM_DESCONF7 (0x00000298/4) #define GEM_INT_Q1_STATUS (0x00000400 / 4) @@ -152,6 +154,9 @@ #define GEM_RECEIVE_Q1_PTR (0x00000480 / 4) #define GEM_RECEIVE_Q7_PTR (GEM_RECEIVE_Q1_PTR + 6) +#define GEM_TBQPH (0x000004C8 / 4) +#define GEM_RBQPH (0x000004D4 / 4) + #define GEM_INT_Q1_ENABLE (0x00000600 / 4) #define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6) @@ -207,6 +212,9 @@ #define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */ #define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */ +#define GEM_DMACFG_ADDR_64B (1U << 30) +#define GEM_DMACFG_TX_BD_EXT (1U << 29) +#define GEM_DMACFG_RX_BD_EXT (1U << 28) #define GEM_DMACFG_RBUFSZ_M 0x00FF0000 /* DMA RX Buffer Size mask */ #define GEM_DMACFG_RBUFSZ_S 16 /* DMA RX Buffer Size shift */ #define GEM_DMACFG_RBUFSZ_MUL 64 /* DMA RX Buffer Size multiplier */ @@ -302,42 +310,47 @@ #define GEM_MODID_VALUE 0x00020118 -static inline unsigned tx_desc_get_buffer(unsigned *desc) +static inline uint64_t tx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc) { - return desc[0]; + uint64_t ret = desc[0]; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + ret |= (uint64_t)desc[2] << 32; + } + return ret; } -static inline unsigned tx_desc_get_used(unsigned *desc) +static inline unsigned tx_desc_get_used(uint32_t *desc) { return (desc[1] & DESC_1_USED) ? 1 : 0; } -static inline void tx_desc_set_used(unsigned *desc) +static inline void tx_desc_set_used(uint32_t *desc) { desc[1] |= DESC_1_USED; } -static inline unsigned tx_desc_get_wrap(unsigned *desc) +static inline unsigned tx_desc_get_wrap(uint32_t *desc) { return (desc[1] & DESC_1_TX_WRAP) ? 1 : 0; } -static inline unsigned tx_desc_get_last(unsigned *desc) +static inline unsigned tx_desc_get_last(uint32_t *desc) { return (desc[1] & DESC_1_TX_LAST) ? 1 : 0; } -static inline void tx_desc_set_last(unsigned *desc) +static inline void tx_desc_set_last(uint32_t *desc) { desc[1] |= DESC_1_TX_LAST; } -static inline unsigned tx_desc_get_length(unsigned *desc) +static inline unsigned tx_desc_get_length(uint32_t *desc) { return desc[1] & DESC_1_LENGTH; } -static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue) +static inline void print_gem_tx_desc(uint32_t *desc, uint8_t queue) { DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue); DB_PRINT("bufaddr: 0x%08x\n", *desc); @@ -347,58 +360,79 @@ static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue) DB_PRINT("length: %d\n", tx_desc_get_length(desc)); } -static inline unsigned rx_desc_get_buffer(unsigned *desc) +static inline uint64_t rx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc) { - return desc[0] & ~0x3UL; + uint64_t ret = desc[0] & ~0x3UL; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + ret |= (uint64_t)desc[2] << 32; + } + return ret; } -static inline unsigned rx_desc_get_wrap(unsigned *desc) +static inline int gem_get_desc_len(CadenceGEMState *s, bool rx_n_tx) +{ + int ret = 2; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + ret += 2; + } + if (s->regs[GEM_DMACFG] & (rx_n_tx ? GEM_DMACFG_RX_BD_EXT + : GEM_DMACFG_TX_BD_EXT)) { + ret += 2; + } + + assert(ret <= DESC_MAX_NUM_WORDS); + return ret; +} + +static inline unsigned rx_desc_get_wrap(uint32_t *desc) { return desc[0] & DESC_0_RX_WRAP ? 1 : 0; } -static inline unsigned rx_desc_get_ownership(unsigned *desc) +static inline unsigned rx_desc_get_ownership(uint32_t *desc) { return desc[0] & DESC_0_RX_OWNERSHIP ? 1 : 0; } -static inline void rx_desc_set_ownership(unsigned *desc) +static inline void rx_desc_set_ownership(uint32_t *desc) { desc[0] |= DESC_0_RX_OWNERSHIP; } -static inline void rx_desc_set_sof(unsigned *desc) +static inline void rx_desc_set_sof(uint32_t *desc) { desc[1] |= DESC_1_RX_SOF; } -static inline void rx_desc_set_eof(unsigned *desc) +static inline void rx_desc_set_eof(uint32_t *desc) { desc[1] |= DESC_1_RX_EOF; } -static inline void rx_desc_set_length(unsigned *desc, unsigned len) +static inline void rx_desc_set_length(uint32_t *desc, unsigned len) { desc[1] &= ~DESC_1_LENGTH; desc[1] |= len; } -static inline void rx_desc_set_broadcast(unsigned *desc) +static inline void rx_desc_set_broadcast(uint32_t *desc) { desc[1] |= R_DESC_1_RX_BROADCAST; } -static inline void rx_desc_set_unicast_hash(unsigned *desc) +static inline void rx_desc_set_unicast_hash(uint32_t *desc) { desc[1] |= R_DESC_1_RX_UNICAST_HASH; } -static inline void rx_desc_set_multicast_hash(unsigned *desc) +static inline void rx_desc_set_multicast_hash(uint32_t *desc) { desc[1] |= R_DESC_1_RX_MULTICAST_HASH; } -static inline void rx_desc_set_sar(unsigned *desc, int sar_idx) +static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx) { desc[1] = deposit32(desc[1], R_DESC_1_RX_SAR_SHIFT, R_DESC_1_RX_SAR_LENGTH, sar_idx); @@ -419,7 +453,7 @@ static void gem_init_register_masks(CadenceGEMState *s) memset(&s->regs_ro[0], 0, sizeof(s->regs_ro)); s->regs_ro[GEM_NWCTRL] = 0xFFF80000; s->regs_ro[GEM_NWSTATUS] = 0xFFFFFFFF; - s->regs_ro[GEM_DMACFG] = 0xFE00F000; + s->regs_ro[GEM_DMACFG] = 0x8E00F000; s->regs_ro[GEM_TXSTATUS] = 0xFFFFFE08; s->regs_ro[GEM_RXQBASE] = 0x00000003; s->regs_ro[GEM_TXQBASE] = 0x00000003; @@ -802,17 +836,42 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, return 0; } +static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q) +{ + hwaddr desc_addr = 0; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + desc_addr = s->regs[tx ? GEM_TBQPH : GEM_RBQPH]; + } + desc_addr <<= 32; + desc_addr |= tx ? s->tx_desc_addr[q] : s->rx_desc_addr[q]; + return desc_addr; +} + +static hwaddr gem_get_tx_desc_addr(CadenceGEMState *s, int q) +{ + return gem_get_desc_addr(s, true, q); +} + +static hwaddr gem_get_rx_desc_addr(CadenceGEMState *s, int q) +{ + return gem_get_desc_addr(s, false, q); +} + static void gem_get_rx_desc(CadenceGEMState *s, int q) { - DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]); + hwaddr desc_addr = gem_get_rx_desc_addr(s, q); + + DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", desc_addr); + /* read current descriptor */ - cpu_physical_memory_read(s->rx_desc_addr[q], - (uint8_t *)s->rx_desc[q], sizeof(s->rx_desc[q])); + address_space_read(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)s->rx_desc[q], + sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Descriptor owned by software ? */ if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { - DB_PRINT("descriptor 0x%x owned by sw.\n", - (unsigned)s->rx_desc_addr[q]); + DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ @@ -916,6 +975,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); while (bytes_to_copy) { + hwaddr desc_addr; + /* Do nothing if receive is not enabled. */ if (!gem_can_receive(nc)) { assert(!first_desc); @@ -926,9 +987,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) rx_desc_get_buffer(s->rx_desc[q])); /* Copy packet data to emulated DMA buffer */ - cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) + - rxbuf_offset, - rxbuf_ptr, MIN(bytes_to_copy, rxbufsize)); + address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) + + rxbuf_offset, + MEMTXATTRS_UNSPECIFIED, rxbuf_ptr, + MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); @@ -962,9 +1024,11 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) } /* Descriptor write-back. */ - cpu_physical_memory_write(s->rx_desc_addr[q], - (uint8_t *)s->rx_desc[q], - sizeof(s->rx_desc[q])); + desc_addr = gem_get_rx_desc_addr(s, q); + address_space_write(&s->dma_as, desc_addr, + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)s->rx_desc[q], + sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Next descriptor */ if (rx_desc_get_wrap(s->rx_desc[q])) { @@ -972,7 +1036,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) s->rx_desc_addr[q] = s->regs[GEM_RXQBASE]; } else { DB_PRINT("incrementing RX descriptor list\n"); - s->rx_desc_addr[q] += 8; + s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true); } gem_get_rx_desc(s, q); @@ -1042,7 +1106,7 @@ static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet, */ static void gem_transmit(CadenceGEMState *s) { - unsigned desc[2]; + uint32_t desc[DESC_MAX_NUM_WORDS]; hwaddr packet_desc_addr; uint8_t tx_packet[2048]; uint8_t *p; @@ -1065,11 +1129,12 @@ static void gem_transmit(CadenceGEMState *s) for (q = s->num_priority_queues - 1; q >= 0; q--) { /* read current descriptor */ - packet_desc_addr = s->tx_desc_addr[q]; + packet_desc_addr = gem_get_tx_desc_addr(s, q); DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); + address_space_read(&s->dma_as, packet_desc_addr, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc, + sizeof(uint32_t) * gem_get_desc_len(s, false)); /* Handle all descriptors owned by hardware */ while (tx_desc_get_used(desc) == 0) { @@ -1082,7 +1147,7 @@ static void gem_transmit(CadenceGEMState *s) /* The real hardware would eat this (and possibly crash). * For QEMU let's lend a helping hand. */ - if ((tx_desc_get_buffer(desc) == 0) || + if ((tx_desc_get_buffer(s, desc) == 0) || (tx_desc_get_length(desc) == 0)) { DB_PRINT("Invalid TX descriptor @ 0x%x\n", (unsigned)packet_desc_addr); @@ -1101,30 +1166,35 @@ static void gem_transmit(CadenceGEMState *s) /* Gather this fragment of the packet from "dma memory" to our * contig buffer. */ - cpu_physical_memory_read(tx_desc_get_buffer(desc), p, - tx_desc_get_length(desc)); + address_space_read(&s->dma_as, tx_desc_get_buffer(s, desc), + MEMTXATTRS_UNSPECIFIED, + p, tx_desc_get_length(desc)); p += tx_desc_get_length(desc); total_bytes += tx_desc_get_length(desc); /* Last descriptor for this packet; hand the whole thing off */ if (tx_desc_get_last(desc)) { - unsigned desc_first[2]; + uint32_t desc_first[DESC_MAX_NUM_WORDS]; + hwaddr desc_addr = gem_get_tx_desc_addr(s, q); /* Modify the 1st descriptor of this packet to be owned by * the processor. */ - cpu_physical_memory_read(s->tx_desc_addr[q], - (uint8_t *)desc_first, - sizeof(desc_first)); + address_space_read(&s->dma_as, desc_addr, + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)desc_first, + sizeof(desc_first)); tx_desc_set_used(desc_first); - cpu_physical_memory_write(s->tx_desc_addr[q], - (uint8_t *)desc_first, - sizeof(desc_first)); + address_space_write(&s->dma_as, desc_addr, + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)desc_first, + sizeof(desc_first)); /* Advance the hardware current descriptor past this packet */ if (tx_desc_get_wrap(desc)) { s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; } else { - s->tx_desc_addr[q] = packet_desc_addr + 8; + s->tx_desc_addr[q] = packet_desc_addr + + 4 * gem_get_desc_len(s, false); } DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); @@ -1168,11 +1238,12 @@ static void gem_transmit(CadenceGEMState *s) tx_desc_set_last(desc); packet_desc_addr = s->regs[GEM_TXQBASE]; } else { - packet_desc_addr += 8; + packet_desc_addr += 4 * gem_get_desc_len(s, false); } DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); + address_space_read(&s->dma_as, packet_desc_addr, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc, + sizeof(uint32_t) * gem_get_desc_len(s, false)); } if (tx_desc_get_used(desc)) { @@ -1213,6 +1284,7 @@ static void gem_reset(DeviceState *d) int i; CadenceGEMState *s = CADENCE_GEM(d); const uint8_t *a; + uint32_t queues_mask = 0; DB_PRINT("\n"); @@ -1228,8 +1300,13 @@ static void gem_reset(DeviceState *d) s->regs[GEM_MODID] = s->revision; s->regs[GEM_DESCONF] = 0x02500111; s->regs[GEM_DESCONF2] = 0x2ab13fff; - s->regs[GEM_DESCONF5] = 0x002f2145; - s->regs[GEM_DESCONF6] = 0x00000200; + s->regs[GEM_DESCONF5] = 0x002f2045; + s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK; + + if (s->num_priority_queues > 1) { + queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1); + s->regs[GEM_DESCONF6] |= queues_mask; + } /* Set MAC address */ a = &s->conf.macaddr.a[0]; @@ -1463,6 +1540,9 @@ static void gem_realize(DeviceState *dev, Error **errp) CadenceGEMState *s = CADENCE_GEM(dev); int i; + address_space_init(&s->dma_as, + s->dma_mr ? s->dma_mr : get_system_memory(), "dma"); + if (s->num_priority_queues == 0 || s->num_priority_queues > MAX_PRIORITY_QUEUES) { error_setg(errp, "Invalid num-priority-queues value: %" PRIx8, @@ -1500,6 +1580,12 @@ static void gem_init(Object *obj) "enet", sizeof(s->regs)); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + + object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, + (Object **)&s->dma_mr, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG, + &error_abort); } static const VMStateDescription vmstate_cadence_gem = { diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 13a9494a8d..5e144cb4e4 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -36,6 +36,7 @@ #include "qemu/range.h" #include "e1000x_common.h" +#include "trace.h" static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -847,6 +848,15 @@ static uint64_t rx_desc_base(E1000State *s) return (bah << 32) + bal; } +static void +e1000_receiver_overrun(E1000State *s, size_t size) +{ + trace_e1000_receiver_overrun(size, s->mac_reg[RDH], s->mac_reg[RDT]); + e1000x_inc_reg_if_not_full(s->mac_reg, RNBC); + e1000x_inc_reg_if_not_full(s->mac_reg, MPC); + set_ics(s, 0, E1000_ICS_RXO); +} + static ssize_t e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) { @@ -916,8 +926,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) desc_offset = 0; total_size = size + e1000x_fcs_len(s->mac_reg); if (!e1000_has_rxbufs(s, total_size)) { - set_ics(s, 0, E1000_ICS_RXO); - return -1; + e1000_receiver_overrun(s, total_size); + return -1; } do { desc_size = total_size - desc_offset; @@ -969,7 +979,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) { DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); - set_ics(s, 0, E1000_ICS_RXO); + e1000_receiver_overrun(s, total_size); return -1; } } while (desc_offset < total_size); diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c index a6932432b1..36855804db 100644 --- a/hw/net/etraxfs_eth.c +++ b/hw/net/etraxfs_eth.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "net/net.h" #include "hw/cris/etraxfs.h" @@ -126,7 +127,7 @@ tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) } static void -tdk_init(struct qemu_phy *phy) +tdk_reset(struct qemu_phy *phy) { phy->regs[0] = 0x3100; /* PHY Id. */ @@ -135,9 +136,6 @@ tdk_init(struct qemu_phy *phy) /* Autonegotiation advertisement reg. */ phy->regs[4] = 0x01E1; phy->link = 1; - - phy->read = tdk_read; - phy->write = tdk_write; } struct qemu_mdio @@ -584,14 +582,35 @@ static NetClientInfo net_etraxfs_info = { .link_status_changed = eth_set_link, }; -static int fs_eth_init(SysBusDevice *sbd) +static void etraxfs_eth_reset(DeviceState *dev) +{ + ETRAXFSEthState *s = ETRAX_FS_ETH(dev); + + memset(s->regs, 0, sizeof(s->regs)); + memset(s->macaddr, 0, sizeof(s->macaddr)); + s->duplex_mismatch = 0; + + s->mdio_bus.mdc = 0; + s->mdio_bus.mdio = 0; + s->mdio_bus.state = 0; + s->mdio_bus.drive = 0; + s->mdio_bus.cnt = 0; + s->mdio_bus.addr = 0; + s->mdio_bus.opc = 0; + s->mdio_bus.req = 0; + s->mdio_bus.data = 0; + + tdk_reset(&s->phy); +} + +static void etraxfs_eth_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); ETRAXFSEthState *s = ETRAX_FS_ETH(dev); if (!s->dma_out || !s->dma_in) { - error_report("Unconnected ETRAX-FS Ethernet MAC"); - return -1; + error_setg(errp, "Unconnected ETRAX-FS Ethernet MAC"); + return; } s->dma_out->client.push = eth_tx_push; @@ -608,10 +627,9 @@ static int fs_eth_init(SysBusDevice *sbd) object_get_typename(OBJECT(s)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - - tdk_init(&s->phy); + s->phy.read = tdk_read; + s->phy.write = tdk_write; mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); - return 0; } static Property etraxfs_eth_properties[] = { @@ -625,9 +643,9 @@ static Property etraxfs_eth_properties[] = { static void etraxfs_eth_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = fs_eth_init; + dc->realize = etraxfs_eth_realize; + dc->reset = etraxfs_eth_reset; dc->props = etraxfs_eth_properties; /* Reason: pointer properties "dma_out", "dma_in" */ dc->user_creatable = false; diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index b9032dac59..a6269d9463 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -1320,9 +1320,9 @@ static NetClientInfo net_lan9118_info = { .link_status_changed = lan9118_set_link, }; -static int lan9118_init1(SysBusDevice *sbd) +static void lan9118_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); lan9118_state *s = LAN9118(dev); QEMUBH *bh; int i; @@ -1349,8 +1349,6 @@ static int lan9118_init1(SysBusDevice *sbd) s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->timer, 10000); ptimer_set_limit(s->timer, 0xffff, 1); - - return 0; } static Property lan9118_properties[] = { @@ -1362,12 +1360,11 @@ static Property lan9118_properties[] = { static void lan9118_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = lan9118_init1; dc->reset = lan9118_reset; dc->props = lan9118_properties; dc->vmsd = &vmstate_lan9118; + dc->realize = lan9118_realize; } static const TypeInfo lan9118_info = { diff --git a/hw/net/lance.c b/hw/net/lance.c index a08d5ac6a8..f987b2fd18 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -97,9 +97,9 @@ static const VMStateDescription vmstate_lance = { } }; -static int lance_init(SysBusDevice *sbd) +static void lance_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); SysBusPCNetState *d = SYSBUS_PCNET(dev); PCNetState *s = &d->state; @@ -115,7 +115,6 @@ static int lance_init(SysBusDevice *sbd) s->phys_mem_read = ledma_memory_read; s->phys_mem_write = ledma_memory_write; pcnet_common_init(dev, s, &net_lance_info); - return 0; } static void lance_reset(DeviceState *dev) @@ -144,9 +143,8 @@ static Property lance_properties[] = { static void lance_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = lance_init; + dc->realize = lance_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "ethernet"; dc->reset = lance_reset; diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index 3eaa19dfde..85c9fc0b65 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -30,6 +30,7 @@ #include "hw/sysbus.h" #include "trace.h" #include "net/net.h" +#include "qemu/log.h" #include "qemu/error-report.h" #include <zlib.h> @@ -214,7 +215,8 @@ static size_t assemble_frame(uint8_t *buf, size_t size, uint32_t crc; if (size < payload_size + 12) { - error_report("milkymist_minimac2: received too big ethernet frame"); + qemu_log_mask(LOG_GUEST_ERROR, "milkymist_minimac2: frame too big " + "(%zd bytes)\n", payload_size); return 0; } @@ -347,8 +349,9 @@ minimac2_read(void *opaque, hwaddr addr, unsigned size) break; default: - error_report("milkymist_minimac2: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); + qemu_log_mask(LOG_GUEST_ERROR, + "milkymist_minimac2_rd%d: 0x%" HWADDR_PRIx "\n", + size, addr << 2); break; } @@ -413,8 +416,10 @@ minimac2_write(void *opaque, hwaddr addr, uint64_t value, break; default: - error_report("milkymist_minimac2: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); + qemu_log_mask(LOG_GUEST_ERROR, + "milkymist_minimac2_wr%d: 0x%" HWADDR_PRIx + " = 0x%" PRIx64 "\n", + size, addr << 2, value); break; } } @@ -452,9 +457,9 @@ static NetClientInfo net_milkymist_minimac2_info = { .receive = minimac2_rx, }; -static int milkymist_minimac2_init(SysBusDevice *sbd) +static void milkymist_minimac2_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev); size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE); @@ -479,8 +484,6 @@ static int milkymist_minimac2_init(SysBusDevice *sbd) s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - - return 0; } static const VMStateDescription vmstate_milkymist_minimac2_mdio = { @@ -521,9 +524,8 @@ static Property milkymist_minimac2_properties[] = { static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = milkymist_minimac2_init; + dc->realize = milkymist_minimac2_realize; dc->reset = milkymist_minimac2_reset; dc->vmsd = &vmstate_milkymist_minimac2; dc->props = milkymist_minimac2_properties; diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index 5a63df7ccb..03b3104278 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -236,9 +236,9 @@ static const MemoryRegionOps mipsnet_ioport_ops = { .impl.max_access_size = 4, }; -static int mipsnet_sysbus_init(SysBusDevice *sbd) +static void mipsnet_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); MIPSnetState *s = MIPS_NET(dev); memory_region_init_io(&s->io, OBJECT(dev), &mipsnet_ioport_ops, s, @@ -249,8 +249,6 @@ static int mipsnet_sysbus_init(SysBusDevice *sbd) s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - - return 0; } static void mipsnet_sysbus_reset(DeviceState *dev) @@ -267,9 +265,8 @@ static Property mipsnet_properties[] = { static void mipsnet_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = mipsnet_sysbus_init; + dc->realize = mipsnet_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "MIPS Simulator network device"; dc->reset = mipsnet_sysbus_reset; diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 07d79e317f..869518ee06 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -174,7 +174,7 @@ static int ne2000_buffer_full(NE2000State *s) ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) { NE2000State *s = qemu_get_nic_opaque(nc); - int size = size_; + size_t size = size_; uint8_t *p; unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; @@ -182,7 +182,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; #if defined(DEBUG_NE2000) - printf("NE2000: received len=%d\n", size); + printf("NE2000: received len=%zu\n", size); #endif if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index d42b79c08c..d6f54f8d82 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -715,9 +715,9 @@ static const MemoryRegionOps open_eth_desc_ops = { .write = open_eth_desc_write, }; -static int sysbus_open_eth_init(SysBusDevice *sbd) +static void sysbus_open_eth_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); OpenEthState *s = OPEN_ETH(dev); memory_region_init_io(&s->reg_io, OBJECT(dev), &open_eth_reg_ops, s, @@ -732,7 +732,6 @@ static int sysbus_open_eth_init(SysBusDevice *sbd) s->nic = qemu_new_nic(&net_open_eth_info, &s->conf, object_get_typename(OBJECT(s)), dev->id, s); - return 0; } static void qdev_open_eth_reset(DeviceState *dev) @@ -750,9 +749,8 @@ static Property open_eth_properties[] = { static void open_eth_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = sysbus_open_eth_init; + dc->realize = sysbus_open_eth_realize; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Opencores 10/100 Mbit Ethernet"; dc->reset = qdev_open_eth_reset; diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 0c44554168..d9ba04bdfc 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -988,14 +988,14 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) uint8_t buf1[60]; int remaining; int crc_err = 0; - int size = size_; + size_t size = size_; if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size || (CSR_LOOP(s) && !s->looptest)) { return -1; } #ifdef PCNET_DEBUG - printf("pcnet_receive size=%d\n", size); + printf("pcnet_receive size=%zu\n", size); #endif /* if too small buffer, then expand it */ diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 46daa16202..2342a095e3 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -817,7 +817,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t RTL8139State *s = qemu_get_nic_opaque(nc); PCIDevice *d = PCI_DEVICE(s); /* size is the length of the buffer passed to the driver */ - int size = size_; + size_t size = size_; const uint8_t *dot1q_buf = NULL; uint32_t packet_header = 0; @@ -826,7 +826,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - DPRINTF(">>> received len=%d\n", size); + DPRINTF(">>> received len=%zu\n", size); /* test if board clock is stopped */ if (!s->clock_enabled) @@ -1035,7 +1035,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t if (size+4 > rx_space) { - DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n", + DPRINTF("C+ Rx mode : descriptor %d size %d received %zu + 4\n", descriptor, rx_space, size); s->IntrStatus |= RxOverflow; @@ -1148,7 +1148,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t if (avail != 0 && RX_ALIGN(size + 8) >= avail) { DPRINTF("rx overflow: rx buffer length %d head 0x%04x " - "read 0x%04x === available 0x%04x need 0x%04x\n", + "read 0x%04x === available 0x%04x need 0x%04zx\n", s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); s->IntrStatus |= RxOverflow; diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index d2fd2040e8..99da2d9297 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -766,9 +766,9 @@ static NetClientInfo net_smc91c111_info = { .receive = smc91c111_receive, }; -static int smc91c111_init1(SysBusDevice *sbd) +static void smc91c111_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); smc91c111_state *s = SMC91C111(dev); memory_region_init_io(&s->mmio, OBJECT(s), &smc91c111_mem_ops, s, @@ -780,7 +780,6 @@ static int smc91c111_init1(SysBusDevice *sbd) object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); /* ??? Save/restore. */ - return 0; } static Property smc91c111_properties[] = { @@ -791,9 +790,8 @@ static Property smc91c111_properties[] = { static void smc91c111_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = smc91c111_init1; + dc->realize = smc91c111_realize; dc->reset = smc91c111_reset; dc->vmsd = &vmstate_smc91c111; dc->props = smc91c111_properties; diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 165562d788..b3375ebb45 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -457,8 +457,10 @@ static const MemoryRegionOps stellaris_enet_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void stellaris_enet_reset(stellaris_enet_state *s) +static void stellaris_enet_reset(DeviceState *dev) { + stellaris_enet_state *s = STELLARIS_ENET(dev); + s->mdv = 0x80; s->rctl = SE_RCTL_BADCRC; s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP @@ -473,9 +475,9 @@ static NetClientInfo net_stellaris_enet_info = { .receive = stellaris_enet_receive, }; -static int stellaris_enet_init(SysBusDevice *sbd) +static void stellaris_enet_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); stellaris_enet_state *s = STELLARIS_ENET(dev); memory_region_init_io(&s->mmio, OBJECT(s), &stellaris_enet_ops, s, @@ -487,9 +489,6 @@ static int stellaris_enet_init(SysBusDevice *sbd) s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - - stellaris_enet_reset(s); - return 0; } static Property stellaris_enet_properties[] = { @@ -500,9 +499,9 @@ static Property stellaris_enet_properties[] = { static void stellaris_enet_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = stellaris_enet_init; + dc->realize = stellaris_enet_realize; + dc->reset = stellaris_enet_reset; dc->props = stellaris_enet_properties; dc->vmsd = &vmstate_stellaris_enet; } diff --git a/hw/net/trace-events b/hw/net/trace-events index c1dea4b156..9d49f62fa1 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -98,6 +98,9 @@ net_rx_pkt_rss_ip6_ex(void) "Calculating IPv6/EX RSS hash" net_rx_pkt_rss_hash(size_t rss_length, uint32_t rss_hash) "RSS hash for %zu bytes: 0x%X" net_rx_pkt_rss_add_chunk(void* ptr, size_t size, size_t input_offset) "Add RSS chunk %p, %zu bytes, RSS input offset %zu bytes" +# hw/net/e1000.c +e1000_receiver_overrun(size_t s, uint32_t rdh, uint32_t rdt) "Receiver overrun: dropped packet of %zu bytes, RDH=%u, RDT=%u" + # hw/net/e1000x_common.c e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d" e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X" diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 4bdd5b8532..385b1a03e9 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -2020,10 +2020,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) if (n->net_conf.tx && strcmp(n->net_conf.tx, "timer") && strcmp(n->net_conf.tx, "bh")) { - error_report("virtio-net: " - "Unknown option tx=%s, valid options: \"timer\" \"bh\"", - n->net_conf.tx); - error_report("Defaulting to \"bh\""); + warn_report("virtio-net: " + "Unknown option tx=%s, valid options: \"timer\" \"bh\"", + n->net_conf.tx); + error_printf("Defaulting to \"bh\""); } n->net_conf.tx_queue_size = MIN(virtio_net_max_tx_queue_size(n), diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index fa001563d3..63f5a62ebf 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -374,9 +374,9 @@ static NetClientInfo net_xgmac_enet_info = { .receive = eth_rx, }; -static int xgmac_enet_init(SysBusDevice *sbd) +static void xgmac_enet_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); XgmacState *s = XGMAC(dev); memory_region_init_io(&s->iomem, OBJECT(s), &enet_mem_ops, s, @@ -397,8 +397,6 @@ static int xgmac_enet_init(SysBusDevice *sbd) (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[1] << 8) | s->conf.macaddr.a[0]; - - return 0; } static Property xgmac_properties[] = { @@ -408,10 +406,9 @@ static Property xgmac_properties[] = { static void xgmac_enet_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - sbc->init = xgmac_enet_init; + dc->realize = xgmac_enet_realize; dc->vmsd = &vmstate_xgmac; dc->props = xgmac_properties; } diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs index a912d25391..b318e53a43 100644 --- a/hw/nvram/Makefile.objs +++ b/hw/nvram/Makefile.objs @@ -1,6 +1,6 @@ common-obj-$(CONFIG_DS1225Y) += ds1225y.o common-obj-y += eeprom93xx.o -common-obj-$(CONFIG_I2C) += eeprom_at24c.o +common-obj-$(CONFIG_AT24C) += eeprom_at24c.o common-obj-y += fw_cfg.o common-obj-y += chrp_nvram.o common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index d79a568f54..946f765f7f 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -434,6 +434,11 @@ static bool fw_cfg_data_mem_valid(void *opaque, hwaddr addr, return addr == 0; } +static uint64_t fw_cfg_ctl_mem_read(void *opaque, hwaddr addr, unsigned size) +{ + return 0; +} + static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { @@ -468,6 +473,7 @@ static bool fw_cfg_comb_valid(void *opaque, hwaddr addr, } static const MemoryRegionOps fw_cfg_ctl_mem_ops = { + .read = fw_cfg_ctl_mem_read, .write = fw_cfg_ctl_mem_write, .endianness = DEVICE_BIG_ENDIAN, .valid.accepts = fw_cfg_ctl_mem_valid, @@ -1109,12 +1115,7 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->ctl_iomem); if (s->data_width > data_ops->valid.max_access_size) { - /* memberwise copy because the "old_mmio" member is const */ - s->wide_data_ops.read = data_ops->read; - s->wide_data_ops.write = data_ops->write; - s->wide_data_ops.endianness = data_ops->endianness; - s->wide_data_ops.valid = data_ops->valid; - s->wide_data_ops.impl = data_ops->impl; + s->wide_data_ops = *data_ops; s->wide_data_ops.valid.max_access_size = s->data_width; s->wide_data_ops.impl.max_access_size = s->data_width; diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 9868e2eccc..9f33582706 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -595,7 +595,7 @@ static const VMStateDescription vmstate_bonito = { } }; -static int bonito_pcihost_initfn(SysBusDevice *dev) +static void bonito_pcihost_realize(DeviceState *dev, Error **errp) { PCIHostState *phb = PCI_HOST_BRIDGE(dev); @@ -603,8 +603,6 @@ static int bonito_pcihost_initfn(SysBusDevice *dev) pci_bonito_set_irq, pci_bonito_map_irq, dev, get_system_memory(), get_system_io(), 0x28, 32, TYPE_PCI_BUS); - - return 0; } static void bonito_realize(PCIDevice *dev, Error **errp) @@ -684,7 +682,6 @@ PCIBus *bonito_init(qemu_irq *pic) pcihost->pic = pic; qdev_init_nofail(dev); - /* set the pcihost pointer before bonito_initfn is called */ d = pci_create(phb->bus, PCI_DEVFN(0, 0), TYPE_PCI_BONITO); s = PCI_BONITO(d); s->pcihost = pcihost; @@ -726,9 +723,9 @@ static const TypeInfo bonito_info = { static void bonito_pcihost_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); - k->init = bonito_pcihost_initfn; + dc->realize = bonito_pcihost_realize; } static const TypeInfo bonito_pcihost_info = { diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index 0e608347c1..47293a3915 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -144,7 +144,7 @@ static void i440fx_update_memory_mappings(PCII440FXState *d) memory_region_transaction_begin(); for (i = 0; i < 13; i++) { pam_update(&d->pam_regions[i], i, - pd->config[I440FX_PAM + (DIV_ROUND_UP(i, 2))]); + pd->config[I440FX_PAM + DIV_ROUND_UP(i, 2)]); } memory_region_set_enabled(&d->smram_region, !(pd->config[I440FX_SMRAM] & SMRAM_D_OPEN)); @@ -327,6 +327,10 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) sysbus_add_io(sbd, 0xcfc, &s->data_mem); sysbus_init_ioports(sbd, 0xcfc, 4); + + /* register i440fx 0xcf8 port as coalesced pio */ + memory_region_set_flush_coalesced(&s->data_mem); + memory_region_add_coalescing(&s->conf_mem, 0, 4); } static void i440fx_realize(PCIDevice *dev, Error **errp) diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 02f9576588..966a7cf92d 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -51,6 +51,10 @@ static void q35_host_realize(DeviceState *dev, Error **errp) sysbus_add_io(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem); sysbus_init_ioports(sbd, MCH_HOST_BRIDGE_CONFIG_DATA, 4); + /* register q35 0xcf8 port as coalesced pio */ + memory_region_set_flush_coalesced(&pci->data_mem); + memory_region_add_coalescing(&pci->conf_mem, 0, 4); + pci->bus = pci_root_bus_new(DEVICE(s), "pcie.0", s->mch.pci_address_space, s->mch.address_space_io, @@ -352,7 +356,7 @@ static void mch_update_pam(MCHPCIState *mch) memory_region_transaction_begin(); for (i = 0; i < 13; i++) { pam_update(&mch->pam_regions[i], i, - pd->config[MCH_HOST_BRIDGE_PAM0 + (DIV_ROUND_UP(i, 2))]); + pd->config[MCH_HOST_BRIDGE_PAM0 + DIV_ROUND_UP(i, 2)]); } memory_region_transaction_commit(); } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 51d0dec466..b937f0dc0a 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1737,9 +1737,6 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, info->id = g_new0(PciDeviceId, 1); info->id->vendor = pci_get_word(dev->config + PCI_VENDOR_ID); info->id->device = pci_get_word(dev->config + PCI_DEVICE_ID); - info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID); - info->id->subsystem_vendor = - pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID); info->regions = qmp_query_pci_regions(dev); info->qdev_id = g_strdup(dev->qdev.id ? dev->qdev.id : ""); @@ -1752,6 +1749,16 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, if (type == PCI_HEADER_TYPE_BRIDGE) { info->has_pci_bridge = true; info->pci_bridge = qmp_query_pci_bridge(dev, bus, bus_num); + } else if (type == PCI_HEADER_TYPE_NORMAL) { + info->id->has_subsystem = info->id->has_subsystem_vendor = true; + info->id->subsystem = pci_get_word(dev->config + PCI_SUBSYSTEM_ID); + info->id->subsystem_vendor = + pci_get_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID); + } else if (type == PCI_HEADER_TYPE_CARDBUS) { + info->id->has_subsystem = info->id->has_subsystem_vendor = true; + info->id->subsystem = pci_get_word(dev->config + PCI_CB_SUBSYSTEM_ID); + info->id->subsystem_vendor = + pci_get_word(dev->config + PCI_CB_SUBSYSTEM_VENDOR_ID); } return info; diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 9750464bf4..ad1bcc7990 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -148,8 +148,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp) chip = object_property_get_link(OBJECT(dev), "chip", &local_err); if (!chip) { - error_propagate(errp, local_err); - error_prepend(errp, "required link 'chip' not found: "); + error_propagate_prepend(errp, local_err, + "required link 'chip' not found: "); return; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 98868d893a..c08130facb 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3128,14 +3128,12 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error *local_err = NULL; sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev); PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort); uint64_t size, addr; uint32_t node; - size = memory_region_size(mr); + size = memory_device_get_region_size(MEMORY_DEVICE(dev), &error_abort); - pc_dimm_plug(dev, MACHINE(ms), &local_err); + pc_dimm_plug(dimm, MACHINE(ms), &local_err); if (local_err) { goto out; } @@ -3158,7 +3156,7 @@ static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; out_unplug: - pc_dimm_unplug(dev, MACHINE(ms)); + pc_dimm_unplug(dimm, MACHINE(ms)); out: error_propagate(errp, local_err); } @@ -3169,9 +3167,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, const sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(hotplug_dev); sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev); PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); Error *local_err = NULL; - MemoryRegion *mr; uint64_t size; Object *memdev; hwaddr pagesize; @@ -3181,11 +3177,11 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } - mr = ddc->get_memory_region(dimm, errp); - if (!mr) { + size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &local_err); + if (local_err) { + error_propagate(errp, local_err); return; } - size = memory_region_size(mr); if (size % SPAPR_MEMORY_BLOCK_SIZE) { error_setg(errp, "Hotplugged memory size must be a multiple of " @@ -3202,7 +3198,7 @@ static void spapr_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } - pc_dimm_pre_plug(dev, MACHINE(hotplug_dev), NULL, errp); + pc_dimm_pre_plug(dimm, MACHINE(hotplug_dev), NULL, errp); } struct sPAPRDIMMState { @@ -3257,9 +3253,8 @@ static sPAPRDIMMState *spapr_recover_pending_dimm_state(sPAPRMachineState *ms, PCDIMMDevice *dimm) { sPAPRDRConnector *drc; - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort); - uint64_t size = memory_region_size(mr); + uint64_t size = memory_device_get_region_size(MEMORY_DEVICE(dimm), + &error_abort); uint32_t nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE; uint32_t avail_lmbs = 0; uint64_t addr_start, addr; @@ -3314,7 +3309,7 @@ static void spapr_memory_unplug(HotplugHandler *hotplug_dev, DeviceState *dev) sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev); sPAPRDIMMState *ds = spapr_pending_dimm_unplugs_find(spapr, PC_DIMM(dev)); - pc_dimm_unplug(dev, MACHINE(hotplug_dev)); + pc_dimm_unplug(PC_DIMM(dev), MACHINE(hotplug_dev)); object_unparent(OBJECT(dev)); spapr_pending_dimm_unplugs_remove(spapr, ds); } @@ -3325,14 +3320,12 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev, sPAPRMachineState *spapr = SPAPR_MACHINE(hotplug_dev); Error *local_err = NULL; PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort); uint32_t nr_lmbs; uint64_t size, addr_start, addr; int i; sPAPRDRConnector *drc; - size = memory_region_size(mr); + size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort); nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE; addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index c2271e6ed4..58afa46204 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1724,16 +1724,15 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) if (smc->legacy_irq_allocation) { irq = spapr_irq_findone(spapr, &local_err); if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "can't allocate LSIs: "); + error_propagate_prepend(errp, local_err, + "can't allocate LSIs: "); return; } } spapr_irq_claim(spapr, irq, true, &local_err); if (local_err) { - error_propagate(errp, local_err); - error_prepend(errp, "can't allocate LSIs: "); + error_propagate_prepend(errp, local_err, "can't allocate LSIs: "); return; } diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c index 7cc606e065..0d2fd52487 100644 --- a/hw/riscv/sifive_clint.c +++ b/hw/riscv/sifive_clint.c @@ -47,12 +47,12 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value) if (cpu->env.timecmp <= rtc_r) { /* if we're setting an MTIMECMP value in the "past", immediately raise the timer interrupt */ - riscv_set_local_interrupt(cpu, MIP_MTIP, 1); + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); return; } /* otherwise, set up the future timer interrupt */ - riscv_set_local_interrupt(cpu, MIP_MTIP, 0); + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0)); diff = cpu->env.timecmp - rtc_r; /* back to ns (note args switched in muldiv64) */ next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + @@ -67,7 +67,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value) static void sifive_clint_timer_cb(void *opaque) { RISCVCPU *cpu = opaque; - riscv_set_local_interrupt(cpu, MIP_MTIP, 1); + riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1)); } /* CPU wants to read rtc or timecmp register */ @@ -132,7 +132,7 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value, if (!env) { error_report("clint: invalid timecmp hartid: %zu", hartid); } else if ((addr & 0x3) == 0) { - riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MSIP, value != 0); + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value)); } else { error_report("clint: invalid sip write: %08x", (uint32_t)addr); } diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index f635e6ff67..9cf9a1f986 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -142,10 +142,10 @@ static void sifive_plic_update(SiFivePLICState *plic) int level = sifive_plic_irqs_pending(plic, addrid); switch (mode) { case PLICMode_M: - riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MEIP, level); + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level)); break; case PLICMode_S: - riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_SEIP, level); + riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level)); break; default: break; diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 862f8ff5f7..ef07df2442 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -230,7 +230,9 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + if (cmdline) { + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + } g_free(nodename); } diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index be5ef85e81..8a712ed490 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -156,8 +156,10 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); - qemu_fdt_add_subnode(fdt, "/chosen"); - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + if (cmdline) { + qemu_fdt_add_subnode(fdt, "/chosen"); + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + } } static void spike_v1_10_0_board_init(MachineState *machine) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 005169eabc..4a137a503c 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -254,7 +254,9 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + if (cmdline) { + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); + } g_free(nodename); return fdt; @@ -385,6 +387,8 @@ static void riscv_virt_board_init(MachineState *machine) serial_mm_init(system_memory, memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); + + g_free(plic_hart_config); } static void riscv_virt_board_machine_init(MachineClass *mc) diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 5dbc00ce9b..ca68806e44 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -26,8 +26,10 @@ obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o obj-y += s390-skeys.o obj-y += s390-stattrib.o obj-y += tod.o +obj-y += tod-qemu.o obj-$(CONFIG_KVM) += tod-kvm.o -obj-$(CONFIG_TCG) += tod-qemu.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o obj-$(CONFIG_KVM) += s390-stattrib-kvm.o obj-y += s390-ccw.o +obj-y += ap-device.o +obj-y += ap-bridge.o diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c new file mode 100644 index 0000000000..3795d30dd7 --- /dev/null +++ b/hw/s390x/ap-bridge.c @@ -0,0 +1,78 @@ +/* + * ap bridge + * + * Copyright 2018 IBM Corp. + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "qemu/bitops.h" +#include "hw/s390x/ap-bridge.h" +#include "cpu.h" + +static char *ap_bus_get_dev_path(DeviceState *dev) +{ + /* at most one */ + return g_strdup_printf("/1"); +} + +static void ap_bus_class_init(ObjectClass *oc, void *data) +{ + BusClass *k = BUS_CLASS(oc); + + k->get_dev_path = ap_bus_get_dev_path; + /* More than one ap device does not make sense */ + k->max_dev = 1; +} + +static const TypeInfo ap_bus_info = { + .name = TYPE_AP_BUS, + .parent = TYPE_BUS, + .instance_size = 0, + .class_init = ap_bus_class_init, +}; + +void s390_init_ap(void) +{ + DeviceState *dev; + + /* If no AP instructions then no need for AP bridge */ + if (!s390_has_feat(S390_FEAT_AP)) { + return; + } + + /* Create bridge device */ + dev = qdev_create(NULL, TYPE_AP_BRIDGE); + object_property_add_child(qdev_get_machine(), TYPE_AP_BRIDGE, + OBJECT(dev), NULL); + qdev_init_nofail(dev); + + /* Create bus on bridge device */ + qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS); + } + +static void ap_bridge_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + +static const TypeInfo ap_bridge_info = { + .name = TYPE_AP_BRIDGE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = 0, + .class_init = ap_bridge_class_init, +}; + +static void ap_register(void) +{ + type_register_static(&ap_bridge_info); + type_register_static(&ap_bus_info); +} + +type_init(ap_register) diff --git a/hw/s390x/ap-device.c b/hw/s390x/ap-device.c new file mode 100644 index 0000000000..f5ac8db968 --- /dev/null +++ b/hw/s390x/ap-device.c @@ -0,0 +1,38 @@ +/* + * Adjunct Processor (AP) matrix device + * + * Copyright 2018 IBM Corp. + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "hw/qdev.h" +#include "hw/s390x/ap-device.h" + +static void ap_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "AP device class"; + dc->hotpluggable = false; +} + +static const TypeInfo ap_device_info = { + .name = AP_DEVICE_TYPE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(APDevice), + .class_size = sizeof(DeviceClass), + .class_init = ap_class_init, + .abstract = true, +}; + +static void ap_device_register(void) +{ + type_register_static(&ap_device_info); +} + +type_init(ap_device_register) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 5a9fe45ce8..04ec5cc970 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -750,20 +750,25 @@ static void sch_handle_halt_func(SubchDev *sch) } -static void copy_sense_id_to_guest(SenseId *dest, SenseId *src) +/* + * As the SenseId struct cannot be packed (would cause unaligned accesses), we + * have to copy the individual fields to an unstructured area using the correct + * layout (see SA22-7204-01 "Common I/O-Device Commands"). + */ +static void copy_sense_id_to_guest(uint8_t *dest, SenseId *src) { int i; - dest->reserved = src->reserved; - dest->cu_type = cpu_to_be16(src->cu_type); - dest->cu_model = src->cu_model; - dest->dev_type = cpu_to_be16(src->dev_type); - dest->dev_model = src->dev_model; - dest->unused = src->unused; - for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) { - dest->ciw[i].type = src->ciw[i].type; - dest->ciw[i].command = src->ciw[i].command; - dest->ciw[i].count = cpu_to_be16(src->ciw[i].count); + dest[0] = src->reserved; + stw_be_p(dest + 1, src->cu_type); + dest[3] = src->cu_model; + stw_be_p(dest + 4, src->dev_type); + dest[6] = src->dev_model; + dest[7] = src->unused; + for (i = 0; i < ARRAY_SIZE(src->ciw); i++) { + dest[8 + i * 4] = src->ciw[i].type; + dest[9 + i * 4] = src->ciw[i].command; + stw_be_p(dest + 10 + i * 4, src->ciw[i].count); } } @@ -1044,9 +1049,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, break; case CCW_CMD_SENSE_ID: { - SenseId sense_id; + /* According to SA22-7204-01, Sense-ID can store up to 256 bytes */ + uint8_t sense_id[256]; - copy_sense_id_to_guest(&sense_id, &sch->id); + copy_sense_id_to_guest(sense_id, &sch->id); /* Sense ID information is device specific. */ if (check_len) { if (ccw.count != sizeof(sense_id)) { @@ -1060,11 +1066,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, * have enough place to store at least bytes 0-3. */ if (len >= 4) { - sense_id.reserved = 0xff; + sense_id[0] = 0xff; } else { - sense_id.reserved = 0; + sense_id[0] = 0; } - ccw_dstream_write_buf(&sch->cds, &sense_id, len); + ccw_dstream_write_buf(&sch->cds, sense_id, len); sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds); ret = 0; break; diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 4e87b89418..b3a07a12d8 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -132,15 +132,15 @@ typedef struct QemuIplParameters QemuIplParameters; struct S390IPLState { /*< private >*/ DeviceState parent_obj; + IplParameterBlock iplb; + QemuIplParameters qipl; uint64_t start_addr; uint64_t compat_start_addr; uint64_t bios_start_addr; uint64_t compat_bios_start_addr; bool enforce_bios; - IplParameterBlock iplb; bool iplb_valid; bool netboot; - QemuIplParameters qipl; /* reset related properties don't have to be migrated or reset */ enum s390_reset reset_type; int reset_cpu_index; @@ -157,6 +157,7 @@ struct S390IPLState { bool iplbext_migration; }; typedef struct S390IPLState S390IPLState; +QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong"); #define S390_IPL_TYPE_FCP 0x00 #define S390_IPL_TYPE_CCW 0x02 diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index e3e0ebb7f6..e42e1b80d6 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -692,27 +692,35 @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn) object_unref(OBJECT(iommu)); } -static int s390_pcihost_init(SysBusDevice *dev) +static void s390_pcihost_realize(DeviceState *dev, Error **errp) { PCIBus *b; BusState *bus; PCIHostState *phb = PCI_HOST_BRIDGE(dev); S390pciState *s = S390_PCI_HOST_BRIDGE(dev); + Error *local_err = NULL; DPRINTF("host_init\n"); - b = pci_register_root_bus(DEVICE(dev), NULL, - s390_pci_set_irq, s390_pci_map_irq, NULL, - get_system_memory(), get_system_io(), 0, 64, - TYPE_PCI_BUS); + b = pci_register_root_bus(dev, NULL, s390_pci_set_irq, s390_pci_map_irq, + NULL, get_system_memory(), get_system_io(), 0, + 64, TYPE_PCI_BUS); pci_setup_iommu(b, s390_pci_dma_iommu, s); bus = BUS(b); - qbus_set_hotplug_handler(bus, DEVICE(dev), NULL); + qbus_set_hotplug_handler(bus, dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } phb->bus = b; - s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL)); - qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL); + s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL)); + qbus_set_hotplug_handler(BUS(s->bus), dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, g_free); @@ -722,9 +730,10 @@ static int s390_pcihost_init(SysBusDevice *dev) QTAILQ_INIT(&s->zpci_devs); css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, - S390_ADAPTER_SUPPRESSIBLE, &error_abort); - - return 0; + S390_ADAPTER_SUPPRESSIBLE, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } } static int s390_pci_msix_init(S390PCIBusDevice *pbdev) @@ -1018,12 +1027,11 @@ static void s390_pcihost_reset(DeviceState *dev) static void s390_pcihost_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); dc->reset = s390_pcihost_reset; - k->init = s390_pcihost_init; + dc->realize = s390_pcihost_realize; hc->plug = s390_pcihost_hot_plug; hc->unplug = s390_pcihost_hot_unplug; msi_nonbroken = true; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index f0f7fdcadd..a0615a8b35 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -32,6 +32,7 @@ #include "ipl.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/css-bridge.h" +#include "hw/s390x/ap-bridge.h" #include "migration/register.h" #include "cpu_models.h" #include "hw/nmi.h" @@ -263,6 +264,9 @@ static void ccw_init(MachineState *machine) /* init the SIGP facility */ s390_init_sigp(); + /* create AP bridge and bus(es) */ + s390_init_ap(); + /* get a BUS */ css_bus = virtual_css_bus_init(); s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, @@ -456,6 +460,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) s390mc->ri_allowed = true; s390mc->cpu_model_allowed = true; s390mc->css_migration_enabled = true; + s390mc->hpage_1m_allowed = true; mc->init = ccw_init; mc->reset = s390_machine_reset; mc->hot_add_cpu = s390_hot_add_cpu; @@ -535,6 +540,12 @@ bool cpu_model_allowed(void) return get_machine_class()->cpu_model_allowed; } +bool hpage_1m_allowed(void) +{ + /* for "none" machine this results in true */ + return get_machine_class()->hpage_1m_allowed; +} + static char *machine_get_loadparm(Object *obj, Error **errp) { S390CcwMachineState *ms = S390_CCW_MACHINE(obj); @@ -747,6 +758,9 @@ static void ccw_machine_3_0_instance_options(MachineState *machine) static void ccw_machine_3_0_class_options(MachineClass *mc) { + S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); + + s390mc->hpage_1m_allowed = false; ccw_machine_3_1_class_options(mc); SET_MACHINE_COMPAT(mc, CCW_COMPAT_3_0); } diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 996b40650d..d1e6534311 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -20,20 +20,7 @@ #include "hw/scsi/scsi.h" #include "sysemu/dma.h" #include "qemu/log.h" - -//#define DEBUG_LSI -//#define DEBUG_LSI_REG - -#ifdef DEBUG_LSI -#define DPRINTF(fmt, ...) \ -do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) -#endif +#include "trace.h" static const char *names[] = { "SCNTL0", "SCNTL1", "SCNTL2", "SCNTL3", "SCID", "SXFER", "SDID", "GPREG", @@ -313,7 +300,7 @@ static inline int lsi_irq_on_rsl(LSIState *s) static void lsi_soft_reset(LSIState *s) { - DPRINTF("Reset\n"); + trace_lsi_reset(); s->carry = 0; s->msg_action = 0; @@ -484,15 +471,13 @@ static void lsi_update_irq(LSIState *s) level = 1; if (level != last_level) { - DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n", - level, s->dstat, s->sist1, s->sist0); + trace_lsi_update_irq(level, s->dstat, s->sist1, s->sist0); last_level = level; } lsi_set_irq(s, level); if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) { - DPRINTF("Handled IRQs & disconnected, looking for pending " - "processes\n"); + trace_lsi_update_irq_disconnected(); QTAILQ_FOREACH(p, &s->queue, next) { if (p->pending) { lsi_reselect(s, p); @@ -508,8 +493,7 @@ static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1) uint32_t mask0; uint32_t mask1; - DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", - stat1, stat0, s->sist1, s->sist0); + trace_lsi_script_scsi_interrupt(stat1, stat0, s->sist1, s->sist0); s->sist0 |= stat0; s->sist1 |= stat1; /* Stop processor on fatal or unmasked interrupt. As a special hack @@ -527,7 +511,7 @@ static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1) /* Stop SCRIPTS execution and raise a DMA interrupt. */ static void lsi_script_dma_interrupt(LSIState *s, int stat) { - DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat); + trace_lsi_script_dma_interrupt(stat, s->dstat); s->dstat |= stat; lsi_update_irq(s); lsi_stop_script(s); @@ -547,9 +531,9 @@ static void lsi_bad_phase(LSIState *s, int out, int new_phase) } else { s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1); } - DPRINTF("Data phase mismatch jump to %08x\n", s->dsp); + trace_lsi_bad_phase_jump(s->dsp); } else { - DPRINTF("Phase mismatch interrupt\n"); + trace_lsi_bad_phase_interrupt(); lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); lsi_stop_script(s); } @@ -576,7 +560,7 @@ static void lsi_disconnect(LSIState *s) static void lsi_bad_selection(LSIState *s, uint32_t id) { - DPRINTF("Selected absent target %d\n", id); + trace_lsi_bad_selection(id); lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); lsi_disconnect(s); } @@ -591,7 +575,7 @@ static void lsi_do_dma(LSIState *s, int out) assert(s->current); if (!s->current->dma_len) { /* Wait until data is available. */ - DPRINTF("DMA no data available\n"); + trace_lsi_do_dma_unavailable(); return; } @@ -611,7 +595,7 @@ static void lsi_do_dma(LSIState *s, int out) else if (s->sbms) addr |= ((uint64_t)s->sbms << 32); - DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count); + trace_lsi_do_dma(addr, count); s->csbc += count; s->dnad += count; s->dbc -= count; @@ -640,7 +624,7 @@ static void lsi_queue_command(LSIState *s) { lsi_request *p = s->current; - DPRINTF("Queueing tag=0x%x\n", p->tag); + trace_lsi_queue_command(p->tag); assert(s->current != NULL); assert(s->current->dma_len == 0); QTAILQ_INSERT_TAIL(&s->queue, s->current, next); @@ -654,9 +638,9 @@ static void lsi_queue_command(LSIState *s) static void lsi_add_msg_byte(LSIState *s, uint8_t data) { if (s->msg_len >= LSI_MAX_MSGIN_LEN) { - BADF("MSG IN data too long\n"); + trace_lsi_add_msg_byte_error(); } else { - DPRINTF("MSG IN 0x%02x\n", data); + trace_lsi_add_msg_byte(data); s->msg[s->msg_len++] = data; } } @@ -676,7 +660,7 @@ static void lsi_reselect(LSIState *s, lsi_request *p) if (!(s->dcntl & LSI_DCNTL_COM)) { s->sfbr = 1 << (id & 0x7); } - DPRINTF("Reselected target %d\n", id); + trace_lsi_reselect(id); s->scntl1 |= LSI_SCNTL1_CON; lsi_set_phase(s, PHASE_MI); s->msg_action = p->out ? 2 : 3; @@ -732,7 +716,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len) lsi_request *p = req->hba_private; if (p->pending) { - BADF("Multiple IO pending for request %p\n", p); + trace_lsi_queue_req_error(p); } p->pending = len; /* Reselect if waiting for it, or if reselection triggers an IRQ @@ -747,7 +731,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len) lsi_reselect(s, p); return 0; } else { - DPRINTF("Queueing IO tag=0x%x\n", p->tag); + trace_lsi_queue_req(p->tag); p->pending = len; return 1; } @@ -760,7 +744,7 @@ static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; - DPRINTF("Command complete status=%d\n", (int)status); + trace_lsi_command_complete(status); s->status = status; s->command_complete = 2; if (s->waiting && s->dbc != 0) { @@ -795,7 +779,7 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len) out = (s->sstat1 & PHASE_MASK) == PHASE_DO; /* host adapter (re)connected */ - DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len); + trace_lsi_transfer_data(req->tag, len); s->current->dma_len = len; s->command_complete = 1; if (s->waiting) { @@ -814,7 +798,7 @@ static void lsi_do_command(LSIState *s) uint32_t id; int n; - DPRINTF("Send command len=%d\n", s->dbc); + trace_lsi_do_command(s->dbc); if (s->dbc > 16) s->dbc = 16; pci_dma_read(PCI_DEVICE(s), s->dnad, buf, s->dbc); @@ -862,9 +846,10 @@ static void lsi_do_command(LSIState *s) static void lsi_do_status(LSIState *s) { uint8_t status; - DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status); - if (s->dbc != 1) - BADF("Bad Status move\n"); + trace_lsi_do_status(s->dbc, s->status); + if (s->dbc != 1) { + trace_lsi_do_status_error(); + } s->dbc = 1; status = s->status; s->sfbr = status; @@ -877,7 +862,7 @@ static void lsi_do_status(LSIState *s) static void lsi_do_msgin(LSIState *s) { int len; - DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len); + trace_lsi_do_msgin(s->dbc, s->msg_len); s->sfbr = s->msg[0]; len = s->msg_len; if (len > s->dbc) @@ -942,36 +927,36 @@ static void lsi_do_msgout(LSIState *s) current_req = lsi_find_by_tag(s, current_tag); } - DPRINTF("MSG out len=%d\n", s->dbc); + trace_lsi_do_msgout(s->dbc); while (s->dbc) { msg = lsi_get_msgbyte(s); s->sfbr = msg; switch (msg) { case 0x04: - DPRINTF("MSG: Disconnect\n"); + trace_lsi_do_msgout_disconnect(); lsi_disconnect(s); break; case 0x08: - DPRINTF("MSG: No Operation\n"); + trace_lsi_do_msgout_noop(); lsi_set_phase(s, PHASE_CMD); break; case 0x01: len = lsi_get_msgbyte(s); msg = lsi_get_msgbyte(s); (void)len; /* avoid a warning about unused variable*/ - DPRINTF("Extended message 0x%x (len %d)\n", msg, len); + trace_lsi_do_msgout_extended(msg, len); switch (msg) { case 1: - DPRINTF("SDTR (ignored)\n"); + trace_lsi_do_msgout_ignored("SDTR"); lsi_skip_msgbytes(s, 2); break; case 3: - DPRINTF("WDTR (ignored)\n"); + trace_lsi_do_msgout_ignored("WDTR"); lsi_skip_msgbytes(s, 1); break; case 4: - DPRINTF("PPR (ignored)\n"); + trace_lsi_do_msgout_ignored("PPR"); lsi_skip_msgbytes(s, 5); break; default: @@ -980,19 +965,20 @@ static void lsi_do_msgout(LSIState *s) break; case 0x20: /* SIMPLE queue */ s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; - DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff); + trace_lsi_do_msgout_simplequeue(s->select_tag & 0xff); break; case 0x21: /* HEAD of queue */ - BADF("HEAD queue not implemented\n"); + qemu_log_mask(LOG_UNIMP, "lsi_scsi: HEAD queue not implemented\n"); s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; break; case 0x22: /* ORDERED queue */ - BADF("ORDERED queue not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: ORDERED queue not implemented\n"); s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; break; case 0x0d: /* The ABORT TAG message clears the current I/O process only. */ - DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag); + trace_lsi_do_msgout_abort(current_tag); if (current_req) { scsi_req_cancel(current_req->req); } @@ -1004,17 +990,17 @@ static void lsi_do_msgout(LSIState *s) /* The ABORT message clears all I/O processes for the selecting initiator on the specified logical unit of the target. */ if (msg == 0x06) { - DPRINTF("MSG: ABORT tag=0x%x\n", current_tag); + trace_lsi_do_msgout_abort(current_tag); } /* The CLEAR QUEUE message clears all I/O processes for all initiators on the specified logical unit of the target. */ if (msg == 0x0e) { - DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag); + trace_lsi_do_msgout_clearqueue(current_tag); } /* The BUS DEVICE RESET message clears all I/O processes for all initiators on all logical units of the target. */ if (msg == 0x0c) { - DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); + trace_lsi_do_msgout_busdevicereset(current_tag); } /* clear the current I/O process */ @@ -1042,14 +1028,14 @@ static void lsi_do_msgout(LSIState *s) goto bad; } s->current_lun = msg & 7; - DPRINTF("Select LUN %d\n", s->current_lun); + trace_lsi_do_msgout_select(s->current_lun); lsi_set_phase(s, PHASE_CMD); break; } } return; bad: - BADF("Unimplemented message 0x%02x\n", msg); + qemu_log_mask(LOG_UNIMP, "Unimplemented message 0x%02x\n", msg); lsi_set_phase(s, PHASE_MI); lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */ s->msg_action = 0; @@ -1061,7 +1047,7 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) int n; uint8_t buf[LSI_BUF_SIZE]; - DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + trace_lsi_memcpy(dest, src, count); while (count) { n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count; lsi_mem_read(s, src, buf, n); @@ -1076,7 +1062,7 @@ static void lsi_wait_reselect(LSIState *s) { lsi_request *p; - DPRINTF("Wait Reselect\n"); + trace_lsi_wait_reselect(); QTAILQ_FOREACH(p, &s->queue, next) { if (p->pending) { @@ -1109,14 +1095,14 @@ again: } addr = read_dword(s, s->dsp + 4); addr_high = 0; - DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr); + trace_lsi_execute_script(s->dsp, insn, addr); s->dsps = addr; s->dcmd = insn >> 24; s->dsp += 8; switch (insn >> 30) { case 0: /* Block move. */ if (s->sist1 & LSI_SIST1_STO) { - DPRINTF("Delayed select timeout\n"); + trace_lsi_execute_script_blockmove_delayed(); lsi_stop_script(s); break; } @@ -1171,8 +1157,9 @@ again: addr_high = s->dbms; break; default: - BADF("Illegal selector specified (0x%x > 0x15)" - " for 64-bit DMA block move", selector); + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: Illegal selector specified (0x%x > 0x15) " + "for 64-bit DMA block move", selector); break; } } @@ -1184,8 +1171,8 @@ again: s->ia = s->dsp - 12; } if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { - DPRINTF("Wrong phase got %d expected %d\n", - s->sstat1 & PHASE_MASK, (insn >> 24) & 7); + trace_lsi_execute_script_blockmove_badphase(s->sstat1 & PHASE_MASK, + (insn >> 24) & 7); lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); break; } @@ -1217,8 +1204,8 @@ again: lsi_do_msgin(s); break; default: - BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK); - exit(1); + qemu_log_mask(LOG_UNIMP, "lsi_scsi: Unimplemented phase %d\n", + s->sstat1 & PHASE_MASK); } s->dfifo = s->dbc & 0xff; s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3); @@ -1246,7 +1233,7 @@ again: case 0: /* Select */ s->sdid = id; if (s->scntl1 & LSI_SCNTL1_CON) { - DPRINTF("Already reselected, jumping to alternative address\n"); + trace_lsi_execute_script_io_alreadyreselected(); s->dsp = s->dnad; break; } @@ -1256,8 +1243,8 @@ again: lsi_bad_selection(s, id); break; } - DPRINTF("Selected target %d%s\n", - id, insn & (1 << 3) ? " ATN" : ""); + trace_lsi_execute_script_io_selected(id, + insn & (1 << 3) ? " ATN" : ""); /* ??? Linux drivers compain when this is set. Maybe it only applies in low-level mode (unimplemented). lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ @@ -1269,7 +1256,7 @@ again: lsi_set_phase(s, PHASE_MO); break; case 1: /* Disconnect */ - DPRINTF("Wait Disconnect\n"); + trace_lsi_execute_script_io_disconnect(); s->scntl1 &= ~LSI_SCNTL1_CON; break; case 2: /* Wait Reselect */ @@ -1278,7 +1265,7 @@ again: } break; case 3: /* Set */ - DPRINTF("Set%s%s%s%s\n", + trace_lsi_execute_script_io_set( insn & (1 << 3) ? " ATN" : "", insn & (1 << 6) ? " ACK" : "", insn & (1 << 9) ? " TM" : "", @@ -1288,14 +1275,14 @@ again: lsi_set_phase(s, PHASE_MO); } if (insn & (1 << 9)) { - BADF("Target mode not implemented\n"); - exit(1); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: Target mode not implemented\n"); } if (insn & (1 << 10)) s->carry = 1; break; case 4: /* Clear */ - DPRINTF("Clear%s%s%s%s\n", + trace_lsi_execute_script_io_clear( insn & (1 << 3) ? " ATN" : "", insn & (1 << 6) ? " ACK" : "", insn & (1 << 9) ? " TM" : "", @@ -1313,18 +1300,17 @@ again: uint8_t data8; int reg; int operator; -#ifdef DEBUG_LSI + static const char *opcode_names[3] = {"Write", "Read", "Read-Modify-Write"}; static const char *operator_names[8] = {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"}; -#endif reg = ((insn >> 16) & 0x7f) | (insn & 0x80); data8 = (insn >> 8) & 0xff; opcode = (insn >> 27) & 7; operator = (insn >> 24) & 7; - DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n", + trace_lsi_execute_script_io_opcode( opcode_names[opcode - 5], reg, operator_names[operator], data8, s->sfbr, (insn & (1 << 23)) ? " SFBR" : ""); @@ -1404,21 +1390,21 @@ again: int jmp; if ((insn & 0x002e0000) == 0) { - DPRINTF("NOP\n"); + trace_lsi_execute_script_tc_nop(); break; } if (s->sist1 & LSI_SIST1_STO) { - DPRINTF("Delayed select timeout\n"); + trace_lsi_execute_script_tc_delayedselect_timeout(); lsi_stop_script(s); break; } cond = jmp = (insn & (1 << 19)) != 0; if (cond == jmp && (insn & (1 << 21))) { - DPRINTF("Compare carry %d\n", s->carry == jmp); + trace_lsi_execute_script_tc_compc(s->carry == jmp); cond = s->carry != 0; } if (cond == jmp && (insn & (1 << 17))) { - DPRINTF("Compare phase %d %c= %d\n", + trace_lsi_execute_script_tc_compp( (s->sstat1 & PHASE_MASK), jmp ? '=' : '!', ((insn >> 24) & 7)); @@ -1428,7 +1414,7 @@ again: uint8_t mask; mask = (~insn >> 8) & 0xff; - DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n", + trace_lsi_execute_script_tc_compd( s->sfbr, mask, jmp ? '=' : '!', insn & mask); cond = (s->sfbr & mask) == (insn & mask); } @@ -1439,21 +1425,21 @@ again: } switch ((insn >> 27) & 7) { case 0: /* Jump */ - DPRINTF("Jump to 0x%08x\n", addr); + trace_lsi_execute_script_tc_jump(addr); s->adder = addr; s->dsp = addr; break; case 1: /* Call */ - DPRINTF("Call 0x%08x\n", addr); + trace_lsi_execute_script_tc_call(addr); s->temp = s->dsp; s->dsp = addr; break; case 2: /* Return */ - DPRINTF("Return to 0x%08x\n", s->temp); + trace_lsi_execute_script_tc_return(s->temp); s->dsp = s->temp; break; case 3: /* Interrupt */ - DPRINTF("Interrupt 0x%08x\n", s->dsps); + trace_lsi_execute_script_tc_interrupt(s->dsps); if ((insn & (1 << 20)) != 0) { s->istat0 |= LSI_ISTAT0_INTF; lsi_update_irq(s); @@ -1462,12 +1448,12 @@ again: } break; default: - DPRINTF("Illegal transfer control\n"); + trace_lsi_execute_script_tc_illegal(); lsi_script_dma_interrupt(s, LSI_DSTAT_IID); break; } } else { - DPRINTF("Control condition failed\n"); + trace_lsi_execute_script_tc_cc_failed(); } } break; @@ -1495,13 +1481,12 @@ again: reg = (insn >> 16) & 0xff; if (insn & (1 << 24)) { pci_dma_read(pci_dev, addr, data, n); - DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, - addr, *(int *)data); + trace_lsi_execute_script_mm_load(reg, n, addr, *(int *)data); for (i = 0; i < n; i++) { lsi_reg_writeb(s, reg + i, data[i]); } } else { - DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + trace_lsi_execute_script_mm_store(reg, n, addr); for (i = 0; i < n; i++) { data[i] = lsi_reg_readb(s, reg + i); } @@ -1515,8 +1500,10 @@ again: assume this is the case and force an unexpected device disconnect. This is apparently sufficient to beat the drivers into submission. */ - if (!(s->sien0 & LSI_SIST0_UDC)) - fprintf(stderr, "inf. loop with UDC masked\n"); + if (!(s->sien0 & LSI_SIST0_UDC)) { + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: inf. loop with UDC masked"); + } lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0); lsi_disconnect(s); } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { @@ -1526,7 +1513,7 @@ again: goto again; } } - DPRINTF("SCRIPTS execution stopped\n"); + trace_lsi_execute_script_stop(); } static uint8_t lsi_reg_readb(LSIState *s, int offset) @@ -1761,10 +1748,8 @@ static uint8_t lsi_reg_readb(LSIState *s, int offset) #undef CASE_GET_REG24 #undef CASE_GET_REG32 -#ifdef DEBUG_LSI_REG - DPRINTF("Read reg %s %x = %02x\n", - offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, ret); -#endif + trace_lsi_reg_read(offset < ARRAY_SIZE(names) ? names[offset] : "???", + offset, ret); return ret; } @@ -1782,21 +1767,22 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \ case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break; -#ifdef DEBUG_LSI_REG - DPRINTF("Write reg %s %x = %02x\n", - offset < ARRAY_SIZE(names) ? names[offset] : "???", offset, val); -#endif + trace_lsi_reg_write(offset < ARRAY_SIZE(names) ? names[offset] : "???", + offset, val); + switch (offset) { case 0x00: /* SCNTL0 */ s->scntl0 = val; if (val & LSI_SCNTL0_START) { - BADF("Start sequence not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: Start sequence not implemented\n"); } break; case 0x01: /* SCNTL1 */ s->scntl1 = val & ~LSI_SCNTL1_SST; if (val & LSI_SCNTL1_IARB) { - BADF("Immediate Arbritration not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: Immediate Arbritration not implemented\n"); } if (val & LSI_SCNTL1_RST) { if (!(s->sstat0 & LSI_SSTAT0_RST)) { @@ -1823,7 +1809,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) break; case 0x06: /* SDID */ if ((s->ssid & 0x80) && (val & 0xf) != (s->ssid & 0xf)) { - BADF("Destination ID does not match SSID\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "lsi_scsi: Destination ID does not match SSID\n"); } s->sdid = val & 0xf; break; @@ -1851,7 +1838,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) lsi_update_irq(s); } if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) { - DPRINTF("Woken by SIGP\n"); + trace_lsi_awoken(); s->waiting = 0; s->dsp = s->dnad; lsi_execute_script(s); @@ -1878,13 +1865,15 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) CASE_SET_REG32(temp, 0x1c) case 0x21: /* CTEST4 */ if (val & 7) { - BADF("Unimplemented CTEST4-FBL 0x%x\n", val); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: Unimplemented CTEST4-FBL 0x%x\n", val); } s->ctest4 = val; break; case 0x22: /* CTEST5 */ if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) { - BADF("CTEST5 DMA increment not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: CTEST5 DMA increment not implemented\n"); } s->ctest5 = val; break; @@ -1941,7 +1930,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) break; case 0x49: /* STIME1 */ if (val & 0xf) { - DPRINTF("General purpose timer not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: General purpose timer not implemented\n"); /* ??? Raising the interrupt immediately seems to be sufficient to keep the FreeBSD driver happy. */ lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN); @@ -1958,13 +1948,15 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) break; case 0x4e: /* STEST2 */ if (val & 1) { - BADF("Low level mode not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: Low level mode not implemented\n"); } s->stest2 = val; break; case 0x4f: /* STEST3 */ if (val & 0x41) { - BADF("SCSI FIFO test mode not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "lsi_scsi: SCSI FIFO test mode not implemented\n"); } s->stest3 = val; break; diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c index 8ae39a76f4..79f99734d2 100644 --- a/hw/scsi/mptendian.c +++ b/hw/scsi/mptendian.c @@ -35,152 +35,155 @@ static void mptsas_fix_sgentry_endianness(MPISGEntry *sge) { - le32_to_cpus(&sge->FlagsLength); + sge->FlagsLength = le32_to_cpu(sge->FlagsLength); if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { - le64_to_cpus(&sge->u.Address64); + sge->u.Address64 = le64_to_cpu(sge->u.Address64); } else { - le32_to_cpus(&sge->u.Address32); + sge->u.Address32 = le32_to_cpu(sge->u.Address32); } } static void mptsas_fix_sgentry_endianness_reply(MPISGEntry *sge) { if (sge->FlagsLength & MPI_SGE_FLAGS_64_BIT_ADDRESSING) { - cpu_to_le64s(&sge->u.Address64); + sge->u.Address64 = cpu_to_le64(sge->u.Address64); } else { - cpu_to_le32s(&sge->u.Address32); + sge->u.Address32 = cpu_to_le32(sge->u.Address32); } - cpu_to_le32s(&sge->FlagsLength); + sge->FlagsLength = cpu_to_le32(sge->FlagsLength); } void mptsas_fix_scsi_io_endianness(MPIMsgSCSIIORequest *req) { - le32_to_cpus(&req->MsgContext); - le32_to_cpus(&req->Control); - le32_to_cpus(&req->DataLength); - le32_to_cpus(&req->SenseBufferLowAddr); + req->MsgContext = le32_to_cpu(req->MsgContext); + req->Control = le32_to_cpu(req->Control); + req->DataLength = le32_to_cpu(req->DataLength); + req->SenseBufferLowAddr = le32_to_cpu(req->SenseBufferLowAddr); } void mptsas_fix_scsi_io_reply_endianness(MPIMsgSCSIIOReply *reply) { - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); - cpu_to_le32s(&reply->TransferCount); - cpu_to_le32s(&reply->SenseCount); - cpu_to_le32s(&reply->ResponseInfo); - cpu_to_le16s(&reply->TaskTag); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); + reply->TransferCount = cpu_to_le32(reply->TransferCount); + reply->SenseCount = cpu_to_le32(reply->SenseCount); + reply->ResponseInfo = cpu_to_le32(reply->ResponseInfo); + reply->TaskTag = cpu_to_le16(reply->TaskTag); } void mptsas_fix_scsi_task_mgmt_endianness(MPIMsgSCSITaskMgmt *req) { - le32_to_cpus(&req->MsgContext); - le32_to_cpus(&req->TaskMsgContext); + req->MsgContext = le32_to_cpu(req->MsgContext); + req->TaskMsgContext = le32_to_cpu(req->TaskMsgContext); } void mptsas_fix_scsi_task_mgmt_reply_endianness(MPIMsgSCSITaskMgmtReply *reply) { - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); - cpu_to_le32s(&reply->TerminationCount); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); + reply->TerminationCount = cpu_to_le32(reply->TerminationCount); } void mptsas_fix_ioc_init_endianness(MPIMsgIOCInit *req) { - le32_to_cpus(&req->MsgContext); - le16_to_cpus(&req->ReplyFrameSize); - le32_to_cpus(&req->HostMfaHighAddr); - le32_to_cpus(&req->SenseBufferHighAddr); - le32_to_cpus(&req->ReplyFifoHostSignalingAddr); + req->MsgContext = le32_to_cpu(req->MsgContext); + req->ReplyFrameSize = le16_to_cpu(req->ReplyFrameSize); + req->HostMfaHighAddr = le32_to_cpu(req->HostMfaHighAddr); + req->SenseBufferHighAddr = le32_to_cpu(req->SenseBufferHighAddr); + req->ReplyFifoHostSignalingAddr = + le32_to_cpu(req->ReplyFifoHostSignalingAddr); mptsas_fix_sgentry_endianness(&req->HostPageBufferSGE); - le16_to_cpus(&req->MsgVersion); - le16_to_cpus(&req->HeaderVersion); + req->MsgVersion = le16_to_cpu(req->MsgVersion); + req->HeaderVersion = le16_to_cpu(req->HeaderVersion); } void mptsas_fix_ioc_init_reply_endianness(MPIMsgIOCInitReply *reply) { - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); } void mptsas_fix_ioc_facts_endianness(MPIMsgIOCFacts *req) { - le32_to_cpus(&req->MsgContext); + req->MsgContext = le32_to_cpu(req->MsgContext); } void mptsas_fix_ioc_facts_reply_endianness(MPIMsgIOCFactsReply *reply) { - cpu_to_le16s(&reply->MsgVersion); - cpu_to_le16s(&reply->HeaderVersion); - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCExceptions); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); - cpu_to_le16s(&reply->ReplyQueueDepth); - cpu_to_le16s(&reply->RequestFrameSize); - cpu_to_le16s(&reply->ProductID); - cpu_to_le32s(&reply->CurrentHostMfaHighAddr); - cpu_to_le16s(&reply->GlobalCredits); - cpu_to_le32s(&reply->CurrentSenseBufferHighAddr); - cpu_to_le16s(&reply->CurReplyFrameSize); - cpu_to_le32s(&reply->FWImageSize); - cpu_to_le32s(&reply->IOCCapabilities); - cpu_to_le16s(&reply->HighPriorityQueueDepth); + reply->MsgVersion = cpu_to_le16(reply->MsgVersion); + reply->HeaderVersion = cpu_to_le16(reply->HeaderVersion); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCExceptions = cpu_to_le16(reply->IOCExceptions); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); + reply->ReplyQueueDepth = cpu_to_le16(reply->ReplyQueueDepth); + reply->RequestFrameSize = cpu_to_le16(reply->RequestFrameSize); + reply->ProductID = cpu_to_le16(reply->ProductID); + reply->CurrentHostMfaHighAddr = cpu_to_le32(reply->CurrentHostMfaHighAddr); + reply->GlobalCredits = cpu_to_le16(reply->GlobalCredits); + reply->CurrentSenseBufferHighAddr = + cpu_to_le32(reply->CurrentSenseBufferHighAddr); + reply->CurReplyFrameSize = cpu_to_le16(reply->CurReplyFrameSize); + reply->FWImageSize = cpu_to_le32(reply->FWImageSize); + reply->IOCCapabilities = cpu_to_le32(reply->IOCCapabilities); + reply->HighPriorityQueueDepth = cpu_to_le16(reply->HighPriorityQueueDepth); mptsas_fix_sgentry_endianness_reply(&reply->HostPageBufferSGE); - cpu_to_le32s(&reply->ReplyFifoHostSignalingAddr); + reply->ReplyFifoHostSignalingAddr = + cpu_to_le32(reply->ReplyFifoHostSignalingAddr); } void mptsas_fix_config_endianness(MPIMsgConfig *req) { - le16_to_cpus(&req->ExtPageLength); - le32_to_cpus(&req->MsgContext); - le32_to_cpus(&req->PageAddress); + req->ExtPageLength = le16_to_cpu(req->ExtPageLength); + req->MsgContext = le32_to_cpu(req->MsgContext); + req->PageAddress = le32_to_cpu(req->PageAddress); mptsas_fix_sgentry_endianness(&req->PageBufferSGE); } void mptsas_fix_config_reply_endianness(MPIMsgConfigReply *reply) { - cpu_to_le16s(&reply->ExtPageLength); - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); + reply->ExtPageLength = cpu_to_le16(reply->ExtPageLength); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); } void mptsas_fix_port_facts_endianness(MPIMsgPortFacts *req) { - le32_to_cpus(&req->MsgContext); + req->MsgContext = le32_to_cpu(req->MsgContext); } void mptsas_fix_port_facts_reply_endianness(MPIMsgPortFactsReply *reply) { - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); - cpu_to_le16s(&reply->MaxDevices); - cpu_to_le16s(&reply->PortSCSIID); - cpu_to_le16s(&reply->ProtocolFlags); - cpu_to_le16s(&reply->MaxPostedCmdBuffers); - cpu_to_le16s(&reply->MaxPersistentIDs); - cpu_to_le16s(&reply->MaxLanBuckets); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); + reply->MaxDevices = cpu_to_le16(reply->MaxDevices); + reply->PortSCSIID = cpu_to_le16(reply->PortSCSIID); + reply->ProtocolFlags = cpu_to_le16(reply->ProtocolFlags); + reply->MaxPostedCmdBuffers = cpu_to_le16(reply->MaxPostedCmdBuffers); + reply->MaxPersistentIDs = cpu_to_le16(reply->MaxPersistentIDs); + reply->MaxLanBuckets = cpu_to_le16(reply->MaxLanBuckets); } void mptsas_fix_port_enable_endianness(MPIMsgPortEnable *req) { - le32_to_cpus(&req->MsgContext); + req->MsgContext = le32_to_cpu(req->MsgContext); } void mptsas_fix_port_enable_reply_endianness(MPIMsgPortEnableReply *reply) { - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); } void mptsas_fix_event_notification_endianness(MPIMsgEventNotify *req) { - le32_to_cpus(&req->MsgContext); + req->MsgContext = le32_to_cpu(req->MsgContext); } void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *reply) @@ -188,16 +191,16 @@ void mptsas_fix_event_notification_reply_endianness(MPIMsgEventNotifyReply *repl int length = reply->EventDataLength; int i; - cpu_to_le16s(&reply->EventDataLength); - cpu_to_le32s(&reply->MsgContext); - cpu_to_le16s(&reply->IOCStatus); - cpu_to_le32s(&reply->IOCLogInfo); - cpu_to_le32s(&reply->Event); - cpu_to_le32s(&reply->EventContext); + reply->EventDataLength = cpu_to_le16(reply->EventDataLength); + reply->MsgContext = cpu_to_le32(reply->MsgContext); + reply->IOCStatus = cpu_to_le16(reply->IOCStatus); + reply->IOCLogInfo = cpu_to_le32(reply->IOCLogInfo); + reply->Event = cpu_to_le32(reply->Event); + reply->EventContext = cpu_to_le32(reply->EventContext); /* Really depends on the event kind. This will do for now. */ for (i = 0; i < length; i++) { - cpu_to_le32s(&reply->Data[i]); + reply->Data[i] = cpu_to_le32(reply->Data[i]); } } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 5ae7baa082..e2c5408aa2 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -441,9 +441,18 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) } switch (error) { case 0: - /* The command has run, no need to fake sense. */ + /* A passthrough command has run and has produced sense data; check + * whether the error has to be handled by the guest or should rather + * pause the host. + */ assert(r->status && *r->status); - scsi_req_complete(&r->req, *r->status); + error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); + if (error == ECANCELED || error == EAGAIN || error == ENOTCONN || + error == 0) { + /* These errors are handled by guest. */ + scsi_req_complete(&r->req, *r->status); + return true; + } break; case ENOMEDIUM: scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); @@ -462,23 +471,17 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) break; } } - if (!error) { - assert(r->status && *r->status); - error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense)); - if (error == ECANCELED || error == EAGAIN || error == ENOTCONN || - error == 0) { - /* These errors are handled by guest. */ - scsi_req_complete(&r->req, *r->status); - return true; - } + blk_error_action(s->qdev.conf.blk, action, is_read, error); + if (action == BLOCK_ERROR_ACTION_IGNORE) { + scsi_req_complete(&r->req, 0); + return true; } - blk_error_action(s->qdev.conf.blk, action, is_read, error); if (action == BLOCK_ERROR_ACTION_STOP) { scsi_req_retry(&r->req); } - return action != BLOCK_ERROR_ACTION_IGNORE; + return false; } static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) @@ -2610,6 +2613,12 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) return; } + if (s->rotation_rate) { + error_report_once("rotation_rate is specified for scsi-block but is " + "not implemented. This option is deprecated and will " + "be removed in a future version"); + } + /* check we are using a driver managing SG_IO (version 3 and after) */ rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); if (rc < 0) { diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 6e299d0338..0fb6a99616 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -229,3 +229,65 @@ spapr_vscsi_process_login(void) "Got login, sending response !" spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun 0x%08" PRIx64 " with no drive" spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d" spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..." + +# hw/scsi/lsi53c895a.c +lsi_reset(void) "Reset" +lsi_update_irq(int level, uint8_t dstat, uint8_t sist1, uint8_t sist0) "Update IRQ level %d dstat 0x%02x sist 0x%02x0x%02x" +lsi_update_irq_disconnected(void) "Handled IRQs & disconnected, looking for pending processes" +lsi_script_scsi_interrupt(uint8_t stat1, uint8_t stat0, uint8_t sist1, uint8_t sist0) "SCSI Interrupt 0x%02x0x%02x prev 0x%02x0x%02x" +lsi_script_dma_interrupt(uint8_t stat, uint8_t dstat) "DMA Interrupt 0x%x prev 0x%x" +lsi_bad_phase_jump(uint32_t dsp) "Data phase mismatch jump to 0x%"PRIX32 +lsi_bad_phase_interrupt(void) "Phase mismatch interrupt" +lsi_bad_selection(uint32_t id) "Selected absent target %"PRIu32 +lsi_do_dma_unavailable(void) "DMA no data available" +lsi_do_dma(uint64_t addr, int len) "DMA addr=0x%"PRIx64" len=%d" +lsi_queue_command(uint32_t tag) "Queueing tag=0x%"PRId32 +lsi_add_msg_byte_error(void) "MSG IN data too long" +lsi_add_msg_byte(uint8_t data) "MSG IN 0x%02x" +lsi_reselect(int id) "Reselected target %d" +lsi_queue_req_error(void *p) "Multiple IO pending for request %p" +lsi_queue_req(uint32_t tag) "Queueing IO tag=0x%"PRIx32 +lsi_command_complete(uint32_t status) "Command complete status=%"PRId32 +lsi_transfer_data(uint32_t tag, uint32_t len) "Data ready tag=0x%"PRIx32" len=%"PRId32 +lsi_do_command(uint32_t dbc) "Send command len=%"PRId32 +lsi_do_status(uint32_t dbc, uint8_t status) "Get status len=%"PRId32" status=%d" +lsi_do_status_error(void) "Bad Status move" +lsi_do_msgin(uint32_t dbc, int len) "Message in len=%"PRId32" %d" +lsi_do_msgout(uint32_t dbc) "MSG out len=%"PRId32 +lsi_do_msgout_disconnect(void) "MSG: Disconnect" +lsi_do_msgout_noop(void) "MSG: No Operation" +lsi_do_msgout_extended(uint8_t msg, uint8_t len) "Extended message 0x%x (len %d)" +lsi_do_msgout_ignored(const char *msg) "%s (ignored)" +lsi_do_msgout_simplequeue(uint8_t select_tag) "SIMPLE queue tag=0x%x" +lsi_do_msgout_abort(uint32_t tag) "MSG: ABORT TAG tag=0x%"PRId32 +lsi_do_msgout_clearqueue(uint32_t tag) "MSG: CLEAR QUEUE tag=0x%"PRIx32 +lsi_do_msgout_busdevicereset(uint32_t tag) "MSG: BUS DEVICE RESET tag=0x%"PRIx32 +lsi_do_msgout_select(int id) "Select LUN %d" +lsi_memcpy(uint32_t dest, uint32_t src, int count) "memcpy dest 0x%"PRIx32" src 0x%"PRIx32" count %d" +lsi_wait_reselect(void) "Wait Reselect" +lsi_execute_script(uint32_t dsp, uint32_t insn, uint32_t addr) "SCRIPTS dsp=0x%"PRIx32" opcode 0x%"PRIx32" arg 0x%"PRIx32 +lsi_execute_script_blockmove_delayed(void) "Delayed select timeout" +lsi_execute_script_blockmove_badphase(uint8_t phase, uint8_t expected) "Wrong phase got %d expected %d" +lsi_execute_script_io_alreadyreselected(void) "Already reselected, jumping to alternative address" +lsi_execute_script_io_selected(uint8_t id, const char *atn) "Selected target %d%s" +lsi_execute_script_io_disconnect(void) "Wait Disconnect" +lsi_execute_script_io_set(const char *atn, const char *ack, const char *tm, const char *cc) "Set%s%s%s%s" +lsi_execute_script_io_clear(const char *atn, const char *ack, const char *tm, const char *cc) "Clear%s%s%s%s" +lsi_execute_script_io_opcode(const char *opcode, int reg, const char *opname, uint8_t data8, uint32_t sfbr, const char *ssfbr) "%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s" +lsi_execute_script_tc_nop(void) "NOP" +lsi_execute_script_tc_delayedselect_timeout(void) "Delayed select timeout" +lsi_execute_script_tc_compc(int result) "Compare carry %d" +lsi_execute_script_tc_compp(uint8_t phase, int op, uint8_t insn_phase) "Compare phase %d %c= %d" +lsi_execute_script_tc_compd(uint32_t sfbr, uint8_t mask, int op, int result) "Compare data 0x%"PRIx32" & 0x%x %c= 0x%x" +lsi_execute_script_tc_jump(uint32_t addr) "Jump to 0x%"PRIx32 +lsi_execute_script_tc_call(uint32_t addr) "Call 0x%"PRIx32 +lsi_execute_script_tc_return(uint32_t addr) "Return to 0x%"PRIx32 +lsi_execute_script_tc_interrupt(uint32_t addr) "Interrupt 0x%"PRIx32 +lsi_execute_script_tc_illegal(void) "Illegal transfer control" +lsi_execute_script_tc_cc_failed(void) "Control condition failed" +lsi_execute_script_mm_load(int reg, int n, uint32_t addr, int data) "Load reg 0x%x size %d addr 0x%"PRIx32" = 0x%08x" +lsi_execute_script_mm_store(int reg, int n, uint32_t addr) "Store reg 0x%x size %d addr 0x%"PRIx32 +lsi_execute_script_stop(void) "SCRIPTS execution stopped" +lsi_awoken(void) "Woken by SIGP" +lsi_reg_read(const char *name, int offset, uint8_t ret) "Read reg %s 0x%x = 0x%02x" +lsi_reg_write(const char *name, int offset, uint8_t val) "Write reg %s 0x%x = 0x%02x" diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 5a3057d1f8..3aa99717e2 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -797,16 +797,8 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, virtio_scsi_acquire(s); blk_set_aio_context(sd->conf.blk, s->ctx); virtio_scsi_release(s); - } -} -/* Announce the new device after it has been plugged */ -static void virtio_scsi_post_hotplug(HotplugHandler *hotplug_dev, - DeviceState *dev) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev); - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - SCSIDevice *sd = SCSI_DEVICE(dev); + } if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { virtio_scsi_acquire(s); @@ -976,7 +968,6 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) vdc->start_ioeventfd = virtio_scsi_dataplane_start; vdc->stop_ioeventfd = virtio_scsi_dataplane_stop; hc->plug = virtio_scsi_hotplug; - hc->post_plug = virtio_scsi_post_hotplug; hc->unplug = virtio_scsi_hotunplug; } diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 95a143bfba..623d0333e8 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -284,6 +284,8 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->cs_polarity = SSI_CS_LOW; dc->vmsd = &vmstate_ssi_sd; dc->reset = ssi_sd_reset; + /* Reason: init() method uses drive_get_next() */ + dc->user_creatable = false; } static const TypeInfo ssi_sd_info = { diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c index 4ec2e35500..379d0685ed 100644 --- a/hw/sh4/sh_pci.c +++ b/hw/sh4/sh_pci.c @@ -120,16 +120,15 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -static int sh_pci_device_init(SysBusDevice *dev) +static void sh_pci_device_realize(DeviceState *dev, Error **errp) { - PCIHostState *phb; - SHPCIState *s; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + SHPCIState *s = SH_PCI_HOST_BRIDGE(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(s); int i; - s = SH_PCI_HOST_BRIDGE(dev); - phb = PCI_HOST_BRIDGE(s); for (i = 0; i < 4; i++) { - sysbus_init_irq(dev, &s->irq[i]); + sysbus_init_irq(sbd, &s->irq[i]); } phb->bus = pci_register_root_bus(DEVICE(dev), "pci", sh_pci_set_irq, sh_pci_map_irq, @@ -143,13 +142,12 @@ static int sh_pci_device_init(SysBusDevice *dev) &s->memconfig_p4, 0, 0x224); memory_region_init_alias(&s->isa, OBJECT(s), "sh_pci.isa", get_system_io(), 0, 0x40000); - sysbus_init_mmio(dev, &s->memconfig_p4); - sysbus_init_mmio(dev, &s->memconfig_a7); + sysbus_init_mmio(sbd, &s->memconfig_p4); + sysbus_init_mmio(sbd, &s->memconfig_a7); s->iobr = 0xfe240000; memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa); s->dev = pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "sh_pci_host"); - return 0; } static void sh_pci_host_realize(PCIDevice *d, Error **errp) @@ -187,9 +185,9 @@ static const TypeInfo sh_pci_host_info = { static void sh_pci_device_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); - sdc->init = sh_pci_device_init; + dc->realize = sh_pci_device_realize; } static const TypeInfo sh_pci_device_info = { diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index a27e54b2fa..920939454e 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -950,6 +950,7 @@ static void save_opt_list(size_t *ndest, const char ***dest, void smbios_entry_add(QemuOpts *opts, Error **errp) { + Error *err = NULL; const char *val; assert(!smbios_immutable); @@ -960,12 +961,16 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) int size; struct smbios_table *table; /* legacy mode only */ - qemu_opts_validate(opts, qemu_smbios_file_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_file_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } size = get_image_size(val); if (size == -1 || size < sizeof(struct smbios_structure_header)) { - error_report("Cannot read SMBIOS file %s", val); - exit(1); + error_setg(errp, "Cannot read SMBIOS file %s", val); + return; } /* @@ -978,14 +983,15 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) smbios_tables_len); if (load_image(val, (uint8_t *)header) != size) { - error_report("Failed to load SMBIOS file %s", val); - exit(1); + error_setg(errp, "Failed to load SMBIOS file %s", val); + return; } if (test_bit(header->type, have_fields_bitmap)) { - error_report("can't load type %d struct, fields already specified!", - header->type); - exit(1); + error_setg(errp, + "can't load type %d struct, fields already specified!", + header->type); + return; } set_bit(header->type, have_binfile_bitmap); @@ -1030,19 +1036,23 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) unsigned long type = strtoul(val, NULL, 0); if (type > SMBIOS_MAX_TYPE) { - error_report("out of range!"); - exit(1); + error_setg(errp, "out of range!"); + return; } if (test_bit(type, have_binfile_bitmap)) { - error_report("can't add fields, binary file already loaded!"); - exit(1); + error_setg(errp, "can't add fields, binary file already loaded!"); + return; } set_bit(type, have_fields_bitmap); switch (type) { case 0: - qemu_opts_validate(opts, qemu_smbios_type0_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type0_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt(&type0.vendor, opts, "vendor"); save_opt(&type0.version, opts, "version"); save_opt(&type0.date, opts, "date"); @@ -1051,14 +1061,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) val = qemu_opt_get(opts, "release"); if (val) { if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) { - error_report("Invalid release"); - exit(1); + error_setg(errp, "Invalid release"); + return; } type0.have_major_minor = true; } return; case 1: - qemu_opts_validate(opts, qemu_smbios_type1_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type1_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt(&type1.manufacturer, opts, "manufacturer"); save_opt(&type1.product, opts, "product"); save_opt(&type1.version, opts, "version"); @@ -1069,14 +1083,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) val = qemu_opt_get(opts, "uuid"); if (val) { if (qemu_uuid_parse(val, &qemu_uuid) != 0) { - error_report("Invalid UUID"); - exit(1); + error_setg(errp, "Invalid UUID"); + return; } qemu_uuid_set = true; } return; case 2: - qemu_opts_validate(opts, qemu_smbios_type2_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type2_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt(&type2.manufacturer, opts, "manufacturer"); save_opt(&type2.product, opts, "product"); save_opt(&type2.version, opts, "version"); @@ -1085,7 +1103,11 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type2.location, opts, "location"); return; case 3: - qemu_opts_validate(opts, qemu_smbios_type3_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type3_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt(&type3.manufacturer, opts, "manufacturer"); save_opt(&type3.version, opts, "version"); save_opt(&type3.serial, opts, "serial"); @@ -1093,7 +1115,11 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type3.sku, opts, "sku"); return; case 4: - qemu_opts_validate(opts, qemu_smbios_type4_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type4_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt(&type4.sock_pfx, opts, "sock_pfx"); save_opt(&type4.manufacturer, opts, "manufacturer"); save_opt(&type4.version, opts, "version"); @@ -1102,11 +1128,19 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type4.part, opts, "part"); return; case 11: - qemu_opts_validate(opts, qemu_smbios_type11_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type11_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt_list(&type11.nvalues, &type11.values, opts, "value"); return; case 17: - qemu_opts_validate(opts, qemu_smbios_type17_opts, &error_fatal); + qemu_opts_validate(opts, qemu_smbios_type17_opts, &err); + if (err) { + error_propagate(errp, err); + return; + } save_opt(&type17.loc_pfx, opts, "loc_pfx"); save_opt(&type17.bank, opts, "bank"); save_opt(&type17.manufacturer, opts, "manufacturer"); @@ -1116,12 +1150,12 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) type17.speed = qemu_opt_get_number(opts, "speed", 0); return; default: - error_report("Don't know how to build fields for SMBIOS type %ld", - type); - exit(1); + error_setg(errp, + "Don't know how to build fields for SMBIOS type %ld", + type); + return; } } - error_report("Must specify type= or file="); - exit(1); + error_setg(errp, "Must specify type= or file="); } diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index 4fa8cb2904..f8a856f611 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -29,7 +29,7 @@ #include "hw/hw.h" #include "hw/boards.h" #include "hw/char/serial.h" -#include "hw/empty_slot.h" +#include "hw/misc/unimp.h" #include "hw/loader.h" #include "hw/sparc/sparc64.h" #include "hw/timer/sun4v-rtc.h" @@ -161,7 +161,7 @@ static void niagara_init(MachineState *machine) serial_mm_init(sysmem, NIAGARA_UART_BASE, 0, NULL, 115200, serial_hd(0), DEVICE_BIG_ENDIAN); } - empty_slot_init(NIAGARA_IOBBASE, NIAGARA_IOBSIZE); + create_unimplemented_device("sun4v-iob", NIAGARA_IOBBASE, NIAGARA_IOBSIZE); sun4v_rtc_init(NIAGARA_RTC_BASE); } diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index 83585bc8b2..3dae303d5b 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -319,9 +319,9 @@ static const MemoryRegionOps spi_ops = { } }; -static int xilinx_spi_init(SysBusDevice *sbd) +static void xilinx_spi_realize(DeviceState *dev, Error **errp) { - DeviceState *dev = DEVICE(sbd); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); XilinxSPI *s = XILINX_SPI(dev); int i; @@ -344,8 +344,6 @@ static int xilinx_spi_init(SysBusDevice *sbd) fifo8_create(&s->tx_fifo, FIFO_CAPACITY); fifo8_create(&s->rx_fifo, FIFO_CAPACITY); - - return 0; } static const VMStateDescription vmstate_xilinx_spi = { @@ -368,9 +366,8 @@ static Property xilinx_spi_properties[] = { static void xilinx_spi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = xilinx_spi_init; + dc->realize = xilinx_spi_realize; dc->reset = xlx_spi_reset; dc->props = xilinx_spi_properties; dc->vmsd = &vmstate_xilinx_spi; diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 54b400b94a..5c786e5128 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -454,8 +454,7 @@ static void aspeed_timer_realize(DeviceState *dev, Error **errp) obj = object_property_get_link(OBJECT(dev), "scu", &err); if (!obj) { - error_propagate(errp, err); - error_prepend(errp, "required link 'scu' not found: "); + error_propagate_prepend(errp, err, "required link 'scu' not found: "); return; } s->scu = ASPEED_SCU(obj); diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index acee47da0e..e4e4de8b8a 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -34,6 +34,7 @@ #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-events-misc.h" #include "qapi/visitor.h" +#include "exec/address-spaces.h" #ifdef TARGET_I386 #include "hw/i386/apic.h" @@ -70,6 +71,7 @@ typedef struct RTCState { ISADevice parent_obj; MemoryRegion io; + MemoryRegion coalesced_io; uint8_t cmos_data[128]; uint8_t cmos_index; int32_t base_year; @@ -990,6 +992,13 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) memory_region_init_io(&s->io, OBJECT(s), &cmos_ops, s, "rtc", 2); isa_register_ioport(isadev, &s->io, base); + /* register rtc 0x70 port for coalesced_pio */ + memory_region_set_flush_coalesced(&s->io); + memory_region_init_io(&s->coalesced_io, OBJECT(s), &cmos_ops, + s, "rtc-index", 1); + memory_region_add_subregion(&s->io, 0, &s->coalesced_io); + memory_region_add_coalescing(&s->coalesced_io, 0, 1); + qdev_set_legacy_instance_id(dev, base, 3); qemu_register_reset(rtc_reset, s); diff --git a/hw/timer/sun4v-rtc.c b/hw/timer/sun4v-rtc.c index 310523225f..4e7f6a1eff 100644 --- a/hw/timer/sun4v-rtc.c +++ b/hw/timer/sun4v-rtc.c @@ -14,15 +14,8 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/timer/sun4v-rtc.h" +#include "trace.h" -//#define DEBUG_SUN4V_RTC - -#ifdef DEBUG_SUN4V_RTC -#define DPRINTF(fmt, ...) \ - do { printf("sun4v_rtc: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif #define TYPE_SUN4V_RTC "sun4v_rtc" #define SUN4V_RTC(obj) OBJECT_CHECK(Sun4vRtc, (obj), TYPE_SUN4V_RTC) @@ -41,14 +34,14 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr, /* accessing the high 32 bits */ val >>= 32; } - DPRINTF("read from " TARGET_FMT_plx " val %lx\n", addr, val); + trace_sun4v_rtc_read(addr, val); return val; } static void sun4v_rtc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr); + trace_sun4v_rtc_read(addr, val); } static const MemoryRegionOps sun4v_rtc_ops = { @@ -70,21 +63,21 @@ void sun4v_rtc_init(hwaddr addr) sysbus_mmio_map(s, 0, addr); } -static int sun4v_rtc_init1(SysBusDevice *dev) +static void sun4v_rtc_realize(DeviceState *dev, Error **errp) { + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); Sun4vRtc *s = SUN4V_RTC(dev); memory_region_init_io(&s->iomem, OBJECT(s), &sun4v_rtc_ops, s, "sun4v-rtc", 0x08ULL); - sysbus_init_mmio(dev, &s->iomem); - return 0; + sysbus_init_mmio(sbd, &s->iomem); } static void sun4v_rtc_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); - k->init = sun4v_rtc_init1; + dc->realize = sun4v_rtc_realize; } static const TypeInfo sun4v_rtc_info = { diff --git a/hw/timer/trace-events b/hw/timer/trace-events index fa4213df5b..75bd3b1042 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -56,7 +56,7 @@ systick_timer_tick(void) "systick reload" systick_read(uint64_t addr, uint32_t value, unsigned size) "systick read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" -# hw/char/cmsdk_apb_timer.c +# hw/timer/cmsdk_apb_timer.c cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset" @@ -66,5 +66,9 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset" +# hw/timer/sun4v-rtc.c +sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64 +sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64 + # hw/timer/xlnx-zynqmp-rtc.c xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d" diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 11f7720d71..bf796d67e6 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -340,8 +340,9 @@ static USBDevice *usb_try_create_simple(USBBus *bus, const char *name, } object_property_set_bool(OBJECT(dev), true, "realized", &err); if (err) { - error_propagate(errp, err); - error_prepend(errp, "Failed to initialize USB device '%s': ", name); + error_propagate_prepend(errp, err, + "Failed to initialize USB device '%s': ", + name); return NULL; } return dev; diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index 5c8b3c9907..25976ed84f 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -409,6 +409,12 @@ static int init_event_notifier(EmulatedState *card, Error **errp) return 0; } +static void clean_event_notifier(EmulatedState *card) +{ + event_notifier_set_handler(&card->notifier, NULL); + event_notifier_cleanup(&card->notifier); +} + #define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb" #define CERTIFICATES_ARGS_TEMPLATE\ "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)" @@ -493,7 +499,7 @@ static void emulated_realize(CCIDCardState *base, Error **errp) card->reader = NULL; card->quit_apdu_thread = 0; if (init_event_notifier(card, errp) < 0) { - return; + goto out1; } card->backend = 0; @@ -507,7 +513,7 @@ static void emulated_realize(CCIDCardState *base, Error **errp) for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) { error_append_hint(errp, "%s\n", ptable->name); } - return; + goto out2; } /* TODO: a passthru backened that works on local machine. third card type?*/ @@ -517,31 +523,39 @@ static void emulated_realize(CCIDCardState *base, Error **errp) } else { error_setg(errp, "%s: you must provide all three certs for" " certificates backend", TYPE_EMULATED_CCID); - return; + goto out2; } } else { if (card->backend != BACKEND_NSS_EMULATED) { error_setg(errp, "%s: bad backend specified. The options are:%s" " (default), %s.", TYPE_EMULATED_CCID, BACKEND_NSS_EMULATED_NAME, BACKEND_CERTIFICATES_NAME); - return; + goto out2; } if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) { error_setg(errp, "%s: unexpected cert parameters to nss emulated " "backend", TYPE_EMULATED_CCID); - return; + goto out2; } /* default to mirroring the local hardware readers */ ret = wrap_vcard_emul_init(NULL); } if (ret != VCARD_EMUL_OK) { error_setg(errp, "%s: failed to initialize vcard", TYPE_EMULATED_CCID); - return; + goto out2; } qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread, card, QEMU_THREAD_JOINABLE); qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread, card, QEMU_THREAD_JOINABLE); + +out2: + clean_event_notifier(card); +out1: + qemu_cond_destroy(&card->handle_apdu_cond); + qemu_mutex_destroy(&card->handle_apdu_mutex); + qemu_mutex_destroy(&card->vreader_mutex); + qemu_mutex_destroy(&card->event_list_mutex); } static void emulated_unrealize(CCIDCardState *base, Error **errp) @@ -556,6 +570,7 @@ static void emulated_unrealize(CCIDCardState *base, Error **errp) qemu_cond_signal(&card->handle_apdu_cond); qemu_thread_join(&card->apdu_thread_id); + clean_event_notifier(card); /* threads exited, can destroy all condvars/mutexes */ qemu_cond_destroy(&card->handle_apdu_cond); qemu_mutex_destroy(&card->handle_apdu_mutex); diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 66656a1133..c34cf5b73a 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -57,7 +57,7 @@ typedef struct { qemu_irq irq; MemoryRegion mem; AddressSpace *as; - int num_ports; + uint32_t num_ports; const char *name; QEMUTimer *eof_timer; @@ -1850,7 +1850,7 @@ static USBBusOps ohci_bus_ops = { }; static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, - int num_ports, dma_addr_t localmem_base, + uint32_t num_ports, dma_addr_t localmem_base, char *masterbus, uint32_t firstport, AddressSpace *as, Error **errp) { @@ -1860,7 +1860,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev, ohci->as = as; if (num_ports > OHCI_MAX_PORTS) { - error_setg(errp, "OHCI num-ports=%d is too big (limit is %d ports)", + error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)", num_ports, OHCI_MAX_PORTS); return; } diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs index a2e7a0a7cf..8b3f664d85 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -6,4 +6,5 @@ obj-$(CONFIG_SOFTMMU) += platform.o obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o obj-$(CONFIG_VFIO_AMD_XGBE) += amd-xgbe.o obj-$(CONFIG_SOFTMMU) += spapr.o +obj-$(CONFIG_VFIO_AP) += ap.o endif diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c index 0c4ec4ba25..ee64a3b4a2 100644 --- a/hw/vfio/amd-xgbe.c +++ b/hw/vfio/amd-xgbe.c @@ -20,6 +20,7 @@ static void amd_xgbe_realize(DeviceState *dev, Error **errp) VFIOAmdXgbeDeviceClass *k = VFIO_AMD_XGBE_DEVICE_GET_CLASS(dev); vdev->compat = g_strdup("amd,xgbe-seattle-v1a"); + vdev->num_compat = 1; k->parent_realize(dev, errp); } diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c new file mode 100644 index 0000000000..3962bb74e5 --- /dev/null +++ b/hw/vfio/ap.c @@ -0,0 +1,181 @@ +/* + * VFIO based AP matrix device assignment + * + * Copyright 2018 IBM Corp. + * Author(s): Tony Krowiak <akrowiak@linux.ibm.com> + * Halil Pasic <pasic@linux.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#include <linux/vfio.h> +#include <sys/ioctl.h> +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "hw/vfio/vfio.h" +#include "hw/vfio/vfio-common.h" +#include "hw/s390x/ap-device.h" +#include "qemu/error-report.h" +#include "qemu/queue.h" +#include "qemu/option.h" +#include "qemu/config-file.h" +#include "cpu.h" +#include "kvm_s390x.h" +#include "sysemu/sysemu.h" +#include "hw/s390x/ap-bridge.h" +#include "exec/address-spaces.h" + +#define VFIO_AP_DEVICE_TYPE "vfio-ap" + +typedef struct VFIOAPDevice { + APDevice apdev; + VFIODevice vdev; +} VFIOAPDevice; + +#define VFIO_AP_DEVICE(obj) \ + OBJECT_CHECK(VFIOAPDevice, (obj), VFIO_AP_DEVICE_TYPE) + +static void vfio_ap_compute_needs_reset(VFIODevice *vdev) +{ + vdev->needs_reset = false; +} + +/* + * We don't need vfio_hot_reset_multi and vfio_eoi operations for + * vfio-ap device now. + */ +struct VFIODeviceOps vfio_ap_ops = { + .vfio_compute_needs_reset = vfio_ap_compute_needs_reset, +}; + +static void vfio_ap_put_device(VFIOAPDevice *vapdev) +{ + g_free(vapdev->vdev.name); + vfio_put_base_device(&vapdev->vdev); +} + +static VFIOGroup *vfio_ap_get_group(VFIOAPDevice *vapdev, Error **errp) +{ + GError *gerror = NULL; + char *symlink, *group_path; + int groupid; + + symlink = g_strdup_printf("%s/iommu_group", vapdev->vdev.sysfsdev); + group_path = g_file_read_link(symlink, &gerror); + g_free(symlink); + + if (!group_path) { + error_setg(errp, "%s: no iommu_group found for %s: %s", + VFIO_AP_DEVICE_TYPE, vapdev->vdev.sysfsdev, gerror->message); + return NULL; + } + + if (sscanf(basename(group_path), "%d", &groupid) != 1) { + error_setg(errp, "vfio: failed to read %s", group_path); + g_free(group_path); + return NULL; + } + + g_free(group_path); + + return vfio_get_group(groupid, &address_space_memory, errp); +} + +static void vfio_ap_realize(DeviceState *dev, Error **errp) +{ + int ret; + char *mdevid; + Error *local_err = NULL; + VFIOGroup *vfio_group; + APDevice *apdev = AP_DEVICE(dev); + VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + + vfio_group = vfio_ap_get_group(vapdev, &local_err); + if (!vfio_group) { + goto out_err; + } + + vapdev->vdev.ops = &vfio_ap_ops; + vapdev->vdev.type = VFIO_DEVICE_TYPE_AP; + mdevid = basename(vapdev->vdev.sysfsdev); + vapdev->vdev.name = g_strdup_printf("%s", mdevid); + vapdev->vdev.dev = dev; + + ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, &local_err); + if (ret) { + goto out_get_dev_err; + } + + return; + +out_get_dev_err: + vfio_ap_put_device(vapdev); + vfio_put_group(vfio_group); +out_err: + error_propagate(errp, local_err); +} + +static void vfio_ap_unrealize(DeviceState *dev, Error **errp) +{ + APDevice *apdev = AP_DEVICE(dev); + VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + VFIOGroup *group = vapdev->vdev.group; + + vfio_ap_put_device(vapdev); + vfio_put_group(group); +} + +static Property vfio_ap_properties[] = { + DEFINE_PROP_STRING("sysfsdev", VFIOAPDevice, vdev.sysfsdev), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vfio_ap_reset(DeviceState *dev) +{ + int ret; + APDevice *apdev = AP_DEVICE(dev); + VFIOAPDevice *vapdev = VFIO_AP_DEVICE(apdev); + + ret = ioctl(vapdev->vdev.fd, VFIO_DEVICE_RESET); + if (ret) { + error_report("%s: failed to reset %s device: %s", __func__, + vapdev->vdev.name, strerror(ret)); + } +} + +static const VMStateDescription vfio_ap_vmstate = { + .name = VFIO_AP_DEVICE_TYPE, + .unmigratable = 1, +}; + +static void vfio_ap_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = vfio_ap_properties; + dc->vmsd = &vfio_ap_vmstate; + dc->desc = "VFIO-based AP device assignment"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->realize = vfio_ap_realize; + dc->unrealize = vfio_ap_unrealize; + dc->hotpluggable = false; + dc->reset = vfio_ap_reset; + dc->bus_type = TYPE_AP_BUS; +} + +static const TypeInfo vfio_ap_info = { + .name = VFIO_AP_DEVICE_TYPE, + .parent = AP_DEVICE_TYPE, + .instance_size = sizeof(VFIOAPDevice), + .class_init = vfio_ap_class_init, +}; + +static void vfio_ap_type_init(void) +{ + type_register_static(&vfio_ap_info); +} + +type_init(vfio_ap_type_init) diff --git a/hw/vfio/calxeda-xgmac.c b/hw/vfio/calxeda-xgmac.c index 24cee6d065..e7767c4b02 100644 --- a/hw/vfio/calxeda-xgmac.c +++ b/hw/vfio/calxeda-xgmac.c @@ -20,6 +20,7 @@ static void calxeda_xgmac_realize(DeviceState *dev, Error **errp) VFIOCalxedaXgmacDeviceClass *k = VFIO_CALXEDA_XGMAC_DEVICE_GET_CLASS(dev); vdev->compat = g_strdup("calxeda,hb-xgmac"); + vdev->num_compat = 1; k->parent_realize(dev, errp); } diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 59c0e5d1d7..dead30e626 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -124,6 +124,9 @@ static void vfio_display_dmabuf_update(void *opaque) primary = vfio_display_get_dmabuf(vdev, DRM_PLANE_TYPE_PRIMARY); if (primary == NULL) { + if (dpy->ramfb) { + ramfb_display_update(dpy->con, dpy->ramfb); + } return; } @@ -181,6 +184,9 @@ static int vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp) vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0, &vfio_display_dmabuf_ops, vdev); + if (vdev->enable_ramfb) { + vdev->dpy->ramfb = ramfb_setup(errp); + } return 0; } @@ -228,6 +234,9 @@ static void vfio_display_region_update(void *opaque) return; } if (!plane.drm_format || !plane.size) { + if (dpy->ramfb) { + ramfb_display_update(dpy->con, dpy->ramfb); + } return; } format = qemu_drm_format_to_pixman(plane.drm_format); @@ -300,6 +309,9 @@ static int vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp) vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0, &vfio_display_region_ops, vdev); + if (vdev->enable_ramfb) { + vdev->dpy->ramfb = ramfb_setup(errp); + } return 0; } diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 481fd08df7..eae31c74d6 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -1670,7 +1670,7 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) * but also no point in us enabling VGA if disabled in hardware. */ if (!(gmch & 0x2) && !vdev->vga && vfio_populate_vga(vdev, &err)) { - error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name); + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); error_report("IGD device %s failed to enable VGA access, " "legacy mode disabled", vdev->vbasedev.name); goto out; @@ -1696,7 +1696,7 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) ret = vfio_pci_igd_opregion_init(vdev, opregion, &err); if (ret) { error_append_hint(&err, "IGD legacy mode disabled\n"); - error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name); + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); goto out; } diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 866f0deeb7..5c7bd96984 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -37,6 +37,9 @@ #define MSIX_CAP_LENGTH 12 +#define TYPE_VFIO_PCI "vfio-pci" +#define PCI_VFIO(obj) OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI) + static void vfio_disable_interrupts(VFIOPCIDevice *vdev); static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled); @@ -222,7 +225,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev) static void vfio_intx_update(PCIDevice *pdev) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); PCIINTxRoute route; Error *err = NULL; @@ -249,7 +252,7 @@ static void vfio_intx_update(PCIDevice *pdev) vfio_intx_enable_kvm(vdev, &err); if (err) { - error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name); + warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } /* Re-enable the interrupt in cased we missed an EOI */ @@ -314,7 +317,7 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp) vfio_intx_enable_kvm(vdev, &err); if (err) { - error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name); + warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } vdev->interrupt = VFIO_INT_INTx; @@ -477,7 +480,7 @@ static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg, static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, MSIMessage *msg, IOHandler *handler) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); VFIOMSIVector *vector; int ret; @@ -574,7 +577,7 @@ static int vfio_msix_vector_use(PCIDevice *pdev, static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); VFIOMSIVector *vector = &vdev->msi_vectors[nr]; trace_vfio_msix_vector_release(vdev->vbasedev.name, nr); @@ -742,7 +745,7 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev) vfio_intx_enable(vdev, &err); if (err) { - error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name); + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } } @@ -1086,7 +1089,7 @@ static const MemoryRegionOps vfio_vga_ops = { */ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); VFIORegion *region = &vdev->bars[bar].region; MemoryRegion *mmap_mr, *region_mr, *base_mr; PCIIORegion *r; @@ -1132,7 +1135,7 @@ static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar) */ uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val; memcpy(&emu_bits, vdev->emulated_config_bits + addr, len); @@ -1165,7 +1168,7 @@ uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, uint32_t val, int len) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); uint32_t val_le = cpu_to_le32(val); trace_vfio_pci_write_config(vdev->vbasedev.name, addr, val, len); @@ -1280,8 +1283,7 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp) if (ret == -ENOTSUP) { return 0; } - error_prepend(&err, "msi_init failed: "); - error_propagate(errp, err); + error_propagate_prepend(errp, err, "msi_init failed: "); return ret; } vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0); @@ -1555,7 +1557,7 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp) &err); if (ret < 0) { if (ret == -ENOTSUP) { - error_report_err(err); + warn_report_err(err); return 0; } @@ -2194,7 +2196,7 @@ static void vfio_pci_post_reset(VFIOPCIDevice *vdev) vfio_intx_enable(vdev, &err); if (err) { - error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name); + error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } for (nr = 0; nr < PCI_NUM_REGIONS - 1; ++nr) { @@ -2588,9 +2590,9 @@ static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) } else if (irq_info.count == 1) { vdev->pci_aer = true; } else { - error_report(WARN_PREFIX - "Could not enable error recovery for the device", - vbasedev->name); + warn_report(VFIO_MSG_PREFIX + "Could not enable error recovery for the device", + vbasedev->name); } } @@ -2715,7 +2717,7 @@ static void vfio_req_notifier_handler(void *opaque) qdev_unplug(&vdev->pdev.qdev, &err); if (err) { - error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name); + warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } } @@ -2801,7 +2803,7 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) static void vfio_realize(PCIDevice *pdev, Error **errp) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); VFIODevice *vbasedev_iter; VFIOGroup *group; char *tmp, *subsys, group_path[PATH_MAX], *group_name; @@ -2828,7 +2830,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) if (stat(vdev->vbasedev.sysfsdev, &st) < 0) { error_setg_errno(errp, errno, "no such host device"); - error_prepend(errp, ERR_PREFIX, vdev->vbasedev.sysfsdev); + error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev); return; } @@ -3067,6 +3069,10 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto out_teardown; } } + if (vdev->enable_ramfb && vdev->dpy == NULL) { + error_setg(errp, "ramfb=on requires display=on"); + goto out_teardown; + } vfio_register_err_notifier(vdev); vfio_register_req_notifier(vdev); @@ -3079,13 +3085,12 @@ out_teardown: vfio_teardown_msi(vdev); vfio_bars_exit(vdev); error: - error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name); + error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name); } static void vfio_instance_finalize(Object *obj) { - PCIDevice *pci_dev = PCI_DEVICE(obj); - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev); + VFIOPCIDevice *vdev = PCI_VFIO(obj); VFIOGroup *group = vdev->vbasedev.group; vfio_display_finalize(vdev); @@ -3105,7 +3110,7 @@ static void vfio_instance_finalize(Object *obj) static void vfio_exitfn(PCIDevice *pdev) { - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(pdev); vfio_unregister_req_notifier(vdev); vfio_unregister_err_notifier(vdev); @@ -3120,8 +3125,7 @@ static void vfio_exitfn(PCIDevice *pdev) static void vfio_pci_reset(DeviceState *dev) { - PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev); - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); + VFIOPCIDevice *vdev = PCI_VFIO(dev); trace_vfio_pci_reset(vdev->vbasedev.name); @@ -3161,7 +3165,7 @@ post_reset: static void vfio_instance_init(Object *obj) { PCIDevice *pci_dev = PCI_DEVICE(obj); - VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(obj)); + VFIOPCIDevice *vdev = PCI_VFIO(obj); device_add_bootindex_property(obj, &vdev->bootindex, "bootindex", NULL, @@ -3245,7 +3249,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) } static const TypeInfo vfio_pci_dev_info = { - .name = "vfio-pci", + .name = TYPE_VFIO_PCI, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(VFIOPCIDevice), .class_init = vfio_pci_dev_class_init, @@ -3258,9 +3262,30 @@ static const TypeInfo vfio_pci_dev_info = { }, }; +static Property vfio_pci_dev_nohotplug_properties[] = { + DEFINE_PROP_BOOL("ramfb", VFIOPCIDevice, enable_ramfb, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = vfio_pci_dev_nohotplug_properties; + dc->hotpluggable = false; +} + +static const TypeInfo vfio_pci_nohotplug_dev_info = { + .name = "vfio-pci-nohotplug", + .parent = "vfio-pci", + .instance_size = sizeof(VFIOPCIDevice), + .class_init = vfio_pci_nohotplug_dev_class_init, +}; + static void register_vfio_pci_dev_type(void) { type_register_static(&vfio_pci_dev_info); + type_register_static(&vfio_pci_nohotplug_dev_info); } type_init(register_vfio_pci_dev_type) diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 52b065421a..b1ae4c0754 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -165,6 +165,7 @@ typedef struct VFIOPCIDevice { bool no_geforce_quirks; bool no_kvm_ioeventfd; bool no_vfio_ioeventfd; + bool enable_ramfb; VFIODisplay *dpy; } VFIOPCIDevice; diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 57c4a0ee2b..398db38f14 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -655,10 +655,32 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp) goto out; } + if (!vdev->compat) { + GError *gerr = NULL; + gchar *contents; + gsize length; + char *path; + + path = g_strdup_printf("%s/of_node/compatible", vbasedev->sysfsdev); + if (!g_file_get_contents(path, &contents, &length, &gerr)) { + error_setg(errp, "%s", gerr->message); + g_error_free(gerr); + g_free(path); + return; + } + g_free(path); + vdev->compat = contents; + for (vdev->num_compat = 0; length; vdev->num_compat++) { + size_t skip = strlen(contents) + 1; + contents += skip; + length -= skip; + } + } + for (i = 0; i < vbasedev->num_regions; i++) { if (vfio_region_mmap(vdev->regions[i])) { - error_report("%s mmap unsupported. Performance may be slow", - memory_region_name(vdev->regions[i]->mem)); + warn_report("%s mmap unsupported, performance may be slow", + memory_region_name(vdev->regions[i]->mem)); } sysbus_init_mmio(sbdev, vdev->regions[i]->mem); } @@ -668,7 +690,7 @@ out: } if (vdev->vbasedev.name) { - error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name); + error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name); } else { error_prepend(errp, "vfio error: "); } @@ -700,6 +722,8 @@ static void vfio_platform_class_init(ObjectClass *klass, void *data) dc->desc = "VFIO-based platform device assignment"; sbc->connect_irq_notifier = vfio_start_irqfd_injection; set_bit(DEVICE_CATEGORY_MISC, dc->categories); + /* Supported by TYPE_VIRT_MACHINE */ + dc->user_creatable = true; } static const TypeInfo vfio_platform_dev_info = { @@ -708,7 +732,6 @@ static const TypeInfo vfio_platform_dev_info = { .instance_size = sizeof(VFIOPlatformDevice), .class_init = vfio_platform_class_init, .class_size = sizeof(VFIOPlatformDeviceClass), - .abstract = true, }; static void register_vfio_platform_dev_type(void) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index b041343632..e09bed0e4a 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -374,8 +374,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, int fds[VHOST_MEMORY_MAX_NREGIONS]; int i, fd; size_t fd_num = 0; - bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK); VhostUserMsg msg_reply; int region_i, msg_i; @@ -384,10 +382,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, .hdr.flags = VHOST_USER_VERSION, }; - if (reply_supported) { - msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; - } - if (u->region_rb_len < dev->mem->nregions) { u->region_rb = g_renew(RAMBlock*, u->region_rb, dev->mem->nregions); u->region_rb_offset = g_renew(ram_addr_t, u->region_rb_offset, @@ -503,10 +497,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, return -1; } - if (reply_supported) { - return process_message_reply(dev, &msg); - } - return 0; } @@ -519,8 +509,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, size_t fd_num = 0; bool do_postcopy = u->postcopy_listen && u->postcopy_fd.handler; bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK) && - !do_postcopy; + VHOST_USER_PROTOCOL_F_REPLY_ACK); if (do_postcopy) { /* Postcopy has enough differences that it's best done in it's own @@ -1291,6 +1280,7 @@ static int vhost_user_postcopy_end(struct vhost_dev *dev, Error **errp) return ret; } postcopy_unregister_shared_ufd(&u->postcopy_fd); + close(u->postcopy_fd.fd); u->postcopy_fd.handler = NULL; trace_vhost_user_postcopy_end_exit(); @@ -1430,6 +1420,12 @@ static int vhost_user_backend_cleanup(struct vhost_dev *dev) postcopy_remove_notifier(&u->postcopy_notifier); u->postcopy_notifier.notify = NULL; } + u->postcopy_listen = false; + if (u->postcopy_fd.handler) { + postcopy_unregister_shared_ufd(&u->postcopy_fd); + close(u->postcopy_fd.fd); + u->postcopy_fd.handler = NULL; + } if (u->slave_fd >= 0) { qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL); close(u->slave_fd); diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 3a01fe90f0..a954799267 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1683,8 +1683,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) if (err) { /* Notice when a system that supports MSIx can't initialize it */ if (err != -ENOTSUP) { - error_report("unable to init msix vectors to %" PRIu32, - proxy->nvectors); + warn_report("unable to init msix vectors to %" PRIu32, + proxy->nvectors); } proxy->nvectors = 0; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index f6a588ab57..4136d239dd 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -358,6 +358,10 @@ int virtio_queue_ready(VirtQueue *vq) * Called within rcu_read_lock(). */ static int virtio_queue_empty_rcu(VirtQueue *vq) { + if (unlikely(vq->vdev->broken)) { + return 1; + } + if (unlikely(!vq->vring.avail)) { return 1; } @@ -373,6 +377,10 @@ int virtio_queue_empty(VirtQueue *vq) { bool empty; + if (unlikely(vq->vdev->broken)) { + return 1; + } + if (unlikely(!vq->vring.avail)) { return 1; } @@ -1161,7 +1169,6 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) return 0; } -bool target_words_bigendian(void); static enum virtio_device_endian virtio_default_endian(void) { if (target_words_bigendian()) { @@ -1604,6 +1611,8 @@ void virtio_del_queue(VirtIODevice *vdev, int n) vdev->vq[n].vring.num = 0; vdev->vq[n].vring.num_default = 0; + vdev->vq[n].handle_output = NULL; + vdev->vq[n].handle_aio_output = NULL; } static void virtio_set_isr(VirtIODevice *vdev, int value) diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index e5a6eff44f..f1f3a3727c 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -830,7 +830,7 @@ static void xen_pt_realize(PCIDevice *d, Error **errp) xen_pt_config_init(s, &err); if (err) { error_append_hint(&err, "PCI Config space initialisation failed"); - error_report_err(err); + error_propagate(errp, err); rc = -1; goto err_out; } diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index aee31c62bb..47f9010c75 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -358,7 +358,7 @@ static uint64_t xen_pt_get_bar_size(PCIIORegion *r) static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s, int index) { - PCIDevice *d = &s->dev; + PCIDevice *d = PCI_DEVICE(s); XenPTRegion *region = NULL; PCIIORegion *r; @@ -469,7 +469,7 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, { XenPTRegInfo *reg = cfg_entry->reg; XenPTRegion *base = NULL; - PCIDevice *d = &s->dev; + PCIDevice *d = PCI_DEVICE(s); const PCIIORegion *r; uint32_t writable_mask = 0; uint32_t bar_emu_mask = 0; @@ -543,7 +543,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s, { XenPTRegInfo *reg = cfg_entry->reg; XenPTRegion *base = NULL; - PCIDevice *d = (PCIDevice *)&s->dev; + PCIDevice *d = PCI_DEVICE(s); uint32_t writable_mask = 0; uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask); pcibus_t r_size = 0; @@ -1587,7 +1587,7 @@ static int xen_pt_pcie_size_init(XenPCIPassthroughState *s, const XenPTRegGroupInfo *grp_reg, uint32_t base_offset, uint8_t *size) { - PCIDevice *d = &s->dev; + PCIDevice *d = PCI_DEVICE(s); uint8_t version = get_capability_version(s, base_offset); uint8_t type = get_device_type(s, base_offset); uint8_t pcie_size = 0; |