diff options
136 files changed, 2666 insertions, 1976 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 5ba7cf056a..e511ba780f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -790,6 +790,7 @@ M: Christian Borntraeger <borntraeger@de.ibm.com> M: Alexander Graf <agraf@suse.de> S: Supported F: hw/char/sclp*.[hc] +F: hw/char/terminal3270.c F: hw/s390x/ F: include/hw/s390x/ F: pc-bios/s390-ccw/ @@ -970,7 +971,9 @@ SCSI M: Paolo Bonzini <pbonzini@redhat.com> S: Supported F: include/hw/scsi/* +F: include/scsi/* F: hw/scsi/* +F: util/scsi* F: tests/virtio-scsi-test.c T: git git://github.com/bonzini/qemu.git scsi-next @@ -1103,11 +1106,12 @@ F: hw/block/nvme* F: tests/nvme-test.c megasas -M: Hannes Reinecke <hare@suse.de> +M: Hannes Reinecke <hare@suse.com> L: qemu-block@nongnu.org S: Supported F: hw/scsi/megasas.c F: hw/scsi/mfi.h +F: tests/megasas-test.c Network packet abstractions M: Dmitry Fleytman <dmitry@daynix.com> @@ -1131,7 +1135,7 @@ F: tests/rocker/ F: docs/specs/rocker.txt NVDIMM -M: Xiao Guangrong <guangrong.xiao@linux.intel.com> +M: Xiao Guangrong <xiaoguangrong.eric@gmail.com> S: Maintained F: hw/acpi/nvdimm.c F: hw/mem/nvdimm.c @@ -1215,6 +1219,13 @@ F: migration/block* F: include/block/aio.h T: git git://github.com/stefanha/qemu.git block +Block SCSI subsystem +M: Paolo Bonzini <pbonzini@redhat.com> +L: qemu-block@nongnu.org +S: Supported +F: include/scsi/* +F: scsi/* + Block Jobs M: Jeff Cody <jcody@redhat.com> L: qemu-block@nongnu.org @@ -335,7 +335,7 @@ subdir-dtc:dtc/libfdt dtc/tests dtc/%: mkdir -p $@ -$(SUBDIR_RULES): libqemuutil.a libqemustub.a $(common-obj-y) $(chardev-obj-y) \ +$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \ $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY)) ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) @@ -355,12 +355,11 @@ Makefile: $(version-obj-y) ###################################################################### # Build libraries -libqemustub.a: $(stub-obj-y) -libqemuutil.a: $(util-obj-y) $(trace-obj-y) +libqemuutil.a: $(util-obj-y) $(trace-obj-y) $(stub-obj-y) ###################################################################### -COMMON_LDADDS = libqemuutil.a libqemustub.a +COMMON_LDADDS = libqemuutil.a qemu-img.o: qemu-img-cmds.h diff --git a/Makefile.objs b/Makefile.objs index d9cf7ad791..9e89100302 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -11,7 +11,7 @@ chardev-obj-y = chardev/ block-obj-y += nbd/ block-obj-y += block.o blockjob.o -block-obj-y += block/ +block-obj-y += block/ scsi/ block-obj-y += qemu-io-cmds.o block-obj-$(CONFIG_REPLICATION) += replication.o @@ -155,6 +155,7 @@ trace-events-subdirs += hw/acpi trace-events-subdirs += hw/arm trace-events-subdirs += hw/alpha trace-events-subdirs += hw/xen +trace-events-subdirs += hw/ide trace-events-subdirs += ui trace-events-subdirs += audio trace-events-subdirs += net diff --git a/Makefile.target b/Makefile.target index 6361f957fb..a4b292d2e2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -101,7 +101,6 @@ obj-y += fpu/softfloat.o obj-y += target/$(TARGET_BASE_ARCH)/ obj-y += disas.o obj-$(call notempty,$(TARGET_XML_FILES)) += gdbstub-xml.o -obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decContext.o obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/decNumber.o @@ -193,7 +192,7 @@ all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y) $(QEMU_PROG_BUILD): config-devices.mak -COMMON_LDADDS = ../libqemuutil.a ../libqemustub.a +COMMON_LDADDS = ../libqemuutil.a # build either PROG or PROGW $(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f85553a851..b0181d7220 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -79,7 +79,6 @@ struct KVMState int coalesced_mmio; struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; bool coalesced_flush_in_progress; - int broken_set_mem_region; int vcpu_events; int robust_singlestep; int debugregs; @@ -127,6 +126,7 @@ static bool kvm_immediate_exit; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS), + KVM_CAP_INFO(JOIN_MEMORY_REGIONS_WORKS), KVM_CAP_LAST_INFO }; @@ -172,7 +172,7 @@ static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml) static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml, hwaddr start_addr, - hwaddr end_addr) + hwaddr size) { KVMState *s = kvm_state; int i; @@ -180,8 +180,7 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml, for (i = 0; i < s->nr_slots; i++) { KVMSlot *mem = &kml->slots[i]; - if (start_addr == mem->start_addr && - end_addr == mem->start_addr + mem->memory_size) { + if (start_addr == mem->start_addr && size == mem->memory_size) { return mem; } } @@ -190,31 +189,33 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml, } /* - * Find overlapping slot with lowest start address + * Calculate and align the start address and the size of the section. + * Return the size. If the size is 0, the aligned section is empty. */ -static KVMSlot *kvm_lookup_overlapping_slot(KVMMemoryListener *kml, - hwaddr start_addr, - hwaddr end_addr) +static hwaddr kvm_align_section(MemoryRegionSection *section, + hwaddr *start) { - KVMState *s = kvm_state; - KVMSlot *found = NULL; - int i; - - for (i = 0; i < s->nr_slots; i++) { - KVMSlot *mem = &kml->slots[i]; + hwaddr size = int128_get64(section->size); + hwaddr delta; - if (mem->memory_size == 0 || - (found && found->start_addr < mem->start_addr)) { - continue; - } + *start = section->offset_within_address_space; - if (end_addr > mem->start_addr && - start_addr < mem->start_addr + mem->memory_size) { - found = mem; - } + /* kvm works in page size chunks, but the function may be called + with sub-page size and unaligned start address. Pad the start + address to next and truncate size to previous page boundary. */ + delta = qemu_real_host_page_size - (*start & ~qemu_real_host_page_mask); + delta &= ~qemu_real_host_page_mask; + *start += delta; + if (delta > size) { + return 0; + } + size -= delta; + size &= qemu_real_host_page_mask; + if (*start & ~qemu_real_host_page_mask) { + return 0; } - return found; + return size; } int kvm_physical_memory_addr_from_host(KVMState *s, void *ram, @@ -382,15 +383,21 @@ static int kvm_slot_update_flags(KVMMemoryListener *kml, KVMSlot *mem, static int kvm_section_update_flags(KVMMemoryListener *kml, MemoryRegionSection *section) { - hwaddr phys_addr = section->offset_within_address_space; - ram_addr_t size = int128_get64(section->size); - KVMSlot *mem = kvm_lookup_matching_slot(kml, phys_addr, phys_addr + size); + hwaddr start_addr, size; + KVMSlot *mem; - if (mem == NULL) { + size = kvm_align_section(section, &start_addr); + if (!size) { return 0; - } else { - return kvm_slot_update_flags(kml, mem, section->mr); } + + mem = kvm_lookup_matching_slot(kml, start_addr, size); + if (!mem) { + fprintf(stderr, "%s: error finding slot\n", __func__); + abort(); + } + + return kvm_slot_update_flags(kml, mem, section->mr); } static void kvm_log_start(MemoryListener *listener, @@ -454,18 +461,16 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, MemoryRegionSection *section) { KVMState *s = kvm_state; - unsigned long size, allocated_size = 0; struct kvm_dirty_log d = {}; KVMSlot *mem; - int ret = 0; - hwaddr start_addr = section->offset_within_address_space; - hwaddr end_addr = start_addr + int128_get64(section->size); + hwaddr start_addr, size; - d.dirty_bitmap = NULL; - while (start_addr < end_addr) { - mem = kvm_lookup_overlapping_slot(kml, start_addr, end_addr); - if (mem == NULL) { - break; + size = kvm_align_section(section, &start_addr); + if (size) { + mem = kvm_lookup_matching_slot(kml, start_addr, size); + if (!mem) { + fprintf(stderr, "%s: error finding slot\n", __func__); + abort(); } /* XXX bad kernel interface alert @@ -482,27 +487,20 @@ static int kvm_physical_sync_dirty_bitmap(KVMMemoryListener *kml, */ size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS), /*HOST_LONG_BITS*/ 64) / 8; - if (!d.dirty_bitmap) { - d.dirty_bitmap = g_malloc(size); - } else if (size > allocated_size) { - d.dirty_bitmap = g_realloc(d.dirty_bitmap, size); - } - allocated_size = size; - memset(d.dirty_bitmap, 0, allocated_size); + d.dirty_bitmap = g_malloc0(size); d.slot = mem->slot | (kml->as_id << 16); if (kvm_vm_ioctl(s, KVM_GET_DIRTY_LOG, &d) == -1) { DPRINTF("ioctl failed %d\n", errno); - ret = -1; - break; + g_free(d.dirty_bitmap); + return -1; } kvm_get_dirty_pages_log_range(section, d.dirty_bitmap); - start_addr = mem->start_addr + mem->memory_size; + g_free(d.dirty_bitmap); } - g_free(d.dirty_bitmap); - return ret; + return 0; } static void kvm_coalesce_mmio_region(MemoryListener *listener, @@ -696,30 +694,12 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) static void kvm_set_phys_mem(KVMMemoryListener *kml, MemoryRegionSection *section, bool add) { - KVMState *s = kvm_state; - KVMSlot *mem, old; + KVMSlot *mem; int err; MemoryRegion *mr = section->mr; bool writeable = !mr->readonly && !mr->rom_device; - hwaddr start_addr = section->offset_within_address_space; - ram_addr_t size = int128_get64(section->size); - void *ram = NULL; - unsigned delta; - - /* kvm works in page size chunks, but the function may be called - with sub-page size and unaligned start address. Pad the start - address to next and truncate size to previous page boundary. */ - delta = qemu_real_host_page_size - (start_addr & ~qemu_real_host_page_mask); - delta &= ~qemu_real_host_page_mask; - if (delta > size) { - return; - } - start_addr += delta; - size -= delta; - size &= qemu_real_host_page_mask; - if (!size || (start_addr & ~qemu_real_host_page_mask)) { - return; - } + hwaddr start_addr, size; + void *ram; if (!memory_region_is_ram(mr)) { if (writeable || !kvm_readonly_mem_allowed) { @@ -731,30 +711,25 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, } } - ram = memory_region_get_ram_ptr(mr) + section->offset_within_region + delta; + size = kvm_align_section(section, &start_addr); + if (!size) { + return; + } + + ram = memory_region_get_ram_ptr(mr) + section->offset_within_region + + (section->offset_within_address_space - start_addr); - while (1) { - mem = kvm_lookup_overlapping_slot(kml, start_addr, start_addr + size); + mem = kvm_lookup_matching_slot(kml, start_addr, size); + if (!add) { if (!mem) { - break; - } - - if (add && start_addr >= mem->start_addr && - (start_addr + size <= mem->start_addr + mem->memory_size) && - (ram - start_addr == mem->ram - mem->start_addr)) { - /* The new slot fits into the existing one and comes with - * identical parameters - update flags and done. */ - kvm_slot_update_flags(kml, mem, mr); + g_assert(!memory_region_is_ram(mr) && !writeable && !mr->romd_mode); return; } - - old = *mem; - if (mem->flags & KVM_MEM_LOG_DIRTY_PAGES) { kvm_physical_sync_dirty_bitmap(kml, section); } - /* unregister the overlapping slot */ + /* unregister the slot */ mem->memory_size = 0; err = kvm_set_user_memory_region(kml, mem); if (err) { @@ -762,84 +737,16 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml, __func__, strerror(-err)); abort(); } - - /* Workaround for older KVM versions: we can't join slots, even not by - * unregistering the previous ones and then registering the larger - * slot. We have to maintain the existing fragmentation. Sigh. - * - * This workaround assumes that the new slot starts at the same - * address as the first existing one. If not or if some overlapping - * slot comes around later, we will fail (not seen in practice so far) - * - and actually require a recent KVM version. */ - if (s->broken_set_mem_region && - old.start_addr == start_addr && old.memory_size < size && add) { - mem = kvm_alloc_slot(kml); - mem->memory_size = old.memory_size; - mem->start_addr = old.start_addr; - mem->ram = old.ram; - mem->flags = kvm_mem_flags(mr); - - err = kvm_set_user_memory_region(kml, mem); - if (err) { - fprintf(stderr, "%s: error updating slot: %s\n", __func__, - strerror(-err)); - abort(); - } - - start_addr += old.memory_size; - ram += old.memory_size; - size -= old.memory_size; - continue; - } - - /* register prefix slot */ - if (old.start_addr < start_addr) { - mem = kvm_alloc_slot(kml); - mem->memory_size = start_addr - old.start_addr; - mem->start_addr = old.start_addr; - mem->ram = old.ram; - mem->flags = kvm_mem_flags(mr); - - err = kvm_set_user_memory_region(kml, mem); - if (err) { - fprintf(stderr, "%s: error registering prefix slot: %s\n", - __func__, strerror(-err)); -#ifdef TARGET_PPC - fprintf(stderr, "%s: This is probably because your kernel's " \ - "PAGE_SIZE is too big. Please try to use 4k " \ - "PAGE_SIZE!\n", __func__); -#endif - abort(); - } - } - - /* register suffix slot */ - if (old.start_addr + old.memory_size > start_addr + size) { - ram_addr_t size_delta; - - mem = kvm_alloc_slot(kml); - mem->start_addr = start_addr + size; - size_delta = mem->start_addr - old.start_addr; - mem->memory_size = old.memory_size - size_delta; - mem->ram = old.ram + size_delta; - mem->flags = kvm_mem_flags(mr); - - err = kvm_set_user_memory_region(kml, mem); - if (err) { - fprintf(stderr, "%s: error registering suffix slot: %s\n", - __func__, strerror(-err)); - abort(); - } - } - } - - /* in case the KVM bug workaround already "consumed" the new slot */ - if (!size) { return; } - if (!add) { + + if (mem) { + /* update the slot */ + kvm_slot_update_flags(kml, mem, mr); return; } + + /* register the new slot */ mem = kvm_alloc_slot(kml); mem->memory_size = size; mem->start_addr = start_addr; @@ -1629,10 +1536,9 @@ static int kvm_init(MachineState *ms) while (nc->name) { if (nc->num > soft_vcpus_limit) { - fprintf(stderr, - "Warning: Number of %s cpus requested (%d) exceeds " - "the recommended cpus supported by KVM (%d)\n", - nc->name, nc->num, soft_vcpus_limit); + warn_report("Number of %s cpus requested (%d) exceeds " + "the recommended cpus supported by KVM (%d)", + nc->name, nc->num, soft_vcpus_limit); if (nc->num > hard_vcpus_limit) { fprintf(stderr, "Number of %s cpus requested (%d) exceeds " @@ -1692,12 +1598,6 @@ static int kvm_init(MachineState *ms) s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO); - s->broken_set_mem_region = 1; - ret = kvm_check_extension(s, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS); - if (ret > 0) { - s->broken_set_mem_region = 0; - } - #ifdef KVM_CAP_VCPU_EVENTS s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS); #endif diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index fdfbf7332c..c071abaf4e 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -1,2 +1,3 @@ +obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o diff --git a/hax-stub.c b/accel/stubs/hax-stub.c index c0e6f892e5..c0e6f892e5 100644 --- a/hax-stub.c +++ b/accel/stubs/hax-stub.c diff --git a/block/iscsi.c b/block/iscsi.c index 8b47d30dcc..4683f3b244 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -34,15 +34,20 @@ #include "qemu/bitops.h" #include "qemu/bitmap.h" #include "block/block_int.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "qemu/iov.h" #include "qemu/uuid.h" #include "qmp-commands.h" #include "qapi/qmp/qstring.h" #include "crypto/secret.h" +#include "scsi/utils.h" +/* Conflict between scsi/utils.h and libiscsi! :( */ +#define SCSI_XFER_NONE ISCSI_XFER_NONE #include <iscsi/iscsi.h> #include <iscsi/scsi-lowlevel.h> +#undef SCSI_XFER_NONE +QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE); #ifdef __linux__ #include <scsi/sg.h> @@ -209,47 +214,9 @@ static inline unsigned exp_random(double mean) static int iscsi_translate_sense(struct scsi_sense *sense) { - int ret; - - switch (sense->key) { - case SCSI_SENSE_NOT_READY: - return -EBUSY; - case SCSI_SENSE_DATA_PROTECTION: - return -EACCES; - case SCSI_SENSE_COMMAND_ABORTED: - return -ECANCELED; - case SCSI_SENSE_ILLEGAL_REQUEST: - /* Parse ASCQ */ - break; - default: - return -EIO; - } - switch (sense->ascq) { - case SCSI_SENSE_ASCQ_PARAMETER_LIST_LENGTH_ERROR: - case SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE: - case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB: - case SCSI_SENSE_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST: - ret = -EINVAL; - break; - case SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE: - ret = -ENOSPC; - break; - case SCSI_SENSE_ASCQ_LOGICAL_UNIT_NOT_SUPPORTED: - ret = -ENOTSUP; - break; - case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT: - case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_CLOSED: - case SCSI_SENSE_ASCQ_MEDIUM_NOT_PRESENT_TRAY_OPEN: - ret = -ENOMEDIUM; - break; - case SCSI_SENSE_ASCQ_WRITE_PROTECTED: - ret = -EACCES; - break; - default: - ret = -EIO; - break; - } - return ret; + return - scsi_sense_to_errno(sense->key, + (sense->ascq & 0xFF00) >> 8, + sense->ascq & 0xFF); } /* Called (via iscsi_service) with QemuMutex held. */ diff --git a/block/qcow2.c b/block/qcow2.c index bae5893327..d33fb3ecdd 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -301,10 +301,11 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, } if (!(s->autoclear_features & QCOW2_AUTOCLEAR_BITMAPS)) { - error_report("WARNING: a program lacking bitmap support " - "modified this file, so all bitmaps are now " - "considered inconsistent. Some clusters may be " - "leaked, run 'qemu-img check -r' on the image " + warn_report("a program lacking bitmap support " + "modified this file, so all bitmaps are now " + "considered inconsistent"); + error_printf("Some clusters may be leaked, " + "run 'qemu-img check -r' on the image " "file to fix."); if (need_update_header != NULL) { /* Updating is needed to drop invalid bitmap extension. */ diff --git a/block/vvfat.c b/block/vvfat.c index c54fa94651..cbabb36f62 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -32,6 +32,7 @@ #include "qapi/qmp/qbool.h" #include "qapi/qmp/qstring.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #ifndef S_IWGRP #define S_IWGRP 0 @@ -1226,8 +1227,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, switch (s->fat_type) { case 32: - fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. " - "You are welcome to do so!\n"); + warn_report("FAT32 has not been tested. You are welcome to do so!"); break; case 16: case 12: @@ -3028,7 +3028,8 @@ DLOG(checkpoint()); if (memcmp(direntries + k, array_get(&(s->directory), dir_index + k), sizeof(direntry_t))) { - fprintf(stderr, "Warning: tried to write to write-protected file\n"); + warn_report("tried to write to write-protected " + "file"); return -1; } } @@ -2025,7 +2025,7 @@ if test "$seccomp" != "no" ; then arm|aarch64) libseccomp_minver="2.2.3" ;; - ppc|ppc64) + ppc|ppc64|s390x) libseccomp_minver="2.3.0" ;; *) diff --git a/default-configs/pci.mak b/default-configs/pci.mak index a758630d30..187e438881 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -43,4 +43,4 @@ CONFIG_VGA=y CONFIG_VGA_PCI=y CONFIG_IVSHMEM_DEVICE=$(CONFIG_IVSHMEM) CONFIG_ROCKER=y -CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index a3972c55fe..d7a3755881 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -43,7 +43,7 @@ CONFIG_XILINX_ETHLITE=y CONFIG_PREP=y CONFIG_MAC=y CONFIG_E500=y -CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) +CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM)) CONFIG_PLATFORM_BUS=y CONFIG_ETSEC=y CONFIG_LIBDECNUMBER=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index af32589b38..9086475bf6 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -48,7 +48,7 @@ CONFIG_POWERNV=y CONFIG_PREP=y CONFIG_MAC=y CONFIG_E500=y -CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) +CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM)) CONFIG_PLATFORM_BUS=y CONFIG_ETSEC=y CONFIG_LIBDECNUMBER=y @@ -56,7 +56,7 @@ CONFIG_SM501=y # For pSeries CONFIG_XICS=$(CONFIG_PSERIES) CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) -CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM)) +CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) # For PReP CONFIG_SERIAL_ISA=y CONFIG_MC146818RTC=y diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 6ab2bc65ac..444bf16b80 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -1,6 +1,6 @@ CONFIG_PCI=y CONFIG_VIRTIO_PCI=$(CONFIG_PCI) -CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) +CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VIRTIO=y CONFIG_SCLPCONSOLE=y CONFIG_TERMINAL3270=y diff --git a/docs/devel/build-system.txt b/docs/devel/build-system.txt index 2af1e668c5..386ef36ee3 100644 --- a/docs/devel/build-system.txt +++ b/docs/devel/build-system.txt @@ -232,15 +232,15 @@ The utility code that is used by all binaries is built into a static archive called libqemuutil.a, which is then linked to all the binaries. In order to provide hooks that are only needed by some of the binaries, code in libqemuutil.a may depend on other functions that are -not fully implemented by all QEMU binaries. To deal with this there is a -second library called libqemustub.a which provides dummy stubs for all -these functions. These will get lazy linked into the binary if the real -implementation is not present. In this way, the libqemustub.a static -library can be thought of as a portable implementation of the weak -symbols concept. All binaries should link to both libqemuutil.a and -libqemustub.a. e.g. - - qemu-img$(EXESUF): qemu-img.o ..snip.. libqemuutil.a libqemustub.a +not fully implemented by all QEMU binaries. Dummy stubs for all these +functions are also provided by this library, and will only be linked +into the binary if the real implementation is not present. In a way, +the stubs can be thought of as a portable implementation of the weak +symbols concept. + +All binaries should link to libqemuutil.a, e.g.: + + qemu-img$(EXESUF): qemu-img.o ..snip.. libqemuutil.a Windows platform portability @@ -15,7 +15,6 @@ #include "qemu/cutils.h" #include "elf.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "exec/hwaddr.h" #include "monitor/monitor.h" #include "sysemu/kvm.h" @@ -56,7 +56,6 @@ #endif #endif -#include "exec/cpu-all.h" #include "qemu/rcu_queue.h" #include "qemu/main-loop.h" #include "translate-all.h" diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 95fcac95a2..cd0a1d357b 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -28,6 +28,7 @@ #include "qapi/opts-visitor.h" #include "qapi-visit.h" #include "qapi-event.h" +#include "qemu/error-report.h" struct acpi_table_header { uint16_t _length; /* our length, not actual part of the hdr */ @@ -183,10 +184,9 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen, } if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) { - fprintf(stderr, - "warning: ACPI table has wrong length, header says " - "%" PRIu32 ", actual size %zu bytes\n", - le32_to_cpu(ext_hdr->length), acpi_payload_size); + warn_report("ACPI table has wrong length, header says " + "%" PRIu32 ", actual size %zu bytes", + le32_to_cpu(ext_hdr->length), acpi_payload_size); } ext_hdr->length = cpu_to_le32(acpi_payload_size); @@ -221,7 +221,7 @@ static void acpi_table_install(const char unsigned *blob, size_t bloblen, } if (!has_header && changed_fields == 0) { - fprintf(stderr, "warning: ACPI table: no headers are specified\n"); + warn_report("ACPI table: no headers are specified"); } /* recalculate checksum */ diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 2e5f670c2b..efb5a29475 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -479,8 +479,8 @@ static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) /* Not fatal, we just won't provide virtio. This will * happen with older device tree blobs. */ - fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in " - "dtb; will not include virtio-mmio devices in the dtb.\n"); + warn_report("couldn't find interrupt controller in " + "dtb; will not include virtio-mmio devices in the dtb"); } else { int i; const hwaddr *map = daughterboard->motherboard_map; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index db40e174c9..2853cdc205 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -517,7 +517,7 @@ static Property floppy_drive_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static int floppy_drive_init(DeviceState *qdev) +static void floppy_drive_realize(DeviceState *qdev, Error **errp) { FloppyDrive *dev = FLOPPY_DRIVE(qdev); FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus); @@ -535,15 +535,15 @@ static int floppy_drive_init(DeviceState *qdev) } if (dev->unit >= MAX_FD) { - error_report("Can't create floppy unit %d, bus supports only %d units", - dev->unit, MAX_FD); - return -1; + error_setg(errp, "Can't create floppy unit %d, bus supports " + "only %d units", dev->unit, MAX_FD); + return; } drive = get_drv(bus->fdc, dev->unit); if (drive->blk) { - error_report("Floppy unit %d is in use", dev->unit); - return -1; + error_setg(errp, "Floppy unit %d is in use", dev->unit); + return; } if (!dev->conf.blk) { @@ -557,8 +557,9 @@ static int floppy_drive_init(DeviceState *qdev) if (dev->conf.logical_block_size != 512 || dev->conf.physical_block_size != 512) { - error_report("Physical and logical block size must be 512 for floppy"); - return -1; + error_setg(errp, "Physical and logical block size must " + "be 512 for floppy"); + return; } /* rerror/werror aren't supported by fdc and therefore not even registered @@ -570,20 +571,20 @@ static int floppy_drive_init(DeviceState *qdev) blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk), false, &local_err); if (local_err) { - error_report_err(local_err); - return -1; + error_propagate(errp, local_err); + return; } /* 'enospc' is the default for -drive, 'report' is what blk_new() gives us * for empty drives. */ if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC && blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) { - error_report("fdc doesn't support drive option werror"); - return -1; + error_setg(errp, "fdc doesn't support drive option werror"); + return; } if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { - error_report("fdc doesn't support drive option rerror"); - return -1; + error_setg(errp, "fdc doesn't support drive option rerror"); + return; } drive->conf = &dev->conf; @@ -599,14 +600,12 @@ static int floppy_drive_init(DeviceState *qdev) dev->type = drive->drive; fd_revalidate(drive); - - return 0; } static void floppy_drive_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - k->init = floppy_drive_init; + k->realize = floppy_drive_realize; set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_FLOPPY_BUS; k->props = floppy_drive_properties; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index a16ac75090..05d1440786 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -22,7 +22,7 @@ #include "sysemu/blockdev.h" #include "hw/virtio/virtio-blk.h" #include "dataplane/virtio-blk.h" -#include "block/scsi.h" +#include "scsi/constants.h" #ifdef __linux__ # include <scsi/sg.h> #endif diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 622ee300f9..3a8f1e1a2d 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -30,6 +30,48 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res); +static void +virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) +{ + le32_to_cpus(&hdr->type); + le32_to_cpus(&hdr->flags); + le64_to_cpus(&hdr->fence_id); + le32_to_cpus(&hdr->ctx_id); + le32_to_cpus(&hdr->padding); +} + +static void virtio_gpu_bswap_32(void *ptr, + size_t size) +{ +#ifdef HOST_WORDS_BIGENDIAN + + size_t i; + struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr; + + virtio_gpu_ctrl_hdr_bswap(hdr); + + i = sizeof(struct virtio_gpu_ctrl_hdr); + while (i < size) { + le32_to_cpus((uint32_t *)(ptr + i)); + i = i + sizeof(uint32_t); + } + +#endif +} + +static void +virtio_gpu_t2d_bswap(struct virtio_gpu_transfer_to_host_2d *t2d) +{ + virtio_gpu_ctrl_hdr_bswap(&t2d->hdr); + le32_to_cpus(&t2d->r.x); + le32_to_cpus(&t2d->r.y); + le32_to_cpus(&t2d->r.width); + le32_to_cpus(&t2d->r.height); + le64_to_cpus(&t2d->offset); + le32_to_cpus(&t2d->resource_id); + le32_to_cpus(&t2d->padding); +} + #ifdef CONFIG_VIRGL #include <virglrenderer.h> #define VIRGL(_g, _virgl, _simple, ...) \ @@ -205,6 +247,7 @@ void virtio_gpu_ctrl_response(VirtIOGPU *g, resp->fence_id = cmd->cmd_hdr.fence_id; resp->ctx_id = cmd->cmd_hdr.ctx_id; } + virtio_gpu_ctrl_hdr_bswap(resp); s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len); if (s != resp_len) { qemu_log_mask(LOG_GUEST_ERROR, @@ -236,8 +279,8 @@ virtio_gpu_fill_display_info(VirtIOGPU *g, for (i = 0; i < g->conf.max_outputs; i++) { if (g->enabled_output_bitmask & (1 << i)) { dpy_info->pmodes[i].enabled = 1; - dpy_info->pmodes[i].r.width = g->req_state[i].width; - dpy_info->pmodes[i].r.height = g->req_state[i].height; + dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); + dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); } } } @@ -287,6 +330,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_resource_create_2d c2d; VIRTIO_GPU_FILL_CMD(c2d); + virtio_gpu_bswap_32(&c2d, sizeof(c2d)); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); @@ -360,6 +404,7 @@ static void virtio_gpu_resource_unref(VirtIOGPU *g, struct virtio_gpu_resource_unref unref; VIRTIO_GPU_FILL_CMD(unref); + virtio_gpu_bswap_32(&unref, sizeof(unref)); trace_virtio_gpu_cmd_res_unref(unref.resource_id); res = virtio_gpu_find_resource(g, unref.resource_id); @@ -383,6 +428,7 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, struct virtio_gpu_transfer_to_host_2d t2d; VIRTIO_GPU_FILL_CMD(t2d); + virtio_gpu_t2d_bswap(&t2d); trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); res = virtio_gpu_find_resource(g, t2d.resource_id); @@ -439,6 +485,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, int i; VIRTIO_GPU_FILL_CMD(rf); + virtio_gpu_bswap_32(&rf, sizeof(rf)); trace_virtio_gpu_cmd_res_flush(rf.resource_id, rf.r.width, rf.r.height, rf.r.x, rf.r.y); @@ -511,6 +558,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, struct virtio_gpu_set_scanout ss; VIRTIO_GPU_FILL_CMD(ss); + virtio_gpu_bswap_32(&ss, sizeof(ss)); trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); @@ -633,13 +681,15 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); } for (i = 0; i < ab->nr_entries; i++) { - hwaddr len = ents[i].length; - (*iov)[i].iov_len = ents[i].length; - (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1); + uint64_t a = le64_to_cpu(ents[i].addr); + uint32_t l = le32_to_cpu(ents[i].length); + hwaddr len = l; + (*iov)[i].iov_len = l; + (*iov)[i].iov_base = cpu_physical_memory_map(a, &len, 1); if (addr) { - (*addr)[i] = ents[i].addr; + (*addr)[i] = a; } - if (!(*iov)[i].iov_base || len != ents[i].length) { + if (!(*iov)[i].iov_base || len != l) { qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" " resource %d element %d\n", __func__, ab->resource_id, i); @@ -686,6 +736,7 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, int ret; VIRTIO_GPU_FILL_CMD(ab); + virtio_gpu_bswap_32(&ab, sizeof(ab)); trace_virtio_gpu_cmd_res_back_attach(ab.resource_id); res = virtio_gpu_find_resource(g, ab.resource_id); @@ -718,6 +769,7 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g, struct virtio_gpu_resource_detach_backing detach; VIRTIO_GPU_FILL_CMD(detach); + virtio_gpu_bswap_32(&detach, sizeof(detach)); trace_virtio_gpu_cmd_res_back_detach(detach.resource_id); res = virtio_gpu_find_resource(g, detach.resource_id); @@ -734,6 +786,7 @@ static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); + virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); switch (cmd->cmd_hdr.type) { case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: @@ -879,6 +932,7 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) "%s: cursor size incorrect %zu vs %zu\n", __func__, s, sizeof(cursor_info)); } else { + virtio_gpu_bswap_32(&cursor_info, sizeof(cursor_info)); update_cursor(g, &cursor_info); } virtqueue_push(vq, elem, 0); @@ -1135,7 +1189,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) } g->config_size = sizeof(struct virtio_gpu_config); - g->virtio_config.num_scanouts = g->conf.max_outputs; + g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, g->config_size); diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index d72bcdcd49..2af37a9129 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2766,17 +2766,22 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) ACPI_BUILD_ALIGN_SIZE); if (tables_blob->len > legacy_table_size) { /* Should happen only with PCI bridges and -M pc-i440fx-2.0. */ - warn_report("migration may not work."); + warn_report("ACPI table size %u exceeds %d bytes," + " migration may not work", + tables_blob->len, legacy_table_size); + error_printf("Try removing CPUs, NUMA nodes, memory slots" + " or PCI bridges."); } g_array_set_size(tables_blob, legacy_table_size); } else { /* Make sure we have a buffer in case we need to resize the tables. */ if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { /* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */ - warn_report("ACPI tables are larger than 64k."); - warn_report("migration may not work."); - warn_report("please remove CPUs, NUMA nodes, " - "memory slots or PCI bridges."); + warn_report("ACPI table size %u exceeds %d bytes," + " migration may not work", + tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); + error_printf("Try removing CPUs, NUMA nodes, memory slots" + " or PCI bridges."); } acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); } diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index 6001f4caa2..c7b70c91d5 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -221,15 +221,34 @@ int load_multiboot(FWCfgState *fw_cfg, uint32_t mh_header_addr = ldl_p(header+i+12); uint32_t mh_load_end_addr = ldl_p(header+i+20); uint32_t mh_bss_end_addr = ldl_p(header+i+24); + mh_load_addr = ldl_p(header+i+16); + if (mh_header_addr < mh_load_addr) { + fprintf(stderr, "invalid mh_load_addr address\n"); + exit(1); + } + uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); uint32_t mb_load_size = 0; mh_entry_addr = ldl_p(header+i+28); if (mh_load_end_addr) { + if (mh_bss_end_addr < mh_load_addr) { + fprintf(stderr, "invalid mh_bss_end_addr address\n"); + exit(1); + } mb_kernel_size = mh_bss_end_addr - mh_load_addr; + + if (mh_load_end_addr < mh_load_addr) { + fprintf(stderr, "invalid mh_load_end_addr address\n"); + exit(1); + } mb_load_size = mh_load_end_addr - mh_load_addr; } else { + if (kernel_file_size < mb_kernel_text_offset) { + fprintf(stderr, "invalid kernel_file_size\n"); + exit(1); + } mb_kernel_size = kernel_file_size - mb_kernel_text_offset; mb_load_size = mb_kernel_size; } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 610c65aeab..05985d4927 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -384,7 +384,7 @@ ISADevice *pc_find_fdc0(void) warn_report("multiple floppy disk controllers with " "iobase=0x3f0 have been found"); error_printf("the one being picked for CMOS setup might not reflect " - "your intent\n"); + "your intent"); } return state.floppy; @@ -1278,7 +1278,7 @@ void pc_acpi_init(const char *default_dsdt) filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, default_dsdt); if (filename == NULL) { - fprintf(stderr, "WARNING: failed to find %s\n", default_dsdt); + warn_report("failed to find %s", default_dsdt); } else { QemuOpts *opts = qemu_opts_create(qemu_find_opts("acpi"), NULL, 0, &error_abort); @@ -2066,9 +2066,8 @@ static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, } if (value < (1ULL << 20)) { - warn_report("small max_ram_below_4g(%"PRIu64 - ") less than 1M. BIOS may not work..", - value); + warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary," + "BIOS may not work with less than 1MiB", value); } pcms->max_ram_below_4g = value; diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index c1cba584d1..6c4ec4be4e 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -101,9 +101,11 @@ static void pc_q35_init(MachineState *machine) lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && lowmem & ((1ULL << 30) - 1)) { - warn_report("Large machine and max_ram_below_4g(%"PRIu64 - ") not a multiple of 1G; possible bad performance.", - pcms->max_ram_below_4g); + warn_report("There is possibly poor performance as the ram size " + " (0x%" PRIx64 ") is more then twice the size of" + " max-ram-below-4g (%"PRIu64") and" + " max-ram-below-4g is not a multiple of 1G.", + (uint64_t)machine->ram_size, pcms->max_ram_below_4g); } } diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index 369c3df8a0..baab93b614 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -9,6 +9,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include <sys/resource.h> @@ -125,8 +126,8 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque) rlimit_as.rlim_cur = rlimit_as.rlim_max; if (rlimit_as.rlim_max != RLIM_INFINITY) { - fprintf(stderr, "Warning: QEMU's maximum size of virtual" - " memory is not infinity.\n"); + warn_report("QEMU's maximum size of virtual" + " memory is not infinity"); } if (rlimit_as.rlim_max < MCACHE_MAX_SIZE + NON_MCACHE_MEMORY_SIZE) { mapcache->max_mcache_size = rlimit_as.rlim_max - diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 406a1b5579..24c65dfab3 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -34,15 +34,7 @@ #include "hw/ide/pci.h" #include "hw/ide/ahci_internal.h" -#define DEBUG_AHCI 0 - -#define DPRINTF(port, fmt, ...) \ -do { \ - if (DEBUG_AHCI) { \ - fprintf(stderr, "ahci: %s: [%d] ", __func__, port); \ - fprintf(stderr, fmt, ## __VA_ARGS__); \ - } \ -} while (0) +#include "trace.h" static void check_cmd(AHCIState *s, int port); static int handle_cmd(AHCIState *s, int port, uint8_t slot); @@ -55,6 +47,27 @@ static bool ahci_map_fis_address(AHCIDevice *ad); static void ahci_unmap_clb_address(AHCIDevice *ad); static void ahci_unmap_fis_address(AHCIDevice *ad); +static const char *AHCIPortIRQ_lookup[AHCI_PORT_IRQ__COUNT] = { + [AHCI_PORT_IRQ_BIT_DHRS] = "DHRS", + [AHCI_PORT_IRQ_BIT_PSS] = "PSS", + [AHCI_PORT_IRQ_BIT_DSS] = "DSS", + [AHCI_PORT_IRQ_BIT_SDBS] = "SDBS", + [AHCI_PORT_IRQ_BIT_UFS] = "UFS", + [AHCI_PORT_IRQ_BIT_DPS] = "DPS", + [AHCI_PORT_IRQ_BIT_PCS] = "PCS", + [AHCI_PORT_IRQ_BIT_DMPS] = "DMPS", + [8 ... 21] = "RESERVED", + [AHCI_PORT_IRQ_BIT_PRCS] = "PRCS", + [AHCI_PORT_IRQ_BIT_IPMS] = "IPMS", + [AHCI_PORT_IRQ_BIT_OFS] = "OFS", + [25] = "RESERVED", + [AHCI_PORT_IRQ_BIT_INFS] = "INFS", + [AHCI_PORT_IRQ_BIT_IFS] = "IFS", + [AHCI_PORT_IRQ_BIT_HBDS] = "HBDS", + [AHCI_PORT_IRQ_BIT_HBFS] = "HBFS", + [AHCI_PORT_IRQ_BIT_TFES] = "TFES", + [AHCI_PORT_IRQ_BIT_CPDS] = "CPDS" +}; static uint32_t ahci_port_read(AHCIState *s, int port, int offset) { @@ -114,9 +127,9 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset) default: val = 0; } - DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val); - return val; + trace_ahci_port_read(s, port, offset, val); + return val; } static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) @@ -125,7 +138,7 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev) PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state), TYPE_PCI_DEVICE); - DPRINTF(0, "raise irq\n"); + trace_ahci_irq_raise(s); if (pci_dev && msi_enabled(pci_dev)) { msi_notify(pci_dev, 0); @@ -140,7 +153,7 @@ static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev) PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state), TYPE_PCI_DEVICE); - DPRINTF(0, "lower irq\n"); + trace_ahci_irq_lower(s); if (!pci_dev || !msi_enabled(pci_dev)) { qemu_irq_lower(s->irq); @@ -150,8 +163,7 @@ static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev) static void ahci_check_irq(AHCIState *s) { int i; - - DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus); + uint32_t old_irq = s->control_regs.irqstatus; s->control_regs.irqstatus = 0; for (i = 0; i < s->ports; i++) { @@ -160,7 +172,7 @@ static void ahci_check_irq(AHCIState *s) s->control_regs.irqstatus |= (1 << i); } } - + trace_ahci_check_irq(s, old_irq, s->control_regs.irqstatus); if (s->control_regs.irqstatus && (s->control_regs.ghc & HOST_CTL_IRQ_EN)) { ahci_irq_raise(s, NULL); @@ -170,12 +182,18 @@ static void ahci_check_irq(AHCIState *s) } static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d, - int irq_type) + enum AHCIPortIRQ irqbit) { - DPRINTF(d->port_no, "trigger irq %#x -> %x\n", - irq_type, d->port_regs.irq_mask & irq_type); + g_assert(irqbit >= 0 && irqbit < 32); + uint32_t irq = 1U << irqbit; + uint32_t irqstat = d->port_regs.irq_stat | irq; - d->port_regs.irq_stat |= irq_type; + trace_ahci_trigger_irq(s, d->port_no, + AHCIPortIRQ_lookup[irqbit], irq, + d->port_regs.irq_stat, irqstat, + irqstat & d->port_regs.irq_mask); + + d->port_regs.irq_stat = irqstat; ahci_check_irq(s); } @@ -240,7 +258,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) { AHCIPortRegs *pr = &s->dev[port].port_regs; - DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val); + trace_ahci_port_write(s, port, offset, val); switch (offset) { case PORT_LST_ADDR: pr->lst_addr = val; @@ -341,8 +359,6 @@ static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr) val = s->control_regs.version; break; } - - DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val); } else if ((addr >= AHCI_PORT_REGS_START_ADDR) && (addr < (AHCI_PORT_REGS_START_ADDR + (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) { @@ -350,6 +366,7 @@ static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr) addr & AHCI_PORT_ADDR_OFFSET_MASK); } + trace_ahci_mem_read_32(s, addr, val); return val; } @@ -379,8 +396,7 @@ static uint64_t ahci_mem_read(void *opaque, hwaddr addr, unsigned size) val = (hi << 32 | lo) >> (ofst * 8); } - DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n", - addr, val, size); + trace_ahci_mem_read(opaque, size, addr, val); return val; } @@ -390,8 +406,7 @@ static void ahci_mem_write(void *opaque, hwaddr addr, { AHCIState *s = opaque; - DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n", - addr, val, size); + trace_ahci_mem_write(s, size, addr, val); /* Only aligned reads are allowed on AHCI */ if (addr & 3) { @@ -401,15 +416,12 @@ static void ahci_mem_write(void *opaque, hwaddr addr, } if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) { - DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val); - switch (addr) { case HOST_CAP: /* R/WO, RO */ /* FIXME handle R/WO */ break; case HOST_CTL: /* R/W */ if (val & HOST_CTL_RESET) { - DPRINTF(-1, "HBA Reset\n"); ahci_reset(s); } else { s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN; @@ -427,7 +439,7 @@ static void ahci_mem_write(void *opaque, hwaddr addr, /* FIXME report write? */ break; default: - DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr); + trace_ahci_mem_write_unknown(s, size, addr, val); } } else if ((addr >= AHCI_PORT_REGS_START_ADDR) && (addr < (AHCI_PORT_REGS_START_ADDR + @@ -559,7 +571,8 @@ static void ahci_set_signature(AHCIDevice *ad, uint32_t sig) s->sector = sig >> 8 & 0xFF; s->nsector = sig & 0xFF; - DPRINTF(ad->port_no, "set hcyl:lcyl:sect:nsect = 0x%08x\n", sig); + trace_ahci_set_signature(ad->hba, ad->port_no, s->nsector, s->sector, + s->lcyl, s->hcyl, sig); } static void ahci_reset_port(AHCIState *s, int port) @@ -569,7 +582,7 @@ static void ahci_reset_port(AHCIState *s, int port) IDEState *ide_state = &d->port.ifs[0]; int i; - DPRINTF(port, "reset port\n"); + trace_ahci_reset_port(s, port); ide_bus_reset(&d->port); ide_state->ncq_queues = AHCI_MAX_CMDS; @@ -622,20 +635,21 @@ static void ahci_reset_port(AHCIState *s, int port) ahci_init_d2h(d); } -static void debug_print_fis(uint8_t *fis, int cmd_len) +/* Buffer pretty output based on a raw FIS structure. */ +static char *ahci_pretty_buffer_fis(uint8_t *fis, int cmd_len) { -#if DEBUG_AHCI int i; + GString *s = g_string_new("FIS:"); - fprintf(stderr, "fis:"); for (i = 0; i < cmd_len; i++) { if ((i & 0xf) == 0) { - fprintf(stderr, "\n%02x:",i); + g_string_append_printf(s, "\n0x%02x: ", i); } - fprintf(stderr, "%02x ",fis[i]); + g_string_append_printf(s, "%02x ", fis[i]); } - fprintf(stderr, "\n"); -#endif + g_string_append_c(s, '\n'); + + return g_string_free(s, FALSE); } static bool ahci_map_fis_address(AHCIDevice *ad) @@ -655,7 +669,7 @@ static bool ahci_map_fis_address(AHCIDevice *ad) static void ahci_unmap_fis_address(AHCIDevice *ad) { if (ad->res_fis == NULL) { - DPRINTF(ad->port_no, "Attempt to unmap NULL FIS address\n"); + trace_ahci_unmap_fis_address_null(ad->hba, ad->port_no); return; } ad->port_regs.cmd &= ~PORT_CMD_FIS_ON; @@ -682,7 +696,7 @@ static bool ahci_map_clb_address(AHCIDevice *ad) static void ahci_unmap_clb_address(AHCIDevice *ad) { if (ad->lst == NULL) { - DPRINTF(ad->port_no, "Attempt to unmap NULL CLB address\n"); + trace_ahci_unmap_clb_address_null(ad->hba, ad->port_no); return; } ad->port_regs.cmd &= ~PORT_CMD_LIST_ON; @@ -723,7 +737,7 @@ static void ahci_write_fis_sdb(AHCIState *s, NCQTransferState *ncq_tfs) /* Trigger IRQ if interrupt bit is set (which currently, it always is) */ if (sdb_fis->flags & 0x40) { - ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS); + ahci_trigger_irq(s, ad, AHCI_PORT_IRQ_BIT_SDBS); } } @@ -766,10 +780,10 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) ad->port.ifs[0].status; if (pio_fis[2] & ERR_STAT) { - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR); + ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES); } - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS); + ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_PSS); } static bool ahci_write_fis_d2h(AHCIDevice *ad) @@ -809,10 +823,10 @@ static bool ahci_write_fis_d2h(AHCIDevice *ad) ad->port.ifs[0].status; if (d2h_fis[2] & ERR_STAT) { - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR); + ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_TFES); } - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS); + ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_DHRS); return true; } @@ -854,20 +868,22 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, IDEBus *bus = &ad->port; BusState *qbus = BUS(bus); + trace_ahci_populate_sglist(ad->hba, ad->port_no); + if (!prdtl) { - DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts); + trace_ahci_populate_sglist_no_prdtl(ad->hba, ad->port_no, opts); return -1; } /* map PRDT */ if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len, DMA_DIRECTION_TO_DEVICE))){ - DPRINTF(ad->port_no, "map failed\n"); + trace_ahci_populate_sglist_no_map(ad->hba, ad->port_no); return -1; } if (prdt_len < real_prdt_len) { - DPRINTF(ad->port_no, "mapped less than expected\n"); + trace_ahci_populate_sglist_short_map(ad->hba, ad->port_no); r = -1; goto out; } @@ -886,9 +902,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, sum += tbl_entry_size; } if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) { - DPRINTF(ad->port_no, "%s: Incorrect offset! " - "off_idx: %d, off_pos: %"PRId64"\n", - __func__, off_idx, off_pos); + trace_ahci_populate_sglist_bad_offset(ad->hba, ad->port_no, + off_idx, off_pos); r = -1; goto out; } @@ -934,8 +949,8 @@ static void ncq_finish(NCQTransferState *ncq_tfs) ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs); - DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n", - ncq_tfs->tag); + trace_ncq_finish(ncq_tfs->drive->hba, ncq_tfs->drive->port_no, + ncq_tfs->tag); block_acct_done(blk_get_stats(ncq_tfs->drive->port.ifs[0].blk), &ncq_tfs->acct); @@ -999,12 +1014,8 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs) switch (ncq_tfs->cmd) { case READ_FPDMA_QUEUED: - DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", tag %d\n", - ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag); - - DPRINTF(port, "tag %d aio read %"PRId64"\n", - ncq_tfs->tag, ncq_tfs->lba); - + trace_execute_ncq_command_read(ad->hba, port, ncq_tfs->tag, + ncq_tfs->sector_count, ncq_tfs->lba); dma_acct_start(ide_state->blk, &ncq_tfs->acct, &ncq_tfs->sglist, BLOCK_ACCT_READ); ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist, @@ -1013,12 +1024,8 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs) ncq_cb, ncq_tfs); break; case WRITE_FPDMA_QUEUED: - DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n", - ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag); - - DPRINTF(port, "tag %d aio write %"PRId64"\n", - ncq_tfs->tag, ncq_tfs->lba); - + trace_execute_ncq_command_read(ad->hba, port, ncq_tfs->tag, + ncq_tfs->sector_count, ncq_tfs->lba); dma_acct_start(ide_state->blk, &ncq_tfs->acct, &ncq_tfs->sglist, BLOCK_ACCT_WRITE); ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist, @@ -1027,8 +1034,8 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs) ncq_cb, ncq_tfs); break; default: - DPRINTF(port, "error: unsupported NCQ command (0x%02x) received\n", - ncq_tfs->cmd); + trace_execute_ncq_command_unsup(ad->hba, port, + ncq_tfs->tag, ncq_tfs->cmd); ncq_err(ncq_tfs); } } @@ -1038,7 +1045,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, uint8_t slot) { AHCIDevice *ad = &s->dev[port]; - IDEState *ide_state = &ad->port.ifs[0]; NCQFrame *ncq_fis = (NCQFrame*)cmd_fis; uint8_t tag = ncq_fis->tag >> 3; NCQTransferState *ncq_tfs = &ad->ncq_tfs[tag]; @@ -1066,21 +1072,20 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, /* Sanity-check the NCQ packet */ if (tag != slot) { - DPRINTF(port, "Warn: NCQ slot (%d) did not match the given tag (%d)\n", - slot, tag); + trace_process_ncq_command_mismatch(s, port, tag, slot); } if (ncq_fis->aux0 || ncq_fis->aux1 || ncq_fis->aux2 || ncq_fis->aux3) { - DPRINTF(port, "Warn: Attempt to use NCQ auxiliary fields.\n"); + trace_process_ncq_command_aux(s, port, tag); } if (ncq_fis->prio || ncq_fis->icc) { - DPRINTF(port, "Warn: Unsupported attempt to use PRIO/ICC fields\n"); + trace_process_ncq_command_prioicc(s, port, tag); } if (ncq_fis->fua & NCQ_FIS_FUA_MASK) { - DPRINTF(port, "Warn: Unsupported attempt to use Force Unit Access\n"); + trace_process_ncq_command_fua(s, port, tag); } if (ncq_fis->tag & NCQ_FIS_RARC_MASK) { - DPRINTF(port, "Warn: Unsupported attempt to use Rebuild Assist\n"); + trace_process_ncq_command_rarc(s, port, tag); } ncq_tfs->sector_count = ((ncq_fis->sector_count_high << 8) | @@ -1096,19 +1101,17 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, "is smaller than the requested size (0x%zx)", ncq_tfs->sglist.size, size); ncq_err(ncq_tfs); - ahci_trigger_irq(ad->hba, ad, PORT_IRQ_OVERFLOW); + ahci_trigger_irq(ad->hba, ad, AHCI_PORT_IRQ_BIT_OFS); return; } else if (ncq_tfs->sglist.size != size) { - DPRINTF(port, "Warn: PRDTL (0x%zx)" - " does not match requested size (0x%zx)", - ncq_tfs->sglist.size, size); + trace_process_ncq_command_large(s, port, tag, + ncq_tfs->sglist.size, size); } - DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", " - "drive max %"PRId64"\n", - ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 1, - ide_state->nb_sectors - 1); - + trace_process_ncq_command(s, port, tag, + ncq_fis->command, + ncq_tfs->lba, + ncq_tfs->lba + ncq_tfs->sector_count - 1); execute_ncq_command(ncq_tfs); } @@ -1129,16 +1132,14 @@ static void handle_reg_h2d_fis(AHCIState *s, int port, uint16_t opts = le16_to_cpu(cmd->opts); if (cmd_fis[1] & 0x0F) { - DPRINTF(port, "Port Multiplier not supported." - " cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n", - cmd_fis[0], cmd_fis[1], cmd_fis[2]); + trace_handle_reg_h2d_fis_pmp(s, port, cmd_fis[1], + cmd_fis[2], cmd_fis[3]); return; } if (cmd_fis[1] & 0x70) { - DPRINTF(port, "Reserved flags set in H2D Register FIS." - " cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n", - cmd_fis[0], cmd_fis[1], cmd_fis[2]); + trace_handle_reg_h2d_fis_res(s, port, cmd_fis[1], + cmd_fis[2], cmd_fis[3]); return; } @@ -1192,7 +1193,11 @@ static void handle_reg_h2d_fis(AHCIState *s, int port, * table to ide_state->io_buffer */ if (opts & AHCI_CMD_ATAPI) { memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10); - debug_print_fis(ide_state->io_buffer, 0x10); + if (trace_event_get_state_backends(TRACE_HANDLE_REG_H2D_FIS_DUMP)) { + char *pretty_fis = ahci_pretty_buffer_fis(ide_state->io_buffer, 0x10); + trace_handle_reg_h2d_fis_dump(s, port, pretty_fis); + g_free(pretty_fis); + } s->dev[port].done_atapi_packet = false; /* XXX send PIO setup FIS */ } @@ -1216,12 +1221,12 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) { /* Engine currently busy, try again later */ - DPRINTF(port, "engine busy\n"); + trace_handle_cmd_busy(s, port); return -1; } if (!s->dev[port].lst) { - DPRINTF(port, "error: lst not given but cmd handled"); + trace_handle_cmd_nolist(s, port); return -1; } cmd = get_cmd_header(s, port, slot); @@ -1231,7 +1236,7 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) /* The device we are working for */ ide_state = &s->dev[port].port.ifs[0]; if (!ide_state->blk) { - DPRINTF(port, "error: guest accessed unused port"); + trace_handle_cmd_badport(s, port); return -1; } @@ -1240,25 +1245,25 @@ static int handle_cmd(AHCIState *s, int port, uint8_t slot) cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len, DMA_DIRECTION_FROM_DEVICE); if (!cmd_fis) { - DPRINTF(port, "error: guest passed us an invalid cmd fis\n"); + trace_handle_cmd_badfis(s, port); return -1; } else if (cmd_len != 0x80) { - ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_HBUS_ERR); - DPRINTF(port, "error: dma_memory_map failed: " - "(len(%02"PRIx64") != 0x80)\n", - cmd_len); + ahci_trigger_irq(s, &s->dev[port], AHCI_PORT_IRQ_BIT_HBFS); + trace_handle_cmd_badmap(s, port, cmd_len); goto out; } - debug_print_fis(cmd_fis, 0x80); - + if (trace_event_get_state_backends(TRACE_HANDLE_CMD_FIS_DUMP)) { + char *pretty_fis = ahci_pretty_buffer_fis(cmd_fis, 0x80); + trace_handle_cmd_fis_dump(s, port, pretty_fis); + g_free(pretty_fis); + } switch (cmd_fis[0]) { case SATA_FIS_TYPE_REGISTER_H2D: handle_reg_h2d_fis(s, port, slot, cmd_fis); break; default: - DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x " - "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1], - cmd_fis[2]); + trace_handle_cmd_unhandled_fis(s, port, + cmd_fis[0], cmd_fis[1], cmd_fis[2]); break; } @@ -1299,9 +1304,9 @@ static void ahci_start_transfer(IDEDMA *dma) has_sglist = 1; } - DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n", - is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata", - has_sglist ? "" : "o"); + trace_ahci_start_transfer(ad->hba, ad->port_no, is_write ? "writ" : "read", + size, is_atapi ? "atapi" : "ata", + has_sglist ? "" : "o"); if (has_sglist && size) { if (is_write) { @@ -1330,7 +1335,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s, BlockCompletionFunc *dma_cb) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - DPRINTF(ad->port_no, "\n"); + trace_ahci_start_dma(ad->hba, ad->port_no); s->io_buffer_offset = 0; dma_cb(s, 0); } @@ -1368,12 +1373,12 @@ static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit) if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd, limit, s->io_buffer_offset) == -1) { - DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n"); + trace_ahci_dma_prepare_buf_fail(ad->hba, ad->port_no); return -1; } s->io_buffer_size = s->sg.size; - DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size); + trace_ahci_dma_prepare_buf(ad->hba, ad->port_no, limit, s->io_buffer_size); return s->io_buffer_size; } @@ -1409,11 +1414,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) /* free sglist, update byte count */ dma_buf_commit(s, l); - s->io_buffer_index += l; - DPRINTF(ad->port_no, "len=%#x\n", l); - + trace_ahci_dma_rw_buf(ad->hba, ad->port_no, l); return 1; } @@ -1421,7 +1424,7 @@ static void ahci_cmd_done(IDEDMA *dma) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - DPRINTF(ad->port_no, "cmd done\n"); + trace_ahci_cmd_done(ad->hba, ad->port_no); /* update d2h status */ ahci_write_fis_d2h(ad); @@ -1495,6 +1498,7 @@ void ahci_uninit(AHCIState *s) ide_exit(s); } + object_unparent(OBJECT(&ad->port)); } g_free(s->dev); @@ -1505,6 +1509,8 @@ void ahci_reset(AHCIState *s) AHCIPortRegs *pr; int i; + trace_ahci_reset(s); + s->control_regs.irqstatus = 0; /* AHCI Enable (AE) * The implementation of this bit is dependent upon the value of the @@ -1755,6 +1761,7 @@ static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr, unsigned size) { AllwinnerAHCIState *a = opaque; + AHCIState *s = &(SYSBUS_AHCI(a)->ahci); uint64_t val = a->regs[addr/4]; switch (addr / 4) { @@ -1765,8 +1772,7 @@ static uint64_t allwinner_ahci_mem_read(void *opaque, hwaddr addr, val &= ~(0x1 << 24); break; } - DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n", - addr, val, size); + trace_allwinner_ahci_mem_read(s, a, addr, val, size); return val; } @@ -1774,9 +1780,9 @@ static void allwinner_ahci_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { AllwinnerAHCIState *a = opaque; + AHCIState *s = &(SYSBUS_AHCI(a)->ahci); - DPRINTF(-1, "addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 ", size=%d\n", - addr, val, size); + trace_allwinner_ahci_mem_write(s, a, addr, val, size); a->regs[addr/4] = val; } diff --git a/hw/ide/ahci_internal.h b/hw/ide/ahci_internal.h index 1e21169e79..ce2e818c8c 100644 --- a/hw/ide/ahci_internal.h +++ b/hw/ide/ahci_internal.h @@ -91,6 +91,31 @@ #define PORT_CMD_ISSUE 0x38 /* command issue */ #define PORT_RESERVED 0x3c /* reserved */ +/* Port interrupt bit descriptors */ +enum AHCIPortIRQ { + AHCI_PORT_IRQ_BIT_DHRS = 0, + AHCI_PORT_IRQ_BIT_PSS = 1, + AHCI_PORT_IRQ_BIT_DSS = 2, + AHCI_PORT_IRQ_BIT_SDBS = 3, + AHCI_PORT_IRQ_BIT_UFS = 4, + AHCI_PORT_IRQ_BIT_DPS = 5, + AHCI_PORT_IRQ_BIT_PCS = 6, + AHCI_PORT_IRQ_BIT_DMPS = 7, + /* RESERVED */ + AHCI_PORT_IRQ_BIT_PRCS = 22, + AHCI_PORT_IRQ_BIT_IPMS = 23, + AHCI_PORT_IRQ_BIT_OFS = 24, + /* RESERVED */ + AHCI_PORT_IRQ_BIT_INFS = 26, + AHCI_PORT_IRQ_BIT_IFS = 27, + AHCI_PORT_IRQ_BIT_HBDS = 28, + AHCI_PORT_IRQ_BIT_HBFS = 29, + AHCI_PORT_IRQ_BIT_TFES = 30, + AHCI_PORT_IRQ_BIT_CPDS = 31, + AHCI_PORT_IRQ__COUNT = 32 +}; + + /* PORT_IRQ_{STAT,MASK} bits */ #define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */ #define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ @@ -98,18 +123,19 @@ #define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ #define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ #define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ + /* reserved */ #define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ #define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ - #define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ -#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ -#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ -#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ -#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ -#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ -#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ -#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ -#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ + /* reserved */ +#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ +#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ +#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ +#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ +#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ +#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ +#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ +#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ #define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \ PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index fc1d19c6d4..c0509c8bf5 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -27,6 +27,7 @@ #include "hw/ide/internal.h" #include "hw/scsi/scsi.h" #include "sysemu/block-backend.h" +#include "trace.h" #define ATAPI_SECTOR_BITS (2 + BDRV_SECTOR_BITS) #define ATAPI_SECTOR_SIZE (1 << ATAPI_SECTOR_BITS) @@ -116,9 +117,7 @@ cd_read_sector_sync(IDEState *s) block_acct_start(blk_get_stats(s->blk), &s->acct, ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); -#ifdef DEBUG_IDE_ATAPI - printf("cd_read_sector_sync: lba=%d\n", s->lba); -#endif + trace_cd_read_sector_sync(s->lba); switch (s->cd_sector_size) { case 2048: @@ -152,9 +151,7 @@ static void cd_read_sector_cb(void *opaque, int ret) { IDEState *s = opaque; -#ifdef DEBUG_IDE_ATAPI - printf("cd_read_sector_cb: lba=%d ret=%d\n", s->lba, ret); -#endif + trace_cd_read_sector_cb(s->lba, ret); if (ret < 0) { block_acct_failed(blk_get_stats(s->blk), &s->acct); @@ -188,9 +185,7 @@ static int cd_read_sector(IDEState *s) s->iov.iov_len = ATAPI_SECTOR_SIZE; qemu_iovec_init_external(&s->qiov, &s->iov, 1); -#ifdef DEBUG_IDE_ATAPI - printf("cd_read_sector: lba=%d\n", s->lba); -#endif + trace_cd_read_sector(s->lba); block_acct_start(blk_get_stats(s->blk), &s->acct, ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); @@ -213,9 +208,7 @@ void ide_atapi_cmd_ok(IDEState *s) void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) { -#ifdef DEBUG_IDE_ATAPI - printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); -#endif + trace_ide_atapi_cmd_error(s, sense_key, asc); s->error = sense_key << 4; s->status = READY_STAT | ERR_STAT; s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; @@ -252,19 +245,14 @@ static uint16_t atapi_byte_count_limit(IDEState *s) void ide_atapi_cmd_reply_end(IDEState *s) { int byte_count_limit, size, ret; -#ifdef DEBUG_IDE_ATAPI - printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", - s->packet_transfer_size, - s->elementary_transfer_size, - s->io_buffer_index); -#endif + trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size, + s->elementary_transfer_size, + s->io_buffer_index); if (s->packet_transfer_size <= 0) { /* end of transfer */ ide_atapi_cmd_ok(s); ide_set_irq(s->bus); -#ifdef DEBUG_IDE_ATAPI - printf("end of transfer, status=0x%x\n", s->status); -#endif + trace_ide_atapi_cmd_reply_end_eot(s, s->status); } else { /* see if a new sector must be read */ if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { @@ -300,9 +288,7 @@ void ide_atapi_cmd_reply_end(IDEState *s) /* a new transfer is needed */ s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; byte_count_limit = atapi_byte_count_limit(s); -#ifdef DEBUG_IDE_ATAPI - printf("byte_count_limit=%d\n", byte_count_limit); -#endif + trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit); size = s->packet_transfer_size; if (size > byte_count_limit) { /* byte count limit must be even if this case */ @@ -324,9 +310,7 @@ void ide_atapi_cmd_reply_end(IDEState *s) ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size, size, ide_atapi_cmd_reply_end); ide_set_irq(s->bus); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif + trace_ide_atapi_cmd_reply_end_new(s, s->status); } } } @@ -368,9 +352,7 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, static void ide_atapi_cmd_check_status(IDEState *s) { -#ifdef DEBUG_IDE_ATAPI - printf("atapi_cmd_check_status\n"); -#endif + trace_ide_atapi_cmd_check_status(s); s->error = MC_ERR | (UNIT_ATTENTION << 4); s->status = ERR_STAT; s->nsector = 0; @@ -434,10 +416,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) s->io_buffer_size = n * 2048; data_offset = 0; } -#ifdef DEBUG_AIO - printf("aio_read_cd: lba=%u n=%d\n", s->lba, n); -#endif - + trace_ide_atapi_cmd_read_dma_cb_aio(s, s->lba, n); s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); s->bus->dma->iov.iov_len = n * ATAPI_SECTOR_SIZE; qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1); @@ -477,10 +456,8 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, int sector_size) { -#ifdef DEBUG_IDE_ATAPI - printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio", - lba, nb_sectors); -#endif + trace_ide_atapi_cmd_read(s, s->atapi_dma ? "dma" : "pio", + lba, nb_sectors); if (s->atapi_dma) { ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); } else { @@ -1330,16 +1307,18 @@ void ide_atapi_cmd(IDEState *s) uint8_t *buf = s->io_buffer; const struct AtapiCmd *cmd = &atapi_cmd_table[s->io_buffer[0]]; -#ifdef DEBUG_IDE_ATAPI - { + trace_ide_atapi_cmd(s, s->io_buffer[0]); + + if (trace_event_get_state_backends(TRACE_IDE_ATAPI_CMD_PACKET)) { + /* Each pretty-printed byte needs two bytes and a space; */ + char *ppacket = g_malloc(ATAPI_PACKET_SIZE * 3 + 1); int i; - printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); - for(i = 0; i < ATAPI_PACKET_SIZE; i++) { - printf(" %02x", buf[i]); + for (i = 0; i < ATAPI_PACKET_SIZE; i++) { + sprintf(ppacket + (i * 3), "%02x ", buf[i]); } - printf("\n"); + trace_ide_atapi_cmd_packet(s, s->lcyl | (s->hcyl << 8), ppacket); + g_free(ppacket); } -#endif /* * If there's a UNIT_ATTENTION condition pending, only command flagged with diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 9ebb8d4fb2..86b2a8f504 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -32,6 +32,7 @@ #include "sysemu/dma.h" #include "hw/ide/pci.h" +#include "trace.h" /* CMD646 specific */ #define CFR 0x50 @@ -195,9 +196,8 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr, val = 0xff; break; } -#ifdef DEBUG_IDE - printf("bmdma: readb " TARGET_FMT_plx " : 0x%02x\n", addr, val); -#endif + + trace_bmdma_read_cmd646(addr, val); return val; } @@ -211,9 +211,7 @@ static void bmdma_write(void *opaque, hwaddr addr, return; } -#ifdef DEBUG_IDE - printf("bmdma: writeb " TARGET_FMT_plx " : 0x%" PRIx64 "\n", addr, val); -#endif + trace_bmdma_write_cmd646(addr, val); switch(addr & 3) { case 0: bmdma_cmd_writeb(bm, val); diff --git a/hw/ide/core.c b/hw/ide/core.c index bea39536b0..a19bd9011c 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -34,8 +34,10 @@ #include "hw/block/block.h" #include "sysemu/block-backend.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" #include "hw/ide/internal.h" +#include "trace.h" /* These values were based on a Seagate ST3500418AS but have been modified to make more sense in QEMU */ @@ -57,6 +59,21 @@ static const int smart_attributes[][12] = { { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32}, }; +const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT] = { + [IDE_DMA_READ] = "DMA READ", + [IDE_DMA_WRITE] = "DMA WRITE", + [IDE_DMA_TRIM] = "DMA TRIM", + [IDE_DMA_ATAPI] = "DMA ATAPI" +}; + +static const char *IDE_DMA_CMD_str(enum ide_dma_cmd enval) +{ + if (enval >= IDE_DMA__BEGIN && enval < IDE_DMA__COUNT) { + return IDE_DMA_CMD_lookup[enval]; + } + return "DMA UNKNOWN CMD"; +} + static void ide_dummy_transfer_stop(IDEState *s); static void padstr(char *str, const char *src, int len) @@ -656,10 +673,7 @@ void ide_cancel_dma_sync(IDEState *s) * write requests) pending and we can avoid to drain. */ QLIST_FOREACH(req, &s->buffered_requests, list) { if (!req->orphaned) { -#ifdef DEBUG_IDE - printf("%s: invoking cb %p of buffered request %p with" - " -ECANCELED\n", __func__, req->original_cb, req); -#endif + trace_ide_cancel_dma_sync_buffered(req->original_cb, req); req->original_cb(req->original_opaque, -ECANCELED); } req->orphaned = true; @@ -678,9 +692,7 @@ void ide_cancel_dma_sync(IDEState *s) * aio operation with preadv/pwritev. */ if (s->bus->dma->aiocb) { -#ifdef DEBUG_IDE - printf("%s: draining all remaining requests", __func__); -#endif + trace_ide_cancel_dma_sync_remaining(); blk_drain(s->blk); assert(s->bus->dma->aiocb == NULL); } @@ -741,9 +753,7 @@ static void ide_sector_read(IDEState *s) n = s->req_nb_sectors; } -#if defined(DEBUG_IDE) - printf("sector=%" PRId64 "\n", sector_num); -#endif + trace_ide_sector_read(sector_num, n); if (!ide_sect_range_ok(s, sector_num, n)) { ide_rw_error(s); @@ -866,10 +876,7 @@ static void ide_dma_cb(void *opaque, int ret) goto eot; } -#ifdef DEBUG_AIO - printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n", - sector_num, n, s->dma_cmd); -#endif + trace_ide_dma_cb(s, sector_num, n, IDE_DMA_CMD_str(s->dma_cmd)); if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) && !ide_sect_range_ok(s, sector_num, n)) { @@ -1005,14 +1012,14 @@ static void ide_sector_write(IDEState *s) s->status = READY_STAT | SEEK_STAT | BUSY_STAT; sector_num = ide_get_sector(s); -#if defined(DEBUG_IDE) - printf("sector=%" PRId64 "\n", sector_num); -#endif + n = s->nsector; if (n > s->req_nb_sectors) { n = s->req_nb_sectors; } + trace_ide_sector_write(sector_num, n); + if (!ide_sect_range_ok(s, sector_num, n)) { ide_rw_error(s); block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE); @@ -1191,60 +1198,83 @@ static void ide_clear_hob(IDEBus *bus) bus->ifs[1].select &= ~(1 << 7); } +/* IOport [W]rite [R]egisters */ +enum ATA_IOPORT_WR { + ATA_IOPORT_WR_DATA = 0, + ATA_IOPORT_WR_FEATURES = 1, + ATA_IOPORT_WR_SECTOR_COUNT = 2, + ATA_IOPORT_WR_SECTOR_NUMBER = 3, + ATA_IOPORT_WR_CYLINDER_LOW = 4, + ATA_IOPORT_WR_CYLINDER_HIGH = 5, + ATA_IOPORT_WR_DEVICE_HEAD = 6, + ATA_IOPORT_WR_COMMAND = 7, + ATA_IOPORT_WR_NUM_REGISTERS, +}; + +const char *ATA_IOPORT_WR_lookup[ATA_IOPORT_WR_NUM_REGISTERS] = { + [ATA_IOPORT_WR_DATA] = "Data", + [ATA_IOPORT_WR_FEATURES] = "Features", + [ATA_IOPORT_WR_SECTOR_COUNT] = "Sector Count", + [ATA_IOPORT_WR_SECTOR_NUMBER] = "Sector Number", + [ATA_IOPORT_WR_CYLINDER_LOW] = "Cylinder Low", + [ATA_IOPORT_WR_CYLINDER_HIGH] = "Cylinder High", + [ATA_IOPORT_WR_DEVICE_HEAD] = "Device/Head", + [ATA_IOPORT_WR_COMMAND] = "Command" +}; + void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) { IDEBus *bus = opaque; + IDEState *s = idebus_active_if(bus); + int reg_num = addr & 7; -#ifdef DEBUG_IDE - printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); -#endif - - addr &= 7; + trace_ide_ioport_write(addr, ATA_IOPORT_WR_lookup[reg_num], val, bus, s); /* ignore writes to command block while busy with previous command */ - if (addr != 7 && (idebus_active_if(bus)->status & (BUSY_STAT|DRQ_STAT))) + if (reg_num != 7 && (s->status & (BUSY_STAT|DRQ_STAT))) { return; + } - switch(addr) { + switch (reg_num) { case 0: break; - case 1: - ide_clear_hob(bus); + case ATA_IOPORT_WR_FEATURES: + ide_clear_hob(bus); /* NOTE: data is written to the two drives */ - bus->ifs[0].hob_feature = bus->ifs[0].feature; - bus->ifs[1].hob_feature = bus->ifs[1].feature; + bus->ifs[0].hob_feature = bus->ifs[0].feature; + bus->ifs[1].hob_feature = bus->ifs[1].feature; bus->ifs[0].feature = val; bus->ifs[1].feature = val; break; - case 2: + case ATA_IOPORT_WR_SECTOR_COUNT: ide_clear_hob(bus); bus->ifs[0].hob_nsector = bus->ifs[0].nsector; bus->ifs[1].hob_nsector = bus->ifs[1].nsector; bus->ifs[0].nsector = val; bus->ifs[1].nsector = val; break; - case 3: + case ATA_IOPORT_WR_SECTOR_NUMBER: ide_clear_hob(bus); bus->ifs[0].hob_sector = bus->ifs[0].sector; bus->ifs[1].hob_sector = bus->ifs[1].sector; bus->ifs[0].sector = val; bus->ifs[1].sector = val; break; - case 4: + case ATA_IOPORT_WR_CYLINDER_LOW: ide_clear_hob(bus); bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl; bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl; bus->ifs[0].lcyl = val; bus->ifs[1].lcyl = val; break; - case 5: + case ATA_IOPORT_WR_CYLINDER_HIGH: ide_clear_hob(bus); bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl; bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl; bus->ifs[0].hcyl = val; bus->ifs[1].hcyl = val; break; - case 6: + case ATA_IOPORT_WR_DEVICE_HEAD: /* FIXME: HOB readback uses bit 7 */ bus->ifs[0].select = (val & ~0x10) | 0xa0; bus->ifs[1].select = (val | 0x10) | 0xa0; @@ -1252,7 +1282,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) bus->unit = (val >> 4) & 1; break; default: - case 7: + case ATA_IOPORT_WR_COMMAND: /* command */ ide_exec_cmd(bus, val); break; @@ -1261,9 +1291,7 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) static void ide_reset(IDEState *s) { -#ifdef DEBUG_IDE - printf("ide: reset\n"); -#endif + trace_ide_reset(s); if (s->pio_aiocb) { blk_aio_cancel(s->pio_aiocb); @@ -2021,10 +2049,9 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) IDEState *s; bool complete; -#if defined(DEBUG_IDE) - printf("ide: CMD=%02x\n", val); -#endif s = idebus_active_if(bus); + trace_ide_exec_cmd(bus, s, val); + /* ignore commands to non existent slave */ if (s != bus->ifs && !s->blk) { return; @@ -2062,22 +2089,46 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) } } -uint32_t ide_ioport_read(void *opaque, uint32_t addr1) +/* IOport [R]ead [R]egisters */ +enum ATA_IOPORT_RR { + ATA_IOPORT_RR_DATA = 0, + ATA_IOPORT_RR_ERROR = 1, + ATA_IOPORT_RR_SECTOR_COUNT = 2, + ATA_IOPORT_RR_SECTOR_NUMBER = 3, + ATA_IOPORT_RR_CYLINDER_LOW = 4, + ATA_IOPORT_RR_CYLINDER_HIGH = 5, + ATA_IOPORT_RR_DEVICE_HEAD = 6, + ATA_IOPORT_RR_STATUS = 7, + ATA_IOPORT_RR_NUM_REGISTERS, +}; + +const char *ATA_IOPORT_RR_lookup[ATA_IOPORT_RR_NUM_REGISTERS] = { + [ATA_IOPORT_RR_DATA] = "Data", + [ATA_IOPORT_RR_ERROR] = "Error", + [ATA_IOPORT_RR_SECTOR_COUNT] = "Sector Count", + [ATA_IOPORT_RR_SECTOR_NUMBER] = "Sector Number", + [ATA_IOPORT_RR_CYLINDER_LOW] = "Cylinder Low", + [ATA_IOPORT_RR_CYLINDER_HIGH] = "Cylinder High", + [ATA_IOPORT_RR_DEVICE_HEAD] = "Device/Head", + [ATA_IOPORT_RR_STATUS] = "Status" +}; + +uint32_t ide_ioport_read(void *opaque, uint32_t addr) { IDEBus *bus = opaque; IDEState *s = idebus_active_if(bus); - uint32_t addr; + uint32_t reg_num; int ret, hob; - addr = addr1 & 7; + reg_num = addr & 7; /* FIXME: HOB readback uses bit 7, but it's always set right now */ //hob = s->select & (1 << 7); hob = 0; - switch(addr) { - case 0: + switch (reg_num) { + case ATA_IOPORT_RR_DATA: ret = 0xff; break; - case 1: + case ATA_IOPORT_RR_ERROR: if ((!bus->ifs[0].blk && !bus->ifs[1].blk) || (s != bus->ifs && !s->blk)) { ret = 0; @@ -2087,7 +2138,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = s->hob_feature; } break; - case 2: + case ATA_IOPORT_RR_SECTOR_COUNT: if (!bus->ifs[0].blk && !bus->ifs[1].blk) { ret = 0; } else if (!hob) { @@ -2096,7 +2147,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = s->hob_nsector; } break; - case 3: + case ATA_IOPORT_RR_SECTOR_NUMBER: if (!bus->ifs[0].blk && !bus->ifs[1].blk) { ret = 0; } else if (!hob) { @@ -2105,7 +2156,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = s->hob_sector; } break; - case 4: + case ATA_IOPORT_RR_CYLINDER_LOW: if (!bus->ifs[0].blk && !bus->ifs[1].blk) { ret = 0; } else if (!hob) { @@ -2114,7 +2165,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = s->hob_lcyl; } break; - case 5: + case ATA_IOPORT_RR_CYLINDER_HIGH: if (!bus->ifs[0].blk && !bus->ifs[1].blk) { ret = 0; } else if (!hob) { @@ -2123,7 +2174,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) ret = s->hob_hcyl; } break; - case 6: + case ATA_IOPORT_RR_DEVICE_HEAD: if (!bus->ifs[0].blk && !bus->ifs[1].blk) { ret = 0; } else { @@ -2131,7 +2182,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) } break; default: - case 7: + case ATA_IOPORT_RR_STATUS: if ((!bus->ifs[0].blk && !bus->ifs[1].blk) || (s != bus->ifs && !s->blk)) { ret = 0; @@ -2141,9 +2192,8 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr1) qemu_irq_lower(bus->irq); break; } -#ifdef DEBUG_IDE - printf("ide: read addr=0x%x val=%02x\n", addr1, ret); -#endif + + trace_ide_ioport_read(addr, ATA_IOPORT_RR_lookup[reg_num], ret, bus, s); return ret; } @@ -2159,9 +2209,8 @@ uint32_t ide_status_read(void *opaque, uint32_t addr) } else { ret = s->status; } -#ifdef DEBUG_IDE - printf("ide: read status addr=0x%x val=%02x\n", addr, ret); -#endif + + trace_ide_status_read(addr, ret, bus, s); return ret; } @@ -2171,9 +2220,8 @@ void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) IDEState *s; int i; -#ifdef DEBUG_IDE - printf("ide: write control addr=0x%x val=%02x\n", addr, val); -#endif + trace_ide_cmd_write(addr, val, bus); + /* common for both drives */ if (!(bus->cmd & IDE_CMD_RESET) && (val & IDE_CMD_RESET)) { @@ -2224,6 +2272,8 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) IDEState *s = idebus_active_if(bus); uint8_t *p; + trace_ide_data_writew(addr, val, bus, s); + /* PIO data access allowed only when DRQ bit is set. The result of a write * during PIO out is indeterminate, just ignore it. */ if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) { @@ -2269,6 +2319,8 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr) s->status &= ~DRQ_STAT; s->end_transfer_func(s); } + + trace_ide_data_readw(addr, ret, bus, s); return ret; } @@ -2278,6 +2330,8 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) IDEState *s = idebus_active_if(bus); uint8_t *p; + trace_ide_data_writel(addr, val, bus, s); + /* PIO data access allowed only when DRQ bit is set. The result of a write * during PIO out is indeterminate, just ignore it. */ if (!(s->status & DRQ_STAT) || ide_is_pio_out(s)) { @@ -2308,7 +2362,8 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr) /* PIO data access allowed only when DRQ bit is set. The result of a read * during PIO in is indeterminate, return 0 and don't move forward. */ if (!(s->status & DRQ_STAT) || !ide_is_pio_out(s)) { - return 0; + ret = 0; + goto out; } p = s->data_ptr; @@ -2323,6 +2378,9 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr) s->status &= ~DRQ_STAT; s->end_transfer_func(s); } + +out: + trace_ide_data_readl(addr, ret, bus, s); return ret; } @@ -2346,9 +2404,7 @@ void ide_bus_reset(IDEBus *bus) /* pending async DMA */ if (bus->dma->aiocb) { -#ifdef DEBUG_AIO - printf("aio_cancel\n"); -#endif + trace_ide_bus_reset_aio(); blk_aio_cancel(bus->dma->aiocb); bus->dma->aiocb = NULL; } @@ -2406,7 +2462,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, const char *version, const char *serial, const char *model, uint64_t wwn, uint32_t cylinders, uint32_t heads, uint32_t secs, - int chs_trans) + int chs_trans, Error **errp) { uint64_t nb_sectors; @@ -2431,11 +2487,11 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, blk_set_guest_block_size(blk, 2048); } else { if (!blk_is_inserted(s->blk)) { - error_report("Device needs media, but drive is empty"); + error_setg(errp, "Device needs media, but drive is empty"); return -1; } if (blk_is_read_only(blk)) { - error_report("Can't use a read-only drive"); + error_setg(errp, "Can't use a read-only drive"); return -1; } blk_set_dev_ops(blk, &ide_hd_block_ops, s); diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index e3fd30e457..17917c0b30 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -575,12 +575,15 @@ PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo) static void dscm1xxxx_class_init(ObjectClass *oc, void *data) { PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); pcc->cis = dscm1xxxx_cis; pcc->cis_len = sizeof(dscm1xxxx_cis); pcc->attach = dscm1xxxx_attach; pcc->detach = dscm1xxxx_detach; + /* Reason: Needs to be wired-up in code, see dscm1xxxx_init() */ + dc->user_creatable = false; } static const TypeInfo dscm1xxxx_type_info = { diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 3cfb510afe..f2dcc0ed77 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -31,6 +31,7 @@ #include "sysemu/dma.h" #include "qemu/error-report.h" #include "hw/ide/pci.h" +#include "trace.h" #define BMDMA_PAGE_SIZE 4096 @@ -196,9 +197,7 @@ static void bmdma_reset(IDEDMA *dma) { BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); -#ifdef DEBUG_IDE - printf("ide: dma_reset\n"); -#endif + trace_bmdma_reset(); bmdma_cancel(bm); bm->cmd = 0; bm->status = 0; @@ -227,9 +226,7 @@ static void bmdma_irq(void *opaque, int n, int level) void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) { -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif + trace_bmdma_cmd_writeb(val); /* Ignore writes to SSBM if it keeps the old value */ if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) { @@ -258,9 +255,7 @@ static uint64_t bmdma_addr_read(void *opaque, hwaddr addr, uint64_t data; data = (bm->addr >> (addr * 8)) & mask; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, (unsigned)data); -#endif + trace_bmdma_addr_read(data); return data; } @@ -271,9 +266,7 @@ static void bmdma_addr_write(void *opaque, hwaddr addr, int shift = addr * 8; uint32_t mask = (1ULL << (width * 8)) - 1; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, (unsigned)data); -#endif + trace_bmdma_addr_write(data); bm->addr &= ~(mask << shift); bm->addr |= ((data & mask) << shift) & ~3; } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 7e2d76705d..dfb21f65fa 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -33,6 +33,7 @@ #include "sysemu/dma.h" #include "hw/ide/pci.h" +#include "trace.h" static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) { @@ -54,9 +55,8 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) val = 0xff; break; } -#ifdef DEBUG_IDE - printf("bmdma: readb 0x%02x : 0x%02x\n", (uint8_t)addr, val); -#endif + + trace_bmdma_read(addr, val); return val; } @@ -69,9 +69,8 @@ static void bmdma_write(void *opaque, hwaddr addr, return; } -#ifdef DEBUG_IDE - printf("bmdma: writeb 0x%02x : 0x%02x\n", (uint8_t)addr, (uint8_t)val); -#endif + trace_bmdma_write(addr, val); + switch(addr & 3) { case 0: bmdma_cmd_writeb(bm, val); diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index cc2f5bd280..d60ac25be0 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -80,7 +80,7 @@ static char *idebus_get_fw_dev_path(DeviceState *dev) return g_strdup(path); } -static int ide_qdev_init(DeviceState *qdev) +static void ide_qdev_realize(DeviceState *qdev, Error **errp) { IDEDevice *dev = IDE_DEVICE(qdev); IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev); @@ -91,34 +91,31 @@ static int ide_qdev_init(DeviceState *qdev) } if (dev->unit >= bus->max_units) { - error_report("Can't create IDE unit %d, bus supports only %d units", + error_setg(errp, "Can't create IDE unit %d, bus supports only %d units", dev->unit, bus->max_units); - goto err; + return; } switch (dev->unit) { case 0: if (bus->master) { - error_report("IDE unit %d is in use", dev->unit); - goto err; + error_setg(errp, "IDE unit %d is in use", dev->unit); + return; } bus->master = dev; break; case 1: if (bus->slave) { - error_report("IDE unit %d is in use", dev->unit); - goto err; + error_setg(errp, "IDE unit %d is in use", dev->unit); + return; } bus->slave = dev; break; default: - error_report("Invalid IDE unit %d", dev->unit); - goto err; + error_setg(errp, "Invalid IDE unit %d", dev->unit); + return; } - return dc->init(dev); - -err: - return -1; + dc->realize(dev, errp); } IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) @@ -159,7 +156,7 @@ typedef struct IDEDrive { IDEDevice dev; } IDEDrive; -static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) +static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp) { IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus); IDEState *s = bus->ifs + dev->unit; @@ -168,8 +165,8 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) if (!dev->conf.blk) { if (kind != IDE_CD) { - error_report("No drive specified"); - return -1; + error_setg(errp, "No drive specified"); + return; } else { /* Anonymous BlockBackend for an empty drive */ dev->conf.blk = blk_new(0, BLK_PERM_ALL); @@ -182,36 +179,36 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) dev->conf.discard_granularity = 512; } else if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) { - error_report("discard_granularity must be 512 for ide"); - return -1; + error_setg(errp, "discard_granularity must be 512 for ide"); + return; } blkconf_blocksizes(&dev->conf); if (dev->conf.logical_block_size != 512) { - error_report("logical_block_size must be 512 for IDE"); - return -1; + error_setg(errp, "logical_block_size must be 512 for IDE"); + return; } blkconf_serial(&dev->conf, &dev->serial); if (kind != IDE_CD) { blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, &err); if (err) { - error_report_err(err); - return -1; + error_propagate(errp, err); + return; } } blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD, &err); if (err) { - error_report_err(err); - return -1; + error_propagate(errp, err); + return; } if (ide_init_drive(s, dev->conf.blk, kind, dev->version, dev->serial, dev->model, dev->wwn, dev->conf.cyls, dev->conf.heads, dev->conf.secs, - dev->chs_trans) < 0) { - return -1; + dev->chs_trans, errp) < 0) { + return; } if (!dev->version) { @@ -223,8 +220,6 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) add_boot_device_path(dev->conf.bootindex, &dev->qdev, dev->unit ? "/disk@1" : "/disk@0"); - - return 0; } static void ide_dev_get_bootindex(Object *obj, Visitor *v, const char *name, @@ -270,17 +265,17 @@ static void ide_dev_instance_init(Object *obj) object_property_set_int(obj, -1, "bootindex", NULL); } -static int ide_hd_initfn(IDEDevice *dev) +static void ide_hd_realize(IDEDevice *dev, Error **errp) { - return ide_dev_initfn(dev, IDE_HD); + ide_dev_initfn(dev, IDE_HD, errp); } -static int ide_cd_initfn(IDEDevice *dev) +static void ide_cd_realize(IDEDevice *dev, Error **errp) { - return ide_dev_initfn(dev, IDE_CD); + ide_dev_initfn(dev, IDE_CD, errp); } -static int ide_drive_initfn(IDEDevice *dev) +static void ide_drive_realize(IDEDevice *dev, Error **errp) { DriveInfo *dinfo = NULL; @@ -288,7 +283,7 @@ static int ide_drive_initfn(IDEDevice *dev) dinfo = blk_legacy_dinfo(dev->conf.blk); } - return ide_dev_initfn(dev, dinfo && dinfo->media_cd ? IDE_CD : IDE_HD); + ide_dev_initfn(dev, dinfo && dinfo->media_cd ? IDE_CD : IDE_HD, errp); } #define DEFINE_IDE_DEV_PROPERTIES() \ @@ -311,10 +306,11 @@ static void ide_hd_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); - k->init = ide_hd_initfn; + + k->realize = ide_hd_realize; dc->fw_name = "drive"; - dc->desc = "virtual IDE disk"; - dc->props = ide_hd_properties; + dc->desc = "virtual IDE disk"; + dc->props = ide_hd_properties; } static const TypeInfo ide_hd_info = { @@ -333,10 +329,11 @@ static void ide_cd_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); - k->init = ide_cd_initfn; + + k->realize = ide_cd_realize; dc->fw_name = "drive"; - dc->desc = "virtual IDE CD-ROM"; - dc->props = ide_cd_properties; + dc->desc = "virtual IDE CD-ROM"; + dc->props = ide_cd_properties; } static const TypeInfo ide_cd_info = { @@ -355,10 +352,11 @@ static void ide_drive_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); - k->init = ide_drive_initfn; + + k->realize = ide_drive_realize; dc->fw_name = "drive"; - dc->desc = "virtual IDE disk or CD-ROM (legacy)"; - dc->props = ide_drive_properties; + dc->desc = "virtual IDE disk or CD-ROM (legacy)"; + dc->props = ide_drive_properties; } static const TypeInfo ide_drive_info = { @@ -371,7 +369,7 @@ static const TypeInfo ide_drive_info = { static void ide_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - k->init = ide_qdev_init; + k->realize = ide_qdev_realize; set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_IDE_BUS; k->props = ide_props; diff --git a/hw/ide/trace-events b/hw/ide/trace-events new file mode 100644 index 0000000000..601bd97d81 --- /dev/null +++ b/hw/ide/trace-events @@ -0,0 +1,111 @@ +# See docs/devel/tracing.txt for syntax documentation. + +# hw/ide/core.c +# portio +ide_ioport_read(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p" +ide_ioport_write(uint32_t addr, const char *reg, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (%s); val 0x%02"PRIx32"; bus %p IDEState %p" +ide_status_read(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Alt Status); val 0x%02"PRIx32"; bus %p; IDEState %p" +ide_cmd_write(uint32_t addr, uint32_t val, void *bus) "IDE PIO wr @ 0x%"PRIx32" (Device Control); val 0x%02"PRIx32"; bus %p" +# Warning: verbose +ide_data_readw(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p" +ide_data_writew(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (Data: Word); val 0x%04"PRIx32"; bus %p; IDEState %p" +ide_data_readl(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO rd @ 0x%"PRIx32" (Data: Long); val 0x%08"PRIx32"; bus %p; IDEState %p" +ide_data_writel(uint32_t addr, uint32_t val, void *bus, void *s) "IDE PIO wr @ 0x%"PRIx32" (Data: Long); val 0x%08"PRIx32"; bus %p; IDEState %p" +# misc +ide_exec_cmd(void *bus, void *state, uint32_t cmd) "IDE exec cmd: bus %p; state %p; cmd 0x%02x" +ide_cancel_dma_sync_buffered(void *fn, void *req) "invoking cb %p of buffered request %p with -ECANCELED" +ide_cancel_dma_sync_remaining(void) "draining all remaining requests" +ide_sector_read(int64_t sector_num, int nsectors) "sector=%"PRId64" nsectors=%d" +ide_sector_write(int64_t sector_num, int nsectors) "sector=%"PRId64" nsectors=%d" +ide_reset(void *s) "IDEstate %p" +ide_bus_reset_aio(void) "aio_cancel" +ide_dma_cb(void *s, int64_t sector_num, int n, const char *dma) "IDEState %p; sector_num=%"PRId64" n=%d cmd=%s" + +# BMDMA HBAs: + +# hw/ide/cmd646.c +bmdma_read_cmd646(uint64_t addr, uint32_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x" +bmdma_write_cmd646(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64 + +# hw/ide/pci.c +bmdma_reset(void) "" +bmdma_cmd_writeb(uint32_t val) "val: 0x%08x" +bmdma_addr_read(uint64_t data) "data: 0x%016"PRIx64 +bmdma_addr_write(uint64_t data) "data: 0x%016"PRIx64 + +# hw/ide/piix.c +bmdma_read(uint64_t addr, uint8_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x" +bmdma_write(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64 + +# hw/ide/via.c +bmdma_read_via(uint64_t addr, uint32_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x" +bmdma_write_via(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64 + +# hw/ide/atapi.c +cd_read_sector_sync(int lba) "lba=%d" +cd_read_sector_cb(int lba, int ret) "lba=%d ret=%d" +cd_read_sector(int lba) "lba=%d" +ide_atapi_cmd_error(void *s, int sense_key, int asc) "IDEState: %p; sense=0x%x asc=0x%x" +ide_atapi_cmd_reply_end(void *s, int tx_size, int elem_tx_size, int32_t index) "IDEState %p; reply: tx_size=%d elem_tx_size=%d index=%"PRId32 +ide_atapi_cmd_reply_end_eot(void *s, int status) "IDEState: %p; end of transfer, status=0x%x" +ide_atapi_cmd_reply_end_bcl(void *s, int bcl) "IDEState: %p; byte_count_limit=%d" +ide_atapi_cmd_reply_end_new(void *s, int status) "IDEState: %p; new transfer started, status=0x%x" +ide_atapi_cmd_check_status(void *s) "IDEState: %p" +ide_atapi_cmd_read(void *s, const char *method, int lba, int nb_sectors) "IDEState: %p; read %s: LBA=%d nb_sectors=%d" +ide_atapi_cmd(void *s, uint8_t cmd) "IDEState: %p; cmd: 0x%02x" +ide_atapi_cmd_read_dma_cb_aio(void *s, int lba, int n) "IDEState: %p; aio read: lba=%d n=%d" +# Warning: Verbose +ide_atapi_cmd_packet(void *s, uint16_t limit, const char *packet) "IDEState: %p; limit=0x%x packet: %s" + +# hw/ide/ahci.c +ahci_port_read(void *s, int port, int offset, uint32_t ret) "ahci(%p)[%d]: port read @ 0x%x: 0x%08x" +ahci_irq_raise(void *s) "ahci(%p): raise irq" +ahci_irq_lower(void *s) "ahci(%p): lower irq" +ahci_check_irq(void *s, uint32_t old, uint32_t new) "ahci(%p): check irq 0x%08x --> 0x%08x" +ahci_trigger_irq(void *s, int port, const char *name, uint32_t val, uint32_t old, uint32_t new, uint32_t effective) "ahci(%p)[%d]: trigger irq +%s (0x%08x); irqstat: 0x%08x --> 0x%08x; effective: 0x%08x" +ahci_port_write(void *s, int port, int offset, uint32_t val) "ahci(%p)[%d]: port write @ 0x%x: 0x%08x" +ahci_mem_read_32(void *s, uint64_t addr, uint32_t val) "ahci(%p): mem read @ 0x%"PRIx64": 0x%08x" +ahci_mem_read(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): read%u @ 0x%"PRIx64": 0x%016"PRIx64 +ahci_mem_write(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u @ 0x%"PRIx64": 0x%016"PRIx64 +ahci_mem_write_unknown(void *s, unsigned size, uint64_t addr, uint64_t val) "ahci(%p): write%u to unknown register 0x%"PRIx64": 0x%016"PRIx64 +ahci_set_signature(void *s, int port, uint8_t nsector, uint8_t sector, uint8_t lcyl, uint8_t hcyl, uint32_t sig) "ahci(%p)[%d]: set signature sector:0x%02x nsector:0x%02x lcyl:0x%02x hcyl:0x%02x (cumulatively: 0x%08x)" +ahci_reset_port(void *s, int port) "ahci(%p)[%d]: reset port" +ahci_unmap_fis_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL FIS address" +ahci_unmap_clb_address_null(void *s, int port) "ahci(%p)[%d]: Attempt to unmap NULL CLB address" +ahci_populate_sglist(void *s, int port) "ahci(%p)[%d]" +ahci_populate_sglist_no_prdtl(void *s, int port, uint16_t opts) "ahci(%p)[%d]: no sg list given by guest: 0x%04x" +ahci_populate_sglist_no_map(void *s, int port) "ahci(%p)[%d]: DMA mapping failed" +ahci_populate_sglist_short_map(void *s, int port) "ahci(%p)[%d]: mapped less than expected" +ahci_populate_sglist_bad_offset(void *s, int port, int off_idx, int64_t off_pos) "ahci(%p)[%d]: Incorrect offset! off_idx: %d, off_pos: %"PRId64 +ncq_finish(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: NCQ transfer finished" +execute_ncq_command_read(void *s, int port, uint8_t tag, int count, int64_t lba) "ahci(%p)[%d][tag:%d]: NCQ reading %d sectors from LBA %"PRId64 +execute_ncq_command_write(void *s, int port, uint8_t tag, int count, int64_t lba) "ahci(%p)[%d][tag:%d]: NCQ writing %d sectors to LBA %"PRId64 +execute_ncq_command_unsup(void *s, int port, uint8_t tag, uint8_t cmd) "ahci(%p)[%d][tag:%d]: error: unsupported NCQ command (0x%02x) received" +process_ncq_command_mismatch(void *s, int port, uint8_t tag, uint8_t slot) "ahci(%p)[%d][tag:%d]: Warning: NCQ slot (%d) did not match the given tag" +process_ncq_command_aux(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Attempt to use NCQ auxiliary fields" +process_ncq_command_prioicc(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Unsupported attempt to use PRIO/ICC fields" +process_ncq_command_fua(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Unsupported attempt to use Force Unit Access" +process_ncq_command_rarc(void *s, int port, uint8_t tag) "ahci(%p)[%d][tag:%d]: Warn: Unsupported attempt to use Rebuild Assist" +process_ncq_command_large(void *s, int port, uint8_t tag, size_t prdtl, size_t size) "ahci(%p)[%d][tag:%d]: Warn: PRDTL (0x%zx) does not match requested size (0x%zx)" +process_ncq_command(void *s, int port, uint8_t tag, uint8_t cmd, uint64_t lba, uint64_t end) "ahci(%p)[%d][tag:%d]: NCQ op 0x%02x on sectors [%"PRId64",%"PRId64"]" +handle_reg_h2d_fis_pmp(void *s, int port, char b0, char b1, char b2) "ahci(%p)[%d]: Port Multiplier not supported, FIS: 0x%02x-%02x-%02x" +handle_reg_h2d_fis_res(void *s, int port, char b0, char b1, char b2) "ahci(%p)[%d]: Reserved flags set in H2D Register FIS, FIS: 0x%02x-%02x-%02x" +handle_cmd_busy(void *s, int port) "ahci(%p)[%d]: engine busy" +handle_cmd_nolist(void *s, int port) "ahci(%p)[%d]: handle_cmd called without s->dev[port].lst" +handle_cmd_badport(void *s, int port) "ahci(%p)[%d]: guest accessed unused port" +handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cmd FIS" +handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80" +handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x" +ahci_start_transfer(void *s, int port, const char *rw, uint32_t size, const char *tgt, const char *sgl) "ahci(%p)[%d]: %sing %d bytes on %s w/%s sglist" +ahci_start_dma(void *s, int port) "ahci(%p)[%d]: start dma" +ahci_dma_prepare_buf(void *s, int port, int32_t io_buffer_size, int32_t limit) "ahci(%p)[%d]: prepare buf limit=%"PRId32" prepared=%"PRId32 +ahci_dma_prepare_buf_fail(void *s, int port) "ahci(%p)[%d]: sglist population failed" +ahci_dma_rw_buf(void *s, int port, int l) "ahci(%p)[%d] len=0x%x" +ahci_cmd_done(void *s, int port) "ahci(%p)[%d]: cmd done" +ahci_reset(void *s) "ahci(%p): HBA reset" +allwinner_ahci_mem_read(void *s, void *a, uint64_t addr, uint64_t val, unsigned size) "ahci(%p): read a=%p addr=0x%"HWADDR_PRIx" val=0x%"PRIx64", size=%d" +allwinner_ahci_mem_write(void *s, void *a, uint64_t addr, uint64_t val, unsigned size) "ahci(%p): write a=%p addr=0x%"HWADDR_PRIx" val=0x%"PRIx64", size=%d" + +# Warning: Verbose +handle_reg_h2d_fis_dump(void *s, int port, const char *fis) "ahci(%p)[%d]: %s" +handle_cmd_fis_dump(void *s, int port, const char *fis) "ahci(%p)[%d]: %s" diff --git a/hw/ide/via.c b/hw/ide/via.c index 5b32ecb386..35c3059325 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -33,6 +33,7 @@ #include "sysemu/dma.h" #include "hw/ide/pci.h" +#include "trace.h" static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) @@ -55,9 +56,8 @@ static uint64_t bmdma_read(void *opaque, hwaddr addr, val = 0xff; break; } -#ifdef DEBUG_IDE - printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val); -#endif + + trace_bmdma_read_via(addr, val); return val; } @@ -70,9 +70,7 @@ static void bmdma_write(void *opaque, hwaddr addr, return; } -#ifdef DEBUG_IDE - printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); -#endif + trace_bmdma_write_via(addr, val); switch (addr & 3) { case 0: bmdma_cmd_writeb(bm, val); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index c82e0af340..e87cd3230b 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -216,8 +216,8 @@ static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size) } if (ram_size) { - fprintf(stderr, "Warning: SPD cannot represent final %dMB" - " of SDRAM\n", (int)ram_size); + warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB" + " of SDRAM", ram_size); } /* fill in SPD memory information */ diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 60da6070bc..7efee94431 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -249,9 +249,8 @@ void mips_r4k_init(MachineState *machine) fprintf(stderr, "qemu: Error registering flash memory.\n"); } } else if (!qtest_enabled()) { - /* not fatal */ - fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", - bios_name); + /* not fatal */ + warn_report("could not load MIPS bios '%s'", bios_name); } g_free(filename); diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 7896812304..7be8b5f13c 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -331,7 +331,7 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp) s->iobase + APPLESMC_ERR_PORT); if (!s->osk || (strlen(s->osk) != 64)) { - fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n"); + warn_report("Using AppleSMC with invalid key"); s->osk = default_osk; } diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 47a015f072..b3ef3ec1e3 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -653,7 +653,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp) } while (n < sizeof(msg)); *pfd = qemu_chr_fe_get_msgfd(&s->server_chr); - return msg; + return le64_to_cpu(msg); } static void ivshmem_recv_setup(IVShmemState *s, Error **errp) diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 7ee19d3abc..dc704b57d6 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -1,4 +1,3 @@ -obj-y += s390-virtio.o obj-y += s390-virtio-hcall.o obj-y += sclp.o obj-y += event-facility.o diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 901dc6a0f3..75d4f301fb 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -793,7 +793,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, CCW1 ccw; if (!ccw_addr) { - return -EIO; + return -EINVAL; /* channel-program check */ } /* Check doubleword aligned and 31 or 24 (fmt 0) bit addressable. */ if (ccw_addr & (sch->ccw_fmt_1 ? 0x80000007 : 0xff000007)) { @@ -980,22 +980,6 @@ static void sch_handle_start_func_virtual(SubchDev *sch) SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; s->cpa = sch->channel_prog + 8; break; - case -EFAULT: - /* memory problem, generate channel data check */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->cstat = SCSW_CSTAT_DATA_CHECK; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | - SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - s->cpa = sch->channel_prog + 8; - break; - case -EBUSY: - /* subchannel busy, generate deferred cc 1 */ - s->flags &= ~SCSW_FLAGS_MASK_CC; - s->flags |= (1 << 8); - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - break; case -EINPROGRESS: /* channel program has been suspended */ s->ctrl &= ~SCSW_ACTL_START_PEND; @@ -1276,16 +1260,16 @@ int css_do_xsch(SubchDev *sch) goto out; } + if (s->ctrl & SCSW_CTRL_MASK_STCTL) { + ret = -EINPROGRESS; + goto out; + } + if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) || ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || (!(s->ctrl & (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) || (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) { - ret = -EINPROGRESS; - goto out; - } - - if (s->ctrl & SCSW_CTRL_MASK_STCTL) { ret = -EBUSY; goto out; } diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 0a31a4ae88..3b9965fde0 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -199,8 +199,8 @@ static S390PCIBusDevice *s390_pci_find_dev_by_uid(S390pciState *s, uint16_t uid) return NULL; } -static S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, - const char *target) +S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target) { S390PCIBusDevice *pbdev; @@ -397,6 +397,17 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, return ret; } +static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu, + IOMMUNotifier *notifier) +{ + /* It's impossible to plug a pci device on s390x that already has iommu + * mappings which need to be replayed, that is due to the "one iommu per + * zpci device" construct. But when we support migration of vfio-pci + * devices in future, we need to revisit this. + */ + return; +} + static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, int devfn) { @@ -465,19 +476,13 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { S390PCIBusDevice *pbdev = opaque; - uint32_t idx = data >> ZPCI_MSI_VEC_BITS; uint32_t vec = data & ZPCI_MSI_VEC_MASK; uint64_t ind_bit; uint32_t sum_bit; - uint32_t e = 0; - - DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec); - if (!pbdev) { - e |= (vec << ERR_EVENT_MVN_OFFSET); - s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e); - return; - } + assert(pbdev); + DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, + pbdev->idx, vec); if (pbdev->state != ZPCI_FS_ENABLED) { return; @@ -1051,6 +1056,7 @@ static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data) IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); imrc->translate = s390_translate_iommu; + imrc->replay = s390_pci_iommu_replay; } static const TypeInfo s390_iommu_memory_region_info = { diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index bd636abc28..560bd82a0f 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -322,6 +322,8 @@ void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx); S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh); S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid); +S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target); S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, S390PCIBusDevice *pbdev); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index eba9ffb5f2..8e088f3dc9 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -413,29 +413,6 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) return 0; } -static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset, - uint64_t *data, uint8_t len) -{ - uint32_t val; - uint8_t *msg_data; - - if (offset % PCI_MSIX_ENTRY_SIZE != 8) { - return; - } - - if (len != 4) { - DPRINTF("access msix table msg data but len is %d\n", len); - return; - } - - msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL; - val = pci_get_long(msg_data) | - ((pbdev->fh & FH_MASK_INDEX) << ZPCI_MSI_VEC_BITS); - pci_set_long(msg_data, val); - DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data); -} - static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) { if (pbdev->msix.available && pbdev->msix.table_bar == pcias && @@ -508,7 +485,6 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) if (trap_msix(pbdev, offset, pcias)) { offset = offset - pbdev->msix.table_offset; mr = &pbdev->pdev->msix_table_mmio; - update_msix_table_msg_data(pbdev, offset, &data, len); } else { mr = pbdev->pdev->io_regions[pcias].memory; } diff --git a/hw/s390x/s390-pci-stub.c b/hw/s390x/s390-pci-stub.c index 7a642d376c..ad4c5a7719 100644 --- a/hw/s390x/s390-pci-stub.c +++ b/hw/s390x/s390-pci-stub.c @@ -70,7 +70,8 @@ S390pciState *s390_get_phb(void) return NULL; } -S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx) +S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target) { return NULL; } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index dd504dd5ae..fafbc6d4fe 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -2,6 +2,7 @@ * virtio ccw machine * * Copyright 2012 IBM Corp. + * Copyright (c) 2009 Alexander Graf <agraf@suse.de> * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> * * This work is licensed under the terms of the GNU GPL, version 2 or (at @@ -15,13 +16,14 @@ #include "cpu.h" #include "hw/boards.h" #include "exec/address-spaces.h" -#include "s390-virtio.h" +#include "hw/s390x/s390-virtio-hcall.h" #include "hw/s390x/sclp.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/ioinst.h" #include "hw/s390x/css.h" #include "virtio-ccw.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "s390-pci-bus.h" #include "hw/s390x/storage-keys.h" #include "hw/s390x/storage-attributes.h" @@ -31,6 +33,67 @@ #include "hw/s390x/css-bridge.h" #include "migration/register.h" #include "cpu_models.h" +#include "qapi/qmp/qerror.h" +#include "hw/nmi.h" + +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) +{ + static MachineState *ms; + + if (!ms) { + ms = MACHINE(qdev_get_machine()); + g_assert(ms->possible_cpus); + } + + /* CPU address corresponds to the core_id and the index */ + if (cpu_addr >= ms->possible_cpus->len) { + return NULL; + } + return S390_CPU(ms->possible_cpus->cpus[cpu_addr].cpu); +} + +static void s390_init_cpus(MachineState *machine) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + const char *typename; + gchar **model_pieces; + ObjectClass *oc; + CPUClass *cc; + int i; + + if (machine->cpu_model == NULL) { + machine->cpu_model = s390_default_cpu_model_name(); + } + if (tcg_enabled() && max_cpus > 1) { + error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " + "supported by TCG (1) on s390x", max_cpus); + exit(1); + } + + /* initialize possible_cpus */ + mc->possible_cpu_arch_ids(machine); + + model_pieces = g_strsplit(machine->cpu_model, ",", 2); + if (!model_pieces[0]) { + error_report("Invalid/empty CPU model name"); + exit(1); + } + + oc = cpu_class_by_name(TYPE_S390_CPU, model_pieces[0]); + if (!oc) { + error_report("Unable to find CPU definition: %s", model_pieces[0]); + exit(1); + } + typename = object_class_get_name(oc); + cc = CPU_CLASS(oc); + /* after parsing, properties will be applied to all *typename* instances */ + cc->parse_features(typename, model_pieces[1], &error_fatal); + g_strfreev(model_pieces); + + for (i = 0; i < smp_cpus; i++) { + s390x_new_cpu(typename, i, &error_fatal); + } +} static const char *const reset_dev_types[] = { TYPE_VIRTUAL_CSS_BRIDGE, @@ -94,7 +157,7 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } -void s390_memory_init(ram_addr_t mem_size) +static void s390_memory_init(ram_addr_t mem_size) { MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -109,11 +172,105 @@ void s390_memory_init(ram_addr_t mem_size) s390_stattrib_init(); } +#define S390_TOD_CLOCK_VALUE_MISSING 0x00 +#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 + +static void gtod_save(QEMUFile *f, void *opaque) +{ + uint64_t tod_low; + uint8_t tod_high; + int r; + + r = s390_get_clock(&tod_high, &tod_low); + if (r) { + warn_report("Unable to get guest clock for migration: %s", + strerror(-r)); + error_printf("Guest clock will not be migrated " + "which could cause the guest to hang."); + qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); + return; + } + + qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); + qemu_put_byte(f, tod_high); + qemu_put_be64(f, tod_low); +} + +static int gtod_load(QEMUFile *f, void *opaque, int version_id) +{ + uint64_t tod_low; + uint8_t tod_high; + int r; + + if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { + warn_report("Guest clock was not migrated. This could " + "cause the guest to hang."); + return 0; + } + + tod_high = qemu_get_byte(f); + tod_low = qemu_get_be64(f); + + r = s390_set_clock(&tod_high, &tod_low); + if (r) { + warn_report("Unable to set guest clock for migration: %s", + strerror(-r)); + error_printf("Guest clock will not be restored " + "which could cause the guest to hang."); + } + + return 0; +} + static SaveVMHandlers savevm_gtod = { .save_state = gtod_save, .load_state = gtod_load, }; +static void s390_init_ipl_dev(const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *firmware, + const char *netboot_fw, bool enforce_bios) +{ + Object *new = object_new(TYPE_S390_IPL); + DeviceState *dev = DEVICE(new); + + if (kernel_filename) { + qdev_prop_set_string(dev, "kernel", kernel_filename); + } + if (initrd_filename) { + qdev_prop_set_string(dev, "initrd", initrd_filename); + } + qdev_prop_set_string(dev, "cmdline", kernel_cmdline); + qdev_prop_set_string(dev, "firmware", firmware); + qdev_prop_set_string(dev, "netboot_fw", netboot_fw); + qdev_prop_set_bit(dev, "enforce_bios", enforce_bios); + object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, + new, NULL); + object_unref(new); + qdev_init_nofail(dev); +} + +static void s390_create_virtio_net(BusState *bus, const char *name) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + DeviceState *dev; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + qemu_check_nic_model(nd, "virtio"); + + dev = qdev_create(bus, name); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + } +} + static void ccw_init(MachineState *machine) { int ret; @@ -167,14 +324,24 @@ static void ccw_init(MachineState *machine) static void s390_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - gchar *name; + MachineState *ms = MACHINE(hotplug_dev); S390CPU *cpu = S390_CPU(dev); - CPUState *cs = CPU(dev); - name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num); - object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name, - errp); - g_free(name); + g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu); + ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev); +} + +static void s390_machine_reset(void) +{ + S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); + + s390_cmma_reset(); + qemu_devices_reset(); + s390_crypto_reset(); + + /* all cpus are stopped - configure and start the ipl cpu only */ + s390_ipl_prepare_cpu(ipl_cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu); } static void s390_machine_device_plug(HotplugHandler *hotplug_dev, @@ -185,6 +352,45 @@ static void s390_machine_device_plug(HotplugHandler *hotplug_dev, } } +static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + error_setg(errp, "CPU hot unplug not supported on this machine"); + return; + } +} + +static CpuInstanceProperties s390_cpu_index_to_props(MachineState *machine, + unsigned cpu_index) +{ + g_assert(machine->possible_cpus && cpu_index < machine->possible_cpus->len); + + return machine->possible_cpus->cpus[cpu_index].props; +} + +static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms) +{ + int i; + + if (ms->possible_cpus) { + g_assert(ms->possible_cpus && ms->possible_cpus->len == max_cpus); + return ms->possible_cpus; + } + + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (i = 0; i < ms->possible_cpus->len; i++) { + ms->possible_cpus->cpus[i].vcpus_count = 1; + ms->possible_cpus->cpus[i].arch_id = i; + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = i; + } + + return ms->possible_cpus; +} + static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, DeviceState *dev) { @@ -197,8 +403,21 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, static void s390_hot_add_cpu(const int64_t id, Error **errp) { MachineState *machine = MACHINE(qdev_get_machine()); + ObjectClass *oc; + + g_assert(machine->possible_cpus->cpus[0].cpu); + oc = OBJECT_CLASS(CPU_GET_CLASS(machine->possible_cpus->cpus[0].cpu)); - s390x_new_cpu(machine->cpu_model, id, errp); + s390x_new_cpu(object_class_get_name(oc), id, errp); +} + +static void s390_nmi(NMIState *n, int cpu_index, Error **errp) +{ + CPUState *cs = qemu_get_cpu(cpu_index); + + if (s390_cpu_restart(S390_CPU(cs))) { + error_setg(errp, QERR_UNSUPPORTED); + } } static void ccw_machine_class_init(ObjectClass *oc, void *data) @@ -223,8 +442,12 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->no_sdcard = 1; mc->use_sclp = 1; mc->max_cpus = 248; + mc->has_hotpluggable_cpus = true; mc->get_hotplug_handler = s390_get_hotplug_handler; + mc->cpu_index_to_instance_props = s390_cpu_index_to_props; + mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; hc->plug = s390_machine_device_plug; + hc->unplug_request = s390_machine_device_unplug_request; nc->nmi_monitor_handler = s390_nmi; } diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c index 23d67d6170..ec7cf8beb3 100644 --- a/hw/s390x/s390-virtio-hcall.c +++ b/hw/s390x/s390-virtio-hcall.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hw/s390x/s390-virtio.h" +#include "hw/s390x/s390-virtio-hcall.h" #define MAX_DIAG_SUBCODES 255 diff --git a/hw/s390x/s390-virtio-hcall.h b/hw/s390x/s390-virtio-hcall.h new file mode 100644 index 0000000000..cbc270eef3 --- /dev/null +++ b/hw/s390x/s390-virtio-hcall.h @@ -0,0 +1,21 @@ +/* + * Support for virtio hypercalls on s390x + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck <cornelia.huck@de.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. + */ + +#ifndef HW_S390_VIRTIO_HCALL_H +#define HW_S390_VIRTIO_HCALL_H + +#include "standard-headers/asm-s390/kvm_virtio.h" +#include "standard-headers/asm-s390/virtio-ccw.h" + +typedef int (*s390_virtio_fn)(const uint64_t *args); +void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); +int s390_virtio_hypercall(CPUS390XState *env); +#endif /* HW_S390_VIRTIO_HCALL_H */ diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c deleted file mode 100644 index da3f49e80e..0000000000 --- a/hw/s390x/s390-virtio.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * QEMU S390 virtio target - * - * Copyright (c) 2009 Alexander Graf <agraf@suse.de> - * Copyright IBM Corp 2012 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * Contributions after 2012-10-29 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - * - * You should have received a copy of the GNU (Lesser) General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "qapi/qmp/qerror.h" -#include "qemu/error-report.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/virtio/virtio.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" - -#include "hw/s390x/sclp.h" -#include "hw/s390x/s390_flic.h" -#include "hw/s390x/s390-virtio.h" -#include "hw/s390x/storage-keys.h" -#include "hw/s390x/ipl.h" -#include "cpu.h" - -#define MAX_BLK_DEVS 10 - -#define S390_TOD_CLOCK_VALUE_MISSING 0x00 -#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 - -static S390CPU **cpu_states; - -S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) -{ - if (cpu_addr >= max_cpus) { - return NULL; - } - - /* Fast lookup via CPU ID */ - return cpu_states[cpu_addr]; -} - -void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *firmware, - const char *netboot_fw, - bool enforce_bios) -{ - Object *new = object_new(TYPE_S390_IPL); - DeviceState *dev = DEVICE(new); - - if (kernel_filename) { - qdev_prop_set_string(dev, "kernel", kernel_filename); - } - if (initrd_filename) { - qdev_prop_set_string(dev, "initrd", initrd_filename); - } - qdev_prop_set_string(dev, "cmdline", kernel_cmdline); - qdev_prop_set_string(dev, "firmware", firmware); - qdev_prop_set_string(dev, "netboot_fw", netboot_fw); - qdev_prop_set_bit(dev, "enforce_bios", enforce_bios); - object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, - new, NULL); - object_unref(new); - qdev_init_nofail(dev); -} - -void s390_init_cpus(MachineState *machine) -{ - int i; - gchar *name; - - if (machine->cpu_model == NULL) { - machine->cpu_model = s390_default_cpu_model_name(); - } - - cpu_states = g_new0(S390CPU *, max_cpus); - - for (i = 0; i < max_cpus; i++) { - name = g_strdup_printf("cpu[%i]", i); - object_property_add_link(OBJECT(machine), name, TYPE_S390_CPU, - (Object **) &cpu_states[i], - object_property_allow_set_link, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - &error_abort); - g_free(name); - } - - for (i = 0; i < smp_cpus; i++) { - s390x_new_cpu(machine->cpu_model, i, &error_fatal); - } -} - - -void s390_create_virtio_net(BusState *bus, const char *name) -{ - int i; - - for (i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - DeviceState *dev; - - if (!nd->model) { - nd->model = g_strdup("virtio"); - } - - qemu_check_nic_model(nd, "virtio"); - - dev = qdev_create(bus, name); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - } -} - -void gtod_save(QEMUFile *f, void *opaque) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - r = s390_get_clock(&tod_high, &tod_low); - if (r) { - fprintf(stderr, "WARNING: Unable to get guest clock for migration. " - "Error code %d. Guest clock will not be migrated " - "which could cause the guest to hang.\n", r); - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); - return; - } - - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); - qemu_put_byte(f, tod_high); - qemu_put_be64(f, tod_low); -} - -int gtod_load(QEMUFile *f, void *opaque, int version_id) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { - fprintf(stderr, "WARNING: Guest clock was not migrated. This could " - "cause the guest to hang.\n"); - return 0; - } - - tod_high = qemu_get_byte(f); - tod_low = qemu_get_be64(f); - - r = s390_set_clock(&tod_high, &tod_low); - if (r) { - fprintf(stderr, "WARNING: Unable to set guest clock value. " - "s390_get_clock returned error %d. This could cause " - "the guest to hang.\n", r); - } - - return 0; -} - -void s390_nmi(NMIState *n, int cpu_index, Error **errp) -{ - CPUState *cs = qemu_get_cpu(cpu_index); - - if (s390_cpu_restart(S390_CPU(cs))) { - error_setg(errp, QERR_UNSUPPORTED); - } -} - -void s390_machine_reset(void) -{ - S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); - - s390_cmma_reset(); - qemu_devices_reset(); - s390_crypto_reset(); - - /* all cpus are stopped - configure and start the ipl cpu only */ - s390_ipl_prepare_cpu(ipl_cpu); - s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu); -} diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h deleted file mode 100644 index ca97fd6814..0000000000 --- a/hw/s390x/s390-virtio.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Virtio interfaces for s390 - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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. - */ - -#ifndef HW_S390_VIRTIO_H -#define HW_S390_VIRTIO_H - -#include "hw/nmi.h" -#include "standard-headers/asm-s390/kvm_virtio.h" -#include "standard-headers/asm-s390/virtio-ccw.h" - -typedef int (*s390_virtio_fn)(const uint64_t *args); -void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); - -void s390_init_cpus(MachineState *machine); -void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *firmware, - const char *netboot_fw, - bool enforce_bios); -void s390_create_virtio_net(BusState *bus, const char *name); -void s390_nmi(NMIState *n, int cpu_index, Error **errp); -void s390_machine_reset(void); -void s390_memory_init(ram_addr_t mem_size); -void gtod_save(QEMUFile *f, void *opaque); -int gtod_load(QEMUFile *f, void *opaque, int version_id); -#endif diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index fd097262c7..30aefbfd15 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -34,16 +34,21 @@ static inline SCLPDevice *get_sclp_device(void) return sclp; } -static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int count) +static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) { + MachineState *ms = MACHINE(qdev_get_machine()); uint8_t features[SCCB_CPU_FEATURE_LEN] = { 0 }; int i; s390_get_feat_block(S390_FEAT_TYPE_SCLP_CPU, features); - for (i = 0; i < count; i++) { - entry[i].address = i; - entry[i].type = 0; - memcpy(entry[i].features, features, sizeof(entry[i].features)); + for (i = 0, *count = 0; i < ms->possible_cpus->len; i++) { + if (!ms->possible_cpus->cpus[i].cpu) { + continue; + } + entry[*count].address = ms->possible_cpus->cpus[i].arch_id; + entry[*count].type = 0; + memcpy(entry[*count].features, features, sizeof(features)); + (*count)++; } } @@ -53,17 +58,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) ReadInfo *read_info = (ReadInfo *) sccb; MachineState *machine = MACHINE(qdev_get_machine()); sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - CPUState *cpu; - int cpu_count = 0; + int cpu_count; int rnsize, rnmax; int slots = MIN(machine->ram_slots, s390_get_memslot_count()); IplParameterBlock *ipib = s390_ipl_get_iplb(); - CPU_FOREACH(cpu) { - cpu_count++; - } - /* CPU information */ + prepare_cpu_entries(sclp, read_info->entries, &cpu_count); read_info->entries_cpu = cpu_to_be16(cpu_count); read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries)); read_info->highest_cpu = cpu_to_be16(max_cpus); @@ -76,8 +77,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, read_info->conf_char_ext); - prepare_cpu_entries(sclp, read_info->entries, cpu_count); - read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | SCLP_HAS_IOA_RECONFIG); @@ -333,13 +332,9 @@ static void unassign_storage(SCLPDevice *sclp, SCCB *sccb) static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) { ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; - CPUState *cpu; - int cpu_count = 0; - - CPU_FOREACH(cpu) { - cpu_count++; - } + int cpu_count; + prepare_cpu_entries(sclp, cpu_info->entries, &cpu_count); cpu_info->nr_configured = cpu_to_be16(cpu_count); cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); cpu_info->nr_standby = cpu_to_be16(0); @@ -348,7 +343,6 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured + cpu_info->nr_configured*sizeof(CPUEntry)); - prepare_cpu_entries(sclp, cpu_info->entries, cpu_count); sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index b1976fdd19..ff1bb1534c 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -487,7 +487,6 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { virtio_bus_get_vdev_config(&dev->bus, vdev->config); - /* XXX config space endianness */ cpu_physical_memory_write(ccw.cda, vdev->config, len); sch->curr_status.scsw.count = ccw.count - len; ret = 0; @@ -510,7 +509,6 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { len = hw_len; - /* XXX config space endianness */ memcpy(vdev->config, config, len); cpu_physical_memory_unmap(config, hw_len, 0, hw_len); virtio_bus_set_vdev_config(&dev->bus, vdev->config); @@ -1007,6 +1005,15 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) NULL); } +static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp) +{ + VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(ccw_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + /* DeviceState to VirtioCcwDevice. Note: used on datapath, * be careful and test performance if you change this. */ @@ -1616,6 +1623,45 @@ static const TypeInfo virtio_ccw_crypto = { .class_init = virtio_ccw_crypto_class_init, }; +static Property virtio_ccw_gpu_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, + VIRTIO_CCW_MAX_REV), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_gpu_instance_init(Object *obj) +{ + VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(obj); + VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); + + ccw_dev->force_revision_1 = true; + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU); +} + +static void virtio_ccw_gpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->realize = virtio_ccw_gpu_realize; + k->exit = virtio_ccw_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_gpu_properties; + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); +} + +static const TypeInfo virtio_ccw_gpu = { + .name = TYPE_VIRTIO_GPU_CCW, + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtIOGPUCcw), + .instance_init = virtio_ccw_gpu_instance_init, + .class_init = virtio_ccw_gpu_class_init, +}; + static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) { VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; @@ -1815,6 +1861,7 @@ static void virtio_ccw_register(void) type_register_static(&vhost_vsock_ccw_info); #endif type_register_static(&virtio_ccw_crypto); + type_register_static(&virtio_ccw_gpu); } type_init(virtio_ccw_register) diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 41d4010378..541fdd2994 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -27,6 +27,7 @@ #ifdef CONFIG_VHOST_VSOCK #include "hw/virtio/vhost-vsock.h" #endif /* CONFIG_VHOST_VSOCK */ +#include "hw/virtio/virtio-gpu.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/css.h" @@ -223,4 +224,13 @@ typedef struct VHostVSockCCWState { #endif /* CONFIG_VHOST_VSOCK */ +#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw" +#define VIRTIO_GPU_CCW(obj) \ + OBJECT_CHECK(VirtIOGPUCcw, (obj), TYPE_VIRTIO_GPU_CCW) + +typedef struct VirtIOGPUCcw { + VirtioCcwDevice parent_obj; + VirtIOGPU vdev; +} VirtIOGPUCcw; + #endif diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index eee831efeb..22c2d91e39 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -593,7 +593,7 @@ const VMStateDescription vmstate_esp = { }; #define TYPE_ESP "esp" -#define ESP(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP) +#define ESP_STATE(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP) typedef struct { /*< private >*/ @@ -644,7 +644,7 @@ void esp_init(hwaddr espaddr, int it_shift, ESPState *esp; dev = qdev_create(NULL, TYPE_ESP); - sysbus = ESP(dev); + sysbus = ESP_STATE(dev); esp = &sysbus->esp; esp->dma_memory_read = dma_memory_read; esp->dma_memory_write = dma_memory_write; @@ -672,7 +672,7 @@ static const struct SCSIBusInfo esp_scsi_info = { static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) { - SysBusESPState *sysbus = ESP(opaque); + SysBusESPState *sysbus = ESP_STATE(opaque); ESPState *s = &sysbus->esp; switch (irq) { @@ -688,7 +688,7 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) static void sysbus_esp_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - SysBusESPState *sysbus = ESP(dev); + SysBusESPState *sysbus = ESP_STATE(dev); ESPState *s = &sysbus->esp; sysbus_init_irq(sbd, &s->irq); @@ -706,7 +706,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp) static void sysbus_esp_hard_reset(DeviceState *dev) { - SysBusESPState *sysbus = ESP(dev); + SysBusESPState *sysbus = ESP_STATE(dev); esp_hard_reset(&sysbus->esp); } diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 734fdaef90..0db68aacee 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -27,7 +27,7 @@ #include "hw/pci/msix.h" #include "qemu/iov.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "trace.h" #include "qapi/error.h" #include "mfi.h" diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c index b7fe2a2a36..3415229b5e 100644 --- a/hw/scsi/mptendian.c +++ b/hw/scsi/mptendian.c @@ -28,7 +28,7 @@ #include "hw/pci/msi.h" #include "qemu/iov.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "trace.h" #include "mptsas.h" diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 765ab53c34..d05fa9f549 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -30,7 +30,7 @@ #include "hw/pci/msi.h" #include "qemu/iov.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "trace.h" #include "qapi/error.h" #include "mptsas.h" @@ -1236,11 +1236,9 @@ static void *mptsas_load_request(QEMUFile *f, SCSIRequest *sreq) n = qemu_get_be32(f); /* TODO: add a way for SCSIBusInfo's load_request to fail, * and fail migration instead of asserting here. - * When we do, we might be able to re-enable NDEBUG below. + * This is just one thing (there are probably more) that must be + * fixed before we can allow NDEBUG compilation. */ -#ifdef NDEBUG -#error building with NDEBUG is not supported -#endif assert(n >= 0); pci_dma_sglist_init(&req->qsg, pci, n); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index e364410a23..977f7bce1f 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -3,7 +3,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "hw/qdev.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" @@ -516,8 +516,10 @@ static size_t scsi_sense_len(SCSIRequest *req) static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) { SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); + int fixed_sense = (req->cmd.buf[1] & 1) == 0; - if (req->lun != 0) { + if (req->lun != 0 && + buf[0] != INQUIRY && buf[0] != REQUEST_SENSE) { scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED)); scsi_req_complete(req, CHECK_CONDITION); return 0; @@ -535,9 +537,28 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) break; case REQUEST_SENSE: scsi_target_alloc_buf(&r->req, scsi_sense_len(req)); - r->len = scsi_device_get_sense(r->req.dev, r->buf, - MIN(req->cmd.xfer, r->buf_len), - (req->cmd.buf[1] & 1) == 0); + if (req->lun != 0) { + const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED); + + if (fixed_sense) { + r->buf[0] = 0x70; + r->buf[2] = sense.key; + r->buf[10] = 10; + r->buf[12] = sense.asc; + r->buf[13] = sense.ascq; + r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN); + } else { + r->buf[0] = 0x72; + r->buf[1] = sense.key; + r->buf[2] = sense.asc; + r->buf[3] = sense.ascq; + r->len = 8; + } + } else { + r->len = scsi_device_get_sense(r->req.dev, r->buf, + MIN(req->cmd.xfer, r->buf_len), + fixed_sense); + } if (r->req.dev->sense_is_ua) { scsi_device_unit_attention_reported(req->dev); r->req.dev->sense_len = 0; @@ -769,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) return 0; } - ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true); + ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true); /* * FIXME: clearing unit attention conditions upon autosense should be done @@ -790,20 +811,14 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed) { - return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed); + return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed); } void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) { trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag, sense.key, sense.asc, sense.ascq); - memset(req->sense, 0, 18); - req->sense[0] = 0x70; - req->sense[2] = sense.key; - req->sense[7] = 10; - req->sense[12] = sense.asc; - req->sense[13] = sense.ascq; - req->sense_len = 18; + req->sense_len = scsi_build_sense(req->sense, sense); } static void scsi_req_enqueue_internal(SCSIRequest *req) @@ -935,36 +950,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf) return xfer * unit; } -uint32_t scsi_data_cdb_xfer(uint8_t *buf) -{ - if ((buf[0] >> 5) == 0 && buf[4] == 0) { - return 256; - } else { - return scsi_cdb_xfer(buf); - } -} - -uint32_t scsi_cdb_xfer(uint8_t *buf) -{ - switch (buf[0] >> 5) { - case 0: - return buf[4]; - break; - case 1: - case 2: - return lduw_be_p(&buf[7]); - break; - case 4: - return ldl_be_p(&buf[10]) & 0xffffffffULL; - break; - case 5: - return ldl_be_p(&buf[6]) & 0xffffffffULL; - break; - default: - return -1; - } -} - static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { cmd->xfer = scsi_cdb_xfer(buf); @@ -1277,53 +1262,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) } } -static uint64_t scsi_cmd_lba(SCSICommand *cmd) -{ - uint8_t *buf = cmd->buf; - uint64_t lba; - - switch (buf[0] >> 5) { - case 0: - lba = ldl_be_p(&buf[0]) & 0x1fffff; - break; - case 1: - case 2: - case 5: - lba = ldl_be_p(&buf[2]) & 0xffffffffULL; - break; - case 4: - lba = ldq_be_p(&buf[2]); - break; - default: - lba = -1; - - } - return lba; -} - -int scsi_cdb_length(uint8_t *buf) { - int cdb_len; - - switch (buf[0] >> 5) { - case 0: - cdb_len = 6; - break; - case 1: - case 2: - cdb_len = 10; - break; - case 4: - cdb_len = 16; - break; - case 5: - cdb_len = 12; - break; - default: - cdb_len = -1; - } - return cdb_len; -} - int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) { int rc; @@ -1370,326 +1308,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense) } } -/* - * Predefined sense codes - */ - -/* No sense data available */ -const struct SCSISense sense_code_NO_SENSE = { - .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 -}; - -/* LUN not ready, Manual intervention required */ -const struct SCSISense sense_code_LUN_NOT_READY = { - .key = NOT_READY, .asc = 0x04, .ascq = 0x03 -}; - -/* LUN not ready, Medium not present */ -const struct SCSISense sense_code_NO_MEDIUM = { - .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 -}; - -/* LUN not ready, medium removal prevented */ -const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { - .key = NOT_READY, .asc = 0x53, .ascq = 0x02 -}; - -/* Hardware error, internal target failure */ -const struct SCSISense sense_code_TARGET_FAILURE = { - .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 -}; - -/* Illegal request, invalid command operation code */ -const struct SCSISense sense_code_INVALID_OPCODE = { - .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 -}; - -/* Illegal request, LBA out of range */ -const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { - .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 -}; - -/* Illegal request, Invalid field in CDB */ -const struct SCSISense sense_code_INVALID_FIELD = { - .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 -}; - -/* Illegal request, Invalid field in parameter list */ -const struct SCSISense sense_code_INVALID_PARAM = { - .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00 -}; - -/* Illegal request, Parameter list length error */ -const struct SCSISense sense_code_INVALID_PARAM_LEN = { - .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00 -}; - -/* Illegal request, LUN not supported */ -const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { - .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 -}; - -/* Illegal request, Saving parameters not supported */ -const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { - .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 -}; - -/* Illegal request, Incompatible medium installed */ -const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { - .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 -}; - -/* Illegal request, medium removal prevented */ -const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { - .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02 -}; - -/* Illegal request, Invalid Transfer Tag */ -const struct SCSISense sense_code_INVALID_TAG = { - .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 -}; - -/* Command aborted, I/O process terminated */ -const struct SCSISense sense_code_IO_ERROR = { - .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 -}; - -/* Command aborted, I_T Nexus loss occurred */ -const struct SCSISense sense_code_I_T_NEXUS_LOSS = { - .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 -}; - -/* Command aborted, Logical Unit failure */ -const struct SCSISense sense_code_LUN_FAILURE = { - .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 -}; - -/* Command aborted, Overlapped Commands Attempted */ -const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { - .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 -}; - -/* Unit attention, Capacity data has changed */ -const struct SCSISense sense_code_CAPACITY_CHANGED = { - .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 -}; - -/* Unit attention, Power on, reset or bus device reset occurred */ -const struct SCSISense sense_code_RESET = { - .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 -}; - -/* Unit attention, No medium */ -const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { - .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 -}; - -/* Unit attention, Medium may have changed */ -const struct SCSISense sense_code_MEDIUM_CHANGED = { - .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 -}; - -/* Unit attention, Reported LUNs data has changed */ -const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { - .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e -}; - -/* Unit attention, Device internal reset */ -const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { - .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 -}; - -/* Data Protection, Write Protected */ -const struct SCSISense sense_code_WRITE_PROTECTED = { - .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00 -}; - -/* Data Protection, Space Allocation Failed Write Protect */ -const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { - .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07 -}; - -/* - * scsi_build_sense - * - * Convert between fixed and descriptor sense buffers - */ -int scsi_build_sense(uint8_t *in_buf, int in_len, - uint8_t *buf, int len, bool fixed) -{ - bool fixed_in; - SCSISense sense; - if (!fixed && len < 8) { - return 0; - } - - if (in_len == 0) { - sense.key = NO_SENSE; - sense.asc = 0; - sense.ascq = 0; - } else { - fixed_in = (in_buf[0] & 2) == 0; - - if (fixed == fixed_in) { - memcpy(buf, in_buf, MIN(len, in_len)); - return MIN(len, in_len); - } - - if (fixed_in) { - sense.key = in_buf[2]; - sense.asc = in_buf[12]; - sense.ascq = in_buf[13]; - } else { - sense.key = in_buf[1]; - sense.asc = in_buf[2]; - sense.ascq = in_buf[3]; - } - } - - memset(buf, 0, len); - if (fixed) { - /* Return fixed format sense buffer */ - buf[0] = 0x70; - buf[2] = sense.key; - buf[7] = 10; - buf[12] = sense.asc; - buf[13] = sense.ascq; - return MIN(len, SCSI_SENSE_LEN); - } else { - /* Return descriptor format sense buffer */ - buf[0] = 0x72; - buf[1] = sense.key; - buf[2] = sense.asc; - buf[3] = sense.ascq; - return 8; - } -} - -const char *scsi_command_name(uint8_t cmd) -{ - static const char *names[] = { - [ TEST_UNIT_READY ] = "TEST_UNIT_READY", - [ REWIND ] = "REWIND", - [ REQUEST_SENSE ] = "REQUEST_SENSE", - [ FORMAT_UNIT ] = "FORMAT_UNIT", - [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS", - [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS", - /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */ - [ READ_6 ] = "READ_6", - [ WRITE_6 ] = "WRITE_6", - [ SET_CAPACITY ] = "SET_CAPACITY", - [ READ_REVERSE ] = "READ_REVERSE", - [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", - [ SPACE ] = "SPACE", - [ INQUIRY ] = "INQUIRY", - [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA", - [ MAINTENANCE_IN ] = "MAINTENANCE_IN", - [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT", - [ MODE_SELECT ] = "MODE_SELECT", - [ RESERVE ] = "RESERVE", - [ RELEASE ] = "RELEASE", - [ COPY ] = "COPY", - [ ERASE ] = "ERASE", - [ MODE_SENSE ] = "MODE_SENSE", - [ START_STOP ] = "START_STOP/LOAD_UNLOAD", - /* LOAD_UNLOAD and START_STOP use the same operation code */ - [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC", - [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC", - [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL", - [ READ_CAPACITY_10 ] = "READ_CAPACITY_10", - [ READ_10 ] = "READ_10", - [ WRITE_10 ] = "WRITE_10", - [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT", - /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */ - [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10", - [ VERIFY_10 ] = "VERIFY_10", - [ SEARCH_HIGH ] = "SEARCH_HIGH", - [ SEARCH_EQUAL ] = "SEARCH_EQUAL", - [ SEARCH_LOW ] = "SEARCH_LOW", - [ SET_LIMITS ] = "SET_LIMITS", - [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION", - /* READ_POSITION and PRE_FETCH use the same operation code */ - [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", - [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", - [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE", - /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */ - [ MEDIUM_SCAN ] = "MEDIUM_SCAN", - [ COMPARE ] = "COMPARE", - [ COPY_VERIFY ] = "COPY_VERIFY", - [ WRITE_BUFFER ] = "WRITE_BUFFER", - [ READ_BUFFER ] = "READ_BUFFER", - [ UPDATE_BLOCK ] = "UPDATE_BLOCK", - [ READ_LONG_10 ] = "READ_LONG_10", - [ WRITE_LONG_10 ] = "WRITE_LONG_10", - [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION", - [ WRITE_SAME_10 ] = "WRITE_SAME_10", - [ UNMAP ] = "UNMAP", - [ READ_TOC ] = "READ_TOC", - [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", - [ SANITIZE ] = "SANITIZE", - [ GET_CONFIGURATION ] = "GET_CONFIGURATION", - [ LOG_SELECT ] = "LOG_SELECT", - [ LOG_SENSE ] = "LOG_SENSE", - [ MODE_SELECT_10 ] = "MODE_SELECT_10", - [ RESERVE_10 ] = "RESERVE_10", - [ RELEASE_10 ] = "RELEASE_10", - [ MODE_SENSE_10 ] = "MODE_SENSE_10", - [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN", - [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT", - [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16", - [ EXTENDED_COPY ] = "EXTENDED_COPY", - [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16", - [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN", - [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT", - [ READ_16 ] = "READ_16", - [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE", - [ WRITE_16 ] = "WRITE_16", - [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", - [ VERIFY_16 ] = "VERIFY_16", - [ PRE_FETCH_16 ] = "PRE_FETCH_16", - [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", - /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ - [ LOCATE_16 ] = "LOCATE_16", - [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16", - /* ERASE_16 and WRITE_SAME_16 use the same operation code */ - [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", - [ WRITE_LONG_16 ] = "WRITE_LONG_16", - [ REPORT_LUNS ] = "REPORT_LUNS", - [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12", - [ MOVE_MEDIUM ] = "MOVE_MEDIUM", - [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM", - [ READ_12 ] = "READ_12", - [ WRITE_12 ] = "WRITE_12", - [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE", - /* ERASE_12 and GET_PERFORMANCE use the same operation code */ - [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12", - [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", - [ VERIFY_12 ] = "VERIFY_12", - [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12", - [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", - [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", - [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", - [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING", - /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ - [ READ_CD ] = "READ_CD", - [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12", - [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE", - [ RESERVE_TRACK ] = "RESERVE_TRACK", - [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET", - [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE", - [ SET_CD_SPEED ] = "SET_CD_SPEED", - [ SET_READ_AHEAD ] = "SET_READ_AHEAD", - [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE", - [ MECHANISM_STATUS ] = "MECHANISM_STATUS", - [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION", - [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION", - }; - - if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) - return "*UNKNOWN*"; - return names[cmd]; -} - SCSIRequest *scsi_req_ref(SCSIRequest *req) { assert(req->refcount > 0); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 5f1e5e8070..6e841fb5ff 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" @@ -106,7 +106,7 @@ typedef struct SCSIDiskState bool tray_locked; } SCSIDiskState; -static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); +static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); static void scsi_free_request(SCSIRequest *req) { @@ -184,19 +184,10 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) return true; } - if (ret < 0) { + if (ret < 0 || (r->status && *r->status)) { return scsi_handle_rw_error(r, -ret, acct_failed); } - if (r->status && *r->status) { - if (acct_failed) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); - } - scsi_req_complete(&r->req, *r->status); - return true; - } - return false; } @@ -422,13 +413,13 @@ static void scsi_read_data(SCSIRequest *req) } /* - * scsi_handle_rw_error has two return values. 0 means that the error - * must be ignored, 1 means that the error has been processed and the + * scsi_handle_rw_error has two return values. False means that the error + * must be ignored, true means that the error has been processed and the * caller should not do anything else for this request. Note that * scsi_handle_rw_error always manages its reference counts, independent * of the return value. */ -static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) +static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) { bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); @@ -440,6 +431,11 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed) block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); } switch (error) { + case 0: + /* The command has run, no need to fake sense. */ + assert(r->status && *r->status); + scsi_req_complete(&r->req, *r->status); + break; case ENOMEDIUM: scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); break; @@ -457,6 +453,18 @@ static int 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_STOP) { scsi_req_retry(&r->req); @@ -1978,8 +1986,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; case REQUEST_SENSE: /* Just return "NO SENSE". */ - buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen, - (req->cmd.buf[1] & 1) == 0); + buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen, + (req->cmd.buf[1] & 1) == 0); if (buflen < 0) { goto illegal_request; } @@ -2972,6 +2980,7 @@ static const TypeInfo scsi_cd_info = { #ifdef __linux__ static Property scsi_block_properties[] = { + DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \ DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7e1cbab77e..bd0d9ff355 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -34,15 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0) do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) #include <scsi/sg.h> -#include "block/scsi.h" - -#define SG_ERR_DRIVER_TIMEOUT 0x06 -#define SG_ERR_DRIVER_SENSE 0x08 - -#define SG_ERR_DID_OK 0x00 -#define SG_ERR_DID_NO_CONNECT 0x01 -#define SG_ERR_DID_BUS_BUSY 0x02 -#define SG_ERR_DID_TIME_OUT 0x03 +#include "scsi/constants.h" #ifndef MAX_UINT #define MAX_UINT ((unsigned int)-1) @@ -89,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req) static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) { int status; + SCSISense sense; assert(r->req.aiocb == NULL); @@ -96,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) scsi_req_cancel_complete(&r->req); goto done; } - if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { - r->req.sense_len = r->io_header.sb_len_wr; - } - - if (ret != 0) { - switch (ret) { - case -EDOM: - status = TASK_SET_FULL; - break; - case -ENOMEM: - status = CHECK_CONDITION; - scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE)); - break; - default: - status = CHECK_CONDITION; - scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR)); - break; - } - } else { - if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT || - r->io_header.host_status == SG_ERR_DID_BUS_BUSY || - r->io_header.host_status == SG_ERR_DID_TIME_OUT || - (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) { - status = BUSY; - BADF("Driver Timeout\n"); - } else if (r->io_header.host_status) { - status = CHECK_CONDITION; - scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS)); - } else if (r->io_header.status) { - status = r->io_header.status; - } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { - status = CHECK_CONDITION; + status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); + if (status == CHECK_CONDITION) { + if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { + r->req.sense_len = r->io_header.sb_len_wr; } else { - status = GOOD; + scsi_req_build_sense(&r->req, sense); } } + DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", r, r->req.tag, status); diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 55ee48c4da..360db53ac8 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -36,7 +36,7 @@ #include "cpu.h" #include "hw/hw.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "srp.h" #include "hw/qdev.h" #include "hw/ppc/spapr.h" diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 944ea4eb53..add4b3f4a4 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -17,7 +17,7 @@ #include "qemu/error-report.h" #include "sysemu/block-backend.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index eb639442d1..3aa99717e2 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -21,7 +21,7 @@ #include "qemu/iov.h" #include "sysemu/block-backend.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" @@ -867,10 +867,10 @@ void virtio_scsi_common_realize(DeviceState *dev, s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE; - s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, ctrl); - s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, evt); + s->ctrl_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, ctrl); + s->event_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, evt); for (i = 0; i < s->conf.num_queues; i++) { - s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, cmd); + s->cmd_vqs[i] = virtio_add_queue(vdev, s->conf.virtqueue_size, cmd); } } @@ -917,6 +917,8 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) static Property virtio_scsi_properties[] = { DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1), + DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI, + parent_obj.conf.virtqueue_size, 128), DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors, 0xFFFF), DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun, diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 77d8b6f9e2..6d3f0bf11d 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -28,7 +28,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "hw/pci/msi.h" #include "vmw_pvscsi.h" #include "trace.h" diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index fffc424396..c218b53f09 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -19,7 +19,7 @@ #include "hw/usb.h" #include "hw/usb/desc.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include "scsi/constants.h" /* --------------------------------------------------------------------- */ diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 604912cb3e..46fd30b075 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -32,6 +32,7 @@ #include "hw/usb/ehci-regs.h" #include "hw/usb/hcd-ehci.h" #include "trace.h" +#include "qemu/error-report.h" #define FRAME_TIMER_FREQ 1000 #define FRAME_TIMER_NS (NANOSECONDS_PER_SECOND / FRAME_TIMER_FREQ) @@ -348,7 +349,7 @@ static void ehci_trace_sitd(EHCIState *s, hwaddr addr, static void ehci_trace_guest_bug(EHCIState *s, const char *message) { trace_usb_ehci_guest_bug(message); - fprintf(stderr, "ehci warning: %s\n", message); + warn_report("%s", message); } static inline bool ehci_enabled(EHCIState *s) @@ -1728,7 +1729,7 @@ static int ehci_state_fetchsitd(EHCIState *ehci, int async) /* siTD is not active, nothing to do */; } else { /* TODO: split transfers are not implemented */ - fprintf(stderr, "WARNING: Skipping active siTD\n"); + warn_report("Skipping active siTD"); } ehci_set_fetch_addr(ehci, async, sitd.next); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index a705e0ec55..37cde38982 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -26,6 +26,7 @@ #include "qapi/visitor.h" #include "qapi-event.h" #include "trace.h" +#include "qemu/error-report.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" @@ -292,7 +293,7 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) s->stats_vq_offset = offset; if (qemu_gettimeofday(&tv) < 0) { - fprintf(stderr, "warning: %s: failed to get time of day\n", __func__); + warn_report("%s: failed to get time of day", __func__); goto out; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 464947f76d..3129d25c00 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1025,11 +1025,9 @@ void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz) /* TODO: teach all callers that this can fail, and return failure instead * of asserting here. - * When we do, we might be able to re-enable NDEBUG below. + * This is just one thing (there are probably more) that must be + * fixed before we can allow NDEBUG compilation. */ -#ifdef NDEBUG -#error building with NDEBUG is not supported -#endif assert(ARRAY_SIZE(data.in_addr) >= data.in_num); assert(ARRAY_SIZE(data.out_addr) >= data.out_num); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 8226904524..087d184ef5 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -371,6 +371,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_10 \ HW_COMPAT_2_10 \ + {\ + .driver = TYPE_X86_CPU,\ + .property = "x-hv-max-vps",\ + .value = "0x40",\ + }, #define PC_COMPAT_2_9 \ HW_COMPAT_2_9 \ diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h index 482a9512be..180e00e32c 100644 --- a/include/hw/ide/internal.h +++ b/include/hw/ide/internal.h @@ -11,12 +11,10 @@ #include "sysemu/dma.h" #include "sysemu/sysemu.h" #include "hw/block/block.h" -#include "block/scsi.h" +#include "scsi/constants.h" +#include "qapi/error.h" /* debug IDE devices */ -//#define DEBUG_IDE -//#define DEBUG_IDE_ATAPI -//#define DEBUG_AIO #define USE_DMA_CDROM typedef struct IDEBus IDEBus; @@ -335,12 +333,16 @@ struct unreported_events { }; enum ide_dma_cmd { - IDE_DMA_READ, + IDE_DMA__BEGIN = 0, + IDE_DMA_READ = IDE_DMA__BEGIN, IDE_DMA_WRITE, IDE_DMA_TRIM, IDE_DMA_ATAPI, + IDE_DMA__COUNT }; +extern const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT]; + #define ide_cmd_is_read(s) \ ((s)->dma_cmd == IDE_DMA_READ) @@ -495,7 +497,7 @@ struct IDEBus { typedef struct IDEDeviceClass { DeviceClass parent_class; - int (*init)(IDEDevice *dev); + void (*realize)(IDEDevice *dev, Error **errp); } IDEDeviceClass; struct IDEDevice { @@ -605,7 +607,7 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, const char *version, const char *serial, const char *model, uint64_t wwn, uint32_t cylinders, uint32_t heads, uint32_t secs, - int chs_trans); + int chs_trans, Error **errp); void ide_init2(IDEBus *bus, qemu_irq irq); void ide_exit(IDEState *s); void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2); diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 41a9d2862b..a9a90c2022 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -56,4 +56,6 @@ bool gs_allowed(void); */ bool css_migration_enabled(void); +void subsystem_reset(void); + #endif diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index a72d096081..847ff32f85 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -16,6 +16,7 @@ #include "hw/sysbus.h" #include "hw/qdev.h" +#include "target/s390x/cpu-qom.h" #define SCLP_CMD_CODE_MASK 0xffff00ff @@ -242,5 +243,6 @@ sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void); sclpMemoryHotplugDev *get_sclp_memory_hotplug_dev(void); void sclp_service_interrupt(uint32_t sccb); void raise_irq_cpu_hotplug(void); +int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); #endif diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 6b85786dbf..23a8ee6a7d 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -4,45 +4,20 @@ #include "hw/qdev.h" #include "hw/block/block.h" #include "sysemu/sysemu.h" +#include "scsi/utils.h" #include "qemu/notify.h" #define MAX_SCSI_DEVS 255 -#define SCSI_CMD_BUF_SIZE 16 -#define SCSI_SENSE_LEN 18 -#define SCSI_SENSE_LEN_SCANNER 32 -#define SCSI_INQUIRY_LEN 36 - typedef struct SCSIBus SCSIBus; typedef struct SCSIBusInfo SCSIBusInfo; -typedef struct SCSICommand SCSICommand; typedef struct SCSIDevice SCSIDevice; typedef struct SCSIRequest SCSIRequest; typedef struct SCSIReqOps SCSIReqOps; -enum SCSIXferMode { - SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ - SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */ - SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ -}; - -typedef struct SCSISense { - uint8_t key; - uint8_t asc; - uint8_t ascq; -} SCSISense; - #define SCSI_SENSE_BUF_SIZE_OLD 96 #define SCSI_SENSE_BUF_SIZE 252 -struct SCSICommand { - uint8_t buf[SCSI_CMD_BUF_SIZE]; - int len; - size_t xfer; - uint64_t lba; - enum SCSIXferMode mode; -}; - struct SCSIRequest { SCSIBus *bus; SCSIDevice *dev; @@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk, void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated); void scsi_legacy_handle_cmdline(void); -/* - * Predefined sense codes - */ - -/* No sense data available */ -extern const struct SCSISense sense_code_NO_SENSE; -/* LUN not ready, Manual intervention required */ -extern const struct SCSISense sense_code_LUN_NOT_READY; -/* LUN not ready, Medium not present */ -extern const struct SCSISense sense_code_NO_MEDIUM; -/* LUN not ready, medium removal prevented */ -extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED; -/* Hardware error, internal target failure */ -extern const struct SCSISense sense_code_TARGET_FAILURE; -/* Illegal request, invalid command operation code */ -extern const struct SCSISense sense_code_INVALID_OPCODE; -/* Illegal request, LBA out of range */ -extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE; -/* Illegal request, Invalid field in CDB */ -extern const struct SCSISense sense_code_INVALID_FIELD; -/* Illegal request, Invalid field in parameter list */ -extern const struct SCSISense sense_code_INVALID_PARAM; -/* Illegal request, Parameter list length error */ -extern const struct SCSISense sense_code_INVALID_PARAM_LEN; -/* Illegal request, LUN not supported */ -extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; -/* Illegal request, Saving parameters not supported */ -extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED; -/* Illegal request, Incompatible format */ -extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT; -/* Illegal request, medium removal prevented */ -extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED; -/* Illegal request, Invalid Transfer Tag */ -extern const struct SCSISense sense_code_INVALID_TAG; -/* Command aborted, I/O process terminated */ -extern const struct SCSISense sense_code_IO_ERROR; -/* Command aborted, I_T Nexus loss occurred */ -extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; -/* Command aborted, Logical Unit failure */ -extern const struct SCSISense sense_code_LUN_FAILURE; -/* Command aborted, Overlapped Commands Attempted */ -extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; -/* LUN not ready, Capacity data has changed */ -extern const struct SCSISense sense_code_CAPACITY_CHANGED; -/* LUN not ready, Medium not present */ -extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; -/* Unit attention, Power on, reset or bus device reset occurred */ -extern const struct SCSISense sense_code_RESET; -/* Unit attention, Medium may have changed*/ -extern const struct SCSISense sense_code_MEDIUM_CHANGED; -/* Unit attention, Reported LUNs data has changed */ -extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED; -/* Unit attention, Device internal reset */ -extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET; -/* Data Protection, Write Protected */ -extern const struct SCSISense sense_code_WRITE_PROTECTED; -/* Data Protection, Space Allocation Failed Write Protect */ -extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; - -#define SENSE_CODE(x) sense_code_ ## x - -uint32_t scsi_data_cdb_xfer(uint8_t *buf); -uint32_t scsi_cdb_xfer(uint8_t *buf); -int scsi_cdb_length(uint8_t *buf); -int scsi_build_sense(uint8_t *in_buf, int in_len, - uint8_t *buf, int len, bool fixed); - SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag, uint32_t lun, void *hba_private); SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index de6ae5a9f6..4c0bcdb788 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -32,7 +32,6 @@ #define VIRTIO_SCSI(obj) \ OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI) -#define VIRTIO_SCSI_VQ_SIZE 128 #define VIRTIO_SCSI_MAX_CHANNEL 0 #define VIRTIO_SCSI_MAX_TARGET 255 #define VIRTIO_SCSI_MAX_LUN 16383 @@ -48,6 +47,7 @@ typedef struct virtio_scsi_config VirtIOSCSIConfig; struct VirtIOSCSIConf { uint32_t num_queues; + uint32_t virtqueue_size; uint32_t max_sectors; uint32_t cmd_per_lun; #ifdef CONFIG_VHOST_SCSI diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index e9fa21788b..72b75bf044 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -107,6 +107,22 @@ extern int daemon(int, int); #include "glib-compat.h" #include "qemu/typedefs.h" +/* + * We have a lot of unaudited code that may fail in strange ways, or + * even be a security risk during migration, if you disable assertions + * at compile-time. You may comment out these safety checks if you + * absolutely want to disable assertion overhead, but it is not + * supported upstream so the risk is all yours. Meanwhile, please + * submit patches to remove any side-effects inside an assertion, or + * fixing error handling that should use Error instead of assert. + */ +#ifdef NDEBUG +#error building with NDEBUG is not supported +#endif +#ifdef G_DISABLE_ASSERT +#error building with G_DISABLE_ASSERT is not supported +#endif + #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 6d33cf1878..0efebdbcf4 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -388,10 +388,10 @@ struct CPUState { DECLARE_BITMAP(trace_dstate, CPU_TRACE_DSTATE_MAX_EVENTS); /* TODO Move common fields from CPUArchState here. */ - int cpu_index; /* used by alpha TCG */ - uint32_t halted; /* used by alpha, cris, ppc TCG */ + int cpu_index; + uint32_t halted; uint32_t can_do_io; - int32_t exception_index; /* used by m68k TCG */ + int32_t exception_index; /* shared by kvm, hax and hvf */ bool vcpu_dirty; diff --git a/include/block/scsi.h b/include/scsi/constants.h index cdf0a58a07..a141dd71f8 100644 --- a/include/block/scsi.h +++ b/include/scsi/constants.h @@ -150,8 +150,6 @@ #define READ_CD 0xbe #define SEND_DVD_STRUCTURE 0xbf -const char *scsi_command_name(uint8_t cmd); - /* * SERVICE ACTION IN subcodes */ diff --git a/include/scsi/utils.h b/include/scsi/utils.h new file mode 100644 index 0000000000..d301b31768 --- /dev/null +++ b/include/scsi/utils.h @@ -0,0 +1,124 @@ +#ifndef SCSI_UTILS_H +#define SCSI_UTILS_H 1 + +#ifdef CONFIG_LINUX +#include <scsi/sg.h> +#endif + +#define SCSI_CMD_BUF_SIZE 16 +#define SCSI_SENSE_LEN 18 +#define SCSI_SENSE_LEN_SCANNER 32 +#define SCSI_INQUIRY_LEN 36 + +enum SCSIXferMode { + SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ + SCSI_XFER_FROM_DEV, /* READ, INQUIRY, MODE_SENSE, ... */ + SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ +}; + +typedef struct SCSICommand { + uint8_t buf[SCSI_CMD_BUF_SIZE]; + int len; + size_t xfer; + uint64_t lba; + enum SCSIXferMode mode; +} SCSICommand; + +typedef struct SCSISense { + uint8_t key; + uint8_t asc; + uint8_t ascq; +} SCSISense; + +int scsi_build_sense(uint8_t *buf, SCSISense sense); + +/* + * Predefined sense codes + */ + +/* No sense data available */ +extern const struct SCSISense sense_code_NO_SENSE; +/* LUN not ready, Manual intervention required */ +extern const struct SCSISense sense_code_LUN_NOT_READY; +/* LUN not ready, Medium not present */ +extern const struct SCSISense sense_code_NO_MEDIUM; +/* LUN not ready, medium removal prevented */ +extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED; +/* Hardware error, internal target failure */ +extern const struct SCSISense sense_code_TARGET_FAILURE; +/* Illegal request, invalid command operation code */ +extern const struct SCSISense sense_code_INVALID_OPCODE; +/* Illegal request, LBA out of range */ +extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE; +/* Illegal request, Invalid field in CDB */ +extern const struct SCSISense sense_code_INVALID_FIELD; +/* Illegal request, Invalid field in parameter list */ +extern const struct SCSISense sense_code_INVALID_PARAM; +/* Illegal request, Parameter list length error */ +extern const struct SCSISense sense_code_INVALID_PARAM_LEN; +/* Illegal request, LUN not supported */ +extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; +/* Illegal request, Saving parameters not supported */ +extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED; +/* Illegal request, Incompatible format */ +extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT; +/* Illegal request, medium removal prevented */ +extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED; +/* Illegal request, Invalid Transfer Tag */ +extern const struct SCSISense sense_code_INVALID_TAG; +/* Command aborted, I/O process terminated */ +extern const struct SCSISense sense_code_IO_ERROR; +/* Command aborted, I_T Nexus loss occurred */ +extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; +/* Command aborted, Logical Unit failure */ +extern const struct SCSISense sense_code_LUN_FAILURE; +/* Command aborted, Overlapped Commands Attempted */ +extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; +/* LUN not ready, Capacity data has changed */ +extern const struct SCSISense sense_code_CAPACITY_CHANGED; +/* LUN not ready, Medium not present */ +extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; +/* Unit attention, Power on, reset or bus device reset occurred */ +extern const struct SCSISense sense_code_RESET; +/* Unit attention, Medium may have changed*/ +extern const struct SCSISense sense_code_MEDIUM_CHANGED; +/* Unit attention, Reported LUNs data has changed */ +extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED; +/* Unit attention, Device internal reset */ +extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET; +/* Data Protection, Write Protected */ +extern const struct SCSISense sense_code_WRITE_PROTECTED; +/* Data Protection, Space Allocation Failed Write Protect */ +extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED; + +#define SENSE_CODE(x) sense_code_ ## x + +int scsi_sense_to_errno(int key, int asc, int ascq); +int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size); + +int scsi_convert_sense(uint8_t *in_buf, int in_len, + uint8_t *buf, int len, bool fixed); +const char *scsi_command_name(uint8_t cmd); + +uint64_t scsi_cmd_lba(SCSICommand *cmd); +uint32_t scsi_data_cdb_xfer(uint8_t *buf); +uint32_t scsi_cdb_xfer(uint8_t *buf); +int scsi_cdb_length(uint8_t *buf); + +/* Linux SG_IO interface. */ +#ifdef CONFIG_LINUX +#define SG_ERR_DRIVER_TIMEOUT 0x06 +#define SG_ERR_DRIVER_SENSE 0x08 + +#define SG_ERR_DID_OK 0x00 +#define SG_ERR_DID_NO_CONNECT 0x01 +#define SG_ERR_DID_BUS_BUSY 0x02 +#define SG_ERR_DID_TIME_OUT 0x03 + +#define SG_ERR_DRIVER_SENSE 0x08 + +int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, + SCSISense *sense); +#endif + +#endif @@ -2701,10 +2701,10 @@ typedef struct MemoryRegionList MemoryRegionList; struct MemoryRegionList { const MemoryRegion *mr; - QTAILQ_ENTRY(MemoryRegionList) queue; + QTAILQ_ENTRY(MemoryRegionList) mrqueue; }; -typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead; +typedef QTAILQ_HEAD(mrqueue, MemoryRegionList) MemoryRegionListHead; #define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \ int128_sub((size), int128_one())) : 0) @@ -2746,7 +2746,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, bool found = false; /* check if the alias is already in the queue */ - QTAILQ_FOREACH(ml, alias_print_queue, queue) { + QTAILQ_FOREACH(ml, alias_print_queue, mrqueue) { if (ml->mr == mr->alias) { found = true; } @@ -2755,7 +2755,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, if (!found) { ml = g_new(MemoryRegionList, 1); ml->mr = mr->alias; - QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue); + QTAILQ_INSERT_TAIL(alias_print_queue, ml, mrqueue); } mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %s): alias %s @%s " TARGET_FMT_plx @@ -2783,26 +2783,26 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) { new_ml = g_new(MemoryRegionList, 1); new_ml->mr = submr; - QTAILQ_FOREACH(ml, &submr_print_queue, queue) { + QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) { if (new_ml->mr->addr < ml->mr->addr || (new_ml->mr->addr == ml->mr->addr && new_ml->mr->priority > ml->mr->priority)) { - QTAILQ_INSERT_BEFORE(ml, new_ml, queue); + QTAILQ_INSERT_BEFORE(ml, new_ml, mrqueue); new_ml = NULL; break; } } if (new_ml) { - QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, queue); + QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, mrqueue); } } - QTAILQ_FOREACH(ml, &submr_print_queue, queue) { + QTAILQ_FOREACH(ml, &submr_print_queue, mrqueue) { mtree_print_mr(mon_printf, f, ml->mr, level + 1, cur_start, alias_print_queue); } - QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, queue, next_ml) { + QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, mrqueue, next_ml) { g_free(ml); } } @@ -2872,13 +2872,13 @@ void mtree_info(fprintf_function mon_printf, void *f, bool flatview) } /* print aliased regions */ - QTAILQ_FOREACH(ml, &ml_head, queue) { + QTAILQ_FOREACH(ml, &ml_head, mrqueue) { mon_printf(f, "memory-region: %s\n", memory_region_name(ml->mr)); mtree_print_mr(mon_printf, f, ml->mr, 1, 0, &ml_head); mon_printf(f, "\n"); } - QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) { + QTAILQ_FOREACH_SAFE(ml, &ml_head, mrqueue, ml2) { g_free(ml); } } @@ -18,6 +18,7 @@ #include "clients.h" #include "hub.h" #include "qemu/iov.h" +#include "qemu/error-report.h" /* * A hub broadcasts incoming packets to all its ports except the source port. @@ -309,8 +310,7 @@ void net_hub_check_clients(void) QLIST_FOREACH(port, &hub->ports, next) { peer = port->nc.peer; if (!peer) { - fprintf(stderr, "Warning: hub port %s has no peer\n", - port->nc.name); + warn_report("hub port %s has no peer", port->nc.name); continue; } @@ -330,12 +330,10 @@ void net_hub_check_clients(void) } } if (has_host_dev && !has_nic) { - fprintf(stderr, "Warning: vlan %d with no nics\n", hub->id); + warn_report("vlan %d with no nics", hub->id); } if (has_nic && !has_host_dev) { - fprintf(stderr, - "Warning: vlan %d is not connected to host network\n", - hub->id); + warn_report("vlan %d is not connected to host network", hub->id); } } } @@ -1493,9 +1493,10 @@ void net_check_clients(void) QTAILQ_FOREACH(nc, &net_clients, next) { if (!nc->peer) { - fprintf(stderr, "Warning: %s %s has no peer\n", - nc->info->type == NET_CLIENT_DRIVER_NIC ? - "nic" : "netdev", nc->name); + warn_report("%s %s has no peer", + nc->info->type == NET_CLIENT_DRIVER_NIC + ? "nic" : "netdev", + nc->name); } } @@ -1506,10 +1507,10 @@ void net_check_clients(void) for (i = 0; i < MAX_NICS; i++) { NICInfo *nd = &nd_table[i]; if (nd->used && !nd->instantiated) { - fprintf(stderr, "Warning: requested NIC (%s, model %s) " - "was not created (not supported by this machine?)\n", - nd->name ? nd->name : "anonymous", - nd->model ? nd->model : "unspecified"); + warn_report("requested NIC (%s, model %s) " + "was not created (not supported by this machine?)", + nd->name ? nd->name : "anonymous", + nd->model ? nd->model : "unspecified"); } } } diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index a9e1374e97..a25d238144 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -50,7 +50,7 @@ libc.a: $(LIBCOBJS) LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \ dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o -LIBNETCFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC) +LIBNETCFLAGS := $(QEMU_CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC) %.o : $(SLOF_DIR)/lib/libnet/%.c $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") diff --git a/qapi-schema.json b/qapi-schema.json index cdff39a456..a3ba1c9a1c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3153,6 +3153,22 @@ # } # ]} # +# For s390x-virtio-ccw machine type started with -smp 1,maxcpus=2 -cpu qemu +# (Since: 2.11): +# +# -> { "execute": "query-hotpluggable-cpus" } +# <- {"return": [ +# { +# "type": "qemu-s390-cpu", "vcpus-count": 1, +# "props": { "core-id": 1 } +# }, +# { +# "qom-path": "/machine/unattached/device[0]", +# "type": "qemu-s390-cpu", "vcpus-count": 1, +# "props": { "core-id": 0 } +# } +# ]} +# ## { 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] } diff --git a/qga/vss-win32.c b/qga/vss-win32.c index a80933c98b..dcb27567bb 100644 --- a/qga/vss-win32.c +++ b/qga/vss-win32.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include <windows.h> +#include "qemu/error-report.h" #include "qga/guest-agent-core.h" #include "qga/vss-win32.h" #include "qga/vss-win32/requester.h" @@ -61,7 +62,7 @@ static bool vss_check_os_version(void) return false; } if (wow64) { - fprintf(stderr, "Warning: Running under WOW64\n"); + warn_report("Running under WOW64"); } #endif return !wow64; diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index fa478074b8..3c0a28e644 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -18,11 +18,12 @@ use Getopt::Long qw(:config no_auto_abbrev); my $quiet = 0; my $tree = 1; my $chk_signoff = 1; -my $chk_patch = 1; +my $chk_patch = undef; +my $chk_branch = undef; my $tst_only; my $emacs = 0; my $terse = 0; -my $file = 0; +my $file = undef; my $no_warnings = 0; my $summary = 1; my $mailback = 0; @@ -35,14 +36,19 @@ sub help { my ($exitcode) = @_; print << "EOM"; -Usage: $P [OPTION]... [FILE]... +Usage: + + $P [OPTION]... [FILE]... + $P [OPTION]... [GIT-REV-LIST] + Version: $V Options: -q, --quiet quiet --no-tree run without a kernel tree --no-signoff do not check for 'Signed-off-by' line - --patch treat FILE as patchfile (default) + --patch treat FILE as patchfile + --branch treat args as GIT revision list --emacs emacs compile window format --terse one line per report -f, --file treat FILE as regular source file @@ -69,6 +75,7 @@ GetOptions( 'tree!' => \$tree, 'signoff!' => \$chk_signoff, 'patch!' => \$chk_patch, + 'branch!' => \$chk_branch, 'emacs!' => \$emacs, 'terse!' => \$terse, 'f|file!' => \$file, @@ -93,6 +100,49 @@ if ($#ARGV < 0) { exit(1); } +if (!defined $chk_branch && !defined $chk_patch && !defined $file) { + $chk_branch = $ARGV[0] =~ /\.\./ ? 1 : 0; + $chk_patch = $chk_branch ? 0 : + $ARGV[0] =~ /\.patch$/ || $ARGV[0] eq "-" ? 1 : 0; + $file = $chk_branch || $chk_patch ? 0 : 1; +} elsif (!defined $chk_branch && !defined $chk_patch) { + if ($file) { + $chk_branch = $chk_patch = 0; + } else { + $chk_branch = $ARGV[0] =~ /\.\./ ? 1 : 0; + $chk_patch = $chk_branch ? 0 : 1; + } +} elsif (!defined $chk_branch && !defined $file) { + if ($chk_patch) { + $chk_branch = $file = 0; + } else { + $chk_branch = $ARGV[0] =~ /\.\./ ? 1 : 0; + $file = $chk_branch ? 0 : 1; + } +} elsif (!defined $chk_patch && !defined $file) { + if ($chk_branch) { + $chk_patch = $file = 0; + } else { + $chk_patch = $ARGV[0] =~ /\.patch$/ || $ARGV[0] eq "-" ? 1 : 0; + $file = $chk_patch ? 0 : 1; + } +} elsif (!defined $chk_branch) { + $chk_branch = $chk_patch || $file ? 0 : 1; +} elsif (!defined $chk_patch) { + $chk_patch = $chk_branch || $file ? 0 : 1; +} elsif (!defined $file) { + $file = $chk_patch || $chk_branch ? 0 : 1; +} + +if (($chk_patch && $chk_branch) || + ($chk_patch && $file) || + ($chk_branch && $file)) { + die "Only one of --file, --branch, --patch is permitted\n"; +} +if (!$chk_patch && !$chk_branch && !$file) { + die "One of --file, --branch, --patch is required\n"; +} + my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; @@ -213,6 +263,7 @@ our @typeList = ( qr{${Ident}_handler}, qr{${Ident}_handler_fn}, qr{target_(?:u)?long}, + qr{hwaddr}, ); # This can be modified by sub possible. Since it can be empty, be careful @@ -251,32 +302,66 @@ $chk_signoff = 0 if ($file); my @rawlines = (); my @lines = (); my $vname; -for my $filename (@ARGV) { - my $FILE; - if ($file) { - open($FILE, '-|', "diff -u /dev/null $filename") || - die "$P: $filename: diff failed - $!\n"; - } elsif ($filename eq '-') { - open($FILE, '<&STDIN'); - } else { - open($FILE, '<', "$filename") || - die "$P: $filename: open failed - $!\n"; - } - if ($filename eq '-') { - $vname = 'Your patch'; - } else { - $vname = $filename; - } - while (<$FILE>) { +if ($chk_branch) { + my @patches; + my $HASH; + open($HASH, "-|", "git", "log", "--format=%H", $ARGV[0]) || + die "$P: git log --format=%H $ARGV[0] failed - $!\n"; + + while (<$HASH>) { chomp; - push(@rawlines, $_); + push @patches, $_; + } + + close $HASH; + + die "$P: no revisions returned for revlist '$chk_branch'\n" + unless @patches; + + for my $hash (@patches) { + my $FILE; + open($FILE, '-|', "git", "show", $hash) || + die "$P: git show $hash - $!\n"; + $vname = $hash; + while (<$FILE>) { + chomp; + push(@rawlines, $_); + } + close($FILE); + if (!process($hash)) { + $exit = 1; + } + @rawlines = (); + @lines = (); } - close($FILE); - if (!process($filename)) { - $exit = 1; +} else { + for my $filename (@ARGV) { + my $FILE; + if ($file) { + open($FILE, '-|', "diff -u /dev/null $filename") || + die "$P: $filename: diff failed - $!\n"; + } elsif ($filename eq '-') { + open($FILE, '<&STDIN'); + } else { + open($FILE, '<', "$filename") || + die "$P: $filename: open failed - $!\n"; + } + if ($filename eq '-') { + $vname = 'Your patch'; + } else { + $vname = $filename; + } + while (<$FILE>) { + chomp; + push(@rawlines, $_); + } + close($FILE); + if (!process($filename)) { + $exit = 1; + } + @rawlines = (); + @lines = (); } - @rawlines = (); - @lines = (); } exit($exit); diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh index 2f906c4d16..ad80fe3fca 100755 --- a/scripts/update-linux-headers.sh +++ b/scripts/update-linux-headers.sh @@ -104,7 +104,9 @@ for arch in $ARCHLIST; do cp "$tmpdir/include/asm/unistd-common.h" "$output/linux-headers/asm-arm/" fi if [ $arch = x86 ]; then - cp_portable "$tmpdir/include/asm/hyperv.h" "$output/include/standard-headers/asm-x86/" + cat <<-EOF >"$output/include/standard-headers/asm-x86/hyperv.h" + /* this is a temporary placeholder until kvm_para.h stops including it */ + EOF cp "$tmpdir/include/asm/unistd_32.h" "$output/linux-headers/asm-x86/" cp "$tmpdir/include/asm/unistd_x32.h" "$output/linux-headers/asm-x86/" cp "$tmpdir/include/asm/unistd_64.h" "$output/linux-headers/asm-x86/" diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs new file mode 100644 index 0000000000..31b82a5a36 --- /dev/null +++ b/scsi/Makefile.objs @@ -0,0 +1 @@ +block-obj-y += utils.o diff --git a/scsi/utils.c b/scsi/utils.c new file mode 100644 index 0000000000..fab60bdf20 --- /dev/null +++ b/scsi/utils.c @@ -0,0 +1,538 @@ +/* + * SCSI helpers + * + * Copyright 2017 Red Hat, Inc. + * + * Authors: + * Fam Zheng <famz@redhat.com> + * Paolo Bonzini <pbonzini@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include "qemu/osdep.h" +#include "scsi/constants.h" +#include "scsi/utils.h" +#include "qemu/bswap.h" + +uint32_t scsi_data_cdb_xfer(uint8_t *buf) +{ + if ((buf[0] >> 5) == 0 && buf[4] == 0) { + return 256; + } else { + return scsi_cdb_xfer(buf); + } +} + +uint32_t scsi_cdb_xfer(uint8_t *buf) +{ + switch (buf[0] >> 5) { + case 0: + return buf[4]; + break; + case 1: + case 2: + return lduw_be_p(&buf[7]); + break; + case 4: + return ldl_be_p(&buf[10]) & 0xffffffffULL; + break; + case 5: + return ldl_be_p(&buf[6]) & 0xffffffffULL; + break; + default: + return -1; + } +} + +uint64_t scsi_cmd_lba(SCSICommand *cmd) +{ + uint8_t *buf = cmd->buf; + uint64_t lba; + + switch (buf[0] >> 5) { + case 0: + lba = ldl_be_p(&buf[0]) & 0x1fffff; + break; + case 1: + case 2: + case 5: + lba = ldl_be_p(&buf[2]) & 0xffffffffULL; + break; + case 4: + lba = ldq_be_p(&buf[2]); + break; + default: + lba = -1; + + } + return lba; +} + +int scsi_cdb_length(uint8_t *buf) +{ + int cdb_len; + + switch (buf[0] >> 5) { + case 0: + cdb_len = 6; + break; + case 1: + case 2: + cdb_len = 10; + break; + case 4: + cdb_len = 16; + break; + case 5: + cdb_len = 12; + break; + default: + cdb_len = -1; + } + return cdb_len; +} + +int scsi_build_sense(uint8_t *buf, SCSISense sense) +{ + memset(buf, 0, 18); + buf[0] = 0x70; + buf[2] = sense.key; + buf[7] = 10; + buf[12] = sense.asc; + buf[13] = sense.ascq; + return 18; +} + +/* + * Predefined sense codes + */ + +/* No sense data available */ +const struct SCSISense sense_code_NO_SENSE = { + .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 +}; + +/* LUN not ready, Manual intervention required */ +const struct SCSISense sense_code_LUN_NOT_READY = { + .key = NOT_READY, .asc = 0x04, .ascq = 0x03 +}; + +/* LUN not ready, Medium not present */ +const struct SCSISense sense_code_NO_MEDIUM = { + .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 +}; + +/* LUN not ready, medium removal prevented */ +const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { + .key = NOT_READY, .asc = 0x53, .ascq = 0x02 +}; + +/* Hardware error, internal target failure */ +const struct SCSISense sense_code_TARGET_FAILURE = { + .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 +}; + +/* Illegal request, invalid command operation code */ +const struct SCSISense sense_code_INVALID_OPCODE = { + .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 +}; + +/* Illegal request, LBA out of range */ +const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { + .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 +}; + +/* Illegal request, Invalid field in CDB */ +const struct SCSISense sense_code_INVALID_FIELD = { + .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 +}; + +/* Illegal request, Invalid field in parameter list */ +const struct SCSISense sense_code_INVALID_PARAM = { + .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00 +}; + +/* Illegal request, Parameter list length error */ +const struct SCSISense sense_code_INVALID_PARAM_LEN = { + .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00 +}; + +/* Illegal request, LUN not supported */ +const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { + .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 +}; + +/* Illegal request, Saving parameters not supported */ +const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { + .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 +}; + +/* Illegal request, Incompatible medium installed */ +const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { + .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 +}; + +/* Illegal request, medium removal prevented */ +const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { + .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02 +}; + +/* Illegal request, Invalid Transfer Tag */ +const struct SCSISense sense_code_INVALID_TAG = { + .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 +}; + +/* Command aborted, I/O process terminated */ +const struct SCSISense sense_code_IO_ERROR = { + .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 +}; + +/* Command aborted, I_T Nexus loss occurred */ +const struct SCSISense sense_code_I_T_NEXUS_LOSS = { + .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 +}; + +/* Command aborted, Logical Unit failure */ +const struct SCSISense sense_code_LUN_FAILURE = { + .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 +}; + +/* Command aborted, Overlapped Commands Attempted */ +const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { + .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 +}; + +/* Unit attention, Capacity data has changed */ +const struct SCSISense sense_code_CAPACITY_CHANGED = { + .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 +}; + +/* Unit attention, Power on, reset or bus device reset occurred */ +const struct SCSISense sense_code_RESET = { + .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 +}; + +/* Unit attention, No medium */ +const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { + .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 +}; + +/* Unit attention, Medium may have changed */ +const struct SCSISense sense_code_MEDIUM_CHANGED = { + .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 +}; + +/* Unit attention, Reported LUNs data has changed */ +const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { + .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e +}; + +/* Unit attention, Device internal reset */ +const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { + .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 +}; + +/* Data Protection, Write Protected */ +const struct SCSISense sense_code_WRITE_PROTECTED = { + .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00 +}; + +/* Data Protection, Space Allocation Failed Write Protect */ +const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { + .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07 +}; + +/* + * scsi_convert_sense + * + * Convert between fixed and descriptor sense buffers + */ +int scsi_convert_sense(uint8_t *in_buf, int in_len, + uint8_t *buf, int len, bool fixed) +{ + bool fixed_in; + SCSISense sense; + if (!fixed && len < 8) { + return 0; + } + + if (in_len == 0) { + sense.key = NO_SENSE; + sense.asc = 0; + sense.ascq = 0; + } else { + fixed_in = (in_buf[0] & 2) == 0; + + if (fixed == fixed_in) { + memcpy(buf, in_buf, MIN(len, in_len)); + return MIN(len, in_len); + } + + if (fixed_in) { + sense.key = in_buf[2]; + sense.asc = in_buf[12]; + sense.ascq = in_buf[13]; + } else { + sense.key = in_buf[1]; + sense.asc = in_buf[2]; + sense.ascq = in_buf[3]; + } + } + + memset(buf, 0, len); + if (fixed) { + /* Return fixed format sense buffer */ + buf[0] = 0x70; + buf[2] = sense.key; + buf[7] = 10; + buf[12] = sense.asc; + buf[13] = sense.ascq; + return MIN(len, SCSI_SENSE_LEN); + } else { + /* Return descriptor format sense buffer */ + buf[0] = 0x72; + buf[1] = sense.key; + buf[2] = sense.asc; + buf[3] = sense.ascq; + return 8; + } +} + +int scsi_sense_to_errno(int key, int asc, int ascq) +{ + switch (key) { + case 0x00: /* NO SENSE */ + case 0x01: /* RECOVERED ERROR */ + case 0x06: /* UNIT ATTENTION */ + /* These sense keys are not errors */ + return 0; + case 0x0b: /* COMMAND ABORTED */ + return ECANCELED; + case 0x02: /* NOT READY */ + case 0x05: /* ILLEGAL REQUEST */ + case 0x07: /* DATA PROTECTION */ + /* Parse ASCQ */ + break; + default: + return EIO; + } + switch ((asc << 8) | ascq) { + case 0x1a00: /* PARAMETER LIST LENGTH ERROR */ + case 0x2000: /* INVALID OPERATION CODE */ + case 0x2400: /* INVALID FIELD IN CDB */ + case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ + return EINVAL; + case 0x2100: /* LBA OUT OF RANGE */ + case 0x2707: /* SPACE ALLOC FAILED */ + return ENOSPC; + case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ + return ENOTSUP; + case 0x3a00: /* MEDIUM NOT PRESENT */ + case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */ + case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */ + return ENOMEDIUM; + case 0x2700: /* WRITE PROTECTED */ + return EACCES; + case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */ + return EAGAIN; + case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */ + return ENOTCONN; + default: + return EIO; + } +} + +int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size) +{ + int key, asc, ascq; + if (sense_size < 1) { + return EIO; + } + switch (sense[0]) { + case 0x70: /* Fixed format sense data. */ + if (sense_size < 14) { + return EIO; + } + key = sense[2] & 0xF; + asc = sense[12]; + ascq = sense[13]; + break; + case 0x72: /* Descriptor format sense data. */ + if (sense_size < 4) { + return EIO; + } + key = sense[1] & 0xF; + asc = sense[2]; + ascq = sense[3]; + break; + default: + return EIO; + break; + } + return scsi_sense_to_errno(key, asc, ascq); +} + +const char *scsi_command_name(uint8_t cmd) +{ + static const char *names[] = { + [ TEST_UNIT_READY ] = "TEST_UNIT_READY", + [ REWIND ] = "REWIND", + [ REQUEST_SENSE ] = "REQUEST_SENSE", + [ FORMAT_UNIT ] = "FORMAT_UNIT", + [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS", + [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS", + /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */ + [ READ_6 ] = "READ_6", + [ WRITE_6 ] = "WRITE_6", + [ SET_CAPACITY ] = "SET_CAPACITY", + [ READ_REVERSE ] = "READ_REVERSE", + [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", + [ SPACE ] = "SPACE", + [ INQUIRY ] = "INQUIRY", + [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA", + [ MAINTENANCE_IN ] = "MAINTENANCE_IN", + [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT", + [ MODE_SELECT ] = "MODE_SELECT", + [ RESERVE ] = "RESERVE", + [ RELEASE ] = "RELEASE", + [ COPY ] = "COPY", + [ ERASE ] = "ERASE", + [ MODE_SENSE ] = "MODE_SENSE", + [ START_STOP ] = "START_STOP/LOAD_UNLOAD", + /* LOAD_UNLOAD and START_STOP use the same operation code */ + [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC", + [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC", + [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL", + [ READ_CAPACITY_10 ] = "READ_CAPACITY_10", + [ READ_10 ] = "READ_10", + [ WRITE_10 ] = "WRITE_10", + [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT", + /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */ + [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10", + [ VERIFY_10 ] = "VERIFY_10", + [ SEARCH_HIGH ] = "SEARCH_HIGH", + [ SEARCH_EQUAL ] = "SEARCH_EQUAL", + [ SEARCH_LOW ] = "SEARCH_LOW", + [ SET_LIMITS ] = "SET_LIMITS", + [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION", + /* READ_POSITION and PRE_FETCH use the same operation code */ + [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", + [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", + [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE", + /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */ + [ MEDIUM_SCAN ] = "MEDIUM_SCAN", + [ COMPARE ] = "COMPARE", + [ COPY_VERIFY ] = "COPY_VERIFY", + [ WRITE_BUFFER ] = "WRITE_BUFFER", + [ READ_BUFFER ] = "READ_BUFFER", + [ UPDATE_BLOCK ] = "UPDATE_BLOCK", + [ READ_LONG_10 ] = "READ_LONG_10", + [ WRITE_LONG_10 ] = "WRITE_LONG_10", + [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION", + [ WRITE_SAME_10 ] = "WRITE_SAME_10", + [ UNMAP ] = "UNMAP", + [ READ_TOC ] = "READ_TOC", + [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", + [ SANITIZE ] = "SANITIZE", + [ GET_CONFIGURATION ] = "GET_CONFIGURATION", + [ LOG_SELECT ] = "LOG_SELECT", + [ LOG_SENSE ] = "LOG_SENSE", + [ MODE_SELECT_10 ] = "MODE_SELECT_10", + [ RESERVE_10 ] = "RESERVE_10", + [ RELEASE_10 ] = "RELEASE_10", + [ MODE_SENSE_10 ] = "MODE_SENSE_10", + [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN", + [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT", + [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16", + [ EXTENDED_COPY ] = "EXTENDED_COPY", + [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16", + [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN", + [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT", + [ READ_16 ] = "READ_16", + [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE", + [ WRITE_16 ] = "WRITE_16", + [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", + [ VERIFY_16 ] = "VERIFY_16", + [ PRE_FETCH_16 ] = "PRE_FETCH_16", + [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", + /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ + [ LOCATE_16 ] = "LOCATE_16", + [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16", + /* ERASE_16 and WRITE_SAME_16 use the same operation code */ + [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", + [ WRITE_LONG_16 ] = "WRITE_LONG_16", + [ REPORT_LUNS ] = "REPORT_LUNS", + [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12", + [ MOVE_MEDIUM ] = "MOVE_MEDIUM", + [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM", + [ READ_12 ] = "READ_12", + [ WRITE_12 ] = "WRITE_12", + [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE", + /* ERASE_12 and GET_PERFORMANCE use the same operation code */ + [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12", + [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", + [ VERIFY_12 ] = "VERIFY_12", + [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12", + [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", + [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", + [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", + [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING", + /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ + [ READ_CD ] = "READ_CD", + [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12", + [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE", + [ RESERVE_TRACK ] = "RESERVE_TRACK", + [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET", + [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE", + [ SET_CD_SPEED ] = "SET_CD_SPEED", + [ SET_READ_AHEAD ] = "SET_READ_AHEAD", + [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE", + [ MECHANISM_STATUS ] = "MECHANISM_STATUS", + [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION", + [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION", + }; + + if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) { + return "*UNKNOWN*"; + } + return names[cmd]; +} + +#ifdef CONFIG_LINUX +int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, + SCSISense *sense) +{ + if (errno_value != 0) { + switch (errno_value) { + case EDOM: + return TASK_SET_FULL; + case ENOMEM: + *sense = SENSE_CODE(TARGET_FAILURE); + return CHECK_CONDITION; + default: + *sense = SENSE_CODE(IO_ERROR); + return CHECK_CONDITION; + } + } else { + if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT || + io_hdr->host_status == SG_ERR_DID_BUS_BUSY || + io_hdr->host_status == SG_ERR_DID_TIME_OUT || + (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) { + return BUSY; + } else if (io_hdr->host_status) { + *sense = SENSE_CODE(I_T_NEXUS_LOSS); + return CHECK_CONDITION; + } else if (io_hdr->status) { + return io_hdr->status; + } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { + return CHECK_CONDITION; + } else { + return GOOD; + } + } +} +#endif diff --git a/target/i386/arch_dump.c b/target/i386/arch_dump.c index e682904052..35b55fc200 100644 --- a/target/i386/arch_dump.c +++ b/target/i386/arch_dump.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "sysemu/dump.h" #include "elf.h" #include "sysemu/memory_mapping.h" diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index 647cff2829..271cb5e41b 100644 --- a/target/i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "sysemu/memory_mapping.h" /* PAE Paging or IA-32e Paging */ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index d0000e40ae..0aa28fc775 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1763,12 +1763,12 @@ static void report_unavailable_features(FeatureWord w, uint32_t mask) if ((1UL << i) & mask) { const char *reg = get_register_name_32(f->cpuid_reg); assert(reg); - fprintf(stderr, "warning: %s doesn't support requested feature: " - "CPUID.%02XH:%s%s%s [bit %d]\n", - kvm_enabled() ? "host" : "TCG", - f->cpuid_eax, reg, - f->feat_names[i] ? "." : "", - f->feat_names[i] ? f->feat_names[i] : "", i); + warn_report("%s doesn't support requested feature: " + "CPUID.%02XH:%s%s%s [bit %d]", + kvm_enabled() ? "host" : "TCG", + f->cpuid_eax, reg, + f->feat_names[i] ? "." : "", + f->feat_names[i] ? f->feat_names[i] : "", i); } } } @@ -3931,12 +3931,12 @@ static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) CPUX86State *env = &cpu->env; GuestPanicInformation *panic_info = NULL; - if (env->features[FEAT_HYPERV_EDX] & HV_X64_GUEST_CRASH_MSR_AVAILABLE) { + if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) { panic_info = g_malloc0(sizeof(GuestPanicInformation)); panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V; - assert(HV_X64_MSR_CRASH_PARAMS >= 5); + assert(HV_CRASH_PARAMS >= 5); panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0]; panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1]; panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2]; @@ -4142,6 +4142,20 @@ static Property x86_cpu_properties[] = { false), DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true), DEFINE_PROP_BOOL("tcg-cpuid", X86CPU, expose_tcg, true), + + /* + * From "Requirements for Implementing the Microsoft + * Hypervisor Interface": + * https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs + * + * "Starting with Windows Server 2012 and Windows 8, if + * CPUID.40000005.EAX contains a value of -1, Windows assumes that + * the hypervisor imposes no specific limit to the number of VPs. + * In this case, Windows Server 2012 guest VMs may use more than + * 64 VPs, up to the maximum supported number of processors applicable + * to the specific Windows version being used." + */ + DEFINE_PROP_INT32("x-hv-max-vps", X86CPU, hv_max_vps, -1), DEFINE_PROP_END_OF_LIST() }; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 4035a11613..b086b1528b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -22,7 +22,7 @@ #include "qemu-common.h" #include "cpu-qom.h" -#include "standard-headers/asm-x86/hyperv.h" +#include "hyperv-proto.h" #ifdef TARGET_X86_64 #define TARGET_LONG_BITS 64 @@ -1095,15 +1095,15 @@ typedef struct CPUX86State { uint64_t msr_hv_guest_os_id; uint64_t msr_hv_vapic; uint64_t msr_hv_tsc; - uint64_t msr_hv_crash_params[HV_X64_MSR_CRASH_PARAMS]; + uint64_t msr_hv_crash_params[HV_CRASH_PARAMS]; uint64_t msr_hv_runtime; uint64_t msr_hv_synic_control; uint64_t msr_hv_synic_version; uint64_t msr_hv_synic_evt_page; uint64_t msr_hv_synic_msg_page; - uint64_t msr_hv_synic_sint[HV_SYNIC_SINT_COUNT]; - uint64_t msr_hv_stimer_config[HV_SYNIC_STIMER_COUNT]; - uint64_t msr_hv_stimer_count[HV_SYNIC_STIMER_COUNT]; + uint64_t msr_hv_synic_sint[HV_SINT_COUNT]; + uint64_t msr_hv_stimer_config[HV_STIMER_COUNT]; + uint64_t msr_hv_stimer_count[HV_STIMER_COUNT]; /* exception/interrupt handling */ int error_code; @@ -1282,6 +1282,8 @@ struct X86CPU { int32_t socket_id; int32_t core_id; int32_t thread_id; + + int32_t hv_max_vps; }; static inline X86CPU *x86_env_get_cpu(CPUX86State *env) diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c index af090343f3..27a0d214f2 100644 --- a/target/i386/hax-mem.c +++ b/target/i386/hax-mem.c @@ -12,6 +12,7 @@ #include "cpu.h" #include "exec/address-spaces.h" #include "exec/exec-all.h" +#include "qemu/error-report.h" #include "target/i386/hax-i386.h" #include "qemu/queue.h" @@ -178,9 +179,8 @@ static void hax_process_section(MemoryRegionSection *section, uint8_t flags) if (!memory_region_is_ram(mr)) { if (memory_region_is_romd(mr)) { /* HAXM kernel module does not support ROMD yet */ - fprintf(stderr, "%s: Warning: Ignoring ROMD region 0x%016" PRIx64 - "->0x%016" PRIx64 "\n", __func__, start_pa, - start_pa + size); + warn_report("Ignoring ROMD region 0x%016" PRIx64 "->0x%016" PRIx64, + start_pa, start_pa + size); } return; } diff --git a/target/i386/hyperv-proto.h b/target/i386/hyperv-proto.h new file mode 100644 index 0000000000..cb4d7f2b7a --- /dev/null +++ b/target/i386/hyperv-proto.h @@ -0,0 +1,260 @@ +/* + * Definitions for Hyper-V guest/hypervisor interaction + * + * Copyright (C) 2017 Parallels 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. + */ + +#ifndef TARGET_I386_HYPERV_PROTO_H +#define TARGET_I386_HYPERV_PROTO_H + +#include "qemu/bitmap.h" + +#define HV_CPUID_VENDOR_AND_MAX_FUNCTIONS 0x40000000 +#define HV_CPUID_INTERFACE 0x40000001 +#define HV_CPUID_VERSION 0x40000002 +#define HV_CPUID_FEATURES 0x40000003 +#define HV_CPUID_ENLIGHTMENT_INFO 0x40000004 +#define HV_CPUID_IMPLEMENT_LIMITS 0x40000005 +#define HV_CPUID_MIN 0x40000005 +#define HV_CPUID_MAX 0x4000ffff +#define HV_HYPERVISOR_PRESENT_BIT 0x80000000 + +/* + * HV_CPUID_FEATURES.EAX bits + */ +#define HV_VP_RUNTIME_AVAILABLE (1u << 0) +#define HV_TIME_REF_COUNT_AVAILABLE (1u << 1) +#define HV_SYNIC_AVAILABLE (1u << 2) +#define HV_SYNTIMERS_AVAILABLE (1u << 3) +#define HV_APIC_ACCESS_AVAILABLE (1u << 4) +#define HV_HYPERCALL_AVAILABLE (1u << 5) +#define HV_VP_INDEX_AVAILABLE (1u << 6) +#define HV_RESET_AVAILABLE (1u << 7) +#define HV_REFERENCE_TSC_AVAILABLE (1u << 9) +#define HV_ACCESS_FREQUENCY_MSRS (1u << 11) + + +/* + * HV_CPUID_FEATURES.EDX bits + */ +#define HV_MWAIT_AVAILABLE (1u << 0) +#define HV_GUEST_DEBUGGING_AVAILABLE (1u << 1) +#define HV_PERF_MONITOR_AVAILABLE (1u << 2) +#define HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1u << 3) +#define HV_HYPERCALL_PARAMS_XMM_AVAILABLE (1u << 4) +#define HV_GUEST_IDLE_STATE_AVAILABLE (1u << 5) +#define HV_FREQUENCY_MSRS_AVAILABLE (1u << 8) +#define HV_GUEST_CRASH_MSR_AVAILABLE (1u << 10) + +/* + * HV_CPUID_ENLIGHTMENT_INFO.EAX bits + */ +#define HV_AS_SWITCH_RECOMMENDED (1u << 0) +#define HV_LOCAL_TLB_FLUSH_RECOMMENDED (1u << 1) +#define HV_REMOTE_TLB_FLUSH_RECOMMENDED (1u << 2) +#define HV_APIC_ACCESS_RECOMMENDED (1u << 3) +#define HV_SYSTEM_RESET_RECOMMENDED (1u << 4) +#define HV_RELAXED_TIMING_RECOMMENDED (1u << 5) + +/* + * Basic virtualized MSRs + */ +#define HV_X64_MSR_GUEST_OS_ID 0x40000000 +#define HV_X64_MSR_HYPERCALL 0x40000001 +#define HV_X64_MSR_VP_INDEX 0x40000002 +#define HV_X64_MSR_RESET 0x40000003 +#define HV_X64_MSR_VP_RUNTIME 0x40000010 +#define HV_X64_MSR_TIME_REF_COUNT 0x40000020 +#define HV_X64_MSR_REFERENCE_TSC 0x40000021 +#define HV_X64_MSR_TSC_FREQUENCY 0x40000022 +#define HV_X64_MSR_APIC_FREQUENCY 0x40000023 + +/* + * Virtual APIC MSRs + */ +#define HV_X64_MSR_EOI 0x40000070 +#define HV_X64_MSR_ICR 0x40000071 +#define HV_X64_MSR_TPR 0x40000072 +#define HV_X64_MSR_APIC_ASSIST_PAGE 0x40000073 + +/* + * Synthetic interrupt controller MSRs + */ +#define HV_X64_MSR_SCONTROL 0x40000080 +#define HV_X64_MSR_SVERSION 0x40000081 +#define HV_X64_MSR_SIEFP 0x40000082 +#define HV_X64_MSR_SIMP 0x40000083 +#define HV_X64_MSR_EOM 0x40000084 +#define HV_X64_MSR_SINT0 0x40000090 +#define HV_X64_MSR_SINT1 0x40000091 +#define HV_X64_MSR_SINT2 0x40000092 +#define HV_X64_MSR_SINT3 0x40000093 +#define HV_X64_MSR_SINT4 0x40000094 +#define HV_X64_MSR_SINT5 0x40000095 +#define HV_X64_MSR_SINT6 0x40000096 +#define HV_X64_MSR_SINT7 0x40000097 +#define HV_X64_MSR_SINT8 0x40000098 +#define HV_X64_MSR_SINT9 0x40000099 +#define HV_X64_MSR_SINT10 0x4000009A +#define HV_X64_MSR_SINT11 0x4000009B +#define HV_X64_MSR_SINT12 0x4000009C +#define HV_X64_MSR_SINT13 0x4000009D +#define HV_X64_MSR_SINT14 0x4000009E +#define HV_X64_MSR_SINT15 0x4000009F + +/* + * Synthetic timer MSRs + */ +#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0 +#define HV_X64_MSR_STIMER0_COUNT 0x400000B1 +#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2 +#define HV_X64_MSR_STIMER1_COUNT 0x400000B3 +#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4 +#define HV_X64_MSR_STIMER2_COUNT 0x400000B5 +#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6 +#define HV_X64_MSR_STIMER3_COUNT 0x400000B7 + +/* + * Guest crash notification MSRs + */ +#define HV_X64_MSR_CRASH_P0 0x40000100 +#define HV_X64_MSR_CRASH_P1 0x40000101 +#define HV_X64_MSR_CRASH_P2 0x40000102 +#define HV_X64_MSR_CRASH_P3 0x40000103 +#define HV_X64_MSR_CRASH_P4 0x40000104 +#define HV_CRASH_PARAMS (HV_X64_MSR_CRASH_P4 - HV_X64_MSR_CRASH_P0 + 1) +#define HV_X64_MSR_CRASH_CTL 0x40000105 +#define HV_CRASH_CTL_NOTIFY (1ull << 63) + +/* + * Hypercall status code + */ +#define HV_STATUS_SUCCESS 0 +#define HV_STATUS_INVALID_HYPERCALL_CODE 2 +#define HV_STATUS_INVALID_HYPERCALL_INPUT 3 +#define HV_STATUS_INVALID_ALIGNMENT 4 +#define HV_STATUS_INVALID_PARAMETER 5 +#define HV_STATUS_INSUFFICIENT_MEMORY 11 +#define HV_STATUS_INVALID_CONNECTION_ID 18 +#define HV_STATUS_INSUFFICIENT_BUFFERS 19 + +/* + * Hypercall numbers + */ +#define HV_POST_MESSAGE 0x005c +#define HV_SIGNAL_EVENT 0x005d +#define HV_HYPERCALL_FAST (1u << 16) + +/* + * Hypercall MSR bits + */ +#define HV_HYPERCALL_ENABLE (1u << 0) + +/* + * Synthetic interrupt controller definitions + */ +#define HV_SYNIC_VERSION 1 +#define HV_SINT_COUNT 16 +#define HV_SYNIC_ENABLE (1u << 0) +#define HV_SIMP_ENABLE (1u << 0) +#define HV_SIEFP_ENABLE (1u << 0) +#define HV_SINT_MASKED (1u << 16) +#define HV_SINT_AUTO_EOI (1u << 17) +#define HV_SINT_VECTOR_MASK 0xff + +#define HV_STIMER_COUNT 4 + +/* + * Message size + */ +#define HV_MESSAGE_PAYLOAD_SIZE 240 + +/* + * Message types + */ +#define HV_MESSAGE_NONE 0x00000000 +#define HV_MESSAGE_VMBUS 0x00000001 +#define HV_MESSAGE_UNMAPPED_GPA 0x80000000 +#define HV_MESSAGE_GPA_INTERCEPT 0x80000001 +#define HV_MESSAGE_TIMER_EXPIRED 0x80000010 +#define HV_MESSAGE_INVALID_VP_REGISTER_VALUE 0x80000020 +#define HV_MESSAGE_UNRECOVERABLE_EXCEPTION 0x80000021 +#define HV_MESSAGE_UNSUPPORTED_FEATURE 0x80000022 +#define HV_MESSAGE_EVENTLOG_BUFFERCOMPLETE 0x80000040 +#define HV_MESSAGE_X64_IOPORT_INTERCEPT 0x80010000 +#define HV_MESSAGE_X64_MSR_INTERCEPT 0x80010001 +#define HV_MESSAGE_X64_CPUID_INTERCEPT 0x80010002 +#define HV_MESSAGE_X64_EXCEPTION_INTERCEPT 0x80010003 +#define HV_MESSAGE_X64_APIC_EOI 0x80010004 +#define HV_MESSAGE_X64_LEGACY_FP_ERROR 0x80010005 + +/* + * Message flags + */ +#define HV_MESSAGE_FLAG_PENDING 0x1 + +/* + * Event flags number per SINT + */ +#define HV_EVENT_FLAGS_COUNT (256 * 8) + +/* + * Connection id valid bits + */ +#define HV_CONNECTION_ID_MASK 0x00ffffff + +/* + * Input structure for POST_MESSAGE hypercall + */ +struct hyperv_post_message_input { + uint32_t connection_id; + uint32_t _reserved; + uint32_t message_type; + uint32_t payload_size; + uint8_t payload[HV_MESSAGE_PAYLOAD_SIZE]; +}; + +/* + * Input structure for SIGNAL_EVENT hypercall + */ +struct hyperv_signal_event_input { + uint32_t connection_id; + uint16_t flag_number; + uint16_t _reserved_zero; +}; + +/* + * SynIC message structures + */ +struct hyperv_message_header { + uint32_t message_type; + uint8_t payload_size; + uint8_t message_flags; /* HV_MESSAGE_FLAG_XX */ + uint8_t _reserved[2]; + uint64_t sender; +}; + +struct hyperv_message { + struct hyperv_message_header header; + uint8_t payload[HV_MESSAGE_PAYLOAD_SIZE]; +}; + +struct hyperv_message_page { + struct hyperv_message slot[HV_SINT_COUNT]; +}; + +/* + * SynIC event flags structures + */ +struct hyperv_event_flags { + DECLARE_BITMAP(flags, HV_EVENT_FLAGS_COUNT); +}; + +struct hyperv_event_flags_page { + struct hyperv_event_flags slot[HV_SINT_COUNT]; +}; + +#endif diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c index 8545574568..a050c9d2d1 100644 --- a/target/i386/hyperv.c +++ b/target/i386/hyperv.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "hyperv.h" -#include "standard-headers/asm-x86/hyperv.h" +#include "hyperv-proto.h" int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) { @@ -50,8 +50,8 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit) code = exit->u.hcall.input & 0xffff; switch (code) { - case HVCALL_POST_MESSAGE: - case HVCALL_SIGNAL_EVENT: + case HV_POST_MESSAGE: + case HV_SIGNAL_EVENT: default: exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE; return 0; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 6db7783edc..b1e32e95d3 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -27,6 +27,7 @@ #include "sysemu/kvm_int.h" #include "kvm_i386.h" #include "hyperv.h" +#include "hyperv-proto.h" #include "exec/gdbstub.h" #include "qemu/host-utils.h" @@ -40,7 +41,6 @@ #include "hw/i386/x86-iommu.h" #include "exec/ioport.h" -#include "standard-headers/asm-x86/hyperv.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" @@ -89,6 +89,7 @@ static bool has_msr_hv_vpindex; static bool has_msr_hv_runtime; static bool has_msr_hv_synic; static bool has_msr_hv_stimer; +static bool has_msr_hv_frequencies; static bool has_msr_xss; static bool has_msr_architectural_pmu; @@ -611,6 +612,15 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) return 0; } +static bool tsc_is_stable_and_known(CPUX86State *env) +{ + if (!env->tsc_khz) { + return false; + } + return (env->features[FEAT_8000_0007_EDX] & CPUID_APM_INVTSC) + || env->user_tsc_khz; +} + static int hyperv_handle_properties(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); @@ -622,29 +632,34 @@ static int hyperv_handle_properties(CPUState *cs) } if (cpu->hyperv_relaxed_timing) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE; } if (cpu->hyperv_vapic) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_APIC_ACCESS_AVAILABLE; } if (cpu->hyperv_time) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_HYPERCALL_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; - env->features[FEAT_HYPERV_EAX] |= 0x200; + env->features[FEAT_HYPERV_EAX] |= HV_HYPERCALL_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_TIME_REF_COUNT_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_REFERENCE_TSC_AVAILABLE; + + if (has_msr_hv_frequencies && tsc_is_stable_and_known(env)) { + env->features[FEAT_HYPERV_EAX] |= HV_ACCESS_FREQUENCY_MSRS; + env->features[FEAT_HYPERV_EDX] |= HV_FREQUENCY_MSRS_AVAILABLE; + } } if (cpu->hyperv_crash && has_msr_hv_crash) { - env->features[FEAT_HYPERV_EDX] |= HV_X64_GUEST_CRASH_MSR_AVAILABLE; + env->features[FEAT_HYPERV_EDX] |= HV_GUEST_CRASH_MSR_AVAILABLE; } - env->features[FEAT_HYPERV_EDX] |= HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE; + env->features[FEAT_HYPERV_EDX] |= HV_CPU_DYNAMIC_PARTITIONING_AVAILABLE; if (cpu->hyperv_reset && has_msr_hv_reset) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_RESET_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_RESET_AVAILABLE; } if (cpu->hyperv_vpindex && has_msr_hv_vpindex) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_INDEX_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_VP_INDEX_AVAILABLE; } if (cpu->hyperv_runtime && has_msr_hv_runtime) { - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_VP_RUNTIME_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_VP_RUNTIME_AVAILABLE; } if (cpu->hyperv_synic) { int sint; @@ -655,10 +670,10 @@ static int hyperv_handle_properties(CPUState *cs) return -ENOSYS; } - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNIC_AVAILABLE; - env->msr_hv_synic_version = HV_SYNIC_VERSION_1; + env->features[FEAT_HYPERV_EAX] |= HV_SYNIC_AVAILABLE; + env->msr_hv_synic_version = HV_SYNIC_VERSION; for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { - env->msr_hv_synic_sint[sint] = HV_SYNIC_SINT_MASKED; + env->msr_hv_synic_sint[sint] = HV_SINT_MASKED; } } if (cpu->hyperv_stimer) { @@ -666,7 +681,7 @@ static int hyperv_handle_properties(CPUState *cs) fprintf(stderr, "Hyper-V timers aren't supported by kernel\n"); return -ENOSYS; } - env->features[FEAT_HYPERV_EAX] |= HV_X64_MSR_SYNTIMER_AVAILABLE; + env->features[FEAT_HYPERV_EAX] |= HV_SYNTIMERS_AVAILABLE; } return 0; } @@ -695,10 +710,29 @@ int kvm_arch_init_vcpu(CPUState *cs) cpuid_i = 0; + r = kvm_arch_set_tsc_khz(cs); + if (r < 0) { + goto fail; + } + + /* vcpu's TSC frequency is either specified by user, or following + * the value used by KVM if the former is not present. In the + * latter case, we query it from KVM and record in env->tsc_khz, + * so that vcpu's TSC frequency can be migrated later via this field. + */ + if (!env->tsc_khz) { + r = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? + kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : + -ENOTSUP; + if (r > 0) { + env->tsc_khz = r; + } + } + /* Paravirtualization CPUIDs */ if (hyperv_enabled(cpu)) { c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS; + c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS; if (!cpu->hyperv_vendor_id) { memcpy(signature, "Microsoft Hv", 12); } else { @@ -711,13 +745,13 @@ int kvm_arch_init_vcpu(CPUState *cs) memset(signature, 0, 12); memcpy(signature, cpu->hyperv_vendor_id, len); } - c->eax = HYPERV_CPUID_MIN; + c->eax = HV_CPUID_MIN; c->ebx = signature[0]; c->ecx = signature[1]; c->edx = signature[2]; c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_INTERFACE; + c->function = HV_CPUID_INTERFACE; memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12); c->eax = signature[0]; c->ebx = 0; @@ -725,12 +759,12 @@ int kvm_arch_init_vcpu(CPUState *cs) c->edx = 0; c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_VERSION; + c->function = HV_CPUID_VERSION; c->eax = 0x00001bbc; c->ebx = 0x00060001; c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_FEATURES; + c->function = HV_CPUID_FEATURES; r = hyperv_handle_properties(cs); if (r) { return r; @@ -740,18 +774,19 @@ int kvm_arch_init_vcpu(CPUState *cs) c->edx = env->features[FEAT_HYPERV_EDX]; c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; + c->function = HV_CPUID_ENLIGHTMENT_INFO; if (cpu->hyperv_relaxed_timing) { - c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED; + c->eax |= HV_RELAXED_TIMING_RECOMMENDED; } if (cpu->hyperv_vapic) { - c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED; + c->eax |= HV_APIC_ACCESS_RECOMMENDED; } c->ebx = cpu->hyperv_spinlock_attempts; c = &cpuid_data.entries[cpuid_i++]; - c->function = HYPERV_CPUID_IMPLEMENT_LIMITS; - c->eax = 0x40; + c->function = HV_CPUID_IMPLEMENT_LIMITS; + + c->eax = cpu->hv_max_vps; c->ebx = 0x40; kvm_base = KVM_CPUID_SIGNATURE_NEXT; @@ -961,34 +996,13 @@ int kvm_arch_init_vcpu(CPUState *cs) } } - r = kvm_arch_set_tsc_khz(cs); - if (r < 0) { - goto fail; - } - - /* vcpu's TSC frequency is either specified by user, or following - * the value used by KVM if the former is not present. In the - * latter case, we query it from KVM and record in env->tsc_khz, - * so that vcpu's TSC frequency can be migrated later via this field. - */ - if (!env->tsc_khz) { - r = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ? - kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : - -ENOTSUP; - if (r > 0) { - env->tsc_khz = r; - } - } - if (cpu->vmware_cpuid_freq /* Guests depend on 0x40000000 to detect this feature, so only expose * it if KVM exposes leaf 0x40000000. (Conflicts with Hyper-V) */ && cpu->expose_kvm && kvm_base == KVM_CPUID_SIGNATURE /* TSC clock must be stable and known for this feature. */ - && ((env->features[FEAT_8000_0007_EDX] & CPUID_APM_INVTSC) - || env->user_tsc_khz != 0) - && env->tsc_khz != 0) { + && tsc_is_stable_and_known(env)) { c = &cpuid_data.entries[cpuid_i++]; c->function = KVM_CPUID_SIGNATURE | 0x10; @@ -1081,65 +1095,55 @@ static int kvm_get_supported_msrs(KVMState *s) int i; for (i = 0; i < kvm_msr_list->nmsrs; i++) { - if (kvm_msr_list->indices[i] == MSR_STAR) { + switch (kvm_msr_list->indices[i]) { + case MSR_STAR: has_msr_star = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_VM_HSAVE_PA) { + break; + case MSR_VM_HSAVE_PA: has_msr_hsave_pa = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_TSC_AUX) { + break; + case MSR_TSC_AUX: has_msr_tsc_aux = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_TSC_ADJUST) { + break; + case MSR_TSC_ADJUST: has_msr_tsc_adjust = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_IA32_TSCDEADLINE) { + break; + case MSR_IA32_TSCDEADLINE: has_msr_tsc_deadline = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_IA32_SMBASE) { + break; + case MSR_IA32_SMBASE: has_msr_smbase = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_IA32_MISC_ENABLE) { + break; + case MSR_IA32_MISC_ENABLE: has_msr_misc_enable = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_IA32_BNDCFGS) { + break; + case MSR_IA32_BNDCFGS: has_msr_bndcfgs = true; - continue; - } - if (kvm_msr_list->indices[i] == MSR_IA32_XSS) { + break; + case MSR_IA32_XSS: has_msr_xss = true; - continue; - } - if (kvm_msr_list->indices[i] == HV_X64_MSR_CRASH_CTL) { + break;; + case HV_X64_MSR_CRASH_CTL: has_msr_hv_crash = true; - continue; - } - if (kvm_msr_list->indices[i] == HV_X64_MSR_RESET) { + break; + case HV_X64_MSR_RESET: has_msr_hv_reset = true; - continue; - } - if (kvm_msr_list->indices[i] == HV_X64_MSR_VP_INDEX) { + break; + case HV_X64_MSR_VP_INDEX: has_msr_hv_vpindex = true; - continue; - } - if (kvm_msr_list->indices[i] == HV_X64_MSR_VP_RUNTIME) { + break; + case HV_X64_MSR_VP_RUNTIME: has_msr_hv_runtime = true; - continue; - } - if (kvm_msr_list->indices[i] == HV_X64_MSR_SCONTROL) { + break; + case HV_X64_MSR_SCONTROL: has_msr_hv_synic = true; - continue; - } - if (kvm_msr_list->indices[i] == HV_X64_MSR_STIMER0_CONFIG) { + break; + case HV_X64_MSR_STIMER0_CONFIG: has_msr_hv_stimer = true; - continue; + break; + case HV_X64_MSR_TSC_FREQUENCY: + has_msr_hv_frequencies = true; + break; } } } @@ -1690,12 +1694,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level) if (has_msr_hv_crash) { int j; - for (j = 0; j < HV_X64_MSR_CRASH_PARAMS; j++) + for (j = 0; j < HV_CRASH_PARAMS; j++) kvm_msr_entry_add(cpu, HV_X64_MSR_CRASH_P0 + j, env->msr_hv_crash_params[j]); - kvm_msr_entry_add(cpu, HV_X64_MSR_CRASH_CTL, - HV_X64_MSR_CRASH_CTL_NOTIFY); + kvm_msr_entry_add(cpu, HV_X64_MSR_CRASH_CTL, HV_CRASH_CTL_NOTIFY); } if (has_msr_hv_runtime) { kvm_msr_entry_add(cpu, HV_X64_MSR_VP_RUNTIME, env->msr_hv_runtime); @@ -2059,7 +2062,7 @@ static int kvm_get_msrs(X86CPU *cpu) if (has_msr_hv_crash) { int j; - for (j = 0; j < HV_X64_MSR_CRASH_PARAMS; j++) { + for (j = 0; j < HV_CRASH_PARAMS; j++) { kvm_msr_entry_add(cpu, HV_X64_MSR_CRASH_P0 + j, 0); } } diff --git a/target/i386/machine.c b/target/i386/machine.c index eab33725a3..29cc58eda9 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -587,7 +587,7 @@ static bool hyperv_crash_enable_needed(void *opaque) CPUX86State *env = &cpu->env; int i; - for (i = 0; i < HV_X64_MSR_CRASH_PARAMS; i++) { + for (i = 0; i < HV_CRASH_PARAMS; i++) { if (env->msr_hv_crash_params[i]) { return true; } @@ -601,8 +601,7 @@ static const VMStateDescription vmstate_msr_hyperv_crash = { .minimum_version_id = 1, .needed = hyperv_crash_enable_needed, .fields = (VMStateField[]) { - VMSTATE_UINT64_ARRAY(env.msr_hv_crash_params, - X86CPU, HV_X64_MSR_CRASH_PARAMS), + VMSTATE_UINT64_ARRAY(env.msr_hv_crash_params, X86CPU, HV_CRASH_PARAMS), VMSTATE_END_OF_LIST() } }; @@ -660,8 +659,7 @@ static const VMStateDescription vmstate_msr_hyperv_synic = { VMSTATE_UINT64(env.msr_hv_synic_control, X86CPU), VMSTATE_UINT64(env.msr_hv_synic_evt_page, X86CPU), VMSTATE_UINT64(env.msr_hv_synic_msg_page, X86CPU), - VMSTATE_UINT64_ARRAY(env.msr_hv_synic_sint, X86CPU, - HV_SYNIC_SINT_COUNT), + VMSTATE_UINT64_ARRAY(env.msr_hv_synic_sint, X86CPU, HV_SINT_COUNT), VMSTATE_END_OF_LIST() } }; @@ -686,10 +684,9 @@ static const VMStateDescription vmstate_msr_hyperv_stimer = { .minimum_version_id = 1, .needed = hyperv_stimer_enable_needed, .fields = (VMStateField[]) { - VMSTATE_UINT64_ARRAY(env.msr_hv_stimer_config, - X86CPU, HV_SYNIC_STIMER_COUNT), - VMSTATE_UINT64_ARRAY(env.msr_hv_stimer_count, - X86CPU, HV_SYNIC_STIMER_COUNT), + VMSTATE_UINT64_ARRAY(env.msr_hv_stimer_config, X86CPU, + HV_STIMER_COUNT), + VMSTATE_UINT64_ARRAY(env.msr_hv_stimer_count, X86CPU, HV_STIMER_COUNT), VMSTATE_END_OF_LIST() } }; diff --git a/target/i386/monitor.c b/target/i386/monitor.c index fe7d57b6aa..75e155ffb1 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -447,7 +447,7 @@ static void mem_info_la57(Monitor *mon, CPUArchState *env) start = -1; for (l0 = 0; l0 < 512; l0++) { cpu_physical_memory_read(pml5_addr + l0 * 8, &pml5e, 8); - pml4e = le64_to_cpu(pml5e); + pml5e = le64_to_cpu(pml5e); end = l0 << 48; if (!(pml5e & PG_PRESENT_MASK)) { prot = 0; @@ -480,7 +480,7 @@ static void mem_info_la57(Monitor *mon, CPUArchState *env) if (pdpe & PG_PSE_MASK) { prot = pdpe & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); - prot &= pml4e; + prot &= pml5e & pml4e; mem_print(mon, &start, &last_prot, end, prot); continue; } @@ -499,7 +499,7 @@ static void mem_info_la57(Monitor *mon, CPUArchState *env) if (pde & PG_PSE_MASK) { prot = pde & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); - prot &= pml4e & pdpe; + prot &= pml5e & pml4e & pdpe; mem_print(mon, &start, &last_prot, end, prot); continue; } @@ -513,7 +513,7 @@ static void mem_info_la57(Monitor *mon, CPUArchState *env) if (pte & PG_PRESENT_MASK) { prot = pte & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK); - prot &= pml4e & pdpe & pde; + prot &= pml5e & pml4e & pdpe & pde; } else { prot = 0; } diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 16509d0a74..ed05989768 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -1617,18 +1617,18 @@ void glue(helper_ptest, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) #define SSE_HELPER_F(name, elem, num, F) \ void glue(name, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) \ { \ - d->elem(0) = F(0); \ - d->elem(1) = F(1); \ if (num > 2) { \ - d->elem(2) = F(2); \ - d->elem(3) = F(3); \ if (num > 4) { \ - d->elem(4) = F(4); \ - d->elem(5) = F(5); \ - d->elem(6) = F(6); \ d->elem(7) = F(7); \ + d->elem(6) = F(6); \ + d->elem(5) = F(5); \ + d->elem(4) = F(4); \ } \ + d->elem(3) = F(3); \ + d->elem(2) = F(2); \ } \ + d->elem(1) = F(1); \ + d->elem(0) = F(0); \ } SSE_HELPER_F(helper_pmovsxbw, W, 8, (int8_t) s->B) @@ -1655,14 +1655,17 @@ SSE_HELPER_Q(helper_pcmpeqq, FCMPEQQ) void glue(helper_packusdw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) { - d->W(0) = satuw((int32_t) d->L(0)); - d->W(1) = satuw((int32_t) d->L(1)); - d->W(2) = satuw((int32_t) d->L(2)); - d->W(3) = satuw((int32_t) d->L(3)); - d->W(4) = satuw((int32_t) s->L(0)); - d->W(5) = satuw((int32_t) s->L(1)); - d->W(6) = satuw((int32_t) s->L(2)); - d->W(7) = satuw((int32_t) s->L(3)); + Reg r; + + r.W(0) = satuw((int32_t) d->L(0)); + r.W(1) = satuw((int32_t) d->L(1)); + r.W(2) = satuw((int32_t) d->L(2)); + r.W(3) = satuw((int32_t) d->L(3)); + r.W(4) = satuw((int32_t) s->L(0)); + r.W(5) = satuw((int32_t) s->L(1)); + r.W(6) = satuw((int32_t) s->L(2)); + r.W(7) = satuw((int32_t) s->L(3)); + *d = r; } #define FMINSB(d, s) MIN((int8_t)d, (int8_t)s) @@ -1707,10 +1710,10 @@ void glue(helper_phminposuw, SUFFIX)(CPUX86State *env, Reg *d, Reg *s) idx = 7; } - d->Q(1) = 0; - d->L(1) = 0; - d->W(1) = idx; d->W(0) = s->W(idx); + d->W(1) = idx; + d->L(1) = 0; + d->Q(1) = 0; } void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, @@ -2037,10 +2040,14 @@ static inline unsigned pcmpxstrx(CPUX86State *env, Reg *d, Reg *s, } break; case 3: - for (j = valids; j >= 0; j--) { + if (validd == -1) { + res = (2 << upper) - 1; + break; + } + for (j = valids - validd; j >= 0; j--) { res <<= 1; v = 1; - for (i = MIN(valids - j, validd); i >= 0; i--) { + for (i = validd; i >= 0; i--) { v &= (pcmp_val(s, ctrl, i + j) == pcmp_val(d, ctrl, i)); } res |= v; diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c index 59e8b5091c..f479239875 100644 --- a/target/i386/svm_helper.c +++ b/target/i386/svm_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" diff --git a/target/i386/translate.c b/target/i386/translate.c index de0c989763..a8986f4c1a 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -4076,10 +4076,11 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask)) goto illegal_op; + s->rip_offset = 1; + if (sse_fn_eppi == SSE_SPECIAL) { ot = mo_64_32(s->dflag); rm = (modrm & 7) | REX_B(s); - s->rip_offset = 1; if (mod != 3) gen_lea_modrm(env, s, modrm); reg = ((modrm >> 3) & 7) | rex_r; diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 3317905e71..3b7b1d962a 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -95,11 +95,11 @@ void kvm_mips_reset_vcpu(MIPSCPU *cpu) CPUMIPSState *env = &cpu->env; if (!kvm_mips_fpu_cap && env->CP0_Config1 & (1 << CP0C1_FP)) { - fprintf(stderr, "Warning: KVM does not support FPU, disabling\n"); + warn_report("KVM does not support FPU, disabling"); env->CP0_Config1 &= ~(1 << CP0C1_FP); } if (!kvm_mips_msa_cap && env->CP0_Config3 & (1 << CP0C3_MSAP)) { - fprintf(stderr, "Warning: KVM does not support MSA, disabling\n"); + warn_report("KVM does not support MSA, disabling"); env->CP0_Config3 &= ~(1 << CP0C3_MSAP); } @@ -526,7 +526,7 @@ static void kvm_mips_update_state(void *opaque, int running, RunState state) if (!cs->vcpu_dirty) { ret = kvm_mips_save_count(cs); if (ret < 0) { - fprintf(stderr, "Failed saving count\n"); + warn_report("Failed saving count"); } } } else { @@ -535,14 +535,14 @@ static void kvm_mips_update_state(void *opaque, int running, RunState state) ret = kvm_mips_put_one_ureg64(cs, KVM_REG_MIPS_COUNT_RESUME, &count_resume); if (ret < 0) { - fprintf(stderr, "Failed setting COUNT_RESUME\n"); + warn_report("Failed setting COUNT_RESUME"); return; } if (!cs->vcpu_dirty) { ret = kvm_mips_restore_count(cs); if (ret < 0) { - fprintf(stderr, "Failed restoring count\n"); + warn_report("Failed restoring count"); } } } diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index 95b9ab6f29..351a65b22f 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "elf.h" -#include "exec/cpu-all.h" #include "sysemu/dump.h" #include "sysemu/kvm.h" diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index c827d1e388..466bf97347 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -9316,14 +9316,13 @@ static void init_ppc_proc(PowerPCCPU *cpu) env->tlb_per_way = env->nb_tlb / env->nb_ways; } if (env->irq_inputs == NULL) { - fprintf(stderr, "WARNING: no internal IRQ controller registered.\n" - " Attempt QEMU to crash very soon !\n"); + warn_report("no internal IRQ controller registered." + " Attempt QEMU to crash very soon !"); } #endif if (env->check_pow == NULL) { - fprintf(stderr, "WARNING: no power management check handler " - "registered.\n" - " Attempt QEMU to crash very soon !\n"); + warn_report("no power management check handler registered." + " Attempt QEMU to crash very soon !"); } } @@ -9877,10 +9876,10 @@ static int ppc_fixup_cpu(PowerPCCPU *cpu) * tree. */ if ((env->insns_flags & ~PPC_TCG_INSNS) || (env->insns_flags2 & ~PPC_TCG_INSNS2)) { - fprintf(stderr, "Warning: Disabling some instructions which are not " - "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")\n", - env->insns_flags & ~PPC_TCG_INSNS, - env->insns_flags2 & ~PPC_TCG_INSNS2); + warn_report("Disabling some instructions which are not " + "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")", + env->insns_flags & ~PPC_TCG_INSNS, + env->insns_flags2 & ~PPC_TCG_INSNS2); } env->insns_flags &= PPC_TCG_INSNS; env->insns_flags2 &= PPC_TCG_INSNS2; diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index 9b0bf92698..6f61ff95af 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -15,7 +15,6 @@ #include "cpu.h" #include "internal.h" #include "elf.h" -#include "exec/cpu-all.h" #include "sysemu/dump.h" diff --git a/target/s390x/cpu-qom.h b/target/s390x/cpu-qom.h index 4e936e7788..2e446fab51 100644 --- a/target/s390x/cpu-qom.h +++ b/target/s390x/cpu-qom.h @@ -21,7 +21,6 @@ #define QEMU_S390_CPU_QOM_H #include "qom/cpu.h" -#include "cpu_models.h" #define TYPE_S390_CPU "s390-cpu" @@ -32,6 +31,9 @@ #define S390_CPU_GET_CLASS(obj) \ OBJECT_GET_CLASS(S390CPUClass, (obj), TYPE_S390_CPU) +typedef struct S390CPUModel S390CPUModel; +typedef struct S390CPUDef S390CPUDef; + /** * S390CPUClass: * @parent_realize: The parent class' realize handler. @@ -52,7 +54,7 @@ typedef struct S390CPUClass { bool is_migration_safe; const char *desc; - int64_t next_cpu_id; + uint32_t next_core_id; DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); @@ -62,5 +64,6 @@ typedef struct S390CPUClass { } S390CPUClass; typedef struct S390CPU S390CPU; +typedef struct CPUS390XState CPUS390XState; #endif diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 74b3e4fd0d..34538c3ab9 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -36,6 +36,7 @@ #include "trace.h" #include "qapi/visitor.h" #include "exec/exec-all.h" +#include "hw/qdev-properties.h" #ifndef CONFIG_USER_ONLY #include "hw/hw.h" #include "sysemu/arch_init.h" @@ -189,34 +190,34 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) } #if !defined(CONFIG_USER_ONLY) - if (cpu->id >= max_cpus) { - error_setg(&err, "Unable to add CPU: %" PRIi64 - ", max allowed: %d", cpu->id, max_cpus - 1); + if (cpu->env.core_id >= max_cpus) { + error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 + ", maximum core-id: %d", cpu->env.core_id, + max_cpus - 1); goto out; } +#else + /* implicitly set for linux-user only */ + cpu->env.core_id = scc->next_core_id; + scc->next_core_id++; #endif - if (cpu_exists(cpu->id)) { - error_setg(&err, "Unable to add CPU: %" PRIi64 - ", it already exists", cpu->id); - goto out; - } - if (cpu->id != scc->next_cpu_id) { - error_setg(&err, "Unable to add CPU: %" PRIi64 - ", The next available id is %" PRIi64, cpu->id, - scc->next_cpu_id); + + if (cpu_exists(cpu->env.core_id)) { + error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 + ", it already exists", cpu->env.core_id); goto out; } + /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */ + cs->cpu_index = env->core_id; cpu_exec_realizefn(cs, &err); if (err != NULL) { goto out; } - scc->next_cpu_id++; #if !defined(CONFIG_USER_ONLY) qemu_register_reset(s390_cpu_machine_reset_cb, cpu); #endif - env->cpu_num = cpu->id; s390_cpu_gdb_init(cs); qemu_init_vcpu(cs); #if !defined(CONFIG_USER_ONLY) @@ -237,45 +238,6 @@ out: error_propagate(errp, err); } -static void s390x_cpu_get_id(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - S390CPU *cpu = S390_CPU(obj); - int64_t value = cpu->id; - - visit_type_int(v, name, &value, errp); -} - -static void s390x_cpu_set_id(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - S390CPU *cpu = S390_CPU(obj); - DeviceState *dev = DEVICE(obj); - const int64_t min = 0; - const int64_t max = UINT32_MAX; - Error *err = NULL; - int64_t value; - - if (dev->realized) { - error_setg(errp, "Attempt to set property '%s' on '%s' after " - "it was realized", name, object_get_typename(obj)); - return; - } - - visit_type_int(v, name, &value, &err); - if (err) { - error_propagate(errp, err); - return; - } - if (value < min || value > max) { - error_setg(errp, "Property %s.%s doesn't take value %" PRId64 - " (minimum: %" PRId64 ", maximum: %" PRId64 ")" , - object_get_typename(obj), name, value, min, max); - return; - } - cpu->id = value; -} - static void s390_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -289,8 +251,6 @@ static void s390_cpu_initfn(Object *obj) cs->env_ptr = env; cs->halted = 1; cs->exception_index = EXCP_HLT; - object_property_add(OBJECT(cpu), "id", "int64_t", s390x_cpu_get_id, - s390x_cpu_set_id, NULL, NULL, NULL); s390_cpu_model_register_props(obj); #if !defined(CONFIG_USER_ONLY) qemu_get_timedate(&tm, 0); @@ -306,13 +266,6 @@ static void s390_cpu_initfn(Object *obj) inited = true; s390x_translate_init(); } - -#if defined(CONFIG_USER_ONLY) - { - S390CPUClass *scc = S390_CPU_GET_CLASS(obj); - cpu->id = scc->next_cpu_id; - } -#endif } static void s390_cpu_finalize(Object *obj) @@ -494,15 +447,21 @@ static gchar *s390_gdb_arch_name(CPUState *cs) return g_strdup("s390:64-bit"); } +static Property s390x_cpu_properties[] = { + DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0), + DEFINE_PROP_END_OF_LIST() +}; + static void s390_cpu_class_init(ObjectClass *oc, void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(scc); DeviceClass *dc = DEVICE_CLASS(oc); - scc->next_cpu_id = 0; scc->parent_realize = dc->realize; dc->realize = s390_cpu_realizefn; + dc->props = s390x_cpu_properties; + dc->user_creatable = true; scc->parent_reset = cc->reset; #if !defined(CONFIG_USER_ONLY) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 0bd97a5670..9b549dc491 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -25,6 +25,7 @@ #include "qemu-common.h" #include "cpu-qom.h" +#include "cpu_models.h" #define TARGET_LONG_BITS 64 @@ -80,7 +81,7 @@ typedef struct MchkQueue { uint16_t type; } MchkQueue; -typedef struct CPUS390XState { +struct CPUS390XState { uint64_t regs[16]; /* GP registers */ /* * The floating point registers are part of the vector registers. @@ -149,7 +150,7 @@ typedef struct CPUS390XState { CPU_COMMON - uint32_t cpu_num; + uint32_t core_id; /* PoP "CPU address", same as cpu_index */ uint64_t cpuid; uint64_t tod_offset; @@ -174,7 +175,7 @@ typedef struct CPUS390XState { /* currently processed sigp order */ uint8_t sigp_order; -} CPUS390XState; +}; static inline CPU_DoubleU *get_freg(CPUS390XState *cs, int nr) { @@ -193,7 +194,6 @@ struct S390CPU { /*< public >*/ CPUS390XState env; - int64_t id; S390CPUModel *model; /* needed for live migration */ void *irqstate; @@ -689,7 +689,7 @@ const char *s390_default_cpu_model_name(void); /* helper.c */ #define cpu_init(cpu_model) cpu_generic_init(TYPE_S390_CPU, cpu_model) -S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp); +S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, Error **errp); /* you can call this signal handler from your SIGBUS and SIGSEGV signal handlers to inform the virtual CPU of exceptions. non zero is returned if the signal was handled by the virtual CPU. */ @@ -721,8 +721,5 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, /* outside of target/s390x/ */ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); -extern void subsystem_reset(void); -int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); -int s390_virtio_hypercall(CPUS390XState *env); #endif diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 18cbf91d9c..5169379db5 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -196,6 +196,9 @@ bool s390_has_feat(S390Feat feat) } } #endif + if (feat == S390_FEAT_ZPCI) { + return true; + } return 0; } return test_bit(feat, cpu->model->features); @@ -270,16 +273,11 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, return last_compatible; } -struct S390PrintCpuListInfo { - FILE *f; - fprintf_function print; -}; - -static void print_cpu_model_list(ObjectClass *klass, void *opaque) +static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) { - struct S390PrintCpuListInfo *info = opaque; - S390CPUClass *scc = S390_CPU_CLASS(klass); - char *name = g_strdup(object_class_get_name(klass)); + CPUListState *s = user_data; + const S390CPUClass *scc = S390_CPU_CLASS((ObjectClass *)data); + char *name = g_strdup(object_class_get_name((ObjectClass *)data)); const char *details = ""; if (scc->is_static) { @@ -290,21 +288,52 @@ static void print_cpu_model_list(ObjectClass *klass, void *opaque) /* strip off the -s390-cpu */ g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0; - (*info->print)(info->f, "s390 %-15s %-35s %s\n", name, scc->desc, - details); + (*s->cpu_fprintf)(s->file, "s390 %-15s %-35s %s\n", name, scc->desc, + details); g_free(name); } +static gint s390_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + const S390CPUClass *cc_a = S390_CPU_CLASS((ObjectClass *)a); + const S390CPUClass *cc_b = S390_CPU_CLASS((ObjectClass *)b); + const char *name_a = object_class_get_name((ObjectClass *)a); + const char *name_b = object_class_get_name((ObjectClass *)b); + + /* move qemu and host to the top of the list, qemu first, host second */ + if (name_a[0] == 'q') { + return -1; + } else if (name_b[0] == 'q') { + return 1; + } else if (name_a[0] == 'h') { + return -1; + } else if (name_b[0] == 'h') { + return 1; + } + + /* keep the same order we have in our table (sorted by release date) */ + if (cc_a->cpu_def != cc_b->cpu_def) { + return cc_a->cpu_def - cc_b->cpu_def; + } + + /* exact same definition - list base model first */ + return cc_a->is_static ? -1 : 1; +} + void s390_cpu_list(FILE *f, fprintf_function print) { - struct S390PrintCpuListInfo info = { - .f = f, - .print = print, + CPUListState s = { + .file = f, + .cpu_fprintf = print, }; S390FeatGroup group; S390Feat feat; + GSList *list; - object_class_foreach(print_cpu_model_list, TYPE_S390_CPU, false, &info); + list = object_class_get_list(TYPE_S390_CPU, false); + list = g_slist_sort(list, s390_cpu_list_compare); + g_slist_foreach(list, s390_print_cpu_model_list_entry, &s); + g_slist_free(list); (*print)(f, "\nRecognized feature flags:\n"); for (feat = 0; feat < S390_FEAT_MAX; feat++) { @@ -915,7 +944,7 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp) cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model); if (tcg_enabled()) { /* basic mode, write the cpu address into the first 4 bit of the ID */ - cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.cpu_num); + cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.core_id); } } diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index c0bee15d7a..4c6dee1871 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -17,7 +17,7 @@ #include "qom/cpu.h" /* static CPU definition */ -typedef struct S390CPUDef { +struct S390CPUDef { const char *name; /* name exposed to the user */ const char *desc; /* description exposed to the user */ uint8_t gen; /* hw generation identification */ @@ -37,10 +37,10 @@ typedef struct S390CPUDef { S390FeatBitmap full_feat; /* used to init full_feat from generated data */ S390FeatInit full_init; -} S390CPUDef; +}; /* CPU model based on a CPU definition */ -typedef struct S390CPUModel { +struct S390CPUModel { const S390CPUDef *def; S390FeatBitmap features; /* values copied from the "host" model, can change during migration */ @@ -48,7 +48,7 @@ typedef struct S390CPUModel { uint32_t cpu_id; /* CPU id */ uint8_t cpu_id_format; /* CPU id format bit */ uint8_t cpu_ver; /* CPU version, usually "ff" for kvm */ -} S390CPUModel; +}; /* * CPU ID diff --git a/target/s390x/diag.c b/target/s390x/diag.c index e6b5e6de37..82a623948d 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -20,6 +20,7 @@ #include "hw/watchdog/wdt_diag288.h" #include "sysemu/cpus.h" #include "hw/s390x/ipl.h" +#include "hw/s390x/s390-virtio-ccw.h" static int modified_clear_reset(S390CPU *cpu) { diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 361f970db3..470cf8f5bc 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -59,8 +59,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr address, { S390CPU *cpu = S390_CPU(cs); - cs->exception_index = EXCP_PGM; - cpu->env.int_pgm_code = PGM_ADDRESSING; + trigger_pgm_exception(&cpu->env, PGM_ADDRESSING, ILEN_AUTO); /* On real machines this value is dropped into LowMem. Since this is userland, simply put this someplace that cpu_loop can find it. */ cpu->env.__excp_addr = address; @@ -251,7 +250,7 @@ static void do_ext_interrupt(CPUS390XState *env) lowcore->ext_params2 = cpu_to_be64(q->param64); lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); - lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64); + lowcore->cpu_addr = cpu_to_be16(env->core_id | VIRTIO_SUBCODE_64); mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); diff --git a/target/s390x/helper.c b/target/s390x/helper.c index ba29504476..97adbcc86d 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -68,53 +68,12 @@ void s390x_cpu_timer(void *opaque) } #endif -S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp) +S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, Error **errp) { - static bool features_parsed; - char *name, *features; - const char *typename; - ObjectClass *oc; - CPUClass *cc; - - name = g_strdup(cpu_model); - features = strchr(name, ','); - if (features) { - features[0] = 0; - features++; - } - - oc = cpu_class_by_name(TYPE_S390_CPU, name); - if (!oc) { - error_setg(errp, "Unknown CPU definition \'%s\'", name); - g_free(name); - return NULL; - } - typename = object_class_get_name(oc); - - if (!features_parsed) { - features_parsed = true; - cc = CPU_CLASS(oc); - cc->parse_features(typename, features, errp); - } - g_free(name); - - if (*errp) { - return NULL; - } - return S390_CPU(CPU(object_new(typename))); -} - -S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp) -{ - S390CPU *cpu; + S390CPU *cpu = S390_CPU(object_new(typename)); Error *err = NULL; - cpu = cpu_s390x_create(cpu_model, &err); - if (err != NULL) { - goto out; - } - - object_property_set_int(OBJECT(cpu), id, "id", &err); + object_property_set_int(OBJECT(cpu), core_id, "core-id", &err); if (err != NULL) { goto out; } diff --git a/target/s390x/internal.h b/target/s390x/internal.h index b4d3583b24..bc8f83129a 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -337,7 +337,6 @@ uint64_t get_psw_mask(CPUS390XState *env); void s390_cpu_recompute_watchpoints(CPUState *cs); void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); -S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp); void do_restart_interrupt(CPUS390XState *env); #ifndef CONFIG_USER_ONLY LowCore *cpu_map_lowcore(CPUS390XState *env); diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index d07763ff2c..720cb1d833 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -48,6 +48,7 @@ #include "hw/s390x/ebcdic.h" #include "exec/memattrs.h" #include "hw/s390x/s390-virtio-ccw.h" +#include "hw/s390x/s390-virtio-hcall.h" #ifndef DEBUG_KVM #define DEBUG_KVM 0 @@ -224,8 +225,8 @@ static void kvm_s390_enable_cmma(void) }; if (mem_path) { - error_report("Warning: CMM will not be enabled because it is not " - "compatible to hugetlbfs."); + warn_report("CMM will not be enabled because it is not " + "compatible with hugetlbfs."); return; } rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); @@ -2423,23 +2424,25 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, uint64_t address, uint32_t data, PCIDevice *dev) { S390PCIBusDevice *pbdev; - uint32_t idx = data >> ZPCI_MSI_VEC_BITS; uint32_t vec = data & ZPCI_MSI_VEC_MASK; - pbdev = s390_pci_find_dev_by_idx(s390_get_phb(), idx); - if (!pbdev) { - DPRINTF("add_msi_route no dev\n"); + if (!dev) { + DPRINTF("add_msi_route no pci device\n"); return -ENODEV; } - pbdev->routes.adapter.ind_offset = vec; + pbdev = s390_pci_find_dev_by_target(s390_get_phb(), DEVICE(dev)->id); + if (!pbdev) { + DPRINTF("add_msi_route no zpci device\n"); + return -ENODEV; + } route->type = KVM_IRQ_ROUTING_S390_ADAPTER; route->flags = 0; route->u.adapter.summary_addr = pbdev->routes.adapter.summary_addr; route->u.adapter.ind_addr = pbdev->routes.adapter.ind_addr; route->u.adapter.summary_offset = pbdev->routes.adapter.summary_offset; - route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset; + route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset + vec; route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id; return 0; } diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 50cc046ca2..293fc8428a 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -34,6 +34,8 @@ #include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "hw/s390x/ebcdic.h" +#include "hw/s390x/s390-virtio-hcall.h" +#include "hw/s390x/sclp.h" #endif /* #define DEBUG_HELPER */ @@ -230,7 +232,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, /* XXX make different for different CPUs? */ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_addr, env->core_id); cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); } else if ((sel1 == 2) && (sel2 == 2)) { /* Basic Machine CPUs */ @@ -258,7 +260,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, /* XXX make different for different CPUs? */ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_addr, env->core_id); stw_p(&sysib.cpu_id, 0); cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); } else if ((sel1 == 2) && (sel2 == 2)) { @@ -445,14 +447,17 @@ void HELPER(chsc)(CPUS390XState *env, uint64_t inst) #ifndef CONFIG_USER_ONLY void HELPER(per_check_exception)(CPUS390XState *env) { - CPUState *cs = CPU(s390_env_get_cpu(env)); + uint32_t ilen; if (env->per_perc_atmid) { - env->int_pgm_code = PGM_PER; - env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address)); - - cs->exception_index = EXCP_PGM; - cpu_loop_exit(cs); + /* + * FIXME: ILEN_AUTO is most probably the right thing to use. ilen + * always has to match the instruction referenced in the PSW. E.g. + * if a PER interrupt is triggered via EXECUTE, we have to use ilen + * of EXECUTE, while per_address contains the target of EXECUTE. + */ + ilen = get_ilen(cpu_ldub_code(env, env->per_address)); + program_interrupt(env, PGM_PER, ilen); } } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 909b12818d..5abd34fb34 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3823,10 +3823,7 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) static ExitStatus op_stap(DisasContext *s, DisasOps *o) { check_privileged(s); - /* ??? Surely cpu address != cpu number. In any case the previous - version of this stored more than the required half-word, so it - is unlikely this has ever been tested. */ - tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, core_id)); return NO_EXIT; } diff --git a/tests/Makefile.include b/tests/Makefile.include index fae5715e9c..abc6707ef2 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -366,6 +366,7 @@ check-qtest-s390x-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) check-qtest-s390x-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) +check-qtest-s390x-y += tests/drive_del-test$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) check-qtest-generic-y += tests/test-hmp$(EXESUF) @@ -561,7 +562,7 @@ QEMU_CFLAGS += -I$(SRC_PATH)/tests # Deps that are common to various different sets of tests below -test-util-obj-y = libqemuutil.a libqemustub.a +test-util-obj-y = libqemuutil.a test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y) test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ tests/test-qapi-event.o tests/test-qmp-introspect.o \ @@ -593,7 +594,7 @@ tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y) tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o migration/page_cache.o $(test-util-obj-y) -tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o +tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o $(test-util-obj-y) tests/test-int128$(EXESUF): tests/test-int128.o tests/rcutorture$(EXESUF): tests/rcutorture.o $(test-util-obj-y) tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o $(test-util-obj-y) @@ -616,9 +617,8 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/qemu-file-channel.o migration/qjson.o \ $(test-io-obj-y) tests/test-timed-average$(EXESUF): tests/test-timed-average.o $(test-util-obj-y) -tests/test-base64$(EXESUF): tests/test-base64.o \ - libqemuutil.a libqemustub.a -tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o libqemustub.a +tests/test-base64$(EXESUF): tests/test-base64.o $(test-util-obj-y) +tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o tests/test-logging$(EXESUF): tests/test-logging.o $(test-util-obj-y) @@ -767,7 +767,7 @@ tests/display-vga-test$(EXESUF): tests/display-vga-test.o tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o tests/test-hmp$(EXESUF): tests/test-hmp.o -tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-pc-obj-y) +tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o @@ -832,7 +832,8 @@ endif qtest-obj-y = tests/libqtest.o $(test-util-obj-y) $(check-qtest-y): $(qtest-obj-y) -tests/test-qga: tests/test-qga.o $(qtest-obj-y) +tests/test-qga$(EXESUF): qemu-ga$(EXESUF) +tests/test-qga$(EXESUF): tests/test-qga.o $(qtest-obj-y) SPEED = quick GTESTER_OPTIONS = -k $(if $(V),--verbose,-q) diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include index aaab1a4208..aa566aa223 100644 --- a/tests/docker/Makefile.include +++ b/tests/docker/Makefile.include @@ -34,7 +34,6 @@ $(DOCKER_SRC_COPY): @mkdir $@ $(call make-archive-maybe, $(SRC_PATH), $@/qemu.tgz) $(call make-archive-maybe, $(SRC_PATH)/dtc, $@/dtc.tgz) - $(call make-archive-maybe, $(SRC_PATH)/pixman, $@/pixman.tgz) $(call quiet-command, cp $(SRC_PATH)/tests/docker/run $@/run, \ "COPY","RUNNER") diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c index 2175139abb..c9ac997555 100644 --- a/tests/drive_del-test.c +++ b/tests/drive_del-test.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "libqos/virtio.h" static void drive_add(void) { @@ -65,14 +66,14 @@ static void test_after_failed_device_add(void) qtest_start("-drive if=none,id=drive0"); - /* Make device_add fail. If this leaks the virtio-blk-pci device then a + /* Make device_add fail. If this leaks the virtio-blk device then a * reference to drive0 will also be held (via qdev properties). */ response = qmp("{'execute': 'device_add'," " 'arguments': {" - " 'driver': 'virtio-blk-pci'," + " 'driver': 'virtio-blk-%s'," " 'drive': 'drive0'" - "}}"); + "}}", qvirtio_get_dev_type()); g_assert(response); error = qdict_get_qdict(response, "error"); g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError"); @@ -82,7 +83,7 @@ static void test_after_failed_device_add(void) drive_del(); /* Try to re-add the drive. This fails with duplicate IDs if a leaked - * virtio-blk-pci exists that holds a reference to the old drive0. + * virtio-blk device exists that holds a reference to the old drive0. */ drive_add(); @@ -91,10 +92,14 @@ static void test_after_failed_device_add(void) static void test_drive_del_device_del(void) { + char *args; + /* Start with a drive used by a device that unplugs instantaneously */ - qtest_start("-drive if=none,id=drive0,file=null-co://,format=raw" - " -device virtio-scsi-pci" - " -device scsi-hd,drive=drive0,id=dev0"); + args = g_strdup_printf("-drive if=none,id=drive0,file=null-co://,format=raw" + " -device virtio-scsi-%s" + " -device scsi-hd,drive=drive0,id=dev0", + qvirtio_get_dev_type()); + qtest_start(args); /* * Delete the drive, and then the device @@ -104,6 +109,7 @@ static void test_drive_del_device_del(void) device_del(); qtest_end(); + g_free(args); } int main(int argc, char **argv) @@ -114,9 +120,10 @@ int main(int argc, char **argv) qtest_add_func("/drive_del/without-dev", test_drive_without_dev); - /* TODO I guess any arch with PCI would do */ + /* TODO I guess any arch with a hot-pluggable virtio bus would do */ if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64") || - !strcmp(arch, "ppc") || !strcmp(arch, "ppc64")) { + !strcmp(arch, "ppc") || !strcmp(arch, "ppc64") || + !strcmp(arch, "s390x")) { qtest_add_func("/drive_del/after_failed_device_add", test_after_failed_device_add); qtest_add_func("/blockdev/drive_del_device_del", diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 9880a6964e..0879a621c8 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -339,3 +339,20 @@ void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx) /* vq->avail->used_event */ writew(vq->avail + 4 + (2 * vq->size), idx); } + +/* + * qvirtio_get_dev_type: + * Returns: the preferred virtio bus/device type for the current architecture. + */ +const char *qvirtio_get_dev_type(void) +{ + const char *arch = qtest_get_arch(); + + if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) { + return "device"; /* for virtio-mmio */ + } else if (g_str_equal(arch, "s390x")) { + return "ccw"; + } else { + return "pci"; + } +} diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 8fbcd1869c..0a04740adf 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -143,4 +143,7 @@ void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head); bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx); void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); + +const char *qvirtio_get_dev_type(void); + #endif diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c index 8a1b0a336c..ca5cc3b13b 100644 --- a/tests/ptimer-test-stubs.c +++ b/tests/ptimer-test-stubs.c @@ -30,6 +30,10 @@ QEMUTimerListGroup main_loop_tlg; int64_t ptimer_test_time_ns; +/* Do not artificially limit period - see hw/core/ptimer.c. */ +int use_icount = 1; +bool qtest_allowed; + void timer_init_tl(QEMUTimer *ts, QEMUTimerList *timer_list, int scale, QEMUTimerCB *cb, void *opaque) diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index 76d7205460..762fb9f42c 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -123,8 +123,7 @@ quit Testing: -drive if=ide QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Device needs media, but drive is empty -QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. +(qemu) QEMU_PROG: Initialization of device ide-hd failed: Device needs media, but drive is empty Testing: -drive if=scsi QEMU X.Y.Z monitor - type 'help' for more information @@ -146,12 +145,10 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive if=none,id=disk -device ide-drive,drive=disk QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty -QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. Testing: -drive if=none,id=disk -device ide-hd,drive=disk QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty -QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk QEMU X.Y.Z monitor - type 'help' for more information @@ -179,8 +176,7 @@ quit Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Block node is read-only -QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. +(qemu) QEMU_PROG: Initialization of device ide-hd failed: Block node is read-only Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on QEMU X.Y.Z monitor - type 'help' for more information @@ -202,12 +198,10 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-drive,drive=disk: Block node is read-only -QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device ide-hd,drive=disk: Block node is read-only -QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk QEMU X.Y.Z monitor - type 'help' for more information diff --git a/tests/qemu-iotests/172.out b/tests/qemu-iotests/172.out index 2732966166..7abbe82427 100644 --- a/tests/qemu-iotests/172.out +++ b/tests/qemu-iotests/172.out @@ -725,11 +725,9 @@ Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device fl Testing: -fda TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=0 QEMU_PROG: -device floppy,drive=none0,unit=0: Floppy unit 0 is in use -QEMU_PROG: -device floppy,drive=none0,unit=0: Device initialization failed. Testing: -fdb TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=1 QEMU_PROG: -device floppy,drive=none0,unit=1: Floppy unit 1 is in use -QEMU_PROG: -device floppy,drive=none0,unit=1: Device initialization failed. === Mixing -drive and -device === @@ -812,7 +810,6 @@ Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.q Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -device floppy,drive=none0,unit=0 QEMU_PROG: -device floppy,drive=none0,unit=0: Floppy unit 0 is in use -QEMU_PROG: -device floppy,drive=none0,unit=0: Device initialization failed. === Mixing -global and -device === @@ -971,18 +968,15 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qco Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveA=none0 -device floppy,drive=none1,unit=0 QEMU_PROG: -device floppy,drive=none1,unit=0: Floppy unit 0 is in use -QEMU_PROG: -device floppy,drive=none1,unit=0: Device initialization failed. Testing: -drive if=none,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -global isa-fdc.driveB=none0 -device floppy,drive=none1,unit=1 QEMU_PROG: -device floppy,drive=none1,unit=1: Floppy unit 1 is in use -QEMU_PROG: -device floppy,drive=none1,unit=1: Device initialization failed. === Too many floppy drives === Testing: -drive if=floppy,file=TEST_DIR/t.qcow2 -drive if=none,file=TEST_DIR/t.qcow2.2 -drive if=none,file=TEST_DIR/t.qcow2.3 -global isa-fdc.driveB=none0 -device floppy,drive=none1 QEMU_PROG: -device floppy,drive=none1: Can't create floppy unit 2, bus supports only 2 units -QEMU_PROG: -device floppy,drive=none1: Device initialization failed. === Creating an empty drive with anonymous BB === @@ -1211,11 +1205,9 @@ Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physica Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,logical_block_size=4096 QEMU_PROG: -device floppy,drive=none0,logical_block_size=4096: Physical and logical block size must be 512 for floppy -QEMU_PROG: -device floppy,drive=none0,logical_block_size=4096: Device initialization failed. Testing: -drive if=none,file=TEST_DIR/t.qcow2 -device floppy,drive=none0,physical_block_size=1024 QEMU_PROG: -device floppy,drive=none0,physical_block_size=1024: Physical and logical block size must be 512 for floppy -QEMU_PROG: -device floppy,drive=none0,physical_block_size=1024: Device initialization failed. === Writethrough caching === diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index d1485128bd..2934305b2b 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "libqtest.h" -#include "block/scsi.h" +#include "scsi/constants.h" #include "libqos/libqos-pc.h" #include "libqos/libqos-spapr.h" #include "libqos/virtio.h" diff --git a/trace/control.c b/trace/control.c index 82d8989c4d..2769934bec 100644 --- a/trace/control.c +++ b/trace/control.c @@ -72,8 +72,8 @@ void trace_event_register_group(TraceEvent **events) if (likely(next_vcpu_id < CPU_TRACE_DSTATE_MAX_EVENTS)) { events[i]->vcpu_id = next_vcpu_id++; } else { - error_report("WARNING: too many vcpu trace events; dropping '%s'", - events[i]->name); + warn_report("too many vcpu trace events; dropping '%s'", + events[i]->name); } } event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1); diff --git a/trace/simple.c b/trace/simple.c index a221a3f703..e82018d923 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -15,6 +15,7 @@ #include "qemu/timer.h" #include "trace/control.h" #include "trace/simple.h" +#include "qemu/error-report.h" /** Trace file header event ID, picked to avoid conflict with real event IDs */ #define HEADER_EVENT_ID (~(uint64_t)0) @@ -405,7 +406,7 @@ bool st_init(void) thread = trace_thread_create(writeout_thread); if (!thread) { - fprintf(stderr, "warning: unable to initialize simple trace backend\n"); + warn_report("unable to initialize simple trace backend"); return false; } diff --git a/ui/keymaps.c b/ui/keymaps.c index fa00b82027..f9762d1497 100644 --- a/ui/keymaps.c +++ b/ui/keymaps.c @@ -26,6 +26,7 @@ #include "keymaps.h" #include "sysemu/sysemu.h" #include "trace.h" +#include "qemu/error-report.h" static int get_keysym(const name2keysym_t *table, const char *name) @@ -76,8 +77,8 @@ static void add_keysym(char *line, int keysym, int keycode, kbd_layout_t *k) { k->keysym2keycode[keysym] = keycode; } else { if (k->extra_count >= MAX_EXTRA_COUNT) { - fprintf(stderr, "Warning: Could not assign keysym %s (0x%x)" - " because of memory constraints.\n", line, keysym); + warn_report("Could not assign keysym %s (0x%x)" + " because of memory constraints.", line, keysym); } else { trace_keymap_add("extra", keysym, keycode, line); k->keysym2keycode_extra[k->extra_count]. @@ -141,7 +142,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, int keysym; keysym = get_keysym(table, keyname); if (keysym == 0) { - /* fprintf(stderr, "Warning: unknown keysym %s\n", line);*/ + /* warn_report("unknown keysym %s", line);*/ } else { const char *rest = line + offset + 1; int keycode = strtol(rest, NULL, 0); @@ -197,8 +198,7 @@ int keysym2scancode(void *kbd_layout, int keysym) if (keysym < MAX_NORMAL_KEYCODE) { if (k->keysym2keycode[keysym] == 0) { trace_keymap_unmapped(keysym); - fprintf(stderr, "Warning: no scancode found for keysym %d\n", - keysym); + warn_report("no scancode found for keysym %d", keysym); } return k->keysym2keycode[keysym]; } else { diff --git a/ui/spice-display.c b/ui/spice-display.c index 042292cc90..0963c7825f 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -850,7 +850,7 @@ static void qemu_spice_gl_unblock_bh(void *opaque) static void qemu_spice_gl_block_timer(void *opaque) { - fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n"); + warn_report("spice: no gl-draw-done within one second"); } static void spice_gl_refresh(DisplayChangeListener *dcl) diff --git a/util/cutils.c b/util/cutils.c index 1534682083..b33ede83d1 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -30,6 +30,7 @@ #include "qemu/iov.h" #include "net/net.h" #include "qemu/cutils.h" +#include "qemu/error-report.h" void strpadcpy(char *buf, int buf_size, const char *str, char pad) { @@ -601,7 +602,7 @@ int parse_debug_env(const char *name, int max, int initial) return initial; } if (debug < 0 || debug > max || errno != 0) { - fprintf(stderr, "warning: %s not in [0, %d]", name, max); + warn_report("%s not in [0, %d]", name, max); return initial; } return debug; diff --git a/util/main-loop.c b/util/main-loop.c index 2f48f41e62..7558eb5f53 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -32,6 +32,7 @@ #include "slirp/libslirp.h" #include "qemu/main-loop.h" #include "block/aio.h" +#include "qemu/error-report.h" #ifndef _WIN32 @@ -236,9 +237,8 @@ static int os_host_main_loop_wait(int64_t timeout) static bool notified; if (!notified && !qtest_enabled() && !qtest_driver()) { - fprintf(stderr, - "main-loop: WARNING: I/O thread spun for %d iterations\n", - MAX_MAIN_LOOP_SPIN); + warn_report("I/O thread spun for %d iterations", + MAX_MAIN_LOOP_SPIN); notified = true; } |